[R-gui] your favourite spreadsheet-like data viewer or editor?

j verzani jverzani at gmail.com
Tue Oct 26 22:29:29 CEST 2010


Liviu Andronic <landronimirc <at> gmail.com> writes:

> 
> 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)



More information about the R-SIG-GUI mailing list