How to reduce height of input fields in Shiny? - css

I have multiple input fields in my shinyApp (fileInput, numericInput, textInput), and I would like to customize their height, as well as the character size.
I have tried with div(), but I could only change the gap between two fields. In this case setting div(style="height: 60px;",numericInput("rat","RATIO", value = 0,step=0.01 , width = '40%')) would only decrease the distance between the numeric input field and the slider.
Here is an example code:
sidebar <- dashboardSidebar(
sidebarMenu(
div(style="height: 70px;",fileInput('uploadfile',"Select result file(s)", multiple=TRUE,accep=".txt")),
div(style="height: 60px;",numericInput("rat","RATIO", value = 0,step=0.01 , width = '40%')),
div(style="height: 60px;",sliderInput("ratio",NULL, min= 0, max= 1, value = 0)),
textInput("mytext","Enter name",value='', width = '50%')
)
)
ui<-dashboardPage(
dashboardHeader(title = "Analysis"),
sidebar,
body <- dashboardBody()
)
server<-shinyServer(function(input, output, session){})
shinyApp(ui = ui, server = server)
I have never done any html, so I am not sure what should I look for exactly.

There are several ways of doing that using CSS.
You can either change all inputs that have the same CSS class. Then all inputs of same type would be styled the same way. Or you use the knowledge that you know the id of the ui elements. For me it sounds like that latter is more interesting for you as it seems you want to do specific styling for each of the inputs.
Within shiny you can overwrite existing CSS with the tags$style() command. You can use the format #id{property: value}. So for the inputfile with the id uploadfile, you could use: #uploadfile{height: 70px}. (Note that if you are interested in adapting classes you would use .className{property: value}
Reproducible example:
sidebar <- dashboardSidebar(
sidebarMenu(
tags$head(
tags$style(
HTML('
#uploadfile{height: 70px}
#rat{height: 60px}
#ratio{height: 60px}
#mytext{width: 50px}
')
)
),
fileInput('uploadfile',"Select result file(s)", multiple=TRUE,accep=".txt"),
numericInput("rat","RATIO", value = 0,step=0.01 , width = '40%'),
sliderInput("ratio",NULL, min= 0, max= 1, value = 0),
textInput("mytext","Enter name",value='', width = '50%')
)
)
ui<-dashboardPage(
dashboardHeader(title = "Analysis"),
sidebar,
body <- dashboardBody()
)
server<-shinyServer(function(input, output, session){})
shinyApp(ui = ui, server = server)

Related

Aligning all sub-menu items in dropMenu to the right and hiding drop arrow

I have an application which uses box::dropdownMenu to render a dropdown menu which the user will use to set plot options. I'm able to implement this functionality without any issue, but I would like to do two additional things.
Is it possible to:
(1) Hide the arrow to the right of the cog-icon?
(2) On the dropdown menu, is it possible to keep the text left-alligned, but have the radio buttons be right aligned?
Current State:
Desired End Result:
Code:
library(shiny)
library(shinyWidgets)
library(shinydashboardPlus)
ui <- fluidPage(
box(
title = "Box Title",
dropdownMenu = dropdown(
width = "200px",
icon = icon("gear"),
materialSwitch(inputId = "Id079", label = "Color:"),
materialSwitch(inputId = "Id079", label = "Display Goal:"),
),
textOutput("text")
)
)
server <- function(input, output, session) {
output$text <- renderText("Hello World!")
}
shinyApp(ui, server)
To remove the arrow, one should change style to something other than the default. You can use fill or bordered for example.
shinyWidgets::dropdown(
width = "200px",
style = "fill",
icon = icon("cog"),
materialSwitch(inputId = "Id079", label = "Color:"),
# Change IDs to unique IDs otherwise it won't work
materialSwitch(inputId = "Id080", label = "Display Goal:"),
)
For the alignment, you can play around with the .label-default elements (attrinutes?)
ui <- fluidPage(
# Need to play with the margin-left part
tags$head(tags$style(HTML(".label-default{
margin-left: 50px;}
"))),
shinyWidgets::dropdown(
width = "300px",
style = "fill",
icon = icon("cog"),
materialSwitch(inputId = "Id079", label = "Color:"),
materialSwitch(inputId = "Id080", label = "Display Goal:"),
),
textOutput("text")
)
The problem with this is that it is not easy to uniformly change the margins for non-equal labels.

Print text using for loop inside box in shiny dashboard

I have the shiny dashboard below and I want to print inside the box "Red1" to "Red21" one below the other using a for() loop like in the screenshot. The box() should be created with renderUI()
library(shiny)
library(shinydashboard)
shinyApp(
ui = dashboardPage(
options = list(sidebarExpandOnHover = TRUE),
header = dashboardHeader(),
sidebar = dashboardSidebar(minified = TRUE, collapsed = TRUE),
body = dashboardBody(
uiOutput("box1")
),
title = "DashboardPage"
),
server = function(input, output) {
output$box1<-renderUI({
box(
for(i in 1:21){
"Red"[i]
br()
},
height = 300,width = 5
)
})
}
)
box() can take a list as first argument, so your code can be rewritten like this:
...
box({
text <- list()
for(i in 1:21){
text <- append(text, list(paste("Red", i), br()))
}
text
})
...
Doing this with an anonymous function (which this is) isn't that good for readability (at least for me) so I would suggest you build that list beforehand.

Shiny: dynamic checkboxGroupInput

I'm building a Shiny app and I would like to add a dynamic "checkboxGroup" which depends on some other input. More precisely, the user can upload N files, the app makes some calculations, then the output is a table with N columns (one for each file uploaded). At this point I would like the user to be able to select only certain columns, i.e. the ones he/she would like to consider, then the table should update according to the user's choice.
I had a look at some shiny apps on the web, and the closest solution is probably something like
https://shiny.rstudio.com/gallery/datatables-demo.html
but unfortunately in that example we have
checkboxGroupInput("show_vars", "Columns in diamonds to show:",
names(diamonds), selected = names(diamonds))
where diamonds is "known", whereas in my case I don't know how many files the user will upload and so how many columns my table will have.
Any ideas?
Cheers
EDITED:
Here there is the portion of code I'm reffering to. It works, the user can upload N excel files with same number of rows. The app returns a tab with N columns (the second column of each file uploaded).
Ideally, now I would like to add N check boxes (all selected initially), and the user can uncheck the columns he/she doesn't want to consider. Say he/she uncheck 2 columns, then the tab changes into a tab with N-2 columns.
Thanks again
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(data.table)
library(dplyr)
library(xlsx)
sidebar <- dashboardSidebar(
width = 350,
sidebarMenu(
tags$style(HTML(".sidebar-menu li a { color: #f4f8e8; }")),
menuItem("Computations",tabName = "tab1", icon = icon("file-text-o"))
))
body <- dashboardBody(
tags$style(".content-wrapper {background-color: #c3f9fa;}"),
style = "color: black;",
tabItems(
tabItem(
tabName = "tab1",
h2("upload files"),
tags$style(HTML(" .progress-bar { background-color: #1dbcbf; }")),
fileInput("csvs",
label="Upload CSVs here",
multiple = TRUE),
textInput(inputId="num_files",
label="number of files uploaded",
value = "",
width = NULL,
placeholder = NULL),
actionButton(inputId = "display_tab", label = "Display Tab after computations"),
box(title = "tab after computations:",tableOutput("all_cols"),width = 100),
checkboxGroupInput(inputId="show_vars", "Columns to keep:", choices = "selectedData", selected = "selectedData")
)))
dbHeader <- dashboardHeader(title = 'Exercise')
ui <- dashboardPage(
skin = "black",
dbHeader,
sidebar,
body
)
server <- function(input, output) {
options(shiny.maxRequestSize=260*1024^2)
computations <- function(num_files, db){
num_files <- as.numeric(num_files)
N <- nrow(db)/num_files #number of rows for 1 file (they all have same size)
tab_to_be_displayed <- db[1:N,2]
for(j in (1:(num_files - 1))){
left <- j*N+1
right <- (j+1)*N
tab_to_be_displayed <- cbind(tab_to_be_displayed, db[left:right,2])
}
return(tab_to_be_displayed)
}
mycsvs<-reactive({
rbindlist(lapply(input$csvs$datapath, fread),
use.names = TRUE, fill = TRUE)
})
selectedData <- reactive({
names(computations(input$num_files, mycsvs()))
})
observeEvent(input$display_tab,{
numero <- input$num_files
comp_tab <- computations(numero, mycsvs())
output$all_cols <- renderTable(comp_tab, align = 'c', rownames = TRUE, colnames = TRUE, digits = 3)
})
}
shinyApp(ui = ui, server = server)
I simplified the code a bit to demonstrate how the group checkboxes could work.
In simplifying, I kept the data as a list from the csv files. Then for computations extracted the second column from all data frames in the list, then used select to show columns based on the checkboxes.
The checkbox items are based on the names of the second columns of the data, with a default of all selected.
Instead of entering the number of files that were read, it is now computed based on the length of the list of data.
Let me know if this is closer to what you need.
library(shiny)
library(shinydashboard)
library(shinyWidgets)
library(data.table)
library(dplyr)
library(xlsx)
sidebar <- dashboardSidebar(
width = 350,
sidebarMenu(
tags$style(HTML(".sidebar-menu li a { color: #f4f8e8; }")),
menuItem("Computations",tabName = "tab1", icon = icon("file-text-o"))
))
body <- dashboardBody(
tags$style(".content-wrapper {background-color: #c3f9fa;}"),
style = "color: black;",
tabItems(
tabItem(
tabName = "tab1",
h2("upload files"),
tags$style(HTML(" .progress-bar { background-color: #1dbcbf; }")),
fileInput("csvs",
label="Upload CSVs here",
multiple = TRUE),
textOutput("numfiles"),
box(title = "tab after computations:",tableOutput("all_cols"),width = 100),
uiOutput("checkboxes")
)))
dbHeader <- dashboardHeader(title = 'Exercise')
ui <- dashboardPage(
skin = "black",
dbHeader,
sidebar,
body
)
server <- function(input, output) {
options(shiny.maxRequestSize=260*1024^2)
db <- reactiveVal(list())
computations <- function(){
req(input$checkboxes)
do.call(cbind, lapply(db(), "[", , 2)) %>%
select_if(names(.) %in% input$checkboxes)
}
observeEvent(input$csvs, {
db(lapply(input$csvs$datapath, fread))
})
output$numfiles <- renderText(paste("Number of files: ", length(db())))
output$checkboxes <- renderUI({
choice_list <- unlist(lapply(db(), function(x) colnames(x)[2]))
checkboxGroupInput("checkboxes", "Columns to keep:", choices = choice_list, selected = choice_list)
})
output$all_cols <- renderTable(computations(), align = 'c', rownames = TRUE, colnames = TRUE, digits = 3)
}
shinyApp(ui = ui, server = server)
It sounds like you need your checkboxGroupInput to be reactive. That requires a combination of renderUI on your server script, and uiOutput on your ui script.

Removing gap between columns in splitLayout within dashboardSidebar

I'm using the splitLayout() function within a dashboardSidebar() from the shinydashboard package. When I do, there is a significant gap between inputs within my splitLayout().
When I used vanilla shiny, I could control this gap with parameter cellArgs = list(style="padding: 0px") but this seems to have a different effect within a dashboardSidebar().
Question:
How can I control the gap between inputs inside a splitLayout() within a dashboardSidebar()?
Here is a MRE which shows my unsuccessful attempts at using padding
library(shinydashboard)
library(shiny)
sidebar <- dashboardSidebar(width=400,
sidebarMenu(
menuItem("Default", tabName = "dashboard", icon = icon("dashboard"),startExpanded = T,
splitLayout(cellWidths = c(100,100,100,100),
textInput("a1",label=NULL,value = 1),
textInput("a2",label=NULL,value = 2),
textInput("a3",label=NULL,value = 3),
textInput("a4",label=NULL,value = 4)
),
splitLayout(cellWidths = c(100,100,100,100),cellArgs = list(style="padding: 0px"),
textInput("b1",label=NULL,value = 1),
textInput("b2",label=NULL,value = 2),
textInput("b3",label=NULL,value = 3),
textInput("b4",label=NULL,value = 4)
),
#see the effect of padding
splitLayout(cellWidths = c(100,100,100,100),cellArgs = list(style="padding: 20px"),
textInput("c1",label=NULL,value = 1),
textInput("c2",label=NULL,value = 2),
textInput("c3",label=NULL,value = 3),
textInput("c4",label=NULL,value = 4)
)
)
)
)
body <- dashboardBody(
)
# Put them together into a dashboardPage
ui <- dashboardPage(
dashboardHeader(title = "Padding demo",titleWidth=400),
sidebar,
body
)
server <- function(input, output) {
}
shinyApp(ui,server)
your problem is not the padding of the the splitCells - that is working fine. It has more to do with that the inputs also have padding around them. To remove this you can add the following code
body <- dashboardBody(
tags$head(
tags$style(
".shiny-input-container{padding:0px !important;}"
)
)
)
hope this helps

(R shiny) cannot change the width of infoBox

I use the library shinydashboard to write my ui.R. In my dashboardBody part, I wrote:
fluidRow(infoBoxOutput("dri"))
And then in my server.R, I wrote:
output$dri = renderInfoBox({
infoBox(
width = 2,
title = tags$b("Score"),
value = tags$b("100"),
color = "aqua",
fill = TRUE,
icon = icon("edit")
)
})*
But the width won't change to 2; it still uses the default one, i.e. 4 (1/3 of the whole webpage width).
Would someone help me with this? Thank you very much!
Maybe you can style it yourself
rm(list = ls())
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(fluidRow(infoBoxOutput("dri")),tags$style("#dri {width:200px;}"))
)
server <- function(input, output) {
output$dri <- renderInfoBox({
infoBox(
title = tags$b("Score"),
value = tags$b("100"),
color = "aqua",
fill = TRUE,
icon = icon("edit")
)
})
}
shinyApp(ui, server)
200 px
1000px
I found this answer on github and it worked for me aswell:
Instead of using renderInfoBox and infoBoxOutput, you can use renderUI
and uiOutput and that worked for me. This makes me think there is an
issue with the renderInfoBox function.

Resources