Adjust plotly output height to box with dynamic height in shiny dashboard - r

In the shiny app below I have a box which height depends on the number of shiny widgets it includes and a plot. I would like the box height to somehow saved every time it changes and be passed to the plot in order to have the same height always.
library(shiny)
library(plotly)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
# Copy the line below to make a set of radio buttons
radioButtons("radio1", label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2),
selected = 1)
),
dashboardBody(
fluidRow(
column(4,
box(
# Copy the line below to make a set of radio buttons
radioButtons("radio2", label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1),
uiOutput("rd3")
)),
plotlyOutput("t2")
)
)
)
server <- function(input, output, session) {
output$rd3<-renderUI({
if(input$radio1==1){
return(NULL)
}
else{
radioButtons("radio3", label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1)
}
})
output$t2<-renderPlotly(
fig <- plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
)
}
shinyApp(ui, server)

The following works based on spsComps::heightMatcher.
However, I needed to trigger a resize event via shinyjs to avoid the plot height getting out of sync after a few clicks, which I think should not be necessary (also makes it quite slow).
library(shiny)
library(plotly)
library(shinydashboard)
library(spsComps)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(# Copy the line below to make a set of radio buttons
radioButtons(
"radio1",
label = h3("Radio buttons"),
choices = list("Choice 1" = 1, "Choice 2" = 2),
selected = 1
)),
dashboardBody(
useShinyjs(),
fluidRow(
column(4,
box(
id = "box_1",
# Copy the line below to make a set of radio buttons
radioButtons(
"radio2",
label = h3("Radio buttons"),
choices = list(
"Choice 1" = 1,
"Choice 2" = 2,
"Choice 3" = 3
),
selected = 1
),
uiOutput("rd3")
)),
box(id = "box_2", plotlyOutput("t2", height = "100%")),
spsComps::heightMatcher("box_2", "box_1")
)
)
)
server <- function(input, output, session) {
observeEvent(input$radio1, {
shinyjs::runjs("$(window).trigger('resize');")
})
output$rd3 <- renderUI({
if (input$radio1 == 1) {
return(NULL)
} else {
radioButtons(
"radio3",
label = h3("Radio buttons"),
choices = list(
"Choice 1" = 1,
"Choice 2" = 2,
"Choice 3" = 3
),
selected = 1
)
}
})
output$t2 <- renderPlotly({fig <-
plot_ly(
data = iris,
x = ~ Sepal.Length,
y = ~ Petal.Length
)})
}
shinyApp(ui, server)

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 - disable selection of radio buttons upon selection of a checkbox

Is it possible to incorperate code in shiny to disable the selection of certain radio buttons upon the selection of a checkbox? For example, upon selection of ID039, selection of ID038 and ID037 would be disabled? For the given example, I need to ensure that if the checkbox option (NA) is selected, the summary table does not compute the minimum score for ID038 and ID037.
library(shinydashboard)
library(shinythemes)
library(shiny)
library(shinyWidgets)
library(DT)
library(tidyverse)
ui <- fluidPage(
theme = shinytheme("united"),
# Application title
titlePanel("TITLE"),
sidebarLayout(
sidebarPanel(
selectInput("select",
label = helpText("Select a critera"),
choices = list("Criteria_1", "Criteria_2"),
selected = c("NULL")
)
),
mainPanel(tabsetPanel(
tabPanel(
"Criteria", conditionalPanel(h3("Question 1", align = "left"),
condition = "input.select == 'Criteria_1'",
prettyRadioButtons(
inputId = "Id037_crit1",
label = "Predictions:",
choices = c(
"Option 1" = 1,
"Option 2" = 2,
"Option 3" = 3
),
inline = TRUE,
status = "danger",
fill = TRUE
),
),
conditionalPanel(h3("Question 2", align = "left"),
condition = "input.select == 'Criteria_1'",
prettyRadioButtons(
inputId = "Id038_crit1",
label = "Hypotheses:",
choices = c(
"Option 1" = 1,
"Option 2" = 2,
"Option 3" = 3
),
inline = TRUE,
status = "danger",
fill = TRUE
)
),
# SERVER ------------------------------------------------------------------
server <- function(input, output) {
calc_min_val <- function(contains) {
radios_inputid <- str_subset(names(input), contains)
map_dbl(radios_inputid, ~ as.numeric(input[[.x]])) %>%
min()
}
summ <- reactive({
min_values <- c("crit1$", "crit2$") %>%
map(calc_min_val)
tibble(
Lowest_Criteria = c("Specific hypotheses and prediction are provided?", "Predictions regarding the electromagnetic area of
interest are sufficient?"),
value = map(min_values, ~.)
)
})
output$summary <- DT::renderDT({
datatable(summ())
})}
shinyApp(ui, server)
To disable the radio buttons you can use shinyjs package and the following code on the server side.
observeEvent(input$Id039_crit1,{
if (input$Id039_crit1) {
shinyjs::disable("Id037_crit1")
shinyjs::disable("Id038_crit1")
}else {
shinyjs::enable("Id037_crit1")
shinyjs::enable("Id038_crit1")
}
})

Reactivity and Renders doesn't work when switching to another tabPanel

I have a reproducible example below where only the first tabPanel is working, however when I switch to another panel, I don't get any renders (the toggle becomes un-interactable also). I have looked into conditionalPanel however I see them getting done without the use of mainPanel I was wondering if it possible to have tabs where each tab has its own mainPanel , so I can see a different sidebar and an output contained within different tabs. Any help is welcome!
options(scipen = 99999) #converts the sci numbers to their regular format
library(shiny)
library(shinyjs)
library(shinyWidgets)
library(shinyalert)
library(esquisse)
library(DT)
library(dplyr)
#library(devtools)
#library(remotes)
#remotes::install_github("dreamRs/esquisse")
library(hrbrthemes)
library(ggthemes)
library(ggplot2)
library(svglite)
ui <- fluidPage(
shinyjs::useShinyjs(), # enables javascript/jQuery enhanchments
# Create Right Side Text
navbarPage(
title= div(HTML("G<em>T</em>")),
#General reports
tabPanel("General Reports",
shinyWidgets::materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
value = TRUE, status = "warning"),
sidebarLayout(
# radio/action buttons
sidebarPanel(
id = "Sidebar",
shinyWidgets::prettyRadioButtons(
inputId = "controller",
label = "Choose:",
choices = c("About"= 1,
"iris"= 2),
icon= icon("check"),
selected = 1,
status = "success",
animation="smooth"
),
br(),
br(),
a(actionButton(inputId = "admin_email", label = "Contact",
icon = icon("envelope", lib = "font-awesome")),
href="mailto:xyz#email.us")
),
#panel where output is shown from server
mainPanel(
id = "main_panel",
tabsetPanel(
id = "hidden_tabs",
type = "hidden",
tabPanelBody(
"panel1", "Text coming soon."
),
tabPanelBody(
"panel2",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel2_data')),
tabPanel(
"DIY Plot",
esquisse::esquisse_ui(
id = "esquisse2",
header = FALSE,
container = esquisseContainer(
width = "100%", height = "760px", fixed = FALSE
),
controls = c("labs", "parameters", "appearance", "filters", "code")
)
)
)
)
)
)
)
),
# monthly reports
tabPanel("Extra General Reports",
shinyWidgets::materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
value = TRUE, status = "warning"),
sidebarLayout(
# radio/action buttons
sidebarPanel(
id = "Sidebar",
shinyWidgets::prettyRadioButtons(
inputId = "controller",
label = "Choose:",
choices = c("About"= 3,
"mtcars"= 4),
icon= icon("check"),
selected = 3,
status = "success",
animation="smooth"
),
br(),
br(),
a(actionButton(inputId = "admin_email", label = "Contact",
icon = icon("envelope", lib = "font-awesome")),
href="mailto:xyz#email.us")
),
#panel where output is shown from server
mainPanel(
id = "main_panel",
tabsetPanel(
id = "hidden_tabs",
type = "hidden",
tabPanelBody(
"panel3", "Text coming soon."
),
tabPanelBody(
"panel4",
tabsetPanel(
tabPanel("Data", DT::DTOutput('panel4_data')),
tabPanel(
"DIY Plot",
esquisse::esquisse_ui(
id = "esquisse4",
header = FALSE,
container = esquisseContainer(
width = "100%", height = "760px", fixed = FALSE
),
controls = c("labs", "parameters", "appearance", "filters", "code")
)
)
)
)
)
)
)
),
#resizes the navbar tabs/button
tags$head(tags$style(HTML('.navbar-brand {width: 270px; font-size:35px; text-align:left;
font-family: "serif";')))
)
)
server <- function(input, output, session) {
# this event hides the side panel when toggled on/off
observeEvent(input$toggleSidebar, {
shinyjs::toggle(id = "Sidebar", condition = input$toggleSidebar)
if(!isTRUE(input$toggleSidebar)) {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-8').addClass('col-sm-12')")
} else {
shinyjs::runjs("$('#main_panel').removeClass('col-sm-12').addClass('col-sm-8')")
}
})
# here we put all the data
data_sets <- list(df1 = data.frame(),
df2 = iris,
df3 = data.frame(),
df4 = mtcars)
# store current dataset in reactive so we can work with plot panels
data_to_use <- reactiveValues(name = "df", data = data.frame())
# modules only need to be called it once but individually for esquisse
esquisse::esquisse_server(id = "esquisse2", data_rv = data_to_use)
esquisse::esquisse_server(id = "esquisse4", data_rv = data_to_use)
observeEvent(input$controller, {
# skip first panel since it is used to display navigation
updateTabsetPanel(session, inputId= "hidden_tabs", selected = paste0("panel", input$controller))
# enswure value is avilable throught selected tabSet
req(input$controller)
# get current data and df name
data_to_use$data <- data_sets[[as.numeric(input$controller)]]
data_to_use$name <- names(data_sets[as.numeric(input$controller)])
# update table and sum. Use server = FALSE to get full table
output[[paste0('panel', input$controller, '_data')]] <- DT::renderDT(server = FALSE, {
DT::datatable(data_to_use$data,
filter = 'top',
extensions = 'Buttons')})
})
}
#runs the app
shinyApp(ui= ui, server= server)
You have two radioButtons, one for each sidebar, but both of them have the inputId = "controller". Same with inputId = "toggleSidebar". InputIds need to be unique in shiny!
I suggest you either use a single sidebar for the entire app, or since both tabs are essentially identical you can also use modules.

Hide one of the checkbox group choices but stiil keep its functionallity activated

I have a basic shiny app below with a checkbox group and the printed results of it. I was wondering if it is possible to somehow hide one of the 3 choices (for example "1") but the printed result should still include "1".
#ui.r
fluidPage(
# Copy the chunk below to make a group of checkboxes
checkboxGroupInput("checkGroup", label = h3("Checkbox group"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1),
hr(),
fluidRow(column(3, verbatimTextOutput("value")))
)
#server.r
function(input, output) {
# You can access the values of the widget (as a vector)
# with input$checkGroup, e.g.
output$value <- renderPrint({ input$checkGroup })
}
With CSS:
ui <- fluidPage(
tags$head(
tags$style(HTML("input[name=checkGroup][value='1'] { display: none }"))
),
checkboxGroupInput("checkGroup", label = h3("Checkbox group"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1),
hr(),
fluidRow(column(3, verbatimTextOutput("value")))
)
It isn't a checkboxGroupInput, but it mimics the idea...
library(shiny)
ui <- fluidPage(
# Copy the chunk below to make a group of checkboxes
checkboxGroupInput("checkGroup", label = h3("Checkbox group"),
choices = list("Choice 1" = 1, "Choice 2" = 2, "Choice 3" = 3),
selected = 1),
hr(),
conditionalPanel(
"input.check1 == 'T'",
checkboxInput("check1", "Choice 1", value = T)
),
checkboxInput("check2", "Choice 2", value = F),
checkboxInput("check3", "Choice 3", value = F),
hr(),
fluidRow(column(3, verbatimTextOutput("value"))),
fluidRow(column(3, verbatimTextOutput("value2")))
)
server <- function(input, output) {
# You can access the values of the widget (as a vector)
# with input$checkGroup, e.g.
output$value <- renderPrint({ input$checkGroup })
output$value2 <- renderPrint({ c(input$check1, input$check2, input$check3)})
}
shinyApp(ui, server)

How to get the correct InputID while using InsertUI in Shiny

I have a question about InsertUI and the respective InputID of the elements.
In the example below, the inputID of selectizeInput "Number_Product1_1" shows the output for the 1. Division in the boxOutput "InputID".
If this InputID is used as input for the boxOutput "Total", no output is displayed.
If more Divisions are added, the quantity of Product1 (in the example below '50') of the 1. division is the output in the boxOutput "Total" of the following divisions. But why is this output not shown for the 1. division?
I am confused. Can someone explain to me why this shift occurs?
Thanks for your inputs!
library(shiny)
library(shinydashboard)
# Define UI
ui <- fluidPage(
titlePanel("Identify Total amount/Divison"),
sidebarLayout(
sidebarPanel(
width = 12,
# Buttons to add/remove a question
actionButton("add", "Add Divison"),
actionButton("remove", "Remove Divison"),
div(id = "questions",
style = "border: 1px solid silver;")
),
mainPanel(
)))
# Define server logic
server <- function(input, output) {
values <- reactiveValues(num_questions = 0)
# Add a division
observeEvent(input$add, ignoreNULL = FALSE, {
values$num_questions <- values$num_questions + 1
num <- values$num_questions
ui = tags$div(
insertUI(
selector = "#questions", where = "beforeEnd",
splitLayout(
cellWidths = c("20%","20%", "20%", "20%", "20%"),
cellArgs = list(style = "padding: 3px"),
id = paste0("question", num),
textAreaInput(inputId = paste0("Division_", num),
label = paste0(num, ". Division:"),
placeholder = "Placeholder"),
selectizeInput(inputId =paste0("Number_Product1_", num),
label = paste0("Product1"), isolate(seq(from = 50, to = 100000, by = 50)), multiple=FALSE),
selectizeInput(inputId =paste0("Number_Product2_", num),
label = paste0("Product2"), isolate(seq(from = 0, to = 100000, by = 50)), multiple=FALSE),
box(
title = "Total", width = 12, background = "black",
input$Number_Product1_1), #### Input from selectizeInput "Product 1"
box(
title = "inputID", width = 12, background = "black",
paste0("Number_Product1_", num)) #### inputID's of the selectizeinput "Product 1"
)))
})
# Remove a division
observeEvent(input$remove, {
num <- values$num_questions
# Don't let the user remove the very first Row
if (num == 1) {
return()
}
removeUI(selector = paste0("#question", num))
values$num_questions <- values$num_questions - 1
})
}
# Run the application
shinyApp(ui = ui, server = server)
I might have to come up with a better explanation, Meanwhile that error is fixed.
My understanding is that within insertUI you are trying to access an id whose value would be created only after insertUI hence I tried to render it separately and assigned the output of it to the box value.
library(shiny)
library(shinydashboard)
# Define UI
ui <- fluidPage(
titlePanel("Identify Total amount/Divison"),
sidebarLayout(
sidebarPanel(
width = 12,
# Buttons to add/remove a question
actionButton("add", "Add Divison"),
actionButton("remove", "Remove Divison"),
div(id = "questions",
style = "border: 1px solid silver;")
),
mainPanel(
)))
# Define server logic
server <- function(input, output) {
values <- reactiveValues(num_questions = 0)
# Add a division
observeEvent(input$add, ignoreNULL = FALSE, ignoreInit = TRUE,{
values$num_questions <- values$num_questions + 1
num <- values$num_questions
#ui = tags$div(
# observe({
insertUI( immediate = TRUE,
selector = "#questions", where = "beforeEnd",
splitLayout(
cellWidths = c("20%","20%", "20%", "20%", "20%"),
cellArgs = list(style = "padding: 3px"),
id = paste0("question", num),
textAreaInput(inputId = paste0("Division_", num),
label = paste0(num, ". Division:"),
placeholder = "Placeholder"),
selectizeInput(inputId =paste0("Number_Product1_", num),
label = paste0("Product1"), isolate(seq(from = 50, to = 100000, by = 50)), multiple=FALSE,
selected = 50),
selectizeInput(inputId =paste0("Number_Product2_", num),
label = paste0("Product2"), isolate(seq(from = 0, to = 100000, by = 50)), multiple=FALSE),
box(
title = "Total", width = 12, background = "black",
print( input$Number_Product1_1),
textOutput("total")
), #### Input from selectizeInput "Product 1"
box(
title = "inputID", width = 12, background = "black",
paste0("Number_Product1_", num)) #### inputID's of the selectizeinput "Product 1"
))
#)
# })
})
#observe({
# require(input$Number_Product1_1)
output$total <- renderText({
input[["Number_Product1_1"]]
})
# })
# Remove a division
observeEvent(input$remove, {
num <- values$num_questions
# Don't let the user remove the very first Row
if (num == 1) {
return()
}
removeUI(selector = paste0("#question", num))
values$num_questions <- values$num_questions - 1
})
}
# Run the application
shinyApp(ui = ui, server = server)
Image:

Resources