Search code examples
rshinyplotlyshinydashboard

Rendering plotly charts in R shiny App UI


In my mod_page_charts I have two charts as an output TypeA_Chart TypeB_Chart,

In my mod_page_ui have added a filter for charts, where i am attempting to filter charts where the output in tabPanel for plotlyOutput should show the chart based on chart type selected.

How do i render UI so that the chart changes based on pickerInput selectio ?

mod_page_ui <- function(id) {
  ns <- NS(id)
  
  tabItem(
    tabName = "chart_page",
    
    fluidPage(
      fluidRow(
        column(12, ),
        
        fluidRow(column(12, tabsetPanel(
          tabPanel("Value Chart " , fluidRow(
            column(
              2,
              align = "center",
              
              h3("Filter Chart"),
              pickerInput(
                inputId  = ns("selectType"),
                label    = "Select Type to View",
                choices  = c("TypeA", "TypeB"),
                selected = c("TypeA", "TypeB"),
              ),
              
              
              uiOutput(ns("attributePicker"))
            ),
            column(12, tabsetPanel(tabPanel(
              "chart Panel ",
              
              plotlyOutput(ns("TypeA_Chart"),
                           
              plotlyOutput(ns("TypeB_Chart")))
            ))))))))}
mod_page_charts <- function(input, output, session) {
  ns <- session$ns
  
  options(scipen = 100, digits = 4)
  
  output$attributePicker <- renderUI({
    if (input$selectType == "TypeA") {
      pickerInput(
        inputId  = ns("selectedTypeA"),
        label    = "Select Category to View",
        choices  = c("Daily", "Weekly"),
        selected = c("Daily", "Weekly"),
        multiple = TRUE,
        options  = list(size = 5)
      ) 
      
    } else if (input$selectType == "TypeB") {
      pickerInput(
        inputId  = ns("selectedTypeB"),
        label    = "Select Category to View",
        choices  = c("Daily", "Weekly"),
        selected = c("Daily", "Weekly"),
        multiple = TRUE,
        options  = list(size = 5)
      )}})
  
  output$TypeA_Chart <- renderPlotly({
    plt <-  generate_plot_typeA(
      data = datatypeA,
      attributeID = input$selectType,
      x = `Dates`,
      y = `Values`,
      title = "Type-A Chart"
      
      
    )
    
  })
  
  output$TypeB_Chart <- renderPlotly({
    plt <- generate_plot_typeB(
      data = datatypeB,
      attributeID = input$selectType,
      x = `Dates`,
      y = `Values`,
      title = "Type-B Chart"
       
    )})

Solution

  • There's a lot of things going on in your code which I'm not sure is all intentional or not. Since it appears that you only want to show a plot based on a condition, conditionalPanel() might be all you need.

    I've stripped it down to its very basics; I've omitted the use of modules and removed the dependency to shinydashboard and shinyWidgets, but it should work the same. Showing a panel does not need anything special from the server component. The app below simply shows the header A is showing and B is showing based on the selected values from the selectInput().

    library(shiny)
    
    shinyApp(
      fluidPage(
        selectInput(
          label    = 'Select Type to View',
          inputId  = 'selectType',
          choices  = c('TypeA', 'TypeB'),
          multiple = TRUE
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeA")',
          h1('A is showing')
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeB")',
          h1('B is showing')
        )
      ),
      server = function(input, output) {}
    )
    

    If it's more convenient, you could also consider the use of checkboxes. Nothing about the condition inside conditionalPanel should change.

    library(shiny)
    
    shinyApp(
      fluidPage(
        checkboxGroupInput(
          inputId = 'selectType',
          label   = 'Select Type to View',
          choices = c('TypeA', 'TypeB')
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeA")',
          h1('A is showing')
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeB")',
          h1('B is showing')
        )
      ),
      server = function(input, output) {}
    )
    

    From here, simply replace the h1() with your plot and render it without considering any of the conditions.

    library(shiny)
    library(plotly)
    
    shinyApp(
      fluidPage(
        checkboxGroupInput(
          inputId = 'selectType',
          label   = 'Select Type to View',
          choices = c('TypeA', 'TypeB')
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeA")',
          plotlyOutput('TypeA_Chart')
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeB")',
          plotlyOutput('TypeB_Chart')
        )
      ),
      server = function(input, output) {
        # sample data
        data <- data.frame(x = 1:10, y = rnorm(10), group = sample(letters[1:3], 10, replace = TRUE))
    
        output$TypeA_Chart <- renderPlotly(
          # no conditions needed
          plot_ly(data, x = ~x, y = ~y, type = 'scatter', mode = 'markers', color = ~group)
        )
    
        output$TypeB_Chart <- renderPlotly(
          plot_ly(data, x = ~group, y = ~y, type = 'bar')
        )
      }
    )
    

    If you insist on using modules, note that Shiny 1.5.0 introduced a moduleServer() function that should streamline the server function creation part. For conditionalPanel(), you have to also pass in the ns function itself.

    library(shiny)
    library(plotly)
    
    chartModuleUI <- function(id) {
      ns <- NS(id)
    
      tagList(
        checkboxGroupInput(
          inputId = ns('selectType'),
          label   = 'Select Type to View',
          choices = c('TypeA', 'TypeB')
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeA")',
          plotlyOutput(ns('TypeA_Chart')),
          ns = ns
        ),
        conditionalPanel(
          condition = 'input.selectType.includes("TypeB")',
          plotlyOutput(ns('TypeB_Chart')),
          ns = ns
        )
      )
    }
    
    chartModuleServer <- function(id) {
      moduleServer(
        id,
        function(input, output, session) {
          data <- data.frame(x = 1:10, y = rnorm(10), group = sample(letters[1:3], 10, replace = TRUE))
    
          output$TypeA_Chart <- renderPlotly(
            plot_ly(data, x = ~x, y = ~y, type = 'scatter', mode = 'markers', color = ~group)
          )
    
          output$TypeB_Chart <- renderPlotly(
            plot_ly(data, x = ~group, y = ~y, type = 'bar')
          )
    
        }
      )
    }
    
    shinyApp(
      fluidPage(
        chartModuleUI('chartModule')
      ),
      server = function(input, output) {
        chartModuleServer('chartModule')
      }
    )