Keep plots and input values when switching between tabs - r

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())
})
}

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)

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)

Related

How to change variable name using textInput in a ShinyApp?

I would like the name of the variables to change according to a text typed in textInput.
For example, when I typed "Stack Overflow" in "A1" field, this name ("Stack Overflow") would appear as the new name, instead conj1.
My code:
library(shiny)
library(shinydashboard)
header <- dashboardHeader(title = "Dashboard", titleWidth = 300)
sidebar <- dashboardSidebar(width = 300,
sidebarMenu(
menuItem(text = "Simulador", tabName = "simulador1",icon = icon("dashboard"))
)
)
body <- dashboardBody(
column(id = "c1", width = 12,
textInput(inputId = "ar1", label = "A 1", placeholder = "Digite")
),
column(id = "colsimul4", width = 12,
textInput(inputId = "lvl1", value = 1,label = "Nível 1", placeholder = "Digite")
),
column(width = 12, tableOutput(outputId = "new"))
)
server <- function(session, input, output) {
fpred_1 <- function(x) {
x
}
predattr1 <- reactive({
fpred_1(x = input$ar1)
})
pred_1 <- reactive({
fpred_1(x = input$lvl1)
})
output$new <- renderTable({
isolate(expr = conj1 <- predattr1())
experiment <- expand.grid(conj1 = c(pred_1()))
isolate(expr = experiment)
})
}
ui <- dashboardPage(header, sidebar, body)
shinyApp(ui, server)
I would like the name of the variables conj to be modified according to what is typed in the field A1
I tried this:
isolate(expr = conj1 <- predattr1())
But doesn't work.
For example, if I typed "Stack Overflow", this name appears instead of conj1.
The values ​​change normally, only the variable names do not.
Edit
I tried that too:
output$new <- renderTable({
isolate(expr = conj1 <- predattr1())
x <- names(predattr1())
experiment <- expand.grid(
colnames(x)[1] = c(pred_1())
)
expr = experiment
})
Nothing...
library(shiny)
library(shinydashboard)
################################################################################
# UI
################################################################################
# Header
header <- dashboardHeader(title = "Dashboard", titleWidth = 300)
# Sidebar
sidebar <- dashboardSidebar(width = 300,
sidebarMenu(menuItem(
text = "Simulador",
tabName = "simulador1",
icon = icon("dashboard")
)))
# Body
body <- dashboardBody(
column(
id = "c1",
width = 12,
# Text input 1
textInput(
inputId = "ar1",
label = "A1",
placeholder = "Digite"
)
),
column(
id = "colsimul4",
width = 12,
# Text input 2
textInput(
inputId = "lvl1",
value = 1,
label = "Nível 1",
placeholder = "Digite"
)
),
# Table appears below text inputs in same column/panel
column(width = 12, tableOutput(outputId = "new"))
)
ui <- dashboardPage(header, sidebar, body)
################################################################################
# Server
################################################################################
server <- function(session, input, output) {
# Create table
experiment <- reactive({
df <- expand.grid(req(input$lvl1))
colnames(df) <- req(input$ar1)
return(df)
})
# Render table
output$new <- renderTable({
experiment()
})
}
shinyApp(ui, server)

Automatically Updating a DT works when using Shiny, but not in shinydashboard with multiple tabs

I designed a Shiny app with a DT that can detect if the input fields changes and automatically update the values. Below is a screen shot and my code. This app works as I expected. When running this app, values are updated accordingly in DT based on the input values.
# Load the packages
library(tidyverse)
library(shiny)
library(DT)
# Create an empty data frame
dat <- tibble(
Input = c("SliderInput", "RadioButtons", "TextInput"),
Value = NA_character_
)
ui <- fluidPage(
titlePanel("DT: Document the Input Values"),
sidebarLayout(
sidebarPanel = sidebarPanel(
# The input widgets
sliderInput(inputId = "Slider", label = "The SliderInput", min = 1, max = 10, value = 5),
br(),
radioButtons(inputId = "Radio", label = "The RadioButtons", choices = c("A", "B", "C")),
br(),
textInput(inputId = "Text", label = "The TextInput", value = "Enter text ...")
),
mainPanel = mainPanel(
# The datatable
DTOutput(outputId = "d1")
)
)
)
server <- function(input, output, session){
# Save the dat to a reactive object
dat_save <- reactiveValues(df = dat)
output$d1 <- renderDT(dat, options = list(pageLength = 5), editable = TRUE, rownames = TRUE)
# Save the condition of the data table d1
d1_proxy <- dataTableProxy("d1")
# Edit the data table
observeEvent(input$d1_cell_edit, {
dat_save$df <- editData(dat_save$df, input$d1_cell_edit, d1_proxy)
})
# Update the input numbers for each cell
observeEvent(input$Slider, {
dat_save$df[1, "Value"] <- as.character(input$Slider)
})
observeEvent(input$Radio, {
dat_save$df[2, "Value"] <- input$Radio
})
observeEvent(input$Text, {
dat_save$df[3, "Value"] <- input$Text
})
observe({
replaceData(d1_proxy, dat_save$df, resetPaging = FALSE)
})
}
shinyApp(ui, server)
However, when I transferred the same code to a shinydahsboard with more than one tab. The DT cannot update the values when first initialize the app. Below is a screenshot and the code.
# Load the packages
library(tidyverse)
library(shiny)
library(shinydashboard)
library(DT)
# Create an empty data frame
dat <- tibble(
Input = c("SliderInput", "RadioButtons", "TextInput"),
Value = NA_character_
)
ui <- function(request) {
dashboardPage(
# The header panel
header = dashboardHeader(title = ""),
# The sidebar panel
sidebar = dashboardSidebar(
# The sidebar manual
sidebarMenu(
id = "tabs",
# Tab 1
menuItem(
text = "Tab1",
tabName = "Tab1"
),
# Tab 2
menuItem(
text = "DT Example",
tabName = "DT_E"
)
)),
# The main panel
body = dashboardBody(
tabItems(
tabItem(
# The tab name
tabName = "Tab1",
h2("Placeholder")
),
# Tab 2: DT example
tabItem(
# The tab name
tabName = "DT_E",
h2("DT: Document the Input Values"),
sidebarPanel(
# The input widgets
sliderInput(inputId = "Slider", label = "The SliderInput", min = 1, max = 10, value = 5),
br(),
radioButtons(inputId = "Radio", label = "The RadioButtons", choices = c("A", "B", "C")),
br(),
textInput(inputId = "Text", label = "The TextInput", value = "Enter text ...")
),
# The datatable
DTOutput(outputId = "d1")
)
)
)
)
}
server <- function(input, output, session){
# Save the dat to a reactive object
dat_save <- reactiveValues(df = dat)
output$d1 <- renderDT(dat, options = list(pageLength = 5), editable = TRUE, rownames = TRUE)
# Save the condition of the data table d1
d1_proxy <- dataTableProxy("d1")
# Edit the data table
observeEvent(input$d1_cell_edit, {
dat_save$df <- editData(dat_save$df, input$d1_cell_edit, d1_proxy)
})
# Update the input numbers for each cell
observeEvent(input$Slider, {
dat_save$df[1, "Value"] <- as.character(input$Slider)
})
observeEvent(input$Radio, {
dat_save$df[2, "Value"] <- input$Radio
})
observeEvent(input$Text, {
dat_save$df[3, "Value"] <- input$Text
})
observe({
replaceData(d1_proxy, dat_save$df, resetPaging = FALSE)
})
}
shinyApp(ui, server)
Notice that if there is only one tab in the shinydashboard, the DT will work. If changed any input values after initializing the app, the DT will also work. But it is a mystery to me why the DT cannot work in the first place when the shinydashboard has multiple tabs. Any suggestions or comments would be great.
After further search, I found a solution from this post and this post. For some reasons, the default setting for shinydashboard is to ignore hidden objects starting the second tab. In my case, adding outputOptions(output, "d1", suspendWhenHidden = FALSE) solves the issue. Below is the complete code.
# Load the packages
library(tidyverse)
library(shiny)
library(shinydashboard)
library(DT)
# Create an empty data frame
dat <- tibble(
Input = c("SliderInput", "RadioButtons", "TextInput"),
Value = NA_character_
)
ui <- function(request) {
dashboardPage(
# The header panel
header = dashboardHeader(title = ""),
# The sidebar panel
sidebar = dashboardSidebar(
# The sidebar manual
sidebarMenu(
id = "tabs",
# Tab 1
menuItem(
text = "Tab1",
tabName = "Tab1"
),
# Tab 2
menuItem(
text = "DT Example",
tabName = "DT_E"
)
)),
# The main panel
body = dashboardBody(
tabItems(
tabItem(
# The tab name
tabName = "Tab1",
h2("Placeholder")
),
# Tab 2: DT example
tabItem(
# The tab name
tabName = "DT_E",
h2("DT: Document the Input Values"),
sidebarPanel(
# The input widgets
sliderInput(inputId = "Slider", label = "The SliderInput", min = 1, max = 10, value = 5),
br(),
radioButtons(inputId = "Radio", label = "The RadioButtons", choices = c("A", "B", "C")),
br(),
textInput(inputId = "Text", label = "The TextInput", value = "Enter text ...")
),
# The datatable
DTOutput(outputId = "d1")
)
)
)
)
}
server <- function(input, output, session){
# Save the dat to a reactive object
dat_save <- reactiveValues(df = dat)
output$d1 <- renderDT(dat, options = list(pageLength = 5), editable = TRUE, rownames = TRUE)
outputOptions(output, "d1", suspendWhenHidden = FALSE)
# Save the condition of the data table d1
d1_proxy <- dataTableProxy("d1")
# Edit the data table in tab 3
observeEvent(input$d1_cell_edit, {
dat_save$df <- editData(dat_save$df, input$d1_cell_edit, d1_proxy)
})
# Update the input numbers for each cell
observeEvent(input$Slider, {
dat_save$df[1, "Value"] <- as.character(input$Slider)
})
observeEvent(input$Radio, {
dat_save$df[2, "Value"] <- input$Radio
})
observeEvent(input$Text, {
dat_save$df[3, "Value"] <- input$Text
})
observe({
replaceData(d1_proxy, dat_save$df, resetPaging = FALSE)
})
}
shinyApp(ui, server)

shiny fix position of collapsible panel

I'm trying to make this shiny app have a collapsible panel fixed at the top. But, whenever I make the position fixed, the collapse functionality doesn't work.
What do I have to do to fix this collapsible panel on top?
library(shiny)
library(shinyWidgets)
library(shinyBS)
library(DT)
ui <- fluidPage(
fluidRow(
column(4),
column(4,
div(
bsCollapse(id = "cntrlC1", open = "Panel 2",
bsCollapsePanel("Control Panel",
htmlOutput("dateSelector", inline = TRUE),
style = "info"
)
)
)
)
),
fluidRow(
DTOutput('sampleTbl')
)
)
server <- function(input, output, session){
output$dateSelector <- renderUI({
airDatepickerInput(
"dateSelector",
label = "Select Start & End Dates",
value = c("2020-01-01", "2020-01-10"),
multiple = 2
)
})
output$sampleTbl <- DT::renderDT(server = TRUE, {
data <- data.frame(A = rep(1, 100), B = rep(2, 100), C = rep(3, 100))
m <- datatable(
data,
options = list(pageLength = 100)
)
m
})
}
shinyApp(ui, server)
Perhaps you are looking for this
ui <- fluidPage(
fluidRow(
column(4),
column(4,
div(
bsCollapse(id = "cntrlC1", open = "Panel 2",
bsCollapsePanel("Control Panel",
htmlOutput("dateSelector", inline = TRUE),
style = "info"
)
), style="position:fixed;"
)
)
),
fluidRow(
column(width=2, textInput("searchField1", "Search")),
column(width=2, uiOutput("saveText1"), actionButton("saveBtn1", "Save"))
),
fluidRow(
DTOutput('sampleTbl')
)
)
server <- function(input, output, session){
output$dateSelector <- renderUI({
airDatepickerInput(
"dateSelector",
label = "Select Start & End Dates",
value = c("2020-01-01", "2020-01-10"),
multiple = 2
)
})
output$sampleTbl <- DT::renderDT(server = TRUE, {
data <- data.frame(A = rep(1, 100), B = rep(2, 100), C = rep(3, 100))
m <- datatable(
data,
options = list(pageLength = 100)
)
m
})
}
shinyApp(ui, server)

Trouble with a Reactive Input in ShinyDashboard

I am using the following dataset: https://docs.google.com/spreadsheets/d/1C_P5xxzYr7HOkaZFfFiDhanqDSuSIrd2UkiC-6_G2q0/edit#gid=0
I am using ShinyDashboard and I have a selectInput that allows me to choose a specific type of Candy bar (in the Candy column in my data set).
How do I take that Candy selection, and then make a graph that contains the frequency for that selected candy bar for each purchase month? In my server.R, I am not sure what to have in that CandyCount reactive element.
My code is as follows:
## ui.R ##
library(shinydashboard)
library(rCharts)
dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(
width = 150,
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("bar-chart"))
)
),
dashboardBody(
sidebarPanel(
htmlOutput("candy")
),
mainPanel(
showOutput("plot2", "polycharts")
)))
##server.R##
server <- function(input, output, session) {
output$candy<- renderUI({
selectInput(
inputId = "candy",
label = "Candy: ",
choices = as.character(unique(dataset$Candy)),
selected = "Twix"
)
})
output$plot2 <- renderChart2({
candySelect<- input$candy
df <- dataset[dataset$candy == candySelect,]
p2 <- rPlot(freq~purchase_month, data = df, type = 'line')
p2$guides(y = list(min = 0, title = ""))
p2$guides(y = list(title = ""))
p2$addParams(height = 300, dom = 'chart2')
return(p2)
})
}
If your okay with using ggplot you could do something like this:
Edited to have dynamic tooltip
## ui.R ##
library(shinydashboard)
library(shinyBS)
require(ggplot2)
dataset <- read.csv("Sample Dataset - Sheet1.csv")
ui <- dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(
width = 150,
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("bar-chart"))
)
),
dashboardBody(
sidebarPanel(
htmlOutput("candy")
),
mainPanel(
uiOutput("plotUI")
)
))
##server.R##
server <- function(input, output, session) {
output$candy<- renderUI({
selectInput(
inputId = "candy",
label = "Candy: ",
choices = as.character(unique(dataset$Candy)),
selected = "Twix"
)
})
output$plotUI <- renderUI({
if(is.null(input$candy)) return(NULL)
local({
candySelect <- input$candy
str1 <- sprintf("The candybar you selected is: %s",candySelect)
str2 <- sprintf("More about %s <a>here</a>",candySelect)
print (str1)
popify(plotOutput('plot'),str1,str2)
})
})
observeEvent(input$candy,{
if(is.null(input$candy)) return(NULL)
candySelect<- input$candy
print ('plot')
# Assuming only one entry for each mont per candybar
d <- dataset[dataset$Candy==candySelect,]
output$plot <- renderPlot({
ggplot(data=d, aes(x=purchase_month,y=freq,group=Candy)) +
geom_line() +
ggtitle(candySelect)
})
})
}
shinyApp(ui = ui, server = server)
I guess this should work otherwise you can bind tooltips using jQuery.

Modify my rChart based on a reactive input?

I am having trouble with some code that I've written.
Here is a sample of the dataset: https://docs.google.com/spreadsheets/d/1C_P5xxzYr7HOkaZFfFiDhanqDSuSIrd2UkiC-6_G2q0/edit?usp=sharing
Objective:
I have a dataset that contains a column of Purchase_Month, candy and freq of the number of times that type of candy was purchased in that given month.
I have an rPlot which I was to change based on the chosen Candy bar in the SelectInput. And output a line chart based on the number of times that candy was purchased that month.
I have my current code below, but it tells me that candyCount is not found.
## ui.R ##
library(shinydashboard)
library(rCharts)
dashboardPage(
dashboardHeader(title = "Dashboard"),
dashboardSidebar(
width = 150,
sidebarMenu(
menuItem("Dashboard", tabName = "dashboard", icon = icon("bar-chart"))
)
),
dashboardBody(
sidebarPanel(
htmlOutput("candy")
),
mainPanel(
showOutput("plot2", "polycharts")
))
)
##server.R##
library(rCharts)
library(ggplot2)
library(ggvis)
server <- function(input, output, session) {
output$candy <- renderUI({
available2 <- dataset[(dataset$candy == input$candy), "candy"]
selectInput(
inputId = "candy",
label = "Choose a candy: ",
choices = sort(as.character(unique(available2))),
selected = unique(available2[1])
)
})
observeEvent(input$candy, {
candyChoice<- toString(input$customer_issue)
print(candyChoice)
candyCount<- dataset[dataset$candy == candyChoice, ]
})
})
output$plot2 <- renderChart2({
p2 <- rPlot(freq~purchase_month, data = candyCount, type = 'line')
p2$guides(y = list(min = 0, title = ""))
p2$guides(y = list(title = sprintf("%s Claims",input$candy)))
p2$addParams(height = 300, dom = 'chart2')
return(p2)
})
}
Updated Data: Why wouldn't this work?
candyCount<- reactive({
dataset[dataset$candy == input$candy, ]
})
output$plot2 <- renderChart2({
p2 <- rPlot(freq~purchase, data = candyCount(), type = 'line')
p2$guides(y = list(min = 0, title = ""))
p2$guides(y = list(title = ""))
p2$addParams(height = 300, dom = 'chart2')
return(p2)
})
output$candy <- renderUI({
available2 <- dataset[(dataset$candy == input$candy), "candy"]
selectInput(
inputId = "candy",
label = "Choose a candy: ",
choices = sort(as.character(unique(available2))),
selected = unique(available2[1])
)
})
In the above you are trying to subset by an input, which is inside your output. The selectInput needs to be inside UI.R.
A working basic example you may find useful.
library(shiny)
df <- read.csv("/path/to/my.csv")
ui <- shinyUI(pageWithSidebar(
headerPanel('Candy Data'),
sidebarPanel(
selectInput('candy', 'Candy', unique(as.character(df[,2])), selected = "Twix")
),
mainPanel(
plotOutput('plot1')
)
))
server <- shinyServer(function(input, output, session) {
selectedData <- reactive({
df[which(df[,2] == input$candy),3]
})
output$plot1 <- renderPlot({
barplot(selectedData())
})
})
shinyApp(ui, server)
In the above example the ui renders a selectInput which has the ID candy. The value, i.e the candy selected is now assigned to input$candy scope. In server we have a reactive function watching for any input change. When the user selects a new candy this function, df[which(df[,2] == input$candy),3] is saying "subset my data frame, df, by the new input$candy". This is now assigned to the selectedData(). Finally we render then boxplot.
EDIT
server.R
require(rCharts)
options(RCHART_WIDTH = 500)
df <- read.csv("path/to/my.csv")
shinyServer(function(input, output, session) {
selectedData <- reactive({
df[which(df[,2] == input$candy),]
})
output$plot1 <- renderChart({
p <- rPlot(freq~purchase_month, data = selectedData(), type = "line")
p$addParams(dom = 'plot1')
return(p)
})
})
ui.R
require(rCharts)
options(RCHART_LIB = 'polycharts')
shinyUI(pageWithSidebar(
headerPanel('Candy Data'),
sidebarPanel(
selectInput('candy', 'Candy', unique(as.character(df[,2])), selected = "Twix")
),
mainPanel(
showOutput('plot1', 'polycharts')
)
))
save files in directory and then runApp.
At available2 you're filtering the data about a selected candy with dataset$candy == input$candy. But you use the same available2 to determine which are the choices at selectInput. I'm guessing you wanted: available2 <- dataset[, "candy"].

Resources