0
votes

I have a complex R shiny application that takes advantage of multiple modules. I have two different modules (which I will call a histogram module and a scatter plot module) that each output a reactive plot. Based on user input, only one of these plots should be displayed at any one time. I am able to manage this with a radio button selection - the user simply selects the histogram or scatter plot.

I am having difficulties arranging these two reactive plot outputs in an appealing way. I would like the histogram and scatter plot to align to the top left portion of the page. If my histogram is listed first in my UI, when the user selects the scatter plot, this scatter plot renders underneath a large blank space. This large blank space is filled when the user selects the histogram plot, but I would like this 'bottom' plot to still display at the top of the shiny application.

In my shiny days before using modules, I simply would put my plot output inside of a conditional panel in the UI (e.g., conditionalPanel("input.displayPlot", plotOutput("plot1")) However, now that I have a complex module, I don't have input logic to put inside of a conditional panel (at least I don't think I do).

I created as simple of a reproducible example as I could manage to recreate this problem. When the user selects the scatter plot, it displays under a large blank space. I would really prefer to keep my radio button selection of the histogram vs scatterplot within my module (as it is is also reactively displayed based on other complex logic), but this might be impossible.

histogramPlotOutput <- function(id) {
  tagList(
    plotOutput(NS(id, "histogram"))
  )
}

histogramUIOutput <- function(id) {
  tagList(
    uiOutput(NS(id, "buttons"))
  )
}

histogramServer <- function(id
) {
  moduleServer(id, function(input, output, session) {

    output$histogram <- renderPlot({
      req(input$radiobuttons)

      if(input$radiobuttons){
        p <- hist(mtcars[["mpg"]])
        p
      }

    })


    output$buttons <- renderUI({
      radioButtons(NS(id, "radiobuttons"),
                   label = "Display Histogram?",
                   choices = c(TRUE, FALSE),
                   selected = TRUE)
    })

    # export the reactive button selection out of histogram server
    # this will be used as an input by scatterPlotServer to
    # determine if an alternate plot should be displayed

    reactive(
      input$radiobuttons
    )

  })
}


scatterPlotOutput <- function(id) {
  tagList(
    plotOutput(NS(id, "scatterplot"))
  )
}

scatterPlotServer <- function(id,
                              display_histogram = TRUE
)
  {

  moduleServer(id, function(input, output, session) {

    output$scatterplot <- renderPlot({
      if(display_histogram() == FALSE){
        p <- plot(mtcars$mpg, mtcars$hp)
        p
      }

    })

  })
}


myApp <- function(){
  ui <- fluidPage(
    histogramPlotOutput("hist1"),
    scatterPlotOutput("scat1"),
    histogramUIOutput("hist1")
    )

  server <- function(input, output, session) {
    display_hist <- histogramServer("hist1")

    scatterPlotServer("scat1",
                      display_histogram = reactive(display_hist()))
  }
  shinyApp(ui, server)
}

myApp()

Thank you in advance for any assistance!

1

1 Answers

1
votes

You might want to use renderUI()/uiOutput() to display either one of your plots:

myApp <- function(){
  ui <- fluidPage(
    uiOutput("plot"),
    histogramUIOutput("hist1")
  )
  
  server <- function(input, output, session) {
    display_hist <- histogramServer("hist1")
    
    scatterPlotServer("scat1",
                      display_histogram = reactive(display_hist()))

    output$plot <- renderUI({
      if(req(display_hist()))
        histogramPlotOutput("hist1")
      else
        scatterPlotOutput("scat1")
      })
  }
  shinyApp(ui, server)
}