Nothing
## GUI for exploring a data set using ggplot2
## Needs some -- alot of -- work! better representation, DRY is violated, passing parameters to
## ggplot2 commands, ...
GUIdescription <- paste("An example GUI for exploring ggplot2 commands that illustrates:",
"the gcombobox with icons and tooltips,",
"dynamically adding widgets;",
"the gexpandgroup container for space management;",
"and gsvg for displaying graphics.",
"Not all the ggplot commands work, including some that should.",
"This seems to be an issue with the device driver not being happy with",
"certain labels.",
sep=" ")
## we want to quiet down the loading of packages
require(reshape, quietly=TRUE, warn=FALSE)
require(plyr, quietly=TRUE, warn=FALSE)
require(grid, quietly=TRUE, warn=FALSE)
require(ggplot2, quietly=TRUE, warn=FALSE)
##################################################
## gpplot setup
## Get Geoms, Stat, Scale, Coord
types <- c("Geom", "Stat","Scale","Coord")
## function to convert GeomBoxplot <-> geom_boxplot
upperToLower <- function(x) {
for(i in types) {
if(length(grep(paste("^",i, sep=""), x))) {
x <- gsub(paste("^",i, sep=""),"",x)
return(paste(tolower(i),tolower(x), sep="_"))
}
}
return(x)
}
lowerToUpper <- function(x) {
.simpleCap <- function(x) {
s <- strsplit(x, " ")[[1]]
paste(toupper(substring(s, 1,1)), substring(s, 2),
sep="", collapse=" ")
}
tmp <- unlist(strsplit(x,"_"))
if(length(tmp) > 1)
return(paste(.simpleCap(tmp[1]),.simpleCap(tmp[2]), sep=""))
else
return(tmp)
}
Units <- list()
for(i in types)
Units[[i]] <- apropos(paste("^",i, sep=""), ignore.case=FALSE)[-1]
## scales are done differently
Units$scales <- apropos("^scale_x",ignore.case=FALSE)
Units$Scales <- lowerToUpper(gsub("_x","",Units$scales))
## make icons if not there
iconFiles <- list()
for(type in types) {
iconFiles[[type]] <- Units[[type]]
for(i in seq_along(Units[[type]])) {
f <- getStaticTmpFile(ext="png", Units[[type]][i])
if(!file.exists(f)) {
obj <- get(Units[[type]][i])
png(f, width=16, height=16)
grid.newpage()
out <- try(grid.draw(obj$icon()), silent=TRUE)
dev.off()
if(inherits(out,"try-error"))
f <- ""
}
iconFiles[[type]][i] <- f
}
addStockIcons(Units[[type]], sapply(iconFiles[[type]], convertStaticFileToUrl))
}
##################################################
## our data set (was baseball from plyr, but too large for an example)
data("Cars93", package="MASS")
bb <- Cars93
w <- gwindow("ggplot2 GUI")
g <- ggroup(cont = w, horizontal=FALSE)
if(!require(ggplot2) || !require(RSVGTipsDevice)) {
glabel("This demo requires the ggplot2 and RSVGTipsDevice packages", cont=g)
} else {
g1 <- ggroup(cont=g, width=700)
ghtml(GUIdescription, cont = g1)
gseparator(cont = g)
hg <- ggroup(horizontal=TRUE, cont = g)
lg <- ggroup(horizontal=FALSE, cont = hg, width=450)
rg <- ggroup(horizontal=FALSE, cont = hg, width=600)
width <- 580; height <- 500
devs <- list()
imageFile <- getStaticTmpFile(ext=".svg")
imageDevice <- gsvg(cont = rg, expand=TRUE, width=width, height=height)
## for ggplot we have commands such as
glabel("p <- ggplot(Cars93) + ", cont = lg)
##################################################
## aesthetics, should be more here
f <- gexpandgroup("aes: specify x and y aesthetics.", cont = lg)
aesWidgets <- list()
tbl <- glayout(cont = f)
tbl[1,1] <- "x"
tbl[1,2] <- (aesWidgets[["x"]] <- gcombobox(c("",names(bb)), editable=TRUE, cont = tbl, selected=0))
tbl[2,1] <- "y"
tbl[2,2] <- (aesWidgets[["y"]] <- gcombobox(c("",names(bb)), editable=TRUE, cont = tbl, selected=0))
## Geoms
f <- gexpandgroup("Geoms: specify geometric object(s) to plot", cont = lg)
GeomCb <- list()
GeomDf <- data.frame(values = c("", upperToLower(Units$Geom)),
icon = c("GeomBlank", Units$Geom),
qtip = c("", sapply(Units$Geom, function(i) {
obj <- getFromNamespace(i, ns="ggplot2")
obj$desc
})),
stringsAsFactors=FALSE)
makeGeomSelector <- function(f) {
g1 <- ggroup(cont = f)
glabel("+ ", cont = g1)
n <- length(GeomCb)
GeomCb[[n+1]] <<- list()
GeomCb[[n+1]]$widget <<- gcombobox(GeomDf, selected=0, cont = g1, handler = function(h,...) {
out <- sapply(GeomCb, function(i) svalue(i$widget))
if(!any(sapply(out, function(i) i == "")))
makeGeomSelector(f)
})
GeomCb[[n+1]]$aes <<- list()
gbutton("aes", cont = g1, action = n + 1, handler = function(h,...) {
n <- h$action
val <- svalue(GeomCb[[n]]$widget)
val <- lowerToUpper(val)
if(val != "") {
pobj <- getFromNamespace(val, ns="ggplot2")
needThese <- setdiff(pobj$required_aes, c("x","y"))
if(is.null(needThese) || length(needThese) == 0) {
gmessage("Nothing to configure", parent=w) ## galert gets buried
return()
} else {
val <- paste(needThese, collapse=" ")
}
}
w1 <- gwindow("Edit aes options", parent=w)
g <- ggroup(cont = w1, horizontal=FALSE)
glabel("This is not working!", cont = g)
tbl <- glayout(cont = g)
lst <- list()
for(i in seq_along(needThese)) {
val <- needThese[i]
tbl[i,1] <- val
tbl[i,2] <- (lst[[val]] <- gedit("", cont = tbl))
if(!is.null(tmp <- GeomCb[[n]]$aes[[val]]) && nchar(as.character(tmp))) { # update if present
svalue(lst[[val]]) <- tmp
}
}
gseparator(cont = g)
g1 <- ggroup(cont = g)
gbutton("dismiss", cont = g1, handler = function(h,...) dispose(w1))
gbutton("ok", cont = g1, handler=function(h,...) {
vals <- lapply(lst, svalue)
GeomCb[[n]]$aes <<- vals
dispose(w1)
})
visible(w1) <- TRUE
})
}
makeGeomSelector(f)
##################################################
## Stats
f <- gexpandgroup("Stats: specify data transformations", cont = lg); visible(f) <- FALSE
StatCb <- list()
StatDf <- data.frame(values = c("", upperToLower(Units$Stat)),
icon = c("GeomBlank", Units$Stat),
qtip = c("", sapply(Units$Stat, function(i) {
obj <- getFromNamespace(i, ns="ggplot2")
obj$desc
})),
stringsAsFactors=FALSE)
makeStatSelector <- function(f) {
g1 <- ggroup(cont = f)
glabel("+ ", cont = g1)
n <- length(StatCb)
StatCb[[n+1]] <<- list()
StatCb[[n+1]]$widget <<- gcombobox(StatDf, cont = g1, handler = function(h,...) {
out <- sapply(StatCb, function(i) svalue(i$widget))
if(!any(sapply(out, function(i) i == "")))
makeStatSelector(f)
})
}
makeStatSelector(f)
##################################################
## Coord
f <- gexpandgroup("Coords: adjust coordinate mappings", cont = lg); visible(f) <- FALSE
CoordCb <- list()
CoordDf <- data.frame(values = c("", upperToLower(Units$Coord)),
icon = c("GeomBlank", Units$Coord),
qtip = c("", sapply(Units$Coord, function(i) {
obj <- getFromNamespace(i, ns="ggplot2")
obj$desc
})),
stringsAsFactors=FALSE)
makeCoordSelector <- function(f) {
g1 <- ggroup(cont = f)
glabel("+ ", cont = g1)
n <- length(CoordCb)
CoordCb[[n+1]] <<- list()
CoordCb[[n+1]]$widget <<- gcombobox(CoordDf, cont = g1, handler = function(h,...) {
out <- sapply(CoordCb, function(i) svalue(i$widget))
if(!any(sapply(out, function(i) i == "")))
makeCoordSelector(f)
})
CoordCb[[n+1]]$aes <<- 1
}
makeCoordSelector(f)
##################################################
## Scale
f <- gexpandgroup("Scales: control mapping between data and aesthetics", cont = lg); visible(f) <- FALSE
## ScaleDf is different as x and y are needed
ScaleCb <- list()
ScaleDf <- matrix(character(2*length(Units$scales)*3 + 3), ncol=3)
ScaleDf[1,] <- c("","GeomBlank","Empty value")
for(i in seq_along(Units$scales)) {
ScaleDf[2*i,1] <- Units$scales[i]
ScaleDf[2*i + 1 ,1] <- gsub("_x","_y",Units$scales[i])
ScaleDf[(2*i):(2*i+1), 2] <- Units$Scale[i]
ScaleDf[(2*i):(2*i+1), 3] <- getFromNamespace(Units$Scale[i], ns="ggplot2")$desc
}
ScaleDf <- as.data.frame(ScaleDf, stringsAsFactors=FALSE)
makeScaleSelector <- function(f) {
g1 <- ggroup(cont = f)
glabel("+ ", cont = g1)
n <- length(ScaleCb)
ScaleCb[[n+1]] <<- list()
ScaleCb[[n+1]]$widget <<- gcombobox(ScaleDf, cont = g1, editable=TRUE, handler = function(h,...) {
out <- sapply(ScaleCb, function(i) svalue(i$widget))
if(!any(sapply(out, function(i) i == "")) && length(ScaleCb) < 2)
makeScaleSelector(f)
})
ScaleCb[[n+1]]$aes <<- 1
}
makeScaleSelector(f)
gseparator(cont = lg)
b <- gbutton("Make plot", cont = lg, handler = function(h,...) makePlots())
## clean up
rm("bb") # dont' store in session
}
gstatusbar("Powered by RApache and gWidgetsWWW", cont = w)
visible(w) <- TRUE
##' function to make plots
makePlots <- function() {
require(reshape, quietly=TRUE, warn=FALSE)
require(plyr, quietly=TRUE, warn=FALSE)
require(grid, quietly=TRUE, warn=FALSE)
require(ggplot2, quietly=TRUE, warn=FALSE)
data("Cars93", package="MASS")
bb <- Cars93
l <- list()
for(i in names(aesWidgets)) {
val <- svalue(aesWidgets[[i]])
if(val != "")
l[[i]] <- val
}
p <- ggplot(bb) +
do.call("aes_string",l)
geoms <- Units$Geom
for(i in GeomCb) {
val <- svalue(i$widget)
if(is.character(val) && nchar(val)) {
type <- geoms[lowerToUpper(val) == geoms] # check that we match
if(length(type)) {
l <- list()
if(length(i$aes)) {
lst <- lapply(i$aes, function(j) {
if(is.na(j) || is.null(j) || nchar(as.character(j))== 0 || !is.character(j))
NULL
else
i
})
if(length(lst)) {
## XXX This isn't working -- FIX ME
l$aes <- do.call("aes_string", lst[-1])
}
}
p <- p + do.call(val, l)
}
}
}
## Stats
stats <- Units$Stat
for(i in StatCb) {
val <- svalue(i$widget)
if(is.character(val) && nchar(val)) {
type <- stats[lowerToUpper(val) == stats] # check that we match
if(length(type)) {
p <- p + do.call(val, list()) # do aes
}
}
}
## Coord
coords <- Units$Coord
for(i in CoordCb) {
val <- svalue(i$widget)
if(is.character(val)) {
type <- coords[lowerToUpper(val) == coords] # check that we match
if(length(type)) {
p <- p + do.call(val, list()) # do aes
}
}
}
## Scales
scales <- Units$scale
scales <- c(scales, gsub("_x","_y",scales))
for(i in ScaleCb) {
val <- svalue(i$widget)
if(is.character(val) && nchar(val)) {
type <- scales[val == scales] # check that we match
if(length(type)) {
p <- p + do.call(val, list()) # do aes
}
}
}
## make images
require(RSVGTipsDevice, quietly=TRUE, warn=FALSE)
if(file.exists(imageFile))
unlink(imageFile) # out with the old ...
imageFile <- getStaticTmpFile(ext="svg")
devSVGTips(imageFile)
out <- try(print(p), silent=TRUE)
dev.off()
if(inherits(out, "try-error")) {
assign("error", p, envir=.GlobalEnv)
gmessage(out, parent=w)
} else {
## update graphic
svalue(imageDevice) <- convertStaticFileToUrl(imageFile)
}
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.