shinydashboard box collapse - r

library(shinydashboard)
library(shiny)
library(dplyr)
trtall <- rbind(rep("A",100),rep("B",100), rep("C",100))
trt <- sample(trtall,80)
agecat.temp <- c(rep("18-40",100), rep("> 40", 100))
agecat <- sample(agecat.temp, 80)
sex <- sample(rbind(rep("M",100),rep("F",100)),80)
race <- sample(rbind(rep("Asian",50),rep("Hispanic",50),rep("Other",50)),80)
df <- data.frame(trt, agecat, sex, race)
body <- dashboardBody(
fluidRow(box(width=12,collapsed=F, collapsible = T, title="Filters", solidHeader = T,status="primary",
box(width=5, height="220px", status="primary",
fluidRow(column(6,uiOutput("uivr1")),
column(6,uiOutput("uivl1")))))))
ui <- dashboardPage(
dashboardHeader(disable = T),
dashboardSidebar(disable = T),
body, skin = "green"
)
server = function(input, output) {
reacui1 <- reactiveVal()
observeEvent(input$vr1,{
reacui1(as.list(df %>% distinct(!!input$vr1) %>% arrange(!!input$vr1)))
})
output$uivr1 <- renderUI(varSelectInput(width = "200px", "vr1",NULL,df))
output$uivl1 <- renderUI(selectInput("vl1",width="200px",multiple=T,NULL,choices=reacui1()))
}
shinyApp(ui,server)
Hi,
I am dynamically trying to create UI in shiny app. The logic works fine until I collapse the box in shiny dashboard.
I did following steps and got unexpected results.
I select 'trt' in "vr1" and choose "A" from "vl1".
I collapsed the box.
Then un-collapsed the box.
I select 'agecat' in "vr1" - now I still see various treatments (A,B,C) but not distinct age categories (18-40, >40) in "vl1"
Can you please help.

The problem comes from the fact that the shown event is not passed down to the elements which are in a box inside the collapsed box.
Compare this to this slightly changed example:
body <- dashboardBody(
fluidRow(
box(width = 12, collapsed = FALSE, collapsible = TRUE,
title = "Filters", solidHeader = TRUE, status = "primary",
# box(width=5, height="220px", status="primary",
fluidRow(column(6, uiOutput("uivr1")),
column(6, uiOutput("uivl1"))
# )
)
)
)
)
and you see that in this case the second input is properly updated.
You can also use your example, go to the JS console and type $('.box').trigger('shown') and you will see that the select input is suddenly updated.
That means the problem is, that shiny still believes that the inputs are hidden and because hidden inputs are not updated you observe this behavior.
But this tells us how we can fix it:
Workaround is to switch off the suspendWhenHidden property. Add this to your server:
session$onFlushed(function() {
outputOptions(output, "uivl1", suspendWhenHidden = FALSE)
})
This is however, just fixing the symptom and not solving the issue.
Another approach would be to make sure the shown.bs.collapse event is also triggered at the box inside the box. For this we can listen to the shown.bs.collapse event and once received, wait a bit (800ms) such that the box is fully visible and then inform all shiny-bound-output children that they should be shown:
js <- "$(() => $('body').on('shown.bs.collapse', '.box', function(evt) {
setTimeout(function(){
$(evt.target).find('.shiny-bound-output').trigger('shown.bs.collapse');
}, 800);
}))"
body <- dashboardBody(
tags$head(tags$script(HTML(js))),
fluidRow(
box(width = 12, collapsed = FALSE, collapsible = TRUE,
title = "Filters", solidHeader = TRUE, status = "primary",
box(width = 5, height = "220px", status = "primary",
fluidRow(column(6, uiOutput("uivr1")),
column(6, uiOutput("uivl1"))
)
)
)
)
)
This is, BTW, already reported as bug: https://github.com/rstudio/shinydashboard/issues/234

Related

How to prevent plot from overspilling out of box in shiny box?

I stumbled upon this wierd interaction between collapsed boxes within boxes and plots:
In the the first instance of this, in the minimal working example below, on the left side, expanding the box pushes the plot over the edge of the box, while in the second instance on the right side, it does not.
Also, uncommenting the code of the action button somehow remedies this somehow.
Can someone explain to me why this is happening and how to solve the issue?
I am aware that I could just use the layout to the right, but I would really like to understand this behavior.
Thanks in advance!
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
fluidPage(
box(width = 12,
title = "Some Title",
collapsible = TRUE,
solidHeader = TRUE,
status = "danger",
box(widht = 12,
title = "Some Sub Title",
collapsible = TRUE,
solidHeader = TRUE,
box(
width = 12,
title = "Details 1",
collapsible = TRUE,
solidHeader = TRUE,
collapsed = TRUE,
status = "info",
tableOutput("Placeholder_Table_1")
),
#actionButton(inputId = "Action_1",
# label = "Does nothing"
#),
plotOutput("Placeholder_Plot_1")
),
box(widht = 12,
title = "Sub Title 2",
collapsible = TRUE,
solidHeader = TRUE,
plotOutput("Placeholder_Plot_2"),
box(
width = 12,
title = "Details 2",
collapsible = TRUE,
solidHeader = TRUE,
collapsed = TRUE,
status = "info",
tableOutput("Placeholder_Table_2")
)
)
)
)
)
)
server <- function(input, output) {
output$Placeholder_Table_1 <- renderTable(
tibble('Variable 1' = "X",
'Variable 2' = "Y",
'Variable 3' = "Z"
)
)
output$Placeholder_Table_2 <- renderTable(
tibble('Variable 1' = "X",
'Variable 2' = "Y",
'Variable 3' = "Z"
)
)
output$Placeholder_Plot_1 <- renderPlot(
ggplot(data = mtcars) +
labs(title = "Placeholder Plot 1")
)
output$Placeholder_Plot_2 <- renderPlot(
ggplot(data = mtcars) +
labs(title = "Placeholder Plot 2")
)
}
shinyApp(ui, server)
The problem is not the plot, it comes from the box.
First thing you need to know is box is actually using .col-xxx classes from bootstrap and these classes have a CSS float: left;. It will cause itself has 0 height of the parent div. Read this: CSS: Floating divs have 0 height.
However, what you see is it takes some spaces on the UI, so what you see the height is box + plot, but in the parent div height calculation, it's just the plot.
To fix, very easy, wrap your box with fluidrow, .row has a CSS display: table which solves the problem.
fluidRow(box(
width = 12,
title = "Details 1",
collapsible = TRUE,
solidHeader = TRUE,
collapsed = TRUE,
status = "info",
tableOutput("Placeholder_Table_1")
)),

How do I render html content for boxes inside a loop in Shiny?

I'm trying to build a Shiny dashboard that responds to user inputs by displaying a series of boxes with nicely formatted html content. Because the user's selections determine how many boxes will be displayed, I'm using lapply() to render the boxes on the server side and then pushing the results of that process to uiOutput() on the ui side.
It's working with one crucial exception: the html content isn't appearing in the boxes. I don't get any error messages or warnings; I just don't get any content inside the boxes, other than the reactive titles.
What follows is a simple, reproducible example. What do I need to do differently to get contents to appear inside the boxes in the body of the ui?
library(shiny)
library(shinydashboard)
library(shinyWidgets)
dat <- data.frame(food = c("hamburger", "hot dog", "pizza", "kale salad"),
price = c("$2.50", "$1.50", "$2.00", "$3.50"),
peanut_gallery = c("beefy!", "dachsund!", "pie time!", "healthy!"),
stringsAsFactors = FALSE)
### UI ###
header <- dashboardHeader(title = "My Food App", titleWidth = 400)
sidebar <- dashboardSidebar(width = 400,
fluidRow(column(width = 12,
checkboxGroupButtons(
inputId = "my_food",
label = "Pick a food",
choices = c("hamburger", "hot dog", "pizza", "kale salad"),
selected = NULL
)
))
)
body <- dashboardBody(
fluidRow(
uiOutput("little_boxes")
)
)
ui <- dashboardPage(header, sidebar, body, skin = "black")
### SERVER ###
server <- function(input, output) {
output$little_boxes <- renderUI({
req(input$my_food)
lapply(input$my_food, function(x) {
df <- dat[dat$food == x,]
contents <- div(h4(df$peanut_gallery),
h5(df$price),
p(sprintf("Isn't %s great? I love to eat it.", df$food)))
box(title = df$food,
width = 6,
background = "red",
collapsible = TRUE, collapsed = TRUE,
uiOutput(contents) )
})
})
}
## RUN ##
shinyApp(ui, server)
Try :
htmltools::tagList(contents)
instead of
uiOutput(contents)

Error: Expected an object with class 'shiny.tag' when trying to output renderValueBox

New to R and R Shiny. My goal is to output the maximum value of a column by a valueBoxOutput, whilst the value is able to update when filters are changed by the user e.g Date etc. I am receiving Error: Expected an object with class 'shiny.tag' which I have no clue what it means and I cannot see why the code is wrong.
ui.R
library(shinythemes)
library(shiny)
library(plotly)
library(lubridate)
library(shinydashboard)
ui <- dashboardPage(skin = "black",
dashboardHeader(title = "Metric Tracker")
dashboardSidebar(
sidebarMenu(
menuItem("Dashboard", tabName = "Dashboard", icon = icon("city")),
dashboardBody(fluidRow(
tabItems(
tabItem(tabName = "Dashboard",
box(collapsible = TRUE, title = "All Brands",status = "info",solidHeader = TRUE, width = 8, plotlyOutput("valuePlot", height = "500px"), plotlyOutput("testplot", height = "500px")),
box(width = 4,title = "Inputs", solidHeader = TRUE, status = "warning", selectInput("value", "1st Value to Track:" , choices = c("Units_Ordered", "Buy_Box_Percentage", "Ordered_Product_Sales", "Session_Percentage","aov"), selected = "Ordered_Product_Sales", multiple = FALSE, selectize = TRUE),
selectInput("value2", "2nd Value to Track:" , choices = c("Units_Ordered", "Buy_Box_Percentage", "Ordered_Product_Sales", "Session_Percentage","aov"), selected = "Units_Ordered", multiple = FALSE, selectize = TRUE),
selectInput("marketplace", "Select Marketplace", choices = c("UK","DE","FR","IT","ES")),
sliderInput("date", "Date Range:", min = as.Date("2019-07-06","%Y-%m-%d"), max = as.Date("2019-10-26","%Y-%m-%d"), value = c(as.Date( "2019-07-06"),as.Date( "2019-10-26")),step = 7, timeFormat = "%Y-%m-%d")),
valueBoxOutput("max", width =3), valueBoxOutput("min", width = 3)
),
server ( I am only including relevant parts of my code so if you believe it maybe somewhere else that is distrputive let me know, but to know everything else works perfectly)
server <- function(input, output){
output$max <- renderValueBox({
maxsales <- filter(metricx2, Date >= input$date[1] & Date <= input$date[2] & Marketplace %in% input$marketplace)
maxsales1 <- max(maxsales$Ordered_Product_Sales)%>%
valueBox(value =maxsales1,subtitle = "Maximum Sales Value")
})
output$min <- renderValueBox({
valueBox(
value = min(metricx2$Ordered_Product_Sales),
subtitle = "Minimum Sales Value"
)
})
}
shinyApp(ui = ui, server = server)
metricx2 is the data frame that I want to pull from. The 'Min' part works but its not reactive to the inputs of the user. Moreover, R has sometimes prompted my to input a reactive function within the render. Yet this has not worked for me. As well as, R struggled to find Ordered_Product_Sales even though it is clearly there which is frustrating.
Hope someone can help and point out an obvious mistake I am probably making.
Thanks
Not sure you want the pipe at the end of this line:
maxsales1 <- max(maxsales$Ordered_Product_Sales)%>%
Your problem is possibly on this server line:
maxsales1 <- max(maxsales$Ordered_Product_Sales)%>% valueBox(value =maxsales1,subtitle = "Maximum Sales Value")
Remove the pipe %>% and it should work.
})

Create Center Navigation Bar in Shiny with Symbols

Currently, I have a shiny app built with the following UI structure.
tabsetPanel(tabPanel("Tab1"),
tabPanel("Tab2"),
tabPanel("Tab3"),
tabPanel("Tab4")
However, I would like to change the look and feel of the navigation bars. I would like to center the tabs in the middle of the page as opposed to having them left-aligned (This post is not reproducible and does not seem sustainable). Then insert a triangle in between each tab panel to show a "story line" to indicated content from tab1, 2, etc. is informing and influencing the rest of the dashboard. Then also have the tab highlighted each time the tab changes (green color below). I inserted a quick screenshot of the general UI format I am going for. I couldn't find much online of people trying to do this. Anything to put me in the right direction would be great! Much appreciated! The below is not a hard guidance or request, but just a general style.
You can mimic a layout like this using shinyWidgets::radioGroupButtons (and get reasonably close). Note that you still might need HTML/CSS customization of the buttons and arrows between them. This post might be a good resource: Create a Button with right triangle/pointer
library(shiny)
library(shinyWidgets)
ui <- fluidPage(titlePanel("Hack with shinyWidgets::radioGroupButtons"),
mainPanel(
fluidRow(
column(width = 3, "some space"),
column(
width = 9,
align = "center",
radioGroupButtons(
inputId = "item",
label = "",
status = "success",
size = "lg",
direction = "horizontal",
justified = FALSE,
width = "100%",
individual = TRUE,
checkIcon = list(
"yes" = icon("check"),
"yes" = icon("check"),
"yes" = icon("check"),
"yes" = icon("check")
),
choiceNames = as.list(names(iris)[1:4]),
choiceValues = as.list(1:4)
)
)
),
tags$hr(),
column(width = 3, "some space"),
column(
width = 9,
align = "center",
textOutput("text"),
wellPanel(dataTableOutput("out"))
)
))
server <- function(input, output) {
out_tbl <- reactive({
x <- iris[,c(5, as.numeric(input$item))]
return(x)
})
output$out <- renderDataTable({
out_tbl()
},options = list(pageLength = 5)
)
output$text <- renderText({paste("Contents for tab", input$item)})
}
shinyApp(ui, server)
A screen shot of the layout:

R/Shiny : Color of boxes depend on select

I try to create dynamic boxes in shiny.
We can change the status (color) of the box with (status = "warning" or "info" etc.)
I would like to change the color of this box (dynamically) depend on the choice of select input like that :
https://image.noelshack.com/fichiers/2018/32/2/1533638864-v1.png
https://image.noelshack.com/fichiers/2018/32/2/1533638864-v2.png
The code looks like this :
SelectInput("s010102i", label = NULL,
choices = list("Value 1" = 1, "Value 2" = 2, "Value 3" = 3),
selected = 1) ,width = 12, background = "blue", status = "info")), column(4,
We need to change the "info" in status by a variable. But when I try to put variable in ui side, it does not work and when i pass by the server like output$s010102i... the status is not equals to "info" in the output but :
ERROR: Invalid status: <div id="s010102o" class="shiny-html-output"></div>. Valid statuses are: primary, success, info, warning, danger.
How can i put this dynamically ? And how to change the selected by a variable ?
Thanks a lot !
Edit -> Here an exploitable code to understand :
library(shiny)
library(shinydashboard)
library(DT)
# Define UI for application that draws a histogram
ui <- fluidPage(
dashboardPage(
dashboardHeader( title = "Simple Test"),
dashboardSidebar(),
dashboardBody(
fluidRow(
box(title = h3("S.01.01.02", style = "display:inline; font-weight:bold"),
selectInput("s010102i", label = NULL,
choices = list("Not good" = 1, "O.K" = 2, "Good" = 3),
selected = 1) ,width = 12, background = "blue", status = renderUI("s010102o"))
# I want a text or a variable here
# Logically "danger", warning or success
# If Not good is selected, i wan that the status (the color) go to red (danger)
))))
# Define server logic required to draw a histogram
server <- function(input, output) {
statut = c("danger","warning","success")
output$s010102o <- reactive({
valueStatut = input$s010102i # Give 1 2 or 3
s010102o = statut[valueStatut] # give the value of the statut if "danger" the box changes to red
})
}
# Run the application
shinyApp(ui = ui, server = server)
The solution is to create the whole box in the server using renderUI and just render it in the UI using uiOutput. You can do something like this:
library(shiny)
library(shinydashboard)
library(DT)
# Define UI for application that draws a histogram
ui <- fluidPage(
dashboardPage(
dashboardHeader( title = "Simple Test"),
dashboardSidebar(),
dashboardBody(
fluidRow(
uiOutput("s010102o")
))))
# Define server logic required to draw a histogram
server <- function(input, output) {
statut = c("danger","warning","success")
output$s010102o <- renderUI({
box(title = h3("S.01.01.02", style = "display:inline; font-weight:bold"),
selectInput("s010102i", label = NULL,
choices = list("Not good" = "danger", "O.K" = "info", "Good" = "success"),
selected = 1) ,width = 12, background = "blue")})
observeEvent(input$s010102i,{
output$s010102o <- renderUI({
box(title = h3("S.01.01.02", style = "display:inline; font-weight:bold"),
selectInput("s010102i", label = NULL,
choices = list("Not good" = "danger", "O.K" = "info", "Good" = "success"),
selected = input$s010102i) ,width = 12, background = "blue",status = input$s010102i)
})
})
}
# Run the application
shinyApp(ui = ui, server = server)
But be careful as you are updating the box in which the input is.

Resources