2
votes

My basic problem is that I'm having trouble getting my plots to render in tabPanels when using the module approach to UI and server logic. I am trying to build an app with several tabPanels (under both navbarPage and navbarMenus) where users input some data with similar structure between tabs, and then the app generates and then plots data specific to user input on that tab.

Here is a much reduced version of my app, but this seems to create the same problems:

# UI module
modUI <- function(id, label="inputvalues") {
  ns <- NS(id)
  tagList(
    numericInput(ns("mean"), "Mean",value = NULL),
    numericInput(ns("sd"),"Std. Dev.",value = NULL),
    actionButton(ns("draw"),"Draw plot")
  )
}

# Server Logic module
mod <- function(input, output, session){
  x <- reactiveValues(data=NULL)
  observeEvent(input$draw, {
    x$data <- data.frame(rnorm(100,input$mean,input$sd))
  })
  reactive({x})
}

# Plotting function
showPlot <- function(data){
  reactive({
  p <- ggplot(data, aes(x=data[,1])) +
    geom_histogram()
  p
  })
}

# UI call
ui <- navbarPage("Fancy Title",
          tabPanel("Panel1",
              sidebarPanel(
                modUI("input1")
              ),
              mainPanel(plotOutput("plot1"))
              ),
          tabPanel("Panel2",
              sidebarPanel(
                modUI("input2")
              ),
              mainPanel(plotOutput("plot2"))
          )
)

# Server call
server <- function(input, output) {
  y <- callModule(mod, "input1")
  output$plot1 <- renderPlot({ showPlot(y()) })

  z <- callModule(mod, "input2")
  output$plot2 <- renderPlot({ showPlot(z()) })
}

shinyApp(ui, server)

Again, what I'm hoping is for Panel 1 to display a graph based on input provided by the user in panel 1, and then for Panel 2 to display a second graph based on what's provided in panel 2. When I input data I click the button and nothing happens. I can flip back and forth between panels and the inputs are there, which is good, but no plot. I get no error messages, and browser() hasn't brought me anywhere useful. I suspect my problem is in passing the plot object from the plotting function to renderPlot; but in having the separate function I'm trying to follow guidelines provided in this article.

Any guidance is much appreciated, as always!

Versions (R, RStudio, Rshiny) are all quite recent.

1

1 Answers

2
votes

I've done a couple of changes to your code:

  • Your code misses namespaces in moduleUI while defining UI Ids - added it.
  • Changed the way reactivevalues are returned from moduleserver
  • a little tweak on showplot (with respect to how the data is handled)

So, your problem was not with plotting but the input data to plot.

Updated code:

library(shiny)

# UI module
modUI <- function(id, label="inputvalues") {
  ns <- NS(id)
  tagList(
    numericInput(ns("mean"), "Mean",value = NULL),
    numericInput(ns("sd"),"Std. Dev.",value = NULL),
    actionButton(ns("draw"),"Draw plot")
  )
}

# Server Logic module
mod <- function(input, output, session){
  x <- reactiveValues(data=NULL)
  observeEvent(input$draw, {
        x$data <- rnorm(100,input$mean,input$sd)
  })
  return(reactive({x$data}))
  }

# Plotting function
showPlot <- function(data){

    data <- data.frame(data = data)
    p <- ggplot(data, aes(x=data)) +
      geom_histogram()
    p

}

# UI call
ui <- navbarPage("Fancy Title",
                 tabPanel("Panel1",
                          sidebarPanel(
                            modUI("input1")
                          ),
                          mainPanel(plotOutput("plot1"))
                 ),
                 tabPanel("Panel2",
                          sidebarPanel(
                            modUI("input2")
                          ),
                          mainPanel(plotOutput("plot2"))
                 )
)

# Server call
server <- function(input, output, session) {
  y <- callModule(mod, "input1")



  output$plot1 <- renderPlot({ showPlot(data.frame(y())) })
  #output$plot1 <- renderPlot(plot(1:100))

  z <- callModule(mod, "input2")
  output$plot2 <- renderPlot({ showPlot(data.frame(z())) })
}

shinyApp(ui, server)