--- title: "Edit a table with Shiny and rhandsontable" date: "2016-08-15" output: html_document --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) ``` With the help of the awesome `rhandsontable` package, I've done a Shiny app allowing to edit a data frame and to save the result in a file than can be loaded in R. I was greatly helped by an example given in the [github repo of this package](https://github.com/jrowen/rhandsontable). For example, take the following data frame: ```{r} ( DF <- data.frame(Value = 1:10, Status = TRUE, Name = LETTERS[1:10], Date = seq(from = Sys.Date(), by = "days", length.out = 10), stringsAsFactors = FALSE) ) ``` The app is launched by running the function `editTable` I will give below. Just take a look before: ```{r, eval=FALSE} editTable(DF, outdir="~/Documents/", outfilename="newDF") ```
Now I edit the table:
I click on the *Save* button and I get the ASCII file `newDF.txt` containing the new data frame: ```{r} dget("newDF.txt") ``` Here is my code: ```{r, eval=FALSE} library(rhandsontable) library(shiny) editTable <- function(DF, outdir=getwd(), outfilename="table"){ ui <- shinyUI(fluidPage( titlePanel("Edit and save a table"), sidebarLayout( sidebarPanel( helpText("Shiny app based on an example given in the rhandsontable package.", "Right-click on the table to delete/insert rows.", "Double-click on a cell to edit"), wellPanel( h3("Table options"), radioButtons("useType", "Use Data Types", c("TRUE", "FALSE")) ), br(), wellPanel( h3("Save table"), div(class='row', div(class="col-sm-6", actionButton("save", "Save")), div(class="col-sm-6", radioButtons("fileType", "File type", c("ASCII", "RDS"))) ) ) ), mainPanel( wellPanel( uiOutput("message", inline=TRUE) ), actionButton("cancel", "Cancel last action"), br(), br(), rHandsontableOutput("hot"), br(), wellPanel( h3("Add a column"), div(class='row', div(class="col-sm-5", uiOutput("ui_newcolname"), actionButton("addcolumn", "Add")), div(class="col-sm-4", radioButtons("newcolumntype", "Type", c("integer", "double", "character"))), div(class="col-sm-3") ) ) ) ) )) server <- shinyServer(function(input, output) { values <- reactiveValues() ## Handsontable observe({ if (!is.null(input$hot)) { values[["previous"]] <- isolate(values[["DF"]]) DF = hot_to_r(input$hot) } else { if (is.null(values[["DF"]])) DF <- DF else DF <- values[["DF"]] } values[["DF"]] <- DF }) output$hot <- renderRHandsontable({ DF <- values[["DF"]] if (!is.null(DF)) rhandsontable(DF, useTypes = as.logical(input$useType), stretchH = "all") }) ## Save observeEvent(input$save, { fileType <- isolate(input$fileType) finalDF <- isolate(values[["DF"]]) if(fileType == "ASCII"){ dput(finalDF, file=file.path(outdir, sprintf("%s.txt", outfilename))) } else{ saveRDS(finalDF, file=file.path(outdir, sprintf("%s.rds", outfilename))) } } ) ## Cancel last action observeEvent(input$cancel, { if(!is.null(isolate(values[["previous"]]))) values[["DF"]] <- isolate(values[["previous"]]) }) ## Add column output$ui_newcolname <- renderUI({ textInput("newcolumnname", "Name", sprintf("newcol%s", 1+ncol(values[["DF"]]))) }) observeEvent(input$addcolumn, { DF <- isolate(values[["DF"]]) values[["previous"]] <- DF newcolumn <- eval(parse(text=sprintf('%s(nrow(DF))', isolate(input$newcolumntype)))) values[["DF"]] <- setNames(cbind(DF, newcolumn, stringsAsFactors=FALSE), c(names(DF), isolate(input$newcolumnname))) }) ## Message output$message <- renderUI({ if(input$save==0){ helpText(sprintf("This table will be saved in folder \"%s\" once you press the Save button.", outdir)) }else{ outfile <- ifelse(isolate(input$fileType)=="ASCII", "table.txt", "table.rds") fun <- ifelse(isolate(input$fileType)=="ASCII", "dget", "readRDS") list(helpText(sprintf("File saved: \"%s\".", file.path(outdir, outfile))), helpText(sprintf("Type %s(\"%s\") to get it.", fun, outfile))) } }) }) ## run app runApp(list(ui=ui, server=server)) return(invisible()) } ```