Specifying different number of output plots/tables (Shiny app) - r

I want to give the user option to select which plots/tables he/she wants to see at the end of an analysis.
All the plots are produced from one dataset and include time series plots, boxplots, histograms etc.
The questions I stumbled upon are
Do I use one or multiple plotOutput("Plot",....) element? So far I have been arranging plots in one figure so one plotOutput was sufficient
Do I use the predefined height, as in plotOutput("Plot",height = "1800px")?
If the number of figures varies this creates empty space, I would like to avoid it.
How to add Tables with results?
Any comments would be very appreciated, Mac

You can wrap you plots in conditionalPanel's to deselect them.
For this you will need 1. multiple plotOutput's.
2. When everything is wrapped in a fluidRow there won't be any empty space.
3. See the following example and: http://shiny.rstudio.com/reference/shiny/0.14/tableOutput.html
library(shiny)
library(shinydashboard)
library(shinyWidgets)
ui <- dashboardPage(
dashboardHeader(title = "Plot selection"),
dashboardSidebar(
materialSwitch(inputId="switch1", label = "Show plot 1", value = TRUE, status = "primary"),
materialSwitch(inputId="switch2", label = "Show plot 2", value = TRUE, status = "primary"),
materialSwitch(inputId="switch3", label = "Show plot 3", value = TRUE, status = "primary"),
materialSwitch(inputId="switch4", label = "Show plot 4", value = TRUE, status = "primary")
),
dashboardBody(
# Boxes need to be put in a row (or column)
fluidRow(
conditionalPanel(condition = "input.switch1", box(plotOutput("plot1", height = 250))),
conditionalPanel(condition = "input.switch2", box(plotOutput("plot2", height = 250))),
conditionalPanel(condition = "input.switch3", box(plotOutput("plot3", height = 250))),
conditionalPanel(condition = "input.switch4", box(plotOutput("plot4", height = 250))),
column(12,
dataTableOutput('table')
)
)
)
)
server <- function(input, output) {
df <- data.frame(col1 = rnorm(500), col2 = rnorm(500), col3 = rnorm(500), col4 = rnorm(500))
output$plot1 <- renderPlot({
plot(df$col1, col="red", main="Plot 1")
})
output$plot2 <- renderPlot({
plot(df$col2, col="green", main="Plot 2")
})
output$plot3 <- renderPlot({
plot(df$col3, col="blue", main="Plot 3")
})
output$plot4 <- renderPlot({
plot(df$col4, col="black", main="Plot 4")
})
output$table <- renderDataTable(df)
}
shinyApp(ui, server)
Edit ----------------------------------------
Here is a pure shiny version:
library(shiny)
ui <- fluidPage(
titlePanel("Plot selection"),
sidebarLayout(
sidebarPanel(width = 2,
checkboxInput(inputId="switch1", label = "Show plot 1", value = TRUE),
checkboxInput(inputId="switch2", label = "Show plot 2", value = TRUE),
checkboxInput(inputId="switch3", label = "Show plot 3", value = TRUE),
checkboxInput(inputId="switch4", label = "Show plot 4", value = TRUE)
),
mainPanel(
fluidRow(
conditionalPanel(condition = "input.switch1", plotOutput("plot1", height = 250)),
conditionalPanel(condition = "input.switch2", plotOutput("plot2", height = 250)),
conditionalPanel(condition = "input.switch3", plotOutput("plot3", height = 250)),
conditionalPanel(condition = "input.switch4", plotOutput("plot4", height = 250)),
column(12,
dataTableOutput('table')
)
)
)
)
)
server <- function(input, output) {
df <- data.frame(col1 = rnorm(500), col2 = rnorm(500), col3 = rnorm(500), col4 = rnorm(500))
output$plot1 <- renderPlot({
plot(df$col1, col="red", main="Plot 1")
})
output$plot2 <- renderPlot({
plot(df$col2, col="green", main="Plot 2")
})
output$plot3 <- renderPlot({
plot(df$col3, col="blue", main="Plot 3")
})
output$plot4 <- renderPlot({
plot(df$col4, col="black", main="Plot 4")
})
output$table <- renderDataTable(df)
}
# shinyApp(ui, server)
shinyApp(ui = ui, server = server)
For further information see:
https://rstudio.github.io/shinydashboard/get_started.html
https://dreamrs.github.io/shinyWidgets/reference/materialSwitch.html

Related

How do I structure the layout of my shiny dashboard?

I am creating a simple shiny app, and would love to structure my app in a certain way. See screenshot below -
Some things to highlight -
The solid line below the value boxes
In 3 sections with the sales map, sales trend plot and bar plot, is it possible to have a title for those sections, along with an info action button which I'll use to provide more info about the chart?
I am able to create the sidebar and value boxes with the code below, however I have trouble understanding how to use columns and/or boxes "below" the value boxes. See code below -
library(shiny)
library(shinydashboard)
# UI ----
ui <- navbarPage(
useShinydashboard(),
title = "My App",
tabPanel(
"Tab1", icon = icon("home"),
fluidPage(
sidebarLayout(
sidebarPanel(
width = 2,
dateRangeInput(inputId = "date_range",
label = h4("Date Range"),
start = as.Date("2018-01-01"),
end = as.Date("2020-12-31"),
min = as.Date("2018-01-01"),
max = as.Date("2020-12-31"),
startview = "year"
)
),
mainPanel(
# Value Box 1
valueBoxOutput(outputId = "box_1", width = 3),
# Value Box 2
valueBoxOutput(outputId = "box_2", width = 3),
# Value Box 3
valueBoxOutput(outputId = "box_3", width = 3),
# Value Box 4
valueBoxOutput(outputId = "box_4", width = 3),
br(),
hr()
)
)
)
)
)
# Server ----
server <- function(input, output) {
# Box 1
output$box_1 <- shinydashboard::renderValueBox({
valueBox(5, "box1", color = "green"
)
})
# Box 2
output$box_2 <- renderValueBox({
valueBox(10, "box2", color = "blue"
)
})
# Box 3
output$box_3 <- renderValueBox({
valueBox(15, "box1", color = "purple"
)
})
# Box 4
output$box_4 <- renderValueBox({
valueBox(20, "box1", color = "orange"
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Here is a possibility:
library(shiny)
library(shinydashboard)
library(shinyBS) # for popovers
# UI ----
ui <- navbarPage(
#useShinydashboard(),
title = "My App",
tabPanel(
"Tab1", icon = icon("home"),
fluidPage(
sidebarLayout(
sidebarPanel(
width = 2,
dateRangeInput(inputId = "date_range",
label = h4("Date Range"),
start = as.Date("2018-01-01"),
end = as.Date("2020-12-31"),
min = as.Date("2018-01-01"),
max = as.Date("2020-12-31"),
startview = "year"
)
),
mainPanel(
fluidRow(
# Value Box 1
valueBoxOutput(outputId = "box_1", width = 3),
# Value Box 2
valueBoxOutput(outputId = "box_2", width = 3),
# Value Box 3
valueBoxOutput(outputId = "box_3", width = 3),
# Value Box 4
valueBoxOutput(outputId = "box_4", width = 3),
),
tags$hr(),
br(),
fluidRow(
column(
width = 6,
tags$fieldset(
tags$legend("Plot 1", tags$span(id = "info1", icon("info-circle"))),
plotOutput("plot1", height = "600px")
)
),
bsPopover(
"info1",
title = "This is plot 1",
content = "This plot is nice",
placement = "left"
),
column(
width = 6,
tags$fieldset(
tags$legend("Plot 2"),
plotOutput("plot2", height = "300px")
),
tags$fieldset(
tags$legend("Plot 3", heigh = "300px"),
plotOutput("plot3")
)
),
)
)
)
)
)
)
# Server ----
server <- function(input, output) {
# Box 1
output$box_1 <- shinydashboard::renderValueBox({
valueBox(5, "box1", color = "green")
})
# Box 2
output$box_2 <- renderValueBox({
valueBox(10, "box2", color = "blue")
})
# Box 3
output$box_3 <- renderValueBox({
valueBox(15, "box1", color = "purple")
})
# Box 4
output$box_4 <- renderValueBox({
valueBox(20, "box1", color = "orange")
})
####
output$plot1 <- renderPlot({
plot(rnorm(10), rnorm(10))
})
output$plot2 <- renderPlot({
plot(rnorm(10), rnorm(10))
})
output$plot3 <- renderPlot({
plot(rnorm(10), rnorm(10))
})
}
# Run the application
shinyApp(ui = ui, server = server)

Shiny app - hide/show text comment under the plot after clicking checkbox

I want to build an app with the checkbox asking whether to show additional text comments under the figures.
I would like to display set of plots with or without an explanation - this shall be left to the user, whether they need more info or not.
Here are some dummy comments:
#info for box1:
"This is the red histogram"
#info for box2:
"This is the blue histogram"
Here is a dummy app:
library(shiny)
library(shinydashboard)
data <- rnorm(10000, mean=8, sd=1.3)
variable <- "This is the blue histogram"
shinyApp(
ui = dashboardPage(
skin = "black",
dashboardHeader(
title = "Example app",
titleWidth = 300
),
dashboardSidebar(
checkboxInput("show_comment",
label = "Show comment?",
value = FALSE)
),
dashboardBody(
box(title = "First histogram",
status= "warning",
plotOutput("plot1", height=300)
),
box(title = "Second histogram",
status= "warning",
plotOutput("plot2", height=300),
hidden(
div(id='text_div',
verbatimTextOutput("text")))
)
)
),
server = function(input, output) {
output$plot1 <- renderPlot({
hist(data, breaks=40, col="red", xlim=c(2,14), ylim=c(0,800))
})
output$plot2 <- renderPlot({
hist(data, breaks=20, col="blue", xlim=c(2,34), ylim=c(0,1000))
})
observeEvent(input$show_comment, {
toggle('text_div')
output$text <- renderText({ paste0(variable)})
})
}
)
The above code does not work properly - it displays comment no matter if the checkbox is clicked or not. I'd like to make it work, therefore seek for advice here.
I was trying to do it on my own using following hints, to no avail:
How to use shiny actionButton to show & hide text output?
This syntax is too complex for me as I am a beginner with shiny, so I was not able to troubleshoot my problem with hints from this thread:
Show and hide text in modularized shiny app based on actionButton() and shinyJS()
I also tried ths:
Hide/show outputs Shiny R
And here is the attempt of using above hint:
library(shiny)
library(shinydashboard)
data <- rnorm(10000, mean=8, sd=1.3)
variable <- "This is the blue histogram"
shinyApp(
ui = dashboardPage(
skin = "black",
dashboardHeader(
title = "Example app",
titleWidth = 300
),
dashboardSidebar(
checkboxInput("show_comment",
label = "Show comment?",
value = FALSE)
),
dashboardBody(
box(title = "First histogram",
status= "warning",
plotOutput("plot1", height=300)
),
box(title = "Second histogram",
status= "warning",
plotOutput("plot2", height=300),
renderText("text", span(variable))
)
)
),
server = function(input, output) {
output$plot1 <- renderPlot({
hist(data, breaks=40, col="red", xlim=c(2,14), ylim=c(0,800))
})
output$plot2 <- renderPlot({
hist(data, breaks=20, col="blue", xlim=c(2,34), ylim=c(0,1000))
})
observeEvent(input$show_comment, {
# every time the button is pressed, alternate between hiding and showing the plot
toggle("text")
})
}
)
I want to put the comments inside the same box, along with the plot - this is why I am trying to enclose it with the box command. However, if it is impossible - I would be glad of any other solution.
First time I use shinyjs so there might be a better approach. But as I understand it from the docs you first have to add useShinyjs() in your UI code
in order for all other shinyjs functions to work.
Second, there is no need to wrap the div for your comment in hidden(). Third, instead of using observeEvent I followed the example in ?toggle and use an observe where I add the state of your checkbox as the condition to trigger the toggle.
library(shiny)
library(shinydashboard)
library(shinyjs)
data <- rnorm(10000, mean = 8, sd = 1.3)
variable <- "This is the blue histogram"
shinyApp(
ui = dashboardPage(
skin = "black",
dashboardHeader(
title = "Example app",
titleWidth = 300
),
dashboardSidebar(
checkboxInput("show_comment",
label = "Show comment?",
value = FALSE
)
),
dashboardBody(
box(
title = "First histogram",
status = "warning",
plotOutput("plot1", height = 300)
),
box(
title = "Second histogram",
status = "warning",
plotOutput("plot2", height = 300),
div(id = "text_div",
verbatimTextOutput("text")
)
)
),
useShinyjs()
),
server = function(input, output) {
output$plot1 <- renderPlot({
hist(data, breaks = 40, col = "red", xlim = c(2, 14), ylim = c(0, 800))
})
output$plot2 <- renderPlot({
hist(data, breaks = 20, col = "blue", xlim = c(2, 34), ylim = c(0, 1000))
})
observe({
toggle(id = "text_div", condition = input$show_comment)
output$text <- renderText({
paste0(variable)
})
})
}
)
#>
#> Listening on http://127.0.0.1:7437

Using ConditionalPanel with checkboxGroupInput

Hello everyone I'm trying to write a function in Shiny R.
I have checkboxgroupinput like this:
checkboxGroupInput("quality", "Columns in quality to show:",
choices = numbers, selected = numbers, width = '50%' ), width =2)
I want a histogram to appear when at least one box is selected otherwise it shows helptex("please select at least one").
How can I do this?
library(shiny)
ui <- fluidPage(
br(),
checkboxGroupInput(
"quality", "Columns in quality to show:",
choices = c("A", "B", "C"), selected = c("A", "B", "C"), width = "50%"
),
br(),
conditionalPanel(
condition = "input.quality.length === 0",
helpText("Select at least one column")
),
conditionalPanel(
condition = "input.quality.length !== 0",
plotOutput("histo")
)
)
server <- function(input, output, session){
output[["histo"]] <- renderPlot({
x <- faithful$waiting
bins <- seq(min(x), max(x), length.out = 11)
hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times")
})
}
shinyApp(ui, server)

R Shiny tabpanel tabs with KPI titles

I'd like to have KPI inside R Shiny tabpanel titles, like below, is there an elegant way to do this or a package which can do it? (Please note, the chart is irrelevant to the question).
This is my attempt:
Here is the code:
library(shinydashboard)
ui <- fluidPage({
ib1 <- infoBox("Test 1", 10 * 2, icon = icon("credit-card"), fill = TRUE)
ib2 <- infoBox("Test 2", 10 * 2, icon = icon("table"), fill = TRUE)
tabsetPanel(
tabPanel(ib1, plotOutput("plot")),
tabPanel(ib2)
)
})
server <- function(input, output, session) {
output$plot <- renderPlot({
hist(
rnorm(100),
main = paste("n =", 100),
xlab = ""
)
})
}
shinyApp(ui, server)

Keep plots and input values when switching between tabs

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)

Resources