tabBox width doesn't expand to contain plot - r

Starting with the code on this page: enter link description here, I would like to be able to control the size of the box plot on Tab 1 of the First tabBox. Hacking in a couple of sliders, and a uiOuput call in the code below, I can now easily control the height and width of the boxplot. But, while the tabBox nicely expands in height to contain the plot, it does not expand in width. At high values of width, the plot extends over the boundary of the box. I see similar results using a simple Box to contain the plot.
Is there a way to change the width of the Box/tabBox to get the desired effect?
library(shiny)
library(shinydashboard)
body <- dashboardBody(
fluidRow(
tabBox(
title = "First tabBox",
# The id lets us use input$tabset1 on the server to find the current tab
id = "tabset1",
tabPanel("Tab1", "First tab content", uiOutput('UI_test')),
tabPanel("Tab2", "Tab content 2")
),
tabBox(
side = "right",
selected = "Tab3",
tabPanel("Tab1", "Tab content 1"),
tabPanel("Tab2", "Tab content 2"),
tabPanel("Tab3", "Note that when side=right, the tab order is reversed.",
sliderInput('sldHt', 'Height', min=100, max=500,
value=200, step=10),
sliderInput('sldWd', 'Width', min=100, max = 500,
value=200, step=10)
)
)
),
fluidRow(
tabBox(
# Title can include an icon
title = tagList(shiny::icon("gear"), "tabBox status"),
tabPanel("Tab1",
"Currently selected tab from first box:",
verbatimTextOutput("tabset1Selected")
),
tabPanel("Tab2", "Tab content 2")
)
)
)
shinyApp(
ui = dashboardPage(
dashboardHeader(title = "tabBoxes"),
dashboardSidebar(),
body
),
server = function(input, output) {
# The currently selected tab from the first box
output$tabset1Selected <- renderText({
input$tabset1
})
output$UI_test = renderUI({
plotOutput('test',
height = input$sldHt,
width = input$sldWd)
})
output$test = renderPlot(
boxplot(len ~ dose, data = ToothGrowth,
boxwex = 0.25, at = 1:3 - 0.2,
subset = supp == "VC", col = "yellow",
main = "Guinea Pigs' Tooth Growth",
xlab = "Vitamin C dose mg",
ylab = "tooth length",
xlim = c(0.5, 3.5), ylim = c(0, 35), yaxs = "i"))
}
)

Related

R Shiny shinyjs window.scrollTo scroll distance limited to active tab

I have a shiny app with a sidebar menue and several different tabs. Within each tab, there is a lot of content that is supposed to be seen together, so the tabs are quite lengthy and navigating can be a pain because a lot of scrolling is needed. However, spliting the content into sub-tabs is not an option.
I have thus tried to implement "location markers" as fake sub-tabs to navigate through.
This works fine, except when you are on another tab and you want to switch directly to the bottom of another tab, i.e. from subtab_1_1 directly to subtab_2_2.
In that case, the tab switches over correctly to subtab_2_1 but the scrollposition() afterwards does not actually scroll the full 50000 pixels, but to the maximum distance of the active tab (i.e. the bottom of Tab 1).
As #YBS pointed out, one solution would be to add lines to each Tab so that they all share the same length. However, that would make using the scroll bar to scroll manualy very unintuitive, as some tabs would go on for much longer as the content of the tab.
Is there any way to circumvent this limitation of window.scrollTo()?
Here is a minimal working example:
library(shiny)
library(shinydashboard)
library(shinyjs)
ui <- dashboardPage(
title = "Title",
dashboardHeader(title = "Header", titleWidth = 350),
skin = "blue",
dashboardSidebar(
width = 350,
disable = FALSE,
sidebarMenu(
id = "tabs",
menuItem(
text = "Tab 1",
tabName = "Tab_1",
icon = icon("database"),
hidden(menuSubItem(
text = "Subtab 1.1",
tabName = "Subtab_1_1",
icon = icon("angle-right")
)),
menuSubItem(
text = "Proxy Subtab 1.1",
tabName = "Proxy_Subtab_1_1",
icon = icon("angle-right")
),
menuSubItem(
text = "Subtab 1.2",
tabName = "Subtab_1_2",
icon = icon("angle-right")
)
),
menuItem(
text = "Tab 2",
tabName = "Tab_2",
icon = icon("database"),
hidden(menuSubItem(
text = "Subtab 2.1",
tabName = "Subtab_2_1",
icon = icon("angle-right")
)),
menuSubItem(
text = "Proxy Subtab 2.1",
tabName = "Proxy_Subtab_2_1",
icon = icon("angle-right")
),
menuSubItem(
text = "Subtab 2.2",
tabName = "Subtab_2_2",
icon = icon("angle-right")
)
)
)
),
dashboardBody(
useShinyjs(),
extendShinyjs(
text = "shinyjs.scrollposition = function(y) {window.scrollTo(0, y)};",
functions = c("scrollposition")
),
tags$script(HTML("$('body').addClass('fixed');")),
tabItems(
tabItem(
tabName = "Subtab_1_1",
fluidPage(
h1("This is Subtab 1_1"),
HTML(rep("<br/><br/><br/>↓<br/>", 10)),
h1("This is supposed to be Subtab 1_2")
)
),
tabItem(
tabName = "Subtab_2_1",
fluidPage(
h1("This is Subtab 2_1"),
plotOutput("Plot_1"),
plotOutput("Plot_2"),
plotOutput("Plot_3"),
plotOutput("Plot_4"),
plotOutput("Plot_5"),
plotOutput("Plot_6"),
h1("This is supposed to be Subtab 2_2")
)
)
)
)
)
server <- function(input, output, session) {
observeEvent(input$tabs, {
if(sum(c("Proxy_Subtab_1_1", "Proxy_Subtab_2_1","Subtab_1_2", "Subtab_2_2") %in% input$tabs) > 0) {
updateTabsetPanel(session, "tabs", switch(input$tabs,
"Proxy_Subtab_1_1" = "Subtab_1_1",
"Proxy_Subtab_2_1" = "Subtab_2_1",
"Subtab_1_2" = "Subtab_1_1",
"Subtab_2_2" = "Subtab_2_1")
)
js$scrollposition(case_when(input$tabs == "Proxy_Subtab_1_1" ~ 0,
input$tabs == "Proxy_Subtab_2_1" ~ 0,
input$tabs == "Subtab_1_2" ~ 50000,
input$tabs == "Subtab_2_2" ~ 50000)
)
}
})
output$Plot_1 <- output$Plot_2 <- output$Plot3 <-
output$Plot_4 <- output$Plot_5 <- output$Plot6 <- renderPlot(
ggplot(data.frame(
x = c(1, 2, 3),
y = c(1, 2, 3),
labels = c(
"",
"Some plots",
""
)
)
) +
geom_text(aes(x = x, y = y, label = labels), size = 6)
)
}
shinyApp(ui = ui, server = server)

How to have shiny dashboard box fill the entire width of my dashbaord

I'm struggling to get my dashboard layout to be formatted in a way that looks good.
I have a box that is not the full width of my dashboard and the plot that is inside of it is actually wider and sticks out of it. (although I do believe once I make a plotly graph it will work fine).
I'm using fillRow but it does not fill the entire row and only half of the page.
Here is my code.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
## Sidebar content
dashboardSidebar(
sidebarMenu(
menuItem("Overview",tabName = "Overview", icon = icon("tachometer-alt")),
menuItem("Assessments",tabName = "Assessments", icon = icon("list"))
)
),
dashboardBody(
tabItems(
# First tab content
tabItem(tabName = "Overview",
# Boxes need to be put in a row (or column)
fluidRow(
valueBoxOutput("rate"),
valueBoxOutput("count"),
valueBoxOutput("users"),
),
fluidRow(
box(title = "Title",
status = "primary",
),
box(align = "center",
title = "Select Inputs",status = "warning", solidHeader = F,
selectInput("dropdown1", "Select Drilldown:", c(50,100,200)))
),
fillRow(width = "100%",
box(
title = "Graph 1", status = "primary", solidHeader = TRUE,
plotOutput("plot1", height = "50vh", width = "100vh")))
),
tabItem(tabName = "Assessments",
h2("Assessmnents tab content")
)
)
)
)
server <- function(input, output) {
set.seed(122)
histdata <- rnorm(500)
output$plot1 <- renderPlot({
data <- histdata[seq_len(input$dropdown1)]
hist(data)
})
output$instructions <- renderText("Company Name")
output$rate <- renderValueBox({
valueBox(
value = 130,
subtitle = "Overview 1",
icon = icon("area-chart"),
color = "aqua"
)
})
output$count <- renderValueBox({
valueBox(
value = 120,
subtitle = "Overview 2",
icon = icon("download"),
color = "red"
)
})
output$users <- renderValueBox({
valueBox(
value = 85,
subtitle = "Overview 3",
icon = icon("users"),
color = "purple"
)
})
}
shinyApp(ui, server)
And a screen shot
My desired goal would be something like this
Is there any reccomended resources I can read to get better at shiny dashboard layouts and controlling the view?
You need to use width = 12 in the box function. Additionally, to make sure the plot is always using the entire width of the box use width = "100%" in plotOutput.
fillRow(
box(
width = 12,
title = "Graph 1",
status = "primary",
solidHeader = TRUE,
plotOutput(
"plot1",
height = "50vh",
width = "100%")
)
)
The Shiny Dashboard documentation is a good place to start learning the structure, appearance, and behavior of Shiny Dashboard. You can also get some extra functionality by using shinydashboardPlus. Finally, shinyWidgets provides a great selection of custom widgets with an improved visual look.
It's all about layout. Here I provide shinydashboard skeleton and some explanation that might suits your problem'. You can put this code inside dashboardBody(tabItems(tabItem(tabName = "Overview",...)))
fluidPage(
fluidRow(
column(width = 4,valueBoxOutput(width = 12,"blue_value_box")) ,
column(width = 4,valueBoxOutput(width = 12,"red_value_box")) ,
column(width = 4,valueBoxOutput(width = 12,"purple_value_box"))
),
fluidRow(
column(width = 6,box(width = 12,"Title")),
column(width = 6,box(width = 12,"Select Inputs",
selectInput("someinputhere")))
),
fluidRow(
column(width = 12,
box(width = 12,plotOutput("histogramofdata"))
)
)
)
First of all the column is not necessary for your case, its just very helpful to explain shiny layout. Keep in mind shiny have a strict width value, 12 maximum. If you define width in something like box or column(), everything inside that will follow its width rather than global width. For example in my example, i put valueboxoutput() inside column(). you can see that the column has width = 4 and the valueboxoutput has 12. The column() will follow the page width and the valuebox will follow column width. I don't know if this is the best practice but i like to use fluidrow() to make a separation by row between an shiny object.
For more clearer example, in the image above, i highlighted the fluidrow() in red and blue for column().

Shiny WebApp and UI: add style and dropdown menu in the header

I'm just starting using R and Shiny App and I'm a bit confused about how to achieve what I'm trying to do. I want to change the UI of my Shiny App. As a C# developer, I work with HTML/CSS, AdminLTE and so on. I can't find a proper documentation how to change the UI in a Shiny App.
What I want to achieve in the UI is something like the following image:
First, I removed the sidebar. Now, my problem is to box the UI. In the header, I want to add a dropdown menu with few options. Then, I want in the middle of the page to have a panel with 2 column: in the first column first row I desire to see the graph generate by R, then same text around it to explain the graph.
On top of that, I want to change the style for example of tabs or buttons.
After 2 days of work, I wrote this code but it is very far from what I want to achieve.
library(shiny)
library(shinydashboard)
# Define UI for application that draws a histogram
ui <- navbarPage(
"Test",
tabPanel(
"Introduction",
titlePanel(
div(
windowTitle = "Test window"
)
),
div(class = "my-class",
h3("LAI287 basal insulin study"),
p("Lorem ipsum dolor sit amet..."),
p("Lorem ipsum dolor sit amet..."),
actionButton(
inputId = "btnStart",
label = "Start analysis",
className = "btn-primary"
)
)
),
tabPanel(
"Attribute specification"
),
tabPanel(
dropdownMenu(type = "notifications",
notificationItem(
text = "5 new users today",
icon("users")
),
notificationItem(
text = "12 items delivered",
icon("truck"),
status = "success"
),
notificationItem(
text = "Server load at 86%",
icon = icon("exclamation-triangle"),
status = "warning"
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
# Run the application
shinyApp(ui = ui, server = server)
The result of this code is in the following screenshot. The only dropdown I found was for messages or notifications.
I know AdminLTE quite well but I don't understand how to write the code for Shiny App. Do you have any idea or suggestion how I can implement this UI? Is there any good tutorial I can read?
Update
I found some documentation on RStudio Shiny dashboard. First, I don't understand the difference between dashboardPage and navbarPage. Can I add a navbarPage to a dashboardPage?
From the documentation, I added this code:
box(
title = "Histogram", status = "primary", solidHeader = TRUE,
collapsible = TRUE,
plotOutput("plot3", height = 250)
),
box(
title = "Inputs", status = "warning", solidHeader = TRUE,
"Box content here", br(), "More box content",
sliderInput("slider", "Slider input:", 1, 100, 50),
textInput("text", "Text input:")
)
and I expect something like
but my result is like that (thanks Jan for the menu)
I saw on the other page of the documentation that it is possible to add
dashboardPage(skin = "blue")
but in my case I don't have a dashboardPage.
Are you aware of the navbarMenu function? You can add menu items to the navbarPage with it:
navbarPage("App Title",
tabPanel("Plot"),
navbarMenu("More",
tabPanel("Summary"),
"----",
"Section header",
tabPanel("Table")
)
)
Layouting can be done with fluid layouts, e.g.
fluidRow(
column(width = 4,
"4"
),
column(width = 3, offset = 2,
"3 offset 2"
)
See the layout guide for the necessary details.
If you are familiar with AdminLTE then I strongly recommend using bs4Dash. It is a very robust package that allows for the use of boxes and other features that are regularly a part of AdminLTE (including Bootstrap 4). But the core of the language is still Shiny, so you may need to work through a few basic examples before attempting anything with greater complexity.
You can change colors, font-sizes, etc. in bs4Dash by following the instructions on this page.
For a demo of what is possible, see here.
I've provided a very basic example at the bottom of this answer.
Otherwise adding a dropdown navigation in bs4Dash is a bit tricky, and will require a combination of Javascript, CSS, and HTML. Luckily, you can modify all of these things.
Good luck!
library(shiny)
library(bs4Dash)
ui <- dashboardPage(
header = dashboardHeader(
leftUi = tagList(
dropdownMenu(
badgeStatus = "info",
type = "notifications",
notificationItem(
inputId = "notice1",
text = "Put text here!",
status = "danger"
)
),
dropdownMenu(
badgeStatus = "info",
type = "tasks",
taskItem(
inputId = "notice2",
text = "My progress",
color = "orange",
value = 10
)
)
)
),
dashboardSidebar(disable = T),
body = dashboardBody(
fluidRow(
column(width = 8,
box(width = NULL, title = "Old Faithful Geyser Data",
collapsible = F,
wellPanel( sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)),
plotOutput("distPlot")
),
box(width = NULL, title = NULL, collapsible = F,
fluidRow(
column(width = 5,
tags$img(src = "https://i.stack.imgur.com/EslMF.png", width = '100%')
),
column(width = 7,
tags$h4("Card Title"),
tags$p("Some text here")
)
)
)
),
column(width = 4,
box(width = NULL, title = "Header", status = "info", collapsible = F),
box(width = NULL, title = "Header", status = "success", collapsible = F),
box(width = NULL, title = "Header", status = "secondary", collapsible = F)
)
)
),
controlbar = dashboardControlbar(
collapsed = FALSE,
div(class = "p-3", skinSelector()),
pinned = TRUE
)
)
server <- function(input, output) {
output$distPlot <- renderPlot({
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
shinyApp(ui = ui, server = server)

Conditional display in box based on tabbox selected in shinydashboard

I use shiny with shinydashboard. I have one tabbox with two tabPanels. Then there is another box which should display either textOutput("a") if tab1 in tabbox is selected or textOutput("b") if tab2 is selected.
I provide whole code for reproducibility but watch out for comments which show where the important part is.
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
skin = "red",
dashboardHeader(title = "lalala", titleWidth = 450),
sidebar <- dashboardSidebar(width = 400,
sidebarMenu(
menuItem(
text = strong("First tab"),
tabName = "first",
icon = icon("dashboard")
)
)),
body <- dashboardBody(fluidRow(
tabBox(
title = "First tabBox",
id = "tabset1",
height = "250px",
############## based on which of this tab is selected
tabPanel("Tab1", "First tab content"),
tabPanel("Tab2", "Tab content 2")
),
box(
title = "Selection criteria for chart",
height = "700px",
width = 4,
solidHeader = TRUE,
status = "danger",
############## I want in this box to display either textouput "a" or "b"
textOutput("a")
)
))
)
server <- function(input, output) {
output$a <- renderText(a <- "ahoj")
output$b <- renderText(b <- "cau")
}
input$tabset1 returns the id of the currently selected tab (so either Tab1 or Tab2). Then you can use an if/else statement to print the content you like depending on this return value.

Using columns to control tabBox content in Shiny dashboard

I'm trying to build a Shiny dashboard page which will have tabbed pages with different types of plots, allow users to change settings dynamically, etc. Starting with the standard demo code from the Shiny Dashboards page, I can get a stacked version of the page (https://rstudio.github.io/shinydashboard/structure.html#tabbox):
library(shiny)
library(shinydashboard)
body <- dashboardBody(
fluidRow(
tabBox(
title = "First tabBox",
# The id lets us use input$tabset1 on the server to find the current tab
id = "tabset1",
tabPanel("Tab1", "First tab content", plotOutput('test')),
tabPanel("Tab2", "Tab content 2")
),
tabBox(
side = "right",
selected = "Tab3",
tabPanel("Tab1", "Tab content 1"),
tabPanel("Tab2", "Tab content 2"),
tabPanel("Tab3", "Note that when side=right, the tab order is reversed.")
)
),
fluidRow(
tabBox(
# Title can include an icon
title = tagList(shiny::icon("gear"), "tabBox status"),
tabPanel("Tab1",
"Currently selected tab from first box:",
verbatimTextOutput("tabset1Selected")
),
tabPanel("Tab2", "Tab content 2")
)
)
)
shinyApp(
ui = dashboardPage(
dashboardHeader(title = "tabBoxes"),
dashboardSidebar(),
body
),
server = function(input, output) {
# The currently selected tab from the first box
output$tabset1Selected <- renderText({
input$tabset1
})
output$test = renderPlot(
boxplot(len ~ dose, data = ToothGrowth,
boxwex = 0.25, at = 1:3 - 0.2,
subset = supp == "VC", col = "yellow",
main = "Guinea Pigs' Tooth Growth",
xlab = "Vitamin C dose mg",
ylab = "tooth length",
xlim = c(0.5, 3.5), ylim = c(0, 35), yaxs = "i"))
}
)
If I modify line 10 to this:
tabPanel("Tab1", column(4,"First tab content"),
column(8, plotOutput('test'))
),
I get the heading and the boxplot split into columns, but the tabBox no longer expands to contain them.
Is there any way to control the contents of the tabPanel to allow columnar formatting of the output?
Just wrap your columns inside a fluidRow or fluidPage. Then the tabPanel gets the right size and stretches out to fit your columns.

Resources