Ahmad Tanwir
Ahmad Tanwir

Reputation: 133

Add a new row with the existing data frame in shiny R by using action button

I am building a shiny form which will take data from the textInput field and combined those input with a text file (which will be uploaded by file input) and show the output in the main panel. There is an action button to update the data for the first time (take the data from text input and merge with the processed text file) and I added another action button for add new data (the purpose of this Add new data to add a new set of data as row with the existing one, The new set of data will be uploaded by the file input). The sample data set is given below, which is a plain text formatted file. This sample dataset can be considered as the second text file. sample data:

#         AREA     ADC-MEAN  ADC-STD DEV  ADC-MIN    ADC-MAX    ADC-MED  
 1      12.0000  0.000644667 1.96669e-005  0.000606000  0.000671000  0.000644000
 2      12.0000  0.000610250 1.43154e-005  0.000577000  0.000624000  0.000617000

I wrote shinnyApp based on the scenario. I am able to do update the text input and the text file output by merging and output as a table. But couldn't able to add a new set of data as rows. The script is given below:

library(shiny)
library(ggplot2)
library(xlsx)
library(xlsxjars)
library(rJava)
library(shinythemes)

# Define UI -----------
# ---------------------

ui <- fluidPage(theme = shinytheme("sandstone"),

                # header
                headerPanel("DTI post analysis conversion"),

                sidebarLayout(
                  # sidebar for form
                  sidebarPanel(
                    h3("Information",""),
                    textInput("ani_id", "Patient ID",""),
                    textInput("scan_id", "Scan ID",""),
                    textInput("Tech_id", "Tech Id",""),
                    textInput("Age_weeks", "Age weeks",""),

                    fileInput("textfile", "Upload the text file"),
                    actionButton("update", "Update"),
                    helpText("Click to insert the data "),
                    br(),
                    actionButton("addEntry", "Add New Data"),
                    helpText("Click to insert new data "),
                    br(),
                    downloadButton("downloadData", "Download"),
                    helpText("Click for download the data (.csv) ")
                  ),

                  # output for viewing
                  mainPanel(

                    DT::dataTableOutput("tableDT") 

                  )   
                )
)


# Define server logic ------
# --------------------------

server <- function(input, output) {

  # process the textinput
  Frontal_Cortex_table <- eventReactive(input$update,{  


    # creating table

    aniRoi2 <- data.frame(Animal_ID = rep(input$ani_id,2), 
                          Scan_ID = rep(input$scan_id,2), 
                          Tech_ID = rep(input$Tech_id,2), 
                          Age_weeks = rep(input$Age_weeks,2), 
                          stringsAsFactors = FALSE)

    return(aniRoi2)
  })

  # process the text file and download

  textdata <- eventReactive(input$update,{
    file1 <- input$textfile
    if(is.null(file1)){return()} 
    a <- read.table(file= file1$datapath, 
                    sep="\t",
                    fill=FALSE, 
                    strip.white=TRUE)[1:2,]

    # Split the text file and shape as column
    af <- as.character(a)
    af1 <- matrix(unlist(strsplit(af, split=" +")), ncol=7, byrow =TRUE)
    ad <- data.frame(af1[1:2,3:7])
    colnames(ad)<- c("ADC_MEAN", "ADC_STD", "ADC_MIN", "ADC_MAX", "ADC_MED")

    return(ad)
  })

  # merge two function as data.frame
  mytable2 <-reactive({

    dm = cbind.data.frame(Frontal_Cortex_table(), textdata())

  })

  # add new row (?)

  addData <- observeEvent(input$addEntry, {
    mytable2 <- isolate({
      newLine <- reactive({cbind.data.frame(Frontal_Cortex_table(), textdata())})
      rbind.data.frame(mytable2,newLine)
    })
  })

  # output the data as table    
  output$tableDT <- DT::renderDataTable(
    mytable2()
  )

  # download the file
  output$downloadData <- downloadHandler(
    filename = function() {
      paste("DTI", "csv", sep = ".")
    },
    content = function(file) {
      write.csv(mytable2(), file, row.names = FALSE)
    }
  )

}

# Run the app ----------
# ----------------------

shinyApp(ui = ui, server = server)

I have got the error message stating that :

Warning: Error in [[: object of type 'closure' is not subsettable Stack trace (innermost first):
    73: rbind.data.frame
    66: isolate
    65: observeEventHandler [/Users/rahatjahan/Dropbox/Database dev/DTIApp/Ask questions.R#95]
     1: runApp

I know, it's kind of long post but try to explain and provide everything so that there would not be any confusion.

Your comment and suggestions would be appreciated.

Upvotes: 3

Views: 7881

Answers (3)

Rich.a.rd
Rich.a.rd

Reputation: 23

A thorough answer Ahmad, thank you. I too found that there was a lot going on. It's taken me a while to work it out, so I've written a really basic one to help others out if they need it. I use tidyverse functions.

ui <- fluidPage(
  textInput("name", "name"),
  actionButton("add", "add"),
  tableOutput("names"),
  actionButton("save", "save")
  )

server <- function(input, output, session) {
  # Create an empty table
  r <- reactiveValues(table = tibble::tibble(col1 = character()))

  observeEvent(input$add, {
    # Adds the text input to the table
    r$table <- r$table |> tibble::add_row(col1 = input$name)
    # Clears text input box
    updateTextInput(session, "name", value = "")
  })
  
  # Displays the table
  output$names <- renderTable(r$table)
  
  # Saves the table to file (subsequent entries are appended) and clears the reactive value
  observeEvent(input$save, {
    r$table |> readr::write_csv("file.csv", append = TRUE)
      r$table <- tibble::tibble(col1 = character())
  })
  
}
shinyApp(ui, server)

Upvotes: 0

Valdrich Fernandes
Valdrich Fernandes

Reputation: 26

If anyone is stuck on this problem in 2021+, have a look at the editData package. It doesn't directly do it for you, but it takes care of a lot of other problems you're probably working on.

For my project, I had to look at the source code of some of the functions and adapt it for my case, but it gave me the solution I was looking for. The source code also has a part on making the edited data downloadable, and that's probably the answer to this question. I haven't tried it myself, but don't see why it won't work

All the best!

Upvotes: 0

Ahmad Tanwir
Ahmad Tanwir

Reputation: 133

The problem is solved, and each iteration it will add new rows. The new text data set:

#         AREA     ADC-MEAN  ADC-STD DEV  ADC-MIN    ADC-MAX    ADC-MED  
 1      12.0000  0.000644667 1.96669e-005  0.000606000  0.000671000  0.000644000
 2      12.0000  0.000610250 1.43154e-005  0.000577000  0.000624000  0.000617000
 3     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 4     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 5     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 6     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 7     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 8     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 9     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 10     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
#         AREA     FA-MEAN  FA-STD DEV     FA-MIN      FA-MAX        FA-MED  
 1      12.0000     0.233833    0.0171773     0.201000     0.262000     0.239000
 2      12.0000     0.247417    0.0135275     0.220000     0.270000     0.248000
 3     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 4     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 5     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 6     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 7     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 8     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 9     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
 10     0.000000     0.000000     0.000000     0.000000     0.000000     0.000000
ADC-MEAN
  0.000644667
  0.000610250
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
ADC-STD DEV
 1.96669e-005
 1.43154e-005
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
FA-MEAN
     0.233833
     0.247417
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
FA-STD DEV
    0.0171773
    0.0135275
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000
     0.000000

And the modified code

library(shiny)
library(ggplot2)
library(xlsx)
library(xlsxjars)
library(rJava)
library(shinythemes)

# Define UI -----------
# ---------------------

ui <- fluidPage(theme = shinytheme("sandstone"),

                # header
                headerPanel("DTI post analysis conversion"),

                sidebarLayout(
                  # sidebar for form
                  sidebarPanel(
                    h3("Information",""),
                    textInput("ani_id", "Patient ID",""),
                    textInput("scan_id", "Scan ID",""),
                    textInput("Tech_id", "Tech Id",""),
                    textInput("Age_weeks", "Age weeks",""),

                    fileInput("textfile", "Upload the text file"),
                    actionButton("update", "Insert 1st Data Set"),
                    helpText("Click to insert the data "),
                    br(),
                    fileInput("anothertextfile", "Upload another Text file"),
                    actionButton("addEntry", "Add New Data"),
                    helpText("Click to insert new data "),
                    br(),
                    actionButton("combine", "Combine the data sets"),
                    downloadButton("downloadData", "Download"),
                    helpText("Click for download the data (.csv) ")
                  ),

                  # output for viewing
                  mainPanel(

                    DT::dataTableOutput("tableDT"),
                    DT::dataTableOutput("tableDT2") 


                  )   
                )
)


# Define server logic ------
# --------------------------

server <- function(input, output) {

  # process the textinput
  Frontal_Cortex_table <- reactive({  


    # creating table

    aniRoi2 <- data.frame(Animal_ID = rep(input$ani_id,2), 
                          Scan_ID = rep(input$scan_id,2), 
                          Tech_ID = rep(input$Tech_id,2), 
                          Age_weeks = rep(input$Age_weeks,2), 
                          stringsAsFactors = FALSE)

    return(aniRoi2)
  })

  # process the text file and download

  textdata <- reactive(
    {
    file1 <- input$textfile
    if(is.null(file1)){return()} 
    #read.table(file=file1$datapath, sep=input$sep, header = input$header, stringsAsFactors = input$stringAsFactors)
    a <- read.table(file= file1$datapath, 
                    sep="\t",
                    fill=FALSE, 
                    strip.white=TRUE)[1:20,]

    # Split the text file and shape as column
    af <- as.character(a)
    #class(af)
    #af
    #nrow(a)
    af1 <- matrix(unlist(strsplit(af, split=" +")), ncol=7, byrow =TRUE)
    # typeof(af1)
    # af1
    ad <- data.frame(af1[1:2,3:7], af1[11:12, 3:7])

    colnames(ad)<- c("ADC_MEAN", "ADC_STD", "ADC_MIN", "ADC_MAX", "ADC_MED", 
                     "FA_MEAN", "FA_STD", "FA_MIN", "FA_MAX", "FA_MED")


    return(ad)
  })


  # merge two function as data.frame
  mytable2 <-eventReactive(input$update,{

     dm <<- cbind.data.frame(Frontal_Cortex_table(), textdata())

  })

  # add new row (?)

  addData1 <- eventReactive(input$addEntry, {
      newLine <<- cbind.data.frame(Frontal_Cortex_table(), textdata())
  })


  addData <- eventReactive(input$addEntry, {
    dm <<- rbind.data.frame(mytable2(),addData1())
  })

  addData2 <- eventReactive(input$addEntry, {
    dm <<- rbind.data.frame(dm,addData1())
  })

  # output as data table      
  output$tableDT <- DT::renderDataTable(
    mytable2()
  )

# the combined data set with added row  
  output$tableDT2 <- DT::renderDataTable(
    addData2()
  )
  # download the file
  output$downloadData <- downloadHandler(
    filename = function() {
      paste("DTI", "csv", sep = ".")
    },
    content = function(file) {
      write.csv(mytable2(), file, row.names = FALSE)
    }
  )

}

# Run the app ----------
# ----------------------

shinyApp(ui = ui, server = server)

Hope that will help.

Upvotes: 4

Related Questions