Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

r - Shiny Reactivity Fails with data.tables

As a follow up to Modifying a reactive value should trigger an observe chunk, I investigated the issue further and realised that the issue probably stems from my usage of data.tables. data.tables are modified by reference unlike data.frames which makes them more efficient to use but also apparently invisible to shiny's reactivity.

In the below example, pressing the commit button triggers the observe chunk in the data.frame case but not in the data.table case. A workaround could be to have a value linked to the changing of data.table which also helps trigger the reactivity.

with data.frame

shinyServer ( 

   function(input, output, session) {

      lReactiveValues = reactiveValues(a = data.frame(firstcol = runif(1)))

      voidaA = observeEvent(
         input$buttonCommit,
         {
            new = runif(1)
            cat(new,' one')
            lReactiveValues$a[letters[ncol(isolate(lReactiveValues$a))]] = new
         }
      )

      voidB = observe(priority = 50,{
         # input$buttonCommit
         cat(ncol(lReactiveValues$a))

         counter = runif(1)
         cat(counter,' two'); 

         if (counter > 0.5) {

            cat('
')

            cat(ncol(lReactiveValues$a),' three
')

         }
      }
      )

   }
)

with data.table

shinyServer ( 

   function(input, output, session) {

      lReactiveValues = reactiveValues(a = data.table(firstcol = runif(1)))
      # lReactiveValues = reactiveValues(a = data.frame(firstcol = runif(1)))

      voidaA = observeEvent(
         input$buttonCommit,
         {
            new = runif(1)
            cat(new,' one')
            setnames(
               lReactiveValues$a[, newcol := new],
               'newcol',
               letters[ncol(isolate(lReactiveValues$a))]
            )
            cat(ncol(lReactiveValues$a))
         }
      )

      voidB = observe(priority = 50,{
         # input$buttonCommit
         cat(ncol(lReactiveValues$a))

         counter = runif(1)
         cat(counter,' two'); 

         if (counter > 0.5) {

            cat('
')

            cat(ncol(lReactiveValues$a),' three
')

         }
      }
      )

   }
)

ui.r

dashboardPage(

   dashboardHeader(

      title = "Analytics"

   ),

   ## Sidebar content
   dashboardSidebar(
   menuItem("Analysis", tabName = "tabAnalysis", icon = icon("calculator"))
   ),

   ## Body content
   dashboardBody(
      tabItems(
         tabItem(
            tabName = "tabAnalysis",
            actionButton("buttonCommit", "Commit!")
         )
      )
      #, style='width: 100%; height: 100%;'

   )
)

Short summary of what the code does - Pressing button should print some text to the console which includes the string 'one'. The button should further trigger the observe chunk prompting the printing of some text containing the string 'two'. Depending on the if condition in the observe chunk, another set of text including 'three' might get printed. In the data.frame's server.r case this behaviour persists all the time the app runs. In the data.table's server.r case, this behaviour occurs for a few clicks of the button after which only the 'one' string is printed and the 'two' and 'three' aren't. This flip in behaviour, think, occurs after the if condition is found to be false for the first time.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

A hacky solution if you are concerned about memory:

Add A DTControl value:

lReactiveValues = reactiveValues(a = data.table(firstcol = runif(1)), DTControl = 0)

Then pair that with the following after your reference change:

lReactiveValues$a[, newcol := new]
lReactiveValues$DTControl <- lReactiveValues$DTControl + 1

Then add this line in your observe function:

lReactiveValues$DTControl

Because your DTControl updates, the reactive function gets triggered. Takes a bit of diligence to make sure you are always pairing the two together, but it can override this reference issue without any memory load.

Regardless, this should be highlighted as an issue in shiny.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...