3

I have a shinydashboard app with two different tab panels. Each tab has different input values and both of them generate a graph when an action button is clicked.

Whenever I switch between these tabs, their respective graphs disappear and input values are reset to default.

I want to keep the tabs in their user modified states (i.e keep both graphs and inputs) even when the user decides to switch between the panels.

Code

library(shiny)
library(shinydashboard)


ui <- fluidPage(
  dashboardPage(
    dashboardHeader(title = "DASHBOARD"),

    dashboardSidebar(
      uiOutput("mysidebar"),
    ),

    dashboardBody(
      tabsetPanel(type = "tabs", id = "tab", 
                  tabPanel("Tab1", fluid = TRUE, value = 1,plotOutput("A")),
                  tabPanel("Tab2", fluid = TRUE, value = 2, plotOutput("B"))
      )
    )
  )

)

server <- function(input, output, session){
  output$mysidebar <- renderUI({

    if(input$tab == 1){
      tagList(
        sliderInput(inputId = "Sample",
                    label = "Enter Number of Samples:",
                    min = 1000, max = 100000,
                    value = 10000),
        fluidRow(
          column(6,
                 actionButton(inputId = "b1", label = "Generate"))
        )}

    if(input$tab == 2){
      tagList(
        sliderInput(inputId = "Weight",
                    label = "Enter Weight:",
                    value = 100),
        fluidRow(
          column(6,
                 actionButton(inputId = "b2", label = "Generate"))
        )}

    p1<- eventReactive(input$b1, {
      #creating a dataframe using input "Sample" in tab1 - Rough example
      df <- input$Sample

    })
    output$SA <- renderPlot({

        plot(df)

    })

    p2 <- eventReactive(input$b2, {
      #creating a dataframe using input "Weight" in tab2-- Rough example
      df2 <- input$Weight

    })
    output$A <- renderPlot({

      plot(p1())

    })
   output$B <- renderPlot({

      plot(p2())

    })
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • 2
    Youre code is not working. There are some syntax errors – SeGa Jul 17 '18 at 11:34
  • In the eventReactive functions p1 and p2, I have just created a dataframe using the input sample from the tabs. I have not written an exact code of this. It's just a rough example for you to get an idea what I am trying to do. I then use these functions to plot outputs for each tab. – Hammad Patel Jul 17 '18 at 11:43
  • Still, copy your code and try to run it. It wont work. In the ui you mix fluidPage with dashboardPage and in the server I think some parenthesis are missing. – SeGa Jul 17 '18 at 11:46
  • Ok there maybe some parenthesis missing because I have extracted this sample chunk from a large code. The main problem is that my plots are disappearing and inputs are resetting to default whenever I switch between the tabs. General idea is the same. Take an an input from a particular tab, create a dataframe, and then plot that dataframe. – Hammad Patel Jul 17 '18 at 11:56
  • Everytime there is a change anywhere within the `renderUI` it will remake the widgets and the outputs, its not a good way of designing it if you need the plots to remain – Pork Chop Jul 17 '18 at 12:22

2 Answers2

2

I'd much rather you use show and hide functionality within shinyjs package like example below, this way the values will be preserved when you switch between the Tabs

library(shiny)
library(shinyjs)
library(shinydashboard)


ui <- fluidPage(
  dashboardPage(
    dashboardHeader(title = "DASHBOARD"),

    dashboardSidebar(
      useShinyjs(),
      sliderInput("Sample","Enter Number of Samples:",min = 1000, max = 100000,value = 10000),
      sliderInput("Weight","Enter Weight:",min = 1, max = 1000,value = 100),
      fluidRow(column(6,actionButton("b1","Generate"),actionButton("b2","Generate")))
    ),

    dashboardBody(
      tabsetPanel(type = "tabs", id = "tab", 
                  tabPanel("Tab1", fluid = TRUE, value = 1,plotOutput("A")),
                  tabPanel("Tab2", fluid = TRUE, value = 2, plotOutput("B"))
      )
    )
  )

)

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

  observe({
    if(input$tab == 1){
      show("Sample")
      show("b1")
      hide("Weight")
      hide("b2")
    }
    if(input$tab == 2){
      hide("Sample")
      hide("b1")
      show("Weight")
      show("b2")
    }
  })

  p1<- eventReactive(input$b1,{
    df <- rnorm(input$Sample)
  })
  output$SA <- renderPlot({
    plot(df)
  })

  p2 <- eventReactive(input$b2,{
    df2 <- rnorm(input$Weight)
  })

  output$A <- renderPlot({plot(p1())})
  output$B <- renderPlot({plot(p2())})
}

shinyApp(ui, server)

enter image description here

Pork Chop
  • 28,528
  • 5
  • 63
  • 77
1

The following code keeps the plots and inputs, by using reactiveValues.

library(shiny)
library(shinydashboard)


ui <- dashboardPage(dashboardHeader(title = "DASHBOARD"),

                    dashboardSidebar(
                      uiOutput("mysidebar")
                    ),

                    dashboardBody(
                      tabsetPanel(type = "tabs", id = "tab",
                                  tabPanel("Tab1",  value = 1,plotOutput("SA")),
                                  tabPanel("Tab2",  value = 2, plotOutput("SA1"))
                      )
                    )
)


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

  slider_react <- reactiveValues(b1=10000, b2 = 100)

  observe({
    if (input$tab == 1){
      output$mysidebar <- renderUI({
        tagList(
          sliderInput(inputId = "Sample",
                      label = "Enter Number of Samples:",
                      min = 1000, max = 100000,
                      # value = 10000),
                      value = slider_react$b1),
          actionButton(inputId = "b1", label = "Generate"))
      })
    }

    if(input$tab == 2){
      output$mysidebar <- renderUI({
        tagList(
          sliderInput(inputId = "Weight",
                      label = "Enter Weight:",
                      min=0, max=1000,
                      # value = 100),
                      value = slider_react$b2),
          actionButton(inputId = "b2", label = "Generate"))
      })
    }
  })


  df_react <- reactiveValues(a1=NULL, a2=NULL)

  p1<- observeEvent(input$b1, {
    #creating a dataframe using input "Sample" in tab1 - Rough example
    df <- runif(input$Sample, 0, 100)
    slider_react$b1 = input$Sample
    df_react$a1 = df
  })
  p2 <- observeEvent(input$b2, {
    #creating a dataframe using input "Weight" in tab2-- Rough example
    df2 <- runif(input$Weight, 0, 100)
    slider_react$b2 = input$Weight
    df_react$a2 = df2
  })

  output$SA <- renderPlot({
    req(df_react$a1)
    plot(df_react$a1)
  })

  output$SA1 <- renderPlot({
    req(df_react$a2)
    plot(df_react$a2)

  })
}

shinyApp(ui, server)
SeGa
  • 9,454
  • 3
  • 31
  • 70
  • Thank you so much! It's working fine now. Any clue on how I can retain the inputs too? – Hammad Patel Jul 17 '18 at 13:10
  • Check out @Pork Chop`s answer. The inputs are created in the ui and with shinyjs he is showing/hiding elements. Like that, the sliderInputs are not recreated everytime you switch between the tabs. I think that solution is much clearer and easier – SeGa Jul 17 '18 at 13:36
  • Just edited my answer. The inputs are retained aswell now, by using another `reactiveValues` object, where the slider-values are stored. – SeGa Jul 17 '18 at 14:06