Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shiny Module that calls a reactive data set in parent Shiny server

Tags:

module

r

shiny

I'm looking to port some older Shiny apps to use Shiny Modules, but running into trouble trying to port over my reactive expressions.

According to the documentation:

The goal is not to prevent modules from interacting with their containing apps, but rather, to make these interactions explicit. If a module needs to use a reactive expression, take the reactive expression as a function parameter.

I have existing reactive expressions that import data from APIs etc. that I would like to pass in, but can't seem to find the syntax. If I modify the given Shiny module example below I can get to the same problem.

Could anyone modify the below so that you can pass in the car_data() reactive data into the module? I've tried just about every combination of isolate and car_data/car_data() I can think of and am stumped :)

I would prefer to not need to call the data within the module itself, as in my case I'm trying to generalise an ETL function applicable to lots of datasets.

library(shiny)
library(ggplot2)

linkedScatterUI <- function(id) {
  ns <- NS(id)

  fluidRow(
    column(6, plotOutput(ns("plot1"), brush = ns("brush"))),
    column(6, plotOutput(ns("plot2"), brush = ns("brush")))
  )
}

linkedScatter <- function(input, output, session, data, left, right) {
  # Yields the data frame with an additional column "selected_"
  # that indicates whether that observation is brushed
  dataWithSelection <- reactive({
    brushedPoints(data(), input$brush, allRows = TRUE)
  })

  output$plot1 <- renderPlot({
    scatterPlot(dataWithSelection(), left())
  })

  output$plot2 <- renderPlot({
    scatterPlot(dataWithSelection(), right())
  })

  return(dataWithSelection)
}

scatterPlot <- function(data, cols) {
  ggplot(data, aes_string(x = cols[1], y = cols[2])) +
    geom_point(aes(color = selected_)) +
    scale_color_manual(values = c("black", "#66D65C"), guide = FALSE)
}

ui <- fixedPage(
  h2("Module example"),
  linkedScatterUI("scatters"),
  textOutput("summary")
)

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

  ### My modification 
  ### making the reactive outside of module call
  car_data <- reactive({
    mpg
    })

  ## This doesn't work
  ## What is the syntax for being able to call car_data()?
  df <- callModule(linkedScatter, "scatters", car_data(),
                   left = reactive(c("cty", "hwy")),
                   right = reactive(c("drv", "hwy"))
  )

  output$summary <- renderText({
    sprintf("%d observation(s) selected", nrow(dplyr::filter(df(), selected_)))
  })
}

shinyApp(ui, server)
like image 465
MarkeD Avatar asked Apr 18 '16 13:04

MarkeD


2 Answers

If you want to pass input which is not part of the module just wrap it around reactive() as stated in a tutorial.

If a module needs to access an input that isn’t part of the module, the containing app should pass the input value wrapped in a reactive expression (i.e. reactive(...)): callModule(myModule, "myModule1", reactive(input$checkbox1))

Update: As correctly stated in another answer and Joe Cheng correct way to pass reactive expression is without brackets ()

callModule(linkedScatter, "scatters", car_data)

One option is also to modularize your API input function so you don't need to define reactive expression outside modules. Example of modularized input can be found from this answer. Below your code with right answer.

library(shiny)
library(ggplot2)

linkedScatterUI <- function(id) {
  ns <- NS(id)

  fluidRow(
    column(6, plotOutput(ns("plot1"), brush = ns("brush"))),
    column(6, plotOutput(ns("plot2"), brush = ns("brush")))
  )
}

linkedScatter <- function(input, output, session, data, left, right) {
  # Yields the data frame with an additional column "selected_"
  # that indicates whether that observation is brushed
  dataWithSelection <- reactive({
    brushedPoints(data(), input$brush, allRows = TRUE)
  })

  output$plot1 <- renderPlot({
    scatterPlot(dataWithSelection(), left())
  })

  output$plot2 <- renderPlot({
    scatterPlot(dataWithSelection(), right())
  })

  return(dataWithSelection)
}

scatterPlot <- function(data, cols) {
  ggplot(data, aes_string(x = cols[1], y = cols[2])) +
    geom_point(aes(color = selected_)) +
    scale_color_manual(values = c("black", "#66D65C"), guide = FALSE)
}

ui <- fixedPage(
  h2("Module example"),
  linkedScatterUI("scatters"),
  textOutput("summary")
)

server <- function(input, output, session) {
data(mpg)
  ### My modification 
  ### making the reactive outside of module call
  car_data <- reactive({
    mpg
    })

  ## Fix This doesn't work by reactive (var) no brackets()
  ## What is the syntax for being able to call car_data()?
  df <- callModule(linkedScatter, "scatters", reactive(car_data),
                   left = reactive(c("cty", "hwy")),
                   right = reactive(c("drv", "hwy"))
  )

  output$summary <- renderText({
    sprintf("%d observation(s) selected", nrow(dplyr::filter(df(), selected_)))
  })
}

shinyApp(ui, server)
like image 110
Mikael Jumppanen Avatar answered Oct 11 '22 06:10

Mikael Jumppanen


Drop the parens after car_data:

df <- callModule(linkedScatter, "scatters", car_data,
                   left = reactive(c("cty", "hwy")),
                   right = reactive(c("drv", "hwy"))
  )

The module seems to want "unresolved" reactives. The parentheses "resolves" them.

like image 39
user2894965 Avatar answered Oct 11 '22 06:10

user2894965