-
Edit a table with Shiny and rhandsontable
2016-08-15
SourceWith 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.For example, take the following data frame:
( DF <- data.frame(Value = 1:10, Status = TRUE, Name = LETTERS[1:10], Date = seq(from = Sys.Date(), by = "days", length.out = 10), stringsAsFactors = FALSE) )
## Value Status Name Date ## 1 1 TRUE A 2016-08-15 ## 2 2 TRUE B 2016-08-16 ## 3 3 TRUE C 2016-08-17 ## 4 4 TRUE D 2016-08-18 ## 5 5 TRUE E 2016-08-19 ## 6 6 TRUE F 2016-08-20 ## 7 7 TRUE G 2016-08-21 ## 8 8 TRUE H 2016-08-22 ## 9 9 TRUE I 2016-08-23 ## 10 10 TRUE J 2016-08-24
The app is launched by running the function
editTable
I will give below. Just take a look before: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:dget("newDF.txt")
## Value Status Name Date ## 1 1000 FALSE Alice 2006-01-01 ## 2 2000 FALSE Bob 2006-01-02 ## 3 3000 FALSE Chris 2006-01-03 ## 4 4 TRUE D 2016-08-18 ## 5 5 TRUE E 2016-08-19 ## 6 6 TRUE F 2016-08-20 ## 7 7 TRUE G 2016-08-21 ## 8 8 TRUE H 2016-08-22 ## 9 9 TRUE I 2016-08-23 ## 10 10 TRUE J 2016-08-24
Here is my code:
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()) }