# 3D-Visualization of Geoelectric Resistivity Measurement Profiles
# Graphical User Interface
# Author: Anja Kleebaum
### load packages
library(geoelectrics)
require(tcltk)
library(tkrplot)
### looking for working directory and change working directory to location of this file
try(setwd(dirname(as.character(sys.calls()[[1]][2]))))
topLevelWindow <- tktoplevel()
tkwm.minsize(topLevelWindow, 400, 300)
tktitle(topLevelWindow) <-
'3D-Visualization of Geoelectric Resistivity Measurement Profiles'
### Load example when starting
data(sinkhole)
profiles <-
list(sinkhole@profiles[[1]], sinkhole@profiles[[2]], sinkhole@profiles[[3]])
selectedProfileNumber <- tclVar(1)
### Read Config File
getColorsForColorRamp <- function(colorRamp) {
switch(colorRamp,
'grey' = {
colors <- c('white', 'grey', 'black')
},
'multicolored' = {
colors <- c('blue', 'green', 'yellow', 'orange', 'red', 'purple')
})
colors
}
readSettingsFromFile <- function() {
if (file.exists('config')) {
config <- read.table('config')
pointsize <- as.character(config[1, 2])
colorRamp <- as.character(config[2, 2])
} else {
pointsize <- 10
colorRamp <- 'grey'
}
assign('pointsize', pointsize, envir = .GlobalEnv)
colors <- getColorsForColorRamp(colorRamp)
assign('colors', colors, envir = .GlobalEnv)
list(pointsize, colorRamp)
}
readSettingsFromFile()
###---Plotting functions in GUI---###
plotProcessedDataGui <- function(profile) {
try(tkgrid.remove(img))
img <- tkrplot(frameRight, function() {
plot(
profile,
dataType = 'processed',
withTopo = FALSE,
main = profile@title,
ylab = 'Depth [m]'
)
})
assign('img', img, envir = .GlobalEnv)
tkgrid(img)
}
levelplotProcessedDataGui <- function(profile) {
img <- levelplot(
profile,
dataType = 'processed',
withTopo = FALSE,
main = profile@title
)
assign('img', img, envir = .GlobalEnv)
print(img)
}
plotProcessedDataWithTopoGui <- function(profile) {
try(tkgrid.remove(img))
img <- tkrplot(frameRight, function() {
plot(profile, dataType = 'processed', withTopo = TRUE)
})
assign('img', img, envir = .GlobalEnv)
tkgrid(img)
}
levelplotProcessedDataWithTopoGui <- function(profile) {
img <- levelplot(profile, dataType = 'processed', withTopo = TRUE)
assign('img', img, envir = .GlobalEnv)
print(img)
}
levelplotRawDataGui <- function(profile) {
img <- levelplot(profile, dataType = 'raw', withTopo = FALSE)
assign('img', img, envir = .GlobalEnv)
print(img)
}
plotRawDataGui <- function(profile) {
try(tkgrid.remove(img))
img <- tkrplot(frameRight, function() {
plot(
profile,
dataType = 'raw',
withTopo = FALSE,
main = profile@title,
ylab = 'Depth [m]'
)
})
assign('img', img, envir = .GlobalEnv)
tkgrid(img)
}
createComboBoxForProfiles <- function(widget, onChangedSelection) {
items <- c()
for (profile in profiles) {
items <- c(items, profile@number)
}
selectedProfileNumber <<- tclVar(1)
try(tkdestroy(comboBox))
comboBox <- ttkcombobox(widget,
values = items,
textvariable = selectedProfileNumber,
width = 3)
assign('comboBox', comboBox, envir = .GlobalEnv)
tkbind(comboBox, '<<ComboboxSelected>>', function() {
onChangedSelection(as.integer(tclvalue(selectedProfileNumber)))
})
try(tkdestroy(comboBoxLabel))
comboBoxLabel <- tklabel(widget, text = 'Profile Number: ')
assign('comboBoxLabel', comboBoxLabel, envir = .GlobalEnv)
tkgrid(comboBoxLabel, sticky = 'w')
tkgrid(comboBox, sticky = 'w', pady = c(0, 10))
onChangedSelection(1)
}
adjustHeightGui <- function() {
adjustHeightDialog <- tktoplevel(topLevelWindow)
tktitle(adjustHeightDialog) <- 'Height Adjustment'
onChangedSelection <- function(selectedProfileNumber) {
}
createComboBoxForProfiles(adjustHeightDialog, onChangedSelection)
height <- tclVar(10)
entry <-
tkentry(adjustHeightDialog,
width = '10',
textvariable = height)
tkgrid(entry, tklabel(adjustHeightDialog, text = ' Meter'))
onOK <- function() {
tkdestroy(adjustHeightDialog)
tkfocus(topLevelWindow)
number <- as.integer(tclvalue(selectedProfileNumber))
profiles[[number]] <<-
adjustHeight(profiles[[number]], as.integer(tclvalue(height)))
}
tkgrid(tkbutton(adjustHeightDialog, text = 'OK', command = onOK))
}
###---GUI methods---####
settings <- function() {
settings <- readSettingsFromFile()
pointsize <- settings[[1]]
colorRamp <- settings[[2]]
settingsDialog <- tktoplevel(topLevelWindow)
tktitle(settingsDialog) <- 'Settings'
sliderValue <- tclVar(pointsize)
slider <- tkscale(
settingsDialog,
from = 0,
to = 20,
showvalue = T,
variable = sliderValue,
resolution = 1,
orient = 'horizontal'
)
tkgrid(tklabel(settingsDialog, text = 'Pointsize: '), slider)
colorRamps <- c('grey', 'multicolored')
colorRamp <- tclVar(colorRamp)
colorComboBox <-
ttkcombobox(
settingsDialog,
values = colorRamps,
textvariable = colorRamp,
width = 10
)
tkgrid(tklabel(settingsDialog, text = 'Color: '), colorComboBox)
onOK <- function() {
tkgrab.release(settingsDialog)
tkdestroy(settingsDialog)
tkfocus(topLevelWindow)
pointsize <- tclvalue(sliderValue)
assign('pointsize', pointsize, envir = .GlobalEnv)
colors <- getColorsForColorRamp(tclvalue(colorRamp))
assign('colors', colors, envir = .GlobalEnv)
# save settings to file
write.table(
c(
'Pointsize' = pointsize,
'ColorRamp' = tclvalue(colorRamp)
),
file = 'config',
quote = FALSE,
col.names = FALSE
)
}
tkgrid(tkbutton(settingsDialog, text = 'OK', command = onOK))
}
info <- function() {
tkmessageBox(
title = 'About this program',
message = ' Developed by Anja Kleebaum\n Thanks to Prof. Dr. Klaus Bitzer & Richard Regner',
icon = 'info',
type = 'ok'
)
}
# Save File
saveFile <- function(type) {
fileType = '{{Geoelectrics Project (R Workspace)} {.RData}} {{All files} *}'
save <- function(fileName) {
save.image(file = fileName, ascii = TRUE)
}
fileName <- as.character(tkgetSaveFile(filetypes = fileType))
if (!nchar(fileName)) {
tkmessageBox(message = 'No file was selected.')
} else {
save(fileName)
}
}
# Open Files
openFile <- function(type) {
switch(type,
'processed' = {
fileType = '{{XYZ Files} {.xyz}} {{All files} *}'
multiFiles <- TRUE
open <- function(fileName) {
}
},
'raw' = {
fileType = '{{Rawdata} {.dat}} {{Rawdata} {.txt}} {{All files} *}'
multiFiles <- TRUE
open <- function(fileName) {
}
},
'rdata' = {
fileType = '{{Geoelectrics Project (R Workspace)} {.RData}} {{All files} *}'
multiFiles <- FALSE
open <- function(fileName) {
load(fileName, envir = .GlobalEnv)
}
})
fileName <-
as.character(tkgetOpenFile(filetypes = fileType, multiple = FALSE))
if (!nchar(fileName)) {
tkmessageBox(message = 'No file was selected!')
} else {
open(fileName)
return(fileName)
}
}
# Update Project
updateProject <- function() {
updateProjectDialog <- tktoplevel(topLevelWindow)
tktitle(updateProjectDialog) <-
'Update geoelectrics project settings'
tkwm.minsize(updateProjectDialog, 700, 200)
onOK <- function() {
tkgrab.release(updateProjectDialog)
tkdestroy(updateProjectDialog)
tkfocus(topLevelWindow)
assign('profiles', profiles, envir = .GlobalEnv)
}
onChangedSelection <- function(selectedProfileNumber) {
try(tkdestroy(profileFrame))
profileFrame <- tkframe(updateProjectDialog,
relief = 'groove',
borderwidth = 0)
assign('profileFrame', profileFrame, envir = .GlobalEnv)
tkgrid(profileFrame)
processedDataLabel <-
tklabel(profileFrame, text = 'Processed data file:')
processedDataAddress <-
tclVar(profiles[[selectedProfileNumber]]@processedData@address)
processedDataEntry <-
tkentry(
profileFrame,
width = '60',
textvariable = processedDataAddress,
state = 'readonly'
)
processedDataButton <-
tkbutton(
profileFrame,
text = 'Change',
command = function() {
tclvalue(processedDataAddress) <- openFile('processed')
profiles[[selectedProfileNumber]]@processedData <-
new('ProcessedData', tclvalue(processedDataAddress))
assign('profiles', profiles, envir = .GlobalEnv)
}
)
tkgrid(processedDataLabel,
processedDataEntry,
processedDataButton)
rawLabel <-
tklabel(profileFrame, text = 'Raw data file:')
rawAddress <-
tclVar(profiles[[selectedProfileNumber]]@rawData@address)
rawEntry <-
tkentry(
profileFrame,
width = '60',
textvariable = rawAddress,
state = 'readonly'
)
rawButton <-
tkbutton(
profileFrame,
text = 'Change',
command = function() {
tclvalue(rawAddress) <- openFile('raw')
profiles[[selectedProfileNumber]]@rawData <-
new('RawData', tclvalue(rawAddress))
assign('profiles', profiles, envir = .GlobalEnv)
}
)
tkgrid(rawLabel, rawEntry, rawButton)
gpsLabel <- tklabel(profileFrame, text = 'GPS file:')
gpsAddress <-
tclVar(profiles[[selectedProfileNumber]]@gpsCoordinates@address)
gpsEntry <-
tkentry(
profileFrame,
width = '60',
textvariable = gpsAddress,
state = 'readonly'
)
gpsButton <-
tkbutton(
profileFrame,
text = 'Change',
command = function() {
tclvalue(gpsAddress) <- openFile('raw')
profiles[[selectedProfileNumber]]@gpsCoordinates <-
new('GpsCoordinates', tclvalue(gpsAddress))
assign('profiles', profiles, envir = .GlobalEnv)
}
)
tkgrid(gpsLabel, gpsEntry, gpsButton)
okButton <- tkbutton(profileFrame, text = 'OK', command = onOK)
tkgrid(
okButton,
sticky = 'e',
columnspan = 3,
pady = c(10, 10)
)
}
createComboBoxForProfiles(updateProjectDialog, onChangedSelection)
return(profiles)
}
modalDialog <- function(title,
question,
entryInit,
entryWidth = 20,
returnValOnCancel = 'ID_CANCEL') {
dialog <- tktoplevel()
tkwm.deiconify(dialog)
tkgrab.set(dialog)
tkfocus(dialog)
tkwm.title(dialog, title)
textEntryVarTcl <- tclVar(paste(entryInit))
textEntryWidget <- tkentry(dialog,
width = paste(entryWidth),
textvariable = textEntryVarTcl)
tkgrid(tklabel(dialog, text = ' '))
tkgrid(tklabel(dialog, text = question), textEntryWidget)
tkgrid(tklabel(dialog, text = ' '))
returnVal <- returnValOnCancel
onOK <- function() {
returnVal <<- tclvalue(textEntryVarTcl)
tkgrab.release(dialog)
tkdestroy(dialog)
tkfocus(topLevelWindow)
}
onCancel <- function() {
tkgrab.release(dialog)
tkdestroy(dialog)
tkfocus(topLevelWindow)
return(returnValOnCancel)
}
okButton <- tkbutton(dialog, text = ' OK ', command = onOK)
cancelButton <-
tkbutton(dialog, text = ' Cancel ', command = onCancel)
tkgrid(okButton, cancelButton)
tkgrid(tklabel(dialog, text = ' '))
tkfocus(dialog)
tkbind(dialog, '<Destroy>', function() {
tkgrab.release(dialog)
tkfocus(topLevelWindow)
})
tkbind(textEntryWidget, '<Return>', onOK)
tkwait.window(dialog)
return(returnVal)
}
dropCurrentProject <- function() {
returnVal <-
tkmessageBox(
message = 'Do you want to save before dropping current project?',
icon = 'question',
type = 'yesnocancel',
default = 'yes'
)
if (tclvalue(returnVal) == 'cancel') {
return()
}
else if (tclvalue(returnVal) == 'yes') {
saveFile('rdata')
}
}
newProject <- function() {
returnVal <-
tkmessageBox(
message = 'Do you want to save before dropping current project?',
icon = 'question',
type = 'yesnocancel',
default = 'yes'
)
if (tclvalue(returnVal) == 'cancel') {
return()
}
else if (tclvalue(returnVal) == 'yes') {
saveFile('rdata')
}
try(rm(profiles, envir = .GlobalEnv))
numberOfProfiles <-
modalDialog('Create a new geoelctrics project',
'Insert Number of Profiles',
1,
5)
profiles <- list()
for (i in 1:as.numeric(numberOfProfiles)) {
profiles[i] <- new('Profile',
number = i)
}
assign('profiles', profiles, envir = .GlobalEnv)
updateProject()
}
### menubar
topMenu <- tkmenu(topLevelWindow)
tkconfigure(topLevelWindow, menu = topMenu)
fileMenu <- tkmenu(topMenu, tearoff = FALSE)
editMenu <- tkmenu(topMenu, tearoff = FALSE)
plot2dMenu <- tkmenu(topMenu, tearoff = FALSE)
plot3dMenu <- tkmenu(topMenu, tearoff = FALSE)
helpMenu <- tkmenu(topMenu, tearoff = FALSE)
# cascaded menus
openFileMenu <- tkmenu(topMenu, tearoff = FALSE)
saveFileMenu <- tkmenu(topMenu, tearoff = FALSE)
plotRawDataMenu <- tkmenu(topMenu, tearoff = FALSE)
plotProcessedDataMenu <- tkmenu(topMenu, tearoff = FALSE)
plot3dSingle <- tkmenu(topMenu, tearoff = FALSE)
plot3dAll <- tkmenu(topMenu, tearoff = FALSE)
example <- tkmenu(topMenu, tearoff = FALSE)
tkadd(topMenu, 'cascade', label = 'File', menu = fileMenu)
tkadd(topMenu, 'cascade', label = 'Edit', menu = editMenu)
tkadd(topMenu, 'cascade', label = 'Plot 2D', menu = plot2dMenu)
tkadd(topMenu, 'cascade', label = 'Plot 3D', menu = plot3dMenu)
tkadd(topMenu, 'cascade', label = 'Help', menu = helpMenu)
tkadd(
fileMenu,
'command',
label = 'New Project',
command = function() {
newProject()
}
)
tkadd(
fileMenu,
'command',
label = 'Open Project',
command = function()
openFile('rdata')
)
tkadd(
fileMenu,
'command',
label = 'Save Project',
command = function()
saveFile('rdata')
)
tkadd(
fileMenu,
'command',
label = 'Update Project',
command = function()
updateProject()
)
tkadd(fileMenu, 'separator')
tkadd(
fileMenu,
'command',
label = 'Quit Program',
command = function() {
ReturnVal <-
tkmessageBox(
message = 'Do you want to save before quitting?',
icon = 'question',
type = 'yesnocancel',
default = 'yes'
)
if (tclvalue(ReturnVal) == 'cancel') {
return()
}
else if (tclvalue(ReturnVal) == 'yes') {
saveFile('rdata')
}
tkdestroy(topLevelWindow)
}
)
tkadd(
editMenu,
'command',
label = 'Plotting Settings',
command = function()
settings()
)
tkadd(editMenu, 'separator')
tkadd(
editMenu,
'command',
label = 'Height Adjustment',
command = function() {
adjustHeightGui()
}
)
tkadd(plot2dMenu, 'cascade', label = 'Rawdata', menu = plotRawDataMenu)
tkadd(plot2dMenu, 'cascade', label = 'After Inversion', menu = plotProcessedDataMenu)
tkadd(
plot3dMenu,
'command',
label = 'Single Profiles',
command = function()
plotProfileWithPlottingFunction(function(profile) {
plot3d(profile, psize = pointsize, col = colors)
})
)
tkadd(
plot3dMenu,
'command',
label = 'All Profiles',
command = function() {
for (i in 1:length(profiles)) {
plot3d(profiles[[i]], psize = pointsize, col = colors)
}
}
)
tkadd(helpMenu, 'cascade', label = 'Load Example', menu = example)
tkadd(helpMenu, 'separator')
tkadd(helpMenu, 'command', label = 'About Program', command = info)
plotProfileWithPlottingFunction <- function(plottingFunction) {
resetFrames()
onChangedSelection <- function(selectedProfileNumber) {
plottingFunction(profiles[[selectedProfileNumber]])
}
createComboBoxForProfiles(topLevelWindow, onChangedSelection)
}
tkadd(
plotRawDataMenu,
'command',
label = 'Points',
command = function()
plotProfileWithPlottingFunction(plotRawDataGui)
)
tkadd(
plotRawDataMenu,
'command',
label = 'Levels',
command = function()
plotProfileWithPlottingFunction(levelplotRawDataGui)
)
tkadd(
plotProcessedDataMenu,
'command',
label = 'Points',
command = function()
plotProfileWithPlottingFunction(plotProcessedDataGui)
)
tkadd(
plotProcessedDataMenu,
'command',
label = 'Levels',
command = function()
plotProfileWithPlottingFunction(levelplotProcessedDataGui)
)
tkadd(
plotProcessedDataMenu,
'command',
label = 'Points with Topography',
command = function()
plotProfileWithPlottingFunction(plotProcessedDataWithTopoGui)
)
tkadd(
plotProcessedDataMenu,
'command',
label = 'Levels with Topography',
command = function()
plotProfileWithPlottingFunction(levelplotProcessedDataWithTopoGui)
)
tkadd(
example,
'command',
label = 'Sinkhole',
command = function() {
data(sinkhole)
profiles <-
list(sinkhole@profiles[[1]], sinkhole@profiles[[2]], sinkhole@profiles[[3]])
assign('profiles', profiles, envir = .GlobalEnv)
}
)
### frames
resetFrames <- function() {
deleteFrame(frameLeft)
deleteFrame(frameRight)
frameLeft <- newFrame('frameLeft')
frameRight <- newFrame('frameRight')
assign('frameLeft', frameLeft, envir = .GlobalEnv)
assign('frameRight', frameRight, envir = .GlobalEnv)
return(tkgrid(frameLeft, frameRight))
}
deleteFrame <- function(frameName) {
tkdestroy(frameName)
}
newFrame <- function(frameName) {
frameName <<-
tkframe(topLevelWindow, relief = 'groove', borderwidth = 0)
}
# left frame
frameLeft <- newFrame('frameLeft')
tkgrid(tklabel(frameLeft, text = ''))
# right frame
frameRight <- newFrame('frameRight')
tkgrid(
tklabel(frameRight, text = 'Welcome to the Software for 3D-Presentation of 2D-Geoelectric Profiles')
)
# create frames
tkgrid(frameLeft, frameRight)
# don't terminate
#Sys.sleep(36000)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.