ACE
ACE

Reputation: 335

Making R Shiny remember the inputs and outputs for app having multi tab panel

I currently have 2 tabPanel() in a Shiny app. The app lets the user upload an excel file. After the upload, the UI elements are generated, in the form of selectizeInput() where the user can select x and y variables. The output is a stacked plotly() graph of one x variable and multiple y variables I have two tab Panels in the app, In the first tabPanel, I select sheet1 of the excel file and their corresponding x and y variables. Similarly, I choose sheet 2 for the second tabPanel and their x and y,

The issue I am having here is I want Shiny to remember the inputs of the 1st tabPanel() after switching to the second tabPanel() and vice versa. Currently, the app refreshes to default state when the user switches between the tab panels. It remembers which sheet is selected in the tabs , but not the x and y variables, Here is a working sample code. I have also attached the excel file for reference - https://docs.google.com/spreadsheets/d/1QYqg0b-_YK7eUhR78usiM4NspZoj5Rfk/edit?usp=sharing&ouid=100116750636203353695&rtpof=true&sd=true

How do I make this work?


options(shiny.maxRequestSize=30*1024^2)

lib <- c("DT","plotly","shiny","data.table", "readr", "openxlsx", "readxl", "tidyverse")

lapply(lib, require, character.only = TRUE)

plotly_stacked <- function(df, x_colName, cols){
  
  
  DF <- df[, cols] %>%
    tidyr::gather(variable, value, -x_colName ) %>%
    transform(id = as.integer(factor(variable)))
  
  DF$variable<- factor( DF$variable, levels = unique( DF$variable))
  names(DF) <- gsub("\\.", " ", names(DF))
  
  p <- plot_ly(data = DF, x = ~Time , y = ~value, color = ~variable, colors = "Dark2",
               yaxis = ~paste0( "y",sort(id, decreasing = F))
  ) %>%
    
    add_lines() %>%
    layout( 
      legend = list(orientation = "h",   # show entries horizontally
                    xanchor = "center",  # use center of legend as anchor
                    x = 0.5)) %>% 
    plotly::subplot(nrows = length(unique(DF$variable)), shareX = TRUE) 
  
  return(p)
  
}

# ui.R ------------------------------------------------------------

ui <-
  
  fluidPage(
    
    
    titlePanel(title = "test data"),
    fileInput("file", "Choose csv file",
              accept = c(".xlsx", ".xls", ".csv", ".txt")
    ),
    
    conditionalPanel(
      condition = "input.tabsetPanelID  == 'tab1'",
      uiOutput("ui_elements1"),
      uiOutput("sheet_elements1")
    ),
    conditionalPanel(
      condition = "input.tabsetPanelID == 'tab2'",
      uiOutput("ui_elements2"),
      uiOutput("sheet_elements2")
    ),
    
    mainPanel(
      tabsetPanel(id = "tabsetPanelID",
                  tabPanel("Tab1", value = "tab1",
                           plotlyOutput("plot1")
                  ) 
                  ,
                  tabPanel("Tab2", value = "tab2",
                           plotlyOutput("plot2"))
      )  
    ) 
  ) 

# server.R ------------------------------------------------------------
server <- function(input, output,session) {
  
  # ui_elementsUI------------------------------------------------------------
  
  ui_elementsUI <- function(x, y) {
    
    tagList(
      h4("Select X and Y datasets"),
      fluidRow(
        
        column(12,
               selectizeInput(inputId = x, label = "X data", choices = names( data()  ))
        )
      ),
      
      fluidRow(
        
        column(12,
               selectizeInput(inputId = y, label = "Y data", choices = names(data()), multiple = T, selected = names(data())[2])
        )
      )
      
    )
    
  }
  # sheet_elementsUI------------------------------------------------------------
  sheet_elementsUI <- function(sheet){
    
    tagList(
      
      fluidRow(
        
        column(12,
               selectInput(inputId = sheet, label = "Sheet", choices = excel_sheets(input$file$datapath))
               
        )
      )
    ) 
  }
  
  
  # Render sheet elements after file upload ------------------------------------
  
  output$sheet_elements1 <- renderUI({
    req(input$file)
    sheet_elementsUI("sheet1")
  })
  
  
  output$sheet_elements2 <- renderUI({
    req(input$file)
    sheet_elementsUI("sheet2")
  })
  
  
  # Render UI elements after file upload ------------------------------------
  
  
  output$ui_elements1 <- renderUI({
    if (has_file()) {
      
      ui_elementsUI("x1","y1")
    }
  })
  
  
  output$ui_elements2 <- renderUI({
    if (has_file()) {
      ui_elementsUI("x2","y2")
    }
  })
  
  plot_render <- reactive({
    validate(
      need(input$file != "", "Plots will display after choosing the csv file. Make sure all your csv files are in the 'data' folder in the main project tree
             ")
    )
    
    foo <-  function(x, y){
      plotly_stacked (df =  data(), x_colName = input[[x]] ,cols = c(input[[x]], input[[y]] ))
    }
    
  })
  
  output$plot1 <- renderPlotly({
    
    plot_render()("x1", "y1")
    
  })
  output$plot2<- renderPlotly({
    
    plot_render()("x2", "y2")
  })
  
  # Reactive expression to read in uploaded file ----------------------------
  
  data <- reactive({
    req(input$file)
    foo <- function(sheet){
      
      df <- read_excel(input$file$datapath, sheet = input[[sheet]])
      
      return(df)
      
    }
    if(  input$tabsetPanelID  == 'tab1'){
      result <- foo("sheet1")
    } else{
      result <- foo("sheet2")
      
    }
    
    return(result)
    
  })
  
  
  # Reactive expression to check if a file has been uploaded ----------------
  
  
  has_file <- reactive({
    !is.null(input$file) && !is.na(input$file$name)
  })
  
}

shinyApp( ui = ui, server = server)

Upvotes: 0

Views: 66

Answers (1)

YBS
YBS

Reputation: 21349

Replace data <- reactive(...) with the following code, and use data1() and data2() for tab1 and tab2, respectively.

foo <- function(sheet){
  df <- read_excel(input$file$datapath, sheet = input[[sheet]])
  return(df)
}

data1 <- reactive({
  req(input$file)
  foo("sheet1")
})

data2 <- reactive({
  req(input$file)
  foo("sheet2")
})

Upvotes: 1

Related Questions