Dear all
I've been looking for a solution to this problem ever since I started
learning R, and I still haven't found one I'm comfortable with. And I
would rather avoid exporting and importing into a spreadsheet just for
this. I am looking for a data viewer/editor that could, among other
things:
- have a 'view' mode (not an 'edit only' mode, to avoid bugs or
unintended modifications)
- have a 'filter' view mode (not a data-modifying subset)
- have a 'sort' view mode (not a data-modifying sort operation)
- select multiple rows/cols
- select multiple individual cells
Here's a list of what I've found sofar:
- View()/Edit(): rudimentary interface; don't interact very well with
tcltk (Rcmdr) on Linux
- relimp::showData(): nice viewer, but too often too unstable; lacks
most of the features above
- tcltk2::tk2edit(): allows multiple row/col/cell selections; has no
'view' mode nor 'filter' or 'sort', and pops up scary errors whenever
'cancelling' changes
- rdataviewer: the interface is too exotic for my habits, and lacks
most of the features above
- RGtk2Extras::dfedit(): allows multiple cell selections and can
perform a 'sort' and displays several features in the c-menu; it is
quite slow on my system with 'iris', no 'view' mode; since it uses
RGtk2 it interacts very badly with tcltk (Rcmdr)
- playwith: features a nice viewer hidden in Labels > Select from
table, but it is awkwardly located, with no advanced features, and
RGtk2 based
- JGR/Deducer::data.viewer(): includes a nifty data editor, perhaps my
favourite from this list, but it is a bit awkward to use when using an
editor different than JGR (console monopolization); it also lacks a
'view' and 'filter' mode as well well as select multiple rows/cols; it
can sort, but not easily when outside JGR
Anything that I've missed? Regards
Liviu
Dear all
I've been looking for a solution to this problem ever since I started
learning R, and I still haven't found one I'm comfortable with. And I
would rather avoid exporting and importing into a spreadsheet just for
this. I am looking for a data viewer/editor that could, among other
things:
- have a 'view' mode (not an 'edit only' mode, to avoid bugs or
unintended modifications)
- have a 'filter' view mode (not a data-modifying subset)
- have a 'sort' view mode (not a data-modifying sort operation)
- select multiple rows/cols
- select multiple individual cells
Here's a list of what I've found sofar:
- View()/Edit(): rudimentary interface; don't interact very well with
tcltk (Rcmdr) on Linux
- relimp::showData(): nice viewer, but too often too unstable; lacks
most of the features above
- tcltk2::tk2edit(): allows multiple row/col/cell selections; has no
'view' mode nor 'filter' or 'sort', and pops up scary errors whenever
'cancelling' changes
- rdataviewer: the interface is too exotic for my habits, and lacks
most of the features above
- RGtk2Extras::dfedit(): allows multiple cell selections and can
perform a 'sort' and displays several features in the c-menu; it is
quite slow on my system with 'iris', no 'view' mode; since it uses
RGtk2 it interacts very badly with tcltk (Rcmdr)
- playwith: features a nice viewer hidden in Labels > Select from
table, but it is awkwardly located, with no advanced features, and
RGtk2 based
- JGR/Deducer::data.viewer(): includes a nifty data editor, perhaps my
favourite from this list, but it is a bit awkward to use when using an
editor different than JGR (console monopolization); it also lacks a
'view' and 'filter' mode as well well as select multiple rows/cols; it
can sort, but not easily when outside JGR
Anything that I've missed? Regards
Liviu
The following uses gWidgets to create something close to what you want. I didn't
add in the editing feature, but that can be had with gdf in place of gtable. (as
well, the filter and sort dialogs could be much improved) The gdf widget isn't
nearly as nice as the Deducer one or the RGtk2Extras one though.
liviu <- function(df,
container=gwindow(sprintf("Viewing %s", deparse(substitute(df)))),
...) {
##' return logical of length x
filterFun <- function(x, expr, ...) UseMethod("filterFun")
filterFun.default <- function(x, expr, ...) x %in% expr
filterFun.numeric <- function(x, expr, ...) x < as.numeric(expr) # modify
filterDialog <- function() {
dlg <- gbasicdialog("Filter by:", handler=function(h,...) {
val <- svalue(filterExpression)
var <- svalue(variableSelector)
if(var == "") {
## evaluate expression within df
ind <- with(tbl[], eval(parse(text=val)))
} else {
ind <- filterFun(tbl[][[var]], val)
}
if(is.logical(ind) && !any(is.na(ind)))
visible(tbl) <- ind
updateTbl()
})
## layout
gp <- ggroup(cont=dlg)
filterExpression <- gedit("", cont=gp)
variableSelector <- gcombobox(c("",names(df)), cont=gp)
## show
visible(dlg, set=TRUE)
}
sortDialog <- function() {
dlg <- gbasicdialog("Sort by:", handler=function(h,...) {
vars <- sortVars[,1]
if(length(vars) && !any(is.na(vars))) {
ind <- order(subset(df, select=vars),
decreasing=!svalue(sortOrder))
tbl[,] <- df[ind,]
visible(tbl) <- rep(TRUE, dim(tbl)[1])
updateTbl()
}
})
## layout
size(dlg) <- c(400,400)
nms <- data.frame(Variables=names(df), stringsAsFactors=FALSE)
nms1 <- data.frame("Sort by"=character(0), stringsAsFactors=FALSE)
ind <- c()
gp <- ggroup(cont=dlg)
allVars <- gtable(nms, cont=gp, expand=TRUE)
bg <- ggroup(horizontal=FALSE, cont=gp)
lbutton <- gbutton("<", cont=bg)
rbutton <- gbutton(">", cont=bg)
sortOrder <- gcheckbox("Increasing", checked=TRUE,
use.togglebutton=TRUE, cont=bg)
sortVars <- gtable(nms1, cont=gp, expand=TRUE)
addHandlerClicked(rbutton, function(h,...) {
vars <- svalue(allVars, index=TRUE)
if(!is.null(vars)) {
ind <<- c(ind, vars)
sortVars[,] <- nms[ind,]
}
})
addHandlerClicked(lbutton, function(h,...) {
vars <- svalue(sortVars, index=TRUE)
if(!is.null(vars)) {
ind <<- setdiff(ind, vars)
sortVars[,] <- nms[ind,]
}
})
## show
visible(dlg, set=TRUE)
}
## layout
g <- ggroup(cont=container, horizontal=FALSE)
tbl <- gtable(df, cont=g, expand=TRUE, multiple=TRUE,
filter.FUN="manual")
gp <- ggroup(cont=g)
gbutton("Filter", cont=gp, handler=function(h,...) {
filterDialog()
})
gbutton("Sort...", cont=gp, handler=function(h,...) {
sortDialog()
})
addSpring(gp)
caseLabel <- glabel("", cont=gp)
updateTbl <- function() {
## update label for no cases, ...
svalue(caseLabel) <- sprintf("%s cases", sum(visible(tbl)))
}
updateTbl()
tbl
}
## test it
tbl <- liviu(mtcars)