Creating GUIs in R with gWidgets
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
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)
Tagged: gui, gWidgets, r
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.