Creating GUIs in R with gWidgets
The gWidgets framework is a way of creating graphical user interfaces in a toolkit independent way. That means that you can choose between tcl/tk, Gtk, Java or Qt underneath the bonnet. There’s also a web-version based upon RApache and ExtJS. Since the code is the same in each case, you can change your mind and swap toolkits at a later date, without having to rewrite everything. Different versions of the toolkit are in different states of development; Gtk is the most complete, but the tcl/tk and Java versions are usable. The Web version has had a recent rewrite, which I haven’t used so I can’t vouch for it’s status. Finally, the Qt version is still experimental (and not yet available on CRAN). Personally, I use the tcl/tk version, since all the necessary components ship with the Windows edition of R.
The framework is fairly high level, making it quick for prototyping user interfaces. The drawback is that you don’t get quite as much control over the styling of your interface. If you need finer control, you may prefer one of the lower level packages: RGtk2, tcltk or rJava. In those cases, you will lose the toolkit independence.
To learn how gWidgets works, we’ll build a dialog box with controls to upload a tab delimited file. To begin, we load the necessary packages.
library(gWidgets) library(gWidgetstcltk) #or gWidgetsGtk2 or gWidgetsrJava or gWidgetsWWW or gWidgetsQt
The textboxes and checkboxes and so forth that we need are known as widgets (hence “gWidgets”). They need to be contained inside a window, which we create using the function gwindow.
win <- gwindow("Tab delimited file upload example")
By default, the widgets will be stacked up vertically. We can create groups of widgets that are stacked horizontally with ggroup(which is a widget in itself). Notice that all widgets must specify their container; in this case it’s just the window.
grp_name <- ggroup(container = win)
A glabel is a widget that represents a text label. Notice that it is contained inside the group we just created.
lbl_data_frame_name <- glabel( "Variable to save data to: ", container = grp_name )
A gedit is a single line textbox. (Not to be confused with a gtext, which is a multiline textbox.)
txt_data_frame_name <- gedit("dfr", container = grp_name)
Another horizontal group, for the upload button.
grp_upload <- ggroup(container = win)
For widgets that we want to respond to an action, we need to add a handler argument. This is always a function accepting a list as its first argument (named h by convention), and dots. The gbutton handler is called whenever the button is clicked. Don’t worry about the contents of the handler function for now; we’ll add them in a moment.
btn_upload <- gbutton(
text = "Upload tab delimited file",
container = grp_upload,
handler = function(h, ...)
{
# TODO!
}
)
Since tab delimited files can have decimal places represented as full-stops or commas (depending upon local conventions), we need a checkbox to choose between cases. We define a function to get the default value from the system locale settings. Conveniently, checkboxes have their own label built-in so we don’t need to create our own this time.
use_comma_for_decimal <- function()
{
unname(Sys.localeconv()["decimal_point"] == ",")
}
chk_eurostyle <- gcheckbox(
text = "Use comma for decimal place",
checked = use_comma_for_decimal(),
container = grp_upload
)
The last widget we’ll include is a status bar, so that users don’t have to refer back to the R main window for messages.
status_bar <- gstatusbar("", container = win)
Finally, here’s the content for the button handler. It creates a file open dialog box, which in turn has its own handler function. The action argument names the function to be applied to the file that is opened. The svalue function returns the “most useful thing” from a widget. For a checkbox, the svalue is whether or not it is checked. For a textbox or status bar, the svalue is its text. The filter argument populates the “Files of type” drop down list in the file open dialog.
function(h, ...)
{
gfile(
text = "Upload tab delimited file",
type = "open",
action = ifelse(svalue(chk_eurostyle), "read.delim2", "read.delim"),
handler = function(h, ...)
{
tryCatch(
{
data_frame_name <- make.names(svalue(txt_data_frame_name))
the_data <- do.call(h$action, list(h$file))
assign(data_frame_name, the_data, envir = globalenv())
svalue(status_bar) <-
paste(nrow(the_data), "records saved to variable", data_frame_name)
},
error = function(e) svalue(status_bar) <- "Could not upload data"
)
},
filter = list(
"Tab delimited" = list(patterns = c("*.txt","*.dlm","*.tab")),
"All files" = list(patterns = c("*"))
)
)
}
And there we have it.
If you’re feeling enthusiastic, see if you can adapt this to work with CSV files, or even better a general delimited file.
One last trick to finish the post: You can create a GUI interface to any function using ggenericwidget. Try
lmwidget <- ggenericwidget(lm)
Leave a Reply Cancel reply
Categories
Archives
- April 2013
- December 2012
- November 2012
- October 2012
- July 2012
- June 2012
- May 2012
- March 2012
- February 2012
- January 2012
- December 2011
- October 2011
- September 2011
- August 2011
- July 2011
- June 2011
- May 2011
- April 2011
- March 2011
- February 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- August 2010
Blogroll
Licensing

The non-code parts of 4D Pie Charts by Richard Cotton are licensed under a Creative Commons Attribution-NoDerivs 2.0 UK: England & Wales License. The code parts of the blog are licensed under the WTFPL v2.0.

Nicely illustrated Richie. Just want to clarify a bit about the different flavors of gWidgets: gWidgetsrJava is more or less not being maintained (it never had any demand for it); gWidgetsQt is just on r-forge and relies on qtbase which is also just on r-forge, and at this time isn’t working under windows, but once that is all ironed out gWidgetsQt should be on par with gWidgetsRGtk2 one. Finally, gWidgetsWWW isn’t quite the same, but close, and not only runs under RApache, will also run locally through the R help page server. Which means it doesn’t need to have a toolkit installed such as tcltk, RGtk2 or qtbase. (However, it is still in need of some users and the accompanying feedback to iron out issues.)
Richie, interesting post, even to a guy like me who has no programming skills. Which brings me to my question. I followed your last instruction concerning the generic widget function using “rpart”, a function w/in the rpart package for recursive partitioning. It seemed to work ( I want to say ‘compile’ from back in the day when they made me learn Fortan 77 – as in 1977). But how does the GUI get invoked? I don’t see anything in the documentation for ggenericwidget. I feebly tried the commands below. Thanks for any insight you can provide. Regards, Paul
> rpart.widget()
Error: could not find function “rpart.widget”
> rpart.widget
guiWidget of type: gGenericWidgetANY for toolkit: guiWidgetsToolkitRGtk2
Glad you liked the post, Paul. How the GUI gets invoked is a technical question best answered by John Verzani – to me it is more or less indistinguishable from magic. Having said that I think I can at least partly answer the rest of your question.
When you create your rpart gui with the command
rpart.widget <- ggenericwidget(rpart)then the window should appear automatically. If you close this window (by clicking the cross in the top right), then the variable
rpart.widgetremains in your workspace but AFAIK there is no way to view the window again without callingggenericwidgetagain.For regular windows (as created by
gwindow), you can show/hide them by callingvisible(my_window) <- TRUE/FALSEbut this functionality hasn’t been extended to ggenericwidgets yet.Note that some text editors regain focus after sending code to R, which can hide the GUI you’ve just created. Tinn-R does this by default, but you can turn it off via Options -> Applications -> R -> RGui -> Options -> Focus. And yes, it did take me a long time to find that.
Thanks, Richie. I was running the GUI RCommander, so I shut it off before using the ggenericwidget command. Still couldn’t get the window to appear, though. No beig deal, I was just playing around with it and don’t have any need really to work through the error. I’d be curious if it’s a really obvious fix, though. thanks, Paul
> rpart.gwidget lmwidget <- ggenericwidget(lm)
Error in objects$Name : $ operator is invalid for atomic vectors
rpart.gwidget lmwidget <- ggenericwidget(lm)In this line you have two things on the left hand side of the assignment, which is presumably a typo.
$ operator is invalid for atomic vectorsThis error message happens when you try to access vectors like they were lists. Compare
l <- list(foo = 1, bar = 2, baz = 3)
v <- c(foo = 1, bar = 2, baz = 3)
l["foo"]
v["foo"]
l$foo
v$foo
It’s hard to know what caused the error without a lot more context.
For invocation it should open,but for some reason doesn’t. I’ll have to check. In the meantime, you can work around this by passing in a top-level window for a container:
w <- gwindow("rpart example")
rp <- ggenericwidget(rpart, container=w)
–J
John, the container worked, thanks for the fix. Richie, thank you for your help. regards, Paul
this is awesomely terrific
That\’s a subtle way of tnhiking about it.