Bursaphelenchus
Bursaphelenchus

Reputation: 25

R Shiny can't change reactive dataframe object

Shiny app loads a .csv with fileInput() but can't change it afterwords.

I want to change (multiply by (-1)) one of the columns of the dataframe within the app with a button after identifying the column

The object loadedData is a read.csv() function that outputs a dataframe that I use in the remainder of the app I've tried changing the object directly, through functions, be it it's reactive data or a static copy that try to override later but can't seem to make the change permanent.

#--------------UI side
#import data
sidebarLayout( 
          sidebarPanel(

            fileInput('main', 'Input file', multiple = FALSE,
                      accept =".csv"),

            checkboxInput("header", "Header", TRUE),


            radioButtons("sep", "Separator",
                         choices = c(Comma = ",",
                                     Semicolon = ";",
                                     Tab = "\t"),
                         selected = ","),


            radioButtons("quote", "Quote",
                         choices = c(None = "",
                                     "Double Quote" = '"',
                                     "Single Quote" = "'"),
                         selected = '"')
          ),
#--------------Server Side

# read dataset 

loadedData <- reactive({
    read.csv(
      input$main$datapath,
      header = input$header,
      sep = input$sep,
      quote = input$quote
    )
  })

# change signal

observeEvent(input$main, {
    output$advancedsignalchange <- renderUI({
      tagList(
        selectInput('signalchangecolumn', 'Signal Change Column', choices = names(loadedData())),
        actionButton('signalchange','Submit signal change')
      )    
    })
    })


observeEvent(input$signalchange,{

    print(loadedData)
    print(names(loadedData()))
    aa <- as.array(input$signalchangecolumn)

    print(loadedData()[aa][[1]][1]) #token value before change

    #loadedData()[aa] <-  loadedData()[aa] *-1  ## can't override
    print(loadedData()[aa] *-1) #change 

    print(loadedData()[aa][[1]][1]) #token value after change


  })

2 errors here: If I uncomment this line in an attempt to override loadedData()

loadedData()[aa] <- loadedData()[aa] *-1

Warning: Error in <-: invalid (NULL) left side of assignment

similarly if I try

loadedData[aa] <- loadedData()[aa] *-1

Warning: Error in <-: object of type 'closure' is not subsettable

so I can't save the change

the print statements are a way to validate the syntax so, say I had a column where the 1st value is "1", output would be,

1

-1 (along with the rest of the column)

1

therefore the syntax itself for the change operation is viable but I can't override the column on the imported dataframe

Upvotes: 1

Views: 1171

Answers (1)

gdevaux
gdevaux

Reputation: 2505

To store and update reactive objects, you can use reactiveVal or reactiveValues instead of reactive.

library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      fileInput("main", "Input file",
        multiple = FALSE,
        accept = ".csv"
      ),

      checkboxInput("header", "Header", TRUE),

      radioButtons("sep", "Separator",
        choices = c(
          Comma = ",",
          Semicolon = ";",
          Tab = "\t"
        ),
        selected = ","
      ),

      radioButtons("quote", "Quote",
        choices = c(
          None = "",
          "Double Quote" = '"',
          "Single Quote" = "'"
        ),
        selected = '"'
      )
    ),

    mainPanel(
      uiOutput("advancedsignalchange"),
      dataTableOutput("data")
    )
  )
)


server <- function(input, output, session) {

  loadedData <- reactiveVal() # create reactive val

  observe({
    req(input$main$datapath) # make sure variable isn't empty
    loadedData(read.csv( # initialize reactiveVal
      input$main$datapath,
      header = input$header,
      sep = input$sep,
      quote = input$quote)) 
  })

  observeEvent(input$main, {
    output$advancedsignalchange <- renderUI({
      tagList(
        selectInput("signalchangecolumn", "Signal Change Column", choices = names(loadedData())),
        actionButton("signalchange", "Submit signal change")
      )
    })
  })

  observeEvent(input$signalchange, {
    aa <- as.array(input$signalchangecolumn)
    tmp <- loadedData()
    tmp[aa] <- tmp[aa] * -1
    loadedData(tmp) # update reactiveVal
  })

  output$data <- renderDataTable(loadedData()) # display data
}


shinyApp(ui, server)

Upvotes: 1

Related Questions