Create stop button with gwidgets2 to interrupt running function on Ubuntu - r

I am making a GUI for a R program which does some quite lengthy calculations while constantly updating plots on a gwidgets GUI. I would like to give the user the possibility to interrupt the calculations if they take too long. I am trying to use a stop button.
The problem is that while the function is running, the window is greyed out and none of the controls will respond, so it is not possible to click the stop button.
This problem only occurs when running the program on Ubuntu, I tested the script on Windows and it worked as expected.
Here's a minimal working example of my code illustrating what I am trying to do:
require(gWidgets2RGtk2)
require(gWidgets2)
stopsignal <- FALSE
w <- gwindow()
button_gp <- ggroup(cont=w)
gbutton("calculate", cont=button_gp, handler=function(...) calculate())
gbutton("stop", cont=button_gp, handler=
function(...) assign("stopsignal", TRUE , envir = .GlobalEnv))
calculate <- function() {
while(TRUE) {
#do something
print("Hello World")
if(stopsignal) break
}
}
I am trying to understand why Ubuntu is behaving differently and how I can fix it.

Related

Rstudio -- graphics locator() gets stuck under manipulate()

I'm QC-ing a large dataset using RStudio. I'm viewing chunks of it using a graphics montage made using regular R graphics, with some manipulate() controls to control the subsetting. When I see something funny on a display, I want to pick some XY coordinate pairs (NOT data points, but in the same space), hit the Finish button provided by locator() to capture my picks, then go back to browsing. In this way I am building up a set of picked XY locations for further processing.
So my manipulate() controls are mostly subsetting parameters, but I also have a button called Pick Points to enter locator() mode.
This almost works, but when I hit Finish to terminate locator(), things don't quite work right. locator() finishes and returns a list of coordinate arrays as expected, but the graphics display stays in locator() crosshair mode and the Finish button persists. Any further clicks or Finish button clicks provoke an error popup Method not found.
I can right-mouse on the graph and Reload to reset things without hurting the running program or my saved data, but it's a bit distracting.
Here's a minimal example that provokes the bug.
demonstrateBug <- function() {
manipulate(
{
if( pickData ){
locData <- locator()
nPoint <- length( locData$x )
message( " ... Picked ", nPoint, " points" )
} else {
plot( runif(10), runif(10) )
}
},
pickData = button("Pick Points")
)
}
I've tried Google but there are very few references to the specific combination of manipulate() and locator(), and nothing about a bug like this.
locator() works OK from the RStudio console when run against a manipulate()-enhanced graphics plot, but that won't do what I want.
If I give locator() a fixed number of points, it returns on cue, but the cross-hairs and button still persist. I don't want a fixed number of points, anyway.
Running R 3.1.2 RStudio 0.99.441 on OSX Yosemite
(I've never asked for help on this platform before, so I hope this all comes out right!)

Loading and saving variables in R with gWidgets

For the past few months I've been building a simulation in R I hope to package. It consists of two usable functions, and many internal ones which one of the two usable functions call while looping, to perform the stages of simulation.
A simple conceptual example is:
# Abstract representation 1st Usable function, generates object containing settings for simulation.
settings <- function(){
matrix(c(1:4),nrow=2,ncol=2)
}
# Abstract representation of one of many internal functions, does some action in simulation.
int.func <- function(x){
out <- x*2
return(out)
}
# Abstract representation of second usable function, takes settings & invokes internal functions generates results & saves as R object files.
sim.func <- function(x){
ans <- int.func(x)
ans2 <- ans-2
save(ans2, file="outtest")
}
With my package so far, using it is done like so after loading and attaching the package with library():
INPUT <- settings()
fix(settings) # If you want to change from the defaults.
sim.func(INPUT)
Nothing needs returning from the simulation function because results and data-dumps get saved as an object with save() commands and the objects can be read in afterwards.
Now I'd like it to have a simple GUI which can be used in conjunction with command line - think Rcmdr but much more simple, to allow my co-workes who have never touched R to use it.
The gui needs to be able to edit the settings - like with the fix command above, to save a settings object to file, and to read in setting from an object file. I've built this with gWidgets:
gui <- function(){
INPUT <- matrix(c(1:4),nrow=2,ncol=2)
mainwin <- gwindow("MainWindow")
button1 <- gbutton("Edit Settings", cont=mainwin, handler=
function(h,...){
fix(INPUT)
print("Settings Edited")
})
button2 <- gbutton("RUN", cont=mainwin, handler=
function(h,...){
sim.func(INPUT)
print("The run is done")
})
savebutton <- gbutton("Write Settings to File",cont=mainwin, handler=
function(h,...){
setfilename <- ginput("Please enter the filename")
save(INPUT, file=setfilename)
})
loadutton <- gbutton("Load Settings from File", cont=mainwin,
handler=function(h,...){
fname <- gfile(test="Choose a file",
type="open",
action="print",
handler =
function(h,...){
do.call(h$action, list(h$file))
}
)
load(fname)})
}
Note the job of the settings function from before is now done on the first line of this gui function.
I add this to the same R file as the three functions above, add gui to the namespace as an export, set gWidgets and gWidgetstcltk as imports, and rebuild, then I library() the package and do gui().
The interface shows up. However I have a few issues:
The gui shows up fine, but if I click button1 ("Edit Settings") to edit settings through fix(INPUT), change the values, close the editor and click the button again to see if the changes have persisted and been stored in INPUT, they have not.
Same goes for reading in an object, it does not overwrite the INPUT object generated by default in the first line of function gui().
I think this has something to do with environments of functions but I'm not too sure. In the gui-less version of my package, the user generates the object containing settings, which is in workspace and feeds it to the simulation function as an argument. However since with the gui version, everything is run inside the function gui() and gWidgets handlers makes use of functions(h,...) I can't help but feel as if environments are the issue here. It's odd that when clicking on button 1, it will find INPUT from the gui() environment, but won't make the changes back there.
Can anybody help out with this and suggest what it is I need to do?
Apologies for a long question, but I've tried to explain clearly. Code is reproducible, as is the issue, just by having library(gWidgets, gWidgetstcltk)
and copying and pasting the code I've provided here, to define the functions and then running gui(). Then click the "Edit Settings" button, change the cells, exit, then click the button again to see if the changes persisted (they don't). The abstract example I've provided faithfully reproduces the same issues I have with my proper simulation functions so if I can't get it working, I won't get the real thing working.
Thanks,
Ben W.
UEA
The Sainsbury Laboratory.
[EDIT] Here is a fix/workaround using .GlobalEnv:
gui <- function(){
INPUT <- matrix(c(1:4),nrow=2,ncol=2)
.GlobalEnv$INPUT <- INPUT
mainwin <- gwindow("MainWindow")
button1 <- gbutton("Set", cont=mainwin, handler=
function(h,...){
INPUT <- .GlobalEnv$INPUT
fix(INPUT)
print("Settings have been edited...")
})
button2 <- gbutton("RUN", cont=mainwin, handler=
function(h,...){
sim.func(.GlobalEnv$INPUT)
print("The run is done")
})
writebutton <- gbutton("Write Settings to File",cont=mainwin, handler=
function(h,...){
setfilename <- ginput("Please enter the filename")
INPUT <- .GlobalEnv$INPUT
save(INPUT, file=setfilename)
})
loadutton <- gbutton("Load Settings from File", cont=mainwin,
handler=function(h,...){
fname <- gfile(test="Choose a file",
type="open",
action="print",
handler =
function(h,...){
do.call(h$action, list(h$file))
}
)
load(fname)
.GlobalEnv$INPUT <- INPUT})
}

How Do I Stop An R gWidgets Script Exiting

I am using the gWidgets toolkit to create a GUI in an R script that is run using Rscript.
When the GUI is created, the script exits.
I can prevent this with a while(TRUE){Sys.sleep(9999)} loop at the end of the script but that seems hacky.
Is there a better way of telling R to exit only when the GUI is closed, or at least to enter the REPL once the GUI is constructed?
You might be able to adapt gbasicdialog for your needs. This constructor creates a modal container from which you can spawn other windows. Here is an example:
library(gWidgets)
options(guiToolkit="RGtk2")
require(fortunes) # just for fun
hold_it <- gbasicdialog(do.buttons=FALSE)
b <- gbutton("click me for a message", cont=hold_it, handler=function(h,...) {
gmessage(paste(fortune(), collapse="\n"), parent=hold_it)
})
visible(hold_it, TRUE)
The same works for the "tcltk" toolkit. It uses pretty much what Greg suggests can be done.
This subject may be closed but as a newbie to gwidgets, I have been confronted with. The solution given by jverzani is obviously a solution. I have chosen another one, not using any supplementary dialog, just because I don't want one, no other reason at all...
In the handler of the gwindow, after disposal I remove the variable from the environment:
handler = function(h,...) {dispose(EDFAnalysis$w); rm(w,envir=EDFAnalysis)}
where EDFAnalysis is the environment of my script... and w is the main gwindow.
Then, at the end of my script I added:
while(exists("w",EDFAnalysis)){Sys.sleep(5)}
of course, smaller value than 5 or greater value can be used. In my case, 5 s is sufficient and not for ever... :-)
The standard way of dealing with this is to request user input to continue. This one-liner will do the trick.
EDIT: readline only works under interactive use, so I've swapped it for scan, which is a little less pretty.
pause_for_input <- function()
{
message("Press ENTER to continue")
invisible(scan(n = 0, quiet = TRUE))
}
So you script should look like
#Create you GUI
#Whatever else
pause_for_input()
If you are using the tcltk package instead of gWidgets then you could possibly use the tkwait.window function from tcltk to tell the script to wait until the gui window goes away before continuing the script.
A good way to do it, I've found, is to use the gtkMain() function in the RGtk2 library. This simply keeps the main loop running until gtkMainQuit() is called.
For completeness: ozjimbob already gave the answer for a most "clean" way how to do it.
The answer of ffeschet did not work with me, neither on Unix nor on Windows.
Hence, in the main "launching" script, you have to at least have these entries:
options("guiToolkit"="RGtk2")
library(RGtk2)
library(gWidgets)
library(gWidgetsRGtk2)
StartMyGUI()
gtkMain()
In the "child" process "StartMyGUI()", your code could e.g. look like this:
StartMyGUI <- function(handler=function(h,...) {
dispose(h$obj)
}) {
window <- gwindow("Hello")
group <- ggroup(container = window)
glabel("Hello World!", container=group, expand=TRUE)
# A group to organize the buttons
button.group <- ggroup(container = group)
# Push buttons to right
addSpring(button.group)
gbutton("OK", handler=handler, container=button.group)
gbutton("Cancel", handler = function(h,...) {
dispose(window)
gtkMainQuit()
},
container=button.group)
return()
}
It is only when the user hits the "Cancel" button that gtkMainQuit() will be called, which exits the mother process in the main "launching" script.

Make R (statistics package) wait for keyboard prompt when run within a bash script

I am using R to generate a series of plots within a loop, with the user hitting the enter key to indicate they have seen the plot and it is time to move on. These are interactive rotatable plots generated with the rgl package and therefore using something like Sys.sleep() is not good enough.
Currently I can use readline() which works find when running R interactively. However, if I want to run my R script within a bash script all the plots appear flashing before the screen. This happens whether I call R using:
R --no-save -f myfile.r
R --no-save -e "source('myfile.r')"
R --no-save << myfile.r
How do I get R to pause and wait for the user to hit when run as a bash subprocess?
Use this:
readLines("stdin", n = 1)
That will get the real stdin instead of what stdin() uses.
I'd invoke it with:
Rscript myfile.r
It's a late answer but my goal was similar: Rscript execution should bring up an rgl window with a plot and nothing else, and it should remain there till the window is closed, i.e. the rgl window should not terminate.
To achieve this, I simply placed this at the end of the R script, and the rgl plot will remain there for manipulation until you quit the window, consuming little CPU time:
play3d(function(time) {Sys.sleep(0.01); list()} )
For regular 2D R plots, locator() works similarly, or locator(1) if one click should close the plot window.
I'm not sure if there is an easy way to wait a keyboard input, but at least you can wait mouse click.
Not elegant but try this script:
quartz() # or maybe windows() in windows
for (i in 1:5) {plot(i, i); locator(1)}
Here is an example script that works for me (tested your first calling method on windows). It uses the tcltk package and creates an extra, small window with a single button, the script will pause (but still allow you to interact with the rgl window) until you either click on the 'continue' button on press a key while that window is active, then continue with the script.
library(tcltk)
library(rgl)
mywait <- function() {
tt <- tktoplevel()
tkpack( tkbutton(tt, text='Continue', command=function()tkdestroy(tt)),
side='bottom')
tkbind(tt,'<Key>', function()tkdestroy(tt) )
tkwait.window(tt)
}
x <- rnorm(10)
y <- rnorm(10)
z <- rnorm(10)
plot3d(x,y,z)
mywait()
x <- rnorm(100)
y <- rnorm(100)
z <- rnorm(100)
plot3d(x,y,z)
mywait()
cor(x,y)
plot.lm uses devAskNewPage(TRUE); perhaps that would also work here.

Making a series of plots that proceed by a click

In the example below I would like to be able to control when I go to the next plot by a using mouse click (or keyboard entry)
for (i in 1:5){
plot(1:i)
Sys.sleep(1)
#add something here that requests mouse click to proceed
}
Is this possible? There is a setting in the X11() help file caled 'clickToConfirm' but I can't work out what that does.
It would also be helpful to me to be to be able to scroll back and forth through plots using the arrow keys. Is this possible?
Currently if I need to look at lots of plots I output them into a big .pdf file and scroll though them all there, but that is a bit cumbersome.
Thanks
Tom
In R, that would be done by setting par(ask=TRUE). Try the following code, which shows how to reset the par when exiting the function :
op <- par(ask=TRUE)
for (i in 1:5){
plot(1:i)
}
par(op)
If you want to keep a history to browse through, you can either open a window and click on recording in the History menu, or you can open the window yourself with the history on. Demonstrated in a function :
plot.fun <- function(){
windows(record=TRUE) # opens a window and starts recording
op <- par(ask=TRUE)
on.exit(par(op))
for (i in 1:5){
plot(1:i)
}
windows.options(record=FALSE) #stops recording.
}
plot.fun()
This will however keep all previous plots in the history for browsing as well, so if you run this code 3 times you'll have 15 plots in the plot history. Also note that the open plot window will keep on recording until you turn off the recording in the menu.
You can play with the plot history, as you'll have a variable .SavedPlots which contains the saved plot history. It can be cleared using the menu History > clear history in the plot window. If you want to clear the history from the console, you could hack that by
.SavedPlots <- NULL
But I advise you not to do this, as changing the .SavedPlots variable can cause R to crash.
See also ?windows and ?recordPlot for a bit more information. But as you're getting close to the internal code of R, be warned that you can get pretty awkward behaviour if you start playing around with these things.
For scrolling back and forth between plots using the arrow keys: it depends on the platform/R interface.
Windows: there is a recording function (see Q5 of the R for Windows FAQ) which uses Page Up/Page Down
MacOS: under the standard GUI, the Quartz window has Apple-left and Apple-right arrow
under the standard Unix (no-GUI) interface, things are more limited. You can use RStudio (which has a lot of buzz right now) ... I would have thought that JGR would have plot history as well, but it doesn't seem to ...
You can use locator - now plots change on click
for (i in 1:5){
plot(1:i)
locator(1)
}

Resources