R Shiny: Side-by-Side UI Inputs in absolutePanel - r

I'm trying to get two selectInputs to appear side by side in an absolute panel in a Shiny App. I tried the solution here, specifically using:
withTags(div(class='row-fluid',
div(class='span3', checkboxInput(inputId =
"simOption", label = "Historical Data",value=TRUE)),
div(class='span5', checkboxInput(inputId =
"simOption2", label = "Historical Data 2",value=TRUE))
))
but that didn't work in my code (the checkboxInputs still appeared vertically).
See the below code for a specific example. Right now, the two selectInputs appear vertically while I'm hoping to get them side-by-side.
library(shiny)
ui <- fluidPage(
navbarPage("Title", id="nav",
tabPanel("Tab",
div(class="outer",
absolutePanel(id = "controls", class = "panel panel-default", fixed = TRUE,
draggable = TRUE, top = 60, left = "auto", right = 20, bottom = "auto",
width = 300, height = "auto",
selectInput("select_1", "1st Thing",
choices=1:10, selected = 1, multiple = FALSE,
width=90),
selectInput("select_2", "2nd Thing",
choices=1:10, selected = 2, multiple = FALSE,
width=90)
)
)
)
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)

You could wrap your two input selectors in a div and add some css.
library(shiny)
ui <- fluidPage(
navbarPage("Title", id="nav",
tabPanel("Tab",
div(class="outer",
absolutePanel(id = "controls", class = "panel panel-default", fixed = TRUE,
draggable = TRUE, top = 60, left = "auto", right = 20, bottom = "auto",
width = 300, height = "auto",
div(style="display:flex",
selectInput("select_1", "1st Thing",
choices=1:10, selected = 1, multiple = FALSE,
width=90),
selectInput("select_2", "2nd Thing",
choices=1:10, selected = 2, multiple = FALSE,
width=90)
)
)
)
)
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)

Related

How to center *reactive* box in RShiny?

I am trying to have an explanatory image and text box appear after a user presses an action button. Ideally, Id like the box to be centered and directly below the image without too much space in between. Also, I'm curious how to make the box wider for aesthetic purposes.
Here is what my attempt looks like:
Here is my code:
ui <- dashboardPage(
dashboardHeader(title = "Test Test Test"),
dashboardSidebar(disable = T),
dashboardBody(useShinyjs(),
shinyUI(fluidPage(
navbarPage(
"Test",
id = "main_navbar",
tabPanel(
"Test",
fluidRow(align="center",
column(width = 6,
numericInput("age", "Age", 40, min = 18, max = 100, step = 2)
)),
fluidRow(align="center",
actionButton("predict", "Predict")
),
br(),
fluidRow(align="center",
imageOutput("waterfallPlot")
),
shinyjs::hidden(
div(style="text-align: justify",
id = "hiddenbox",
box(
title = "Hidden Box",
status = "primary",
solidHeader = TRUE,
collapsible = TRUE,
uiOutput(outputId = "waterfallDescription")
)
)
)
)
)
))))
server <- function(input, output, session) {
results <- eventReactive(input$predict, {
output <- as.integer(input$age)
output
})
output$waterfallPlot <- renderImage({
# Return a list containing the filename
temp <- results()
list(src = waterfallPlots[1],
contentType = 'image/png'
,width = 400,
height = 300
)
}, deleteFile = FALSE)
observeEvent(input$predict, {
shinyjs::show(id = "hiddenbox")
})
output$waterfallDescription <- renderText({
temp <- results()
HTML(paste0("<p>","bold","</b>", " The waterfall chart to the left explains why your prediction
differs from the average person’s prediction.The average prediction is shown at the bottom.", "</p>", "<p>",
"Each factor that goes into the model is shown in increasing order of impact going up.
For example, a blue bar pointing left means that your input for that feature decreases the model’s
output from the average output by the listed number.", "</p>"))
})
}
shinyApp(ui, server)
library(shiny);
library(shinydashboard)
library(shinyjs)
ui <- dashboardPage(
dashboardHeader(title = "Test Test Test"),
dashboardSidebar(disable = T),
dashboardBody(useShinyjs(),
shinyUI(fluidPage(
navbarPage(
"Test",
id = "main_navbar",
tabPanel(
"Test",
fluidRow(align="center",
column(width = 12,
numericInput("age", "Age", 40, min = 18, max = 100, step = 2)
)),
fluidRow(align="center",
actionButton("predict", "Predict")
),
br(),
fluidRow(align="center",
imageOutput("waterfallPlot", height = "200px")
),
shinyjs::hidden(
div(style="text-align: justify",
id = "hiddenbox",
box(
width = 12,
title = "Hidden Box",
status = "primary",
solidHeader = TRUE,
collapsible = TRUE,
uiOutput(outputId = "waterfallDescription")
)
)
)
)
)
))))
server <- function(input, output, session) {
results <- eventReactive(input$predict, {
output <- as.integer(input$age)
output
})
output$waterfallPlot <- renderImage({
# Return a list containing the filename
temp <- results()
list(src = tempfile(),
contentType = 'image/png'
,width = 400,
height = 300
)
}, deleteFile = FALSE)
observeEvent(input$predict, {
shinyjs::show(id = "hiddenbox")
})
output$waterfallDescription <- renderText({
temp <- results()
HTML(paste0("<p>","bold","</b>", " The waterfall chart to the left explains why your prediction
differs from the average person’s prediction.The average prediction is shown at the bottom.", "</p>", "<p>",
"Each factor that goes into the model is shown in increasing order of impact going up.
For example, a blue bar pointing left means that your input for that feature decreases the model’s
output from the average output by the listed number.", "</p>"))
})
}
shinyApp(ui, server)
You can use width to change box width, from 1-12.
Use height of imageOutput to adjust the gap between image and box.

How can I format navlistPanel in a bs4Dash box so that the tabItems are underneath each other?

I am trying to add a navlistPanel to a box() in bs4Dash and when I set the column width to 12, the tabItems squeeze next to each other like this:
Adding the widths = c(4,8) argument to navlistPanel also gives me the same result. If I set the column width to 4 or less, the navlistPanel is properly formatted.
My goal is to have a box() with column = 12 and a vertical tab menu inside it with width = 4 and have the tabs look correct.
I've also tried using tabsetPanel with vertical = TRUE, but the content doesn't show up in the right location, it shows up below. See picture #2:
Reprexes for both are below:
library(shiny)
library(bs4Dash)
ui <- dashboardPage(
header = dashboardHeader(
title = dashboardBrand(
title = "My dashboard",
color = "primary",
href = "https://adminlte.io/themes/v3",
image = "https://adminlte.io/themes/v3/dist/img/AdminLTELogo.png"
)),
sidebar = bs4DashSidebar(),
controlbar = dashboardControlbar(),
body = dashboardBody(fluidRow(column(
12,
box(
title = "Title",
status = "primary",
solidHeader = TRUE,
collapsible = FALSE,
maximizable = TRUE,
color = "white",
height = 175,
width = NULL,
navlistPanel(
"Header",
tabPanel("First"),
tabPanel("Second"),
tabPanel("Third")
)
)
))),
help = FALSE,
dark = NULL,
scrollToTop = FALSE
)
server = function(input, output, session) {
}
shinyApp(ui, server)
library(shiny)
library(bs4Dash)
ui <- dashboardPage(
header = dashboardHeader(
title = dashboardBrand(
title = "My dashboard",
color = "primary",
href = "https://adminlte.io/themes/v3",
image = "https://adminlte.io/themes/v3/dist/img/AdminLTELogo.png"
)),
sidebar = bs4DashSidebar(),
controlbar = dashboardControlbar(),
body = dashboardBody(fluidRow(column(
12,
box(
title = "Title",
status = "primary",
solidHeader = TRUE,
collapsible = FALSE,
maximizable = TRUE,
color = "white",
height = 175,
width = NULL,
tabsetPanel(
id = NULL,
vertical = TRUE,
tabPanel("First",
"The content is below and I want it to the right of the tabset"),
tabPanel("Second"),
tabPanel("Third")
)
)
))),
help = FALSE,
dark = NULL,
scrollToTop = FALSE
)
server = function(input, output, session) {
}
shinyApp(ui, server)

R shiny: slickROutput disappears when switching tabpanel()

I am making a Shiny app with tabPanels embedded in a navbarPage.
In each tabPanel, I generate a serie of image. When switching from one panel to the other one, the image loaded in one of them disappear.
I have to "refresh" manually the page to see it again. The problem seems similar than the one posted here but I cannot really subset my tabPanels, even though I gave $id and value to them.
Here is a reproducible example:
library(shiny)
library(shinythemes)
library(slickR)
## ui ----
# Image list
imgs <- list(
stackoverflow =
"https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
stackexchange =
"https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png"
)
ui <- navbarPage(title = div(
HTML('<span style="font-size:180%;color:white;font-weight:bold;"> Navbarpage</span></a>'),
tags$style(style = 'position:absolute; right:42px;'),
tags$style(HTML("#panel1{font-size: 25px}")),
tags$style(HTML("#panel2{font-size: 25px}")),
tags$style(HTML("#panel_about{font-size: 25px}"))
),
theme = shinytheme("flatly"),
windowTitle = "Navbarpage",
id = "navbar",
## First tabpanel ----
tabPanel(h1(id = "panel1", "Panel 1"), value = 1, fluid = TRUE,
fluidRow(column(4,
selectInput("img_list", "Image list",
choices = imgs,
selected = imgs[1])),
column(8,
slickROutput("plot_panel1"))),
),
tabPanel(h1(id = "panel2", "Panel 2"), value = 2, fluid = TRUE,
fluidRow(column(4,
selectInput("img_list", "Image list",
choices = imgs,
selected = imgs[1])),
column(8,
slickROutput("plot_panel2"))),
)
) # closes navbarpage
## server ----
server <- function(input, output, session){
observe({
output$plot_panel1 <- renderSlickR({
slick1 <- slick_list(slick_div(
input$img_list,
css = htmltools::css(width = "100%", margin.left = "auto",
margin.right = "auto"),
type = "img", links = NULL))
slickR(slick1)
})
})
observe({
output$plot_panel2 <- renderSlickR({
slick2 <- slick_list(slick_div(
input$img_list,
css = htmltools::css(width = "100%", margin.left = "auto",
margin.right = "auto"),
type = "img", links = NULL))
slickR(slick2)
})
})
}
shinyApp(ui, server)
And what it produces:
When there are multiple slickR objects to be rendered, you need to use a unique slideId for each. Furthermore you should not wrap render* functions in observe and use the same id for two selectInputs.
Please check the following:
library(shiny)
library(shinythemes)
library(slickR)
## ui ----
# Image list
imgs <- list(
stackoverflow =
"https://upload.wikimedia.org/wikipedia/fr/9/95/Stack_Overflow_website_logo.png",
stackexchange =
"https://upload.wikimedia.org/wikipedia/commons/6/6f/Stack_Exchange_Logo.png"
)
ui <- navbarPage(title = div(
HTML('<span style="font-size:180%;color:white;font-weight:bold;"> Navbarpage</span></a>'),
tags$style(style = 'position:absolute; right:42px;'),
tags$style(HTML("#panel1{font-size: 25px}")),
tags$style(HTML("#panel2{font-size: 25px}")),
tags$style(HTML("#panel_about{font-size: 25px}"))
),
theme = shinytheme("flatly"),
windowTitle = "Navbarpage",
id = "navbar",
## First tabpanel ----
tabPanel(h1(id = "panel1", "Panel 1"), value = 1, fluid = TRUE,
fluidRow(column(4,
selectInput("img_list1", "Image list",
choices = imgs,
selected = imgs[1])),
column(8,
slickROutput("plot_panel1"))),
),
tabPanel(h1(id = "panel2", "Panel 2"), value = 2, fluid = TRUE,
fluidRow(column(4,
selectInput("img_list2", "Image list",
choices = imgs,
selected = imgs[1])),
column(8,
slickROutput("plot_panel2"))),
)
) # closes navbarpage
## server ----
server <- function(input, output, session){
output$plot_panel1 <- renderSlickR({
slick1 <- slick_list(slick_div(
input$img_list1,
css = htmltools::css(width = "100%", margin.left = "auto",
margin.right = "auto"),
type = "img", links = NULL))
slickR(slick1, slideId = "slide1")
})
output$plot_panel2 <- renderSlickR({
slick2 <- slick_list(slick_div(
input$img_list2,
css = htmltools::css(width = "100%", margin.left = "auto",
margin.right = "auto"),
type = "img", links = NULL))
slickR(slick2, slideId = "slide2")
})
}
shinyApp(ui, server)

fluidRow with multiple columns

How to align widgets in fluidRow without huge gaps. Take for example this code:
library(shiny)
ui <- bootstrapPage(
absolutePanel(
id = "pn", top = 5, right = 5, class = "panel panel-default",
fluidRow(
column(width = 3, selectInput("place_format", NULL, choices = character(0))),
column(width = 7, selectizeInput("place", NULL, choices = character(0))),
column(width = 2, actionButton("zoom","Zoom!"))
)
)
)
server <- function(input, output){}
shinyApp(ui = ui, server = server)
if all width aren't4 there is 'huge' gap between button and 2nd widget. And also after button there is a 'lot' of free space.
The definition of your absolutePanel is incomplete. Please see the details section in ?absolutePanel
The position (top, left, right, bottom) and size (width, height)
parameters are all optional, but you should specify exactly two of
top, bottom, and height and exactly two of left, right, and width for
predictable results.
Please check the following example:
library(shiny)
ui <- bootstrapPage(
absolutePanel(
id = "pn", top = "100px", left = "100px", right = "100px", bottom = "100px", class = "panel panel-default",
fluidRow(
column(width = 3, selectInput("place_format", NULL, choices = character(0), width = "100%")),
column(width = 7, selectizeInput("place", NULL, choices = character(0), width = "100%")),
column(width = 2, actionButton("zoom","Zoom!", width = "100%"))
)
)
)
server <- function(input, output){}
shinyApp(ui = ui, server = server)

How to apply css style to actionBttn from shinywigets in shiny

I have an example shiny app as below. In order to the actionButton with selectInput, I need to add style='margin-top:25px'. Shinywidgets package has actionBttn widgets with some built-in style. For example, I like the one with style='gradient'. But I wonder how I can use css style to add margin on the top to align the actionBttn with other element?
library(shiny)
library(shinydashboard)
library(shinyWidgets)
ui <- dashboardPage(
dashboardHeader(title = "example"),
dashboardSidebar(),
dashboardBody(
box(width=12,
column(width = 3, dateRangeInput("dateRange", "Date Range",
start = "2017-01-01",
end = Sys.Date(),
min = "2001-01-01",
max = Sys.Date(),
format = "mm/dd/yy",
separator = " - ") ),
column(width=3, selectizeInput(inputId = 'var',
label='Select variable',
choices = c('cut', 'color'),
multiple=FALSE,
options = list(
maxItems = 1,
placeholder = '',
onInitialize = I("function() { this.setValue(''); }"))) ),
column(width=1, offset =2, actionButton('Apply', 'Apply', style='margin-top:25px') ),
column(width=3, actionBttn(
inputId = 'clear',
label = "Clear",
style = "gradient",
color = "danger" ) )
)
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
Hard to say with out your .css but You can find a sample in here
To add a style to an existing element created by a package, sometimes you have to wrap that element. Here's three approaches:
Wrap the element itself in a div with the style you want. May not work for all CSS elements.
Write your own custom function using the source from your desired element. Here I used the source from https://github.com/dreamRs/shinyWidgets/blob/ac8134e944f91fdcc4490ace6d839c46e7df02ff/R/actionBttn.R#L63
Add in some external CSS that targets only that element. This is my least favored approach because it moves the logic away from where it's actually being applied, and you have to keep track of it for each element you want to modify.
library(shiny)
library(shinyWidgets)
# new function for approach #2
actionBttn_with_style <- function(inputId, label = NULL, icon = NULL, style = "unite",
color = "default", size = "md", block = FALSE,
no_outline = TRUE, my_additional_style = "") {
value <- shiny::restoreInput(id = inputId, default = NULL)
style <- match.arg(
arg = style,
choices = c("simple", "bordered", "minimal", "stretch", "jelly",
"gradient", "fill", "material-circle", "material-flat",
"pill", "float", "unite")
)
color <- match.arg(
arg = color,
choices = c("default", "primary", "warning", "danger", "success", "royal")
)
size <- match.arg(arg = size, choices = c("xs", "sm", "md", "lg"))
tagBttn <- htmltools::tags$button(
id = inputId, type = "button", class = "action-button bttn", `data-val` = value,
class = paste0("bttn-", style),
class = paste0("bttn-", size),
class = paste0("bttn-", color), list(icon, label),
class = if (block) "bttn-block",
class = if (no_outline) "bttn-no-outline",
style = my_additional_style
)
shinyWidgets:::attachShinyWidgetsDep(tagBttn, "bttn")
}
After you make your custom button function, you can use it just like actionBttn inside your ui.
ui <- dashboardPage(
dashboardHeader(
title = "example"
),
dashboardSidebar(),
dashboardBody(
# for approach #3, but this is far away from the button in the code
htmltools::tags$head(
htmltools::tags$style('button#clear_ext_css { margin-top:25px }')
),
box(
width = 12,
column(
width = 2,
dateRangeInput(
"dateRange",
"Date Range",
start = "2017-01-01",
end = Sys.Date(),
min = "2001-01-01",
max = Sys.Date(),
format = "mm/dd/yy",
separator = " - "
)
),
column(
width = 1,
actionButton('Apply', 'Apply', style = 'margin-top:25px')
),
column(
width = 3,
# approach #1, just wrapping it in a styled div
div(
actionBttn(
inputId = 'clear_div',
label = "Clear with div",
style = "gradient",
color = "danger"
),
style = 'margin-top:25px'
)
),
column(
width = 3,
# approach #2, custom function from above
actionBttn_with_style(
inputId = 'clear_fn',
label = "Clear with custom function",
style = "gradient",
color = "danger",
my_additional_style = 'margin-top:25px'
)
),
column(
width = 3,
# approach #3, but you don't see any custom logic here
actionBttn(
inputId = 'clear_ext_css',
label = "Clear with external CSS",
style = "gradient",
color = "danger"
)
)
)
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)

Resources