How to fine-tune the positioning of objects rendered in r shiny? - css

I'm trying to adjust the positioning of conditionally-rendered objects in R shiny. When running the below skeleton code and clicking the "Delete" action button, I'd like to nudge the conditionally-rendered text ("Select series to delete >>") a bit to the right, and move the little selectInput() box that also conditionally appears on the far right a bit to the left, closer to "Select series to delete >>". I've fiddled with column widths, etc., and I've exhausted all the formatting options which I know of which are limited. Any suggestions for fine-tuning the positioning of these items? My guess is this would entail some CSS which I know almost nothing about.
Skeleton code:
library(dplyr)
library(shiny)
library(shinyjs)
toggleView <- function(input, output_name){
observeEvent(input$delSeries, {show(output_name)})
observeEvent(input$addSeries, {hide(output_name)})
}
ui <- fluidPage(br(),
useShinyjs(),
fluidRow(
column(1,actionButton("addSeries", "Add",width = '70px')),
column(1,actionButton("delSeries","Delete",width = '70px')),
column(3,h5((hidden((textOutput("delFlag")))))),
column(3,hidden(uiOutput("delSeries2")))
)
)
server <- function(input, output, session) {
output$delFlag <- renderText("Select series to delete >>")
output$delSeries2 <-
renderUI(
selectInput("delSeries3",
label = NULL,
choices = c(""),
selected = "",
width = '110px')
)
toggleView(input,"delSeries2")
toggleView(input,"delFlag")
}
shinyApp(ui,server)

You can add some styles to the 2 columns like so:
library(dplyr)
library(shiny)
library(shinyjs)
toggleView <- function(input, output_name){
observeEvent(input$delSeries, {hide(output_name)})
observeEvent(input$addSeries, {show(output_name)})
}
# (0)
css <- HTML("
.row .nudge-right {
padding-right:0;
}
.row .nudge-left {
padding-left:0;
}
")
ui <- fluidPage(
tags$head(tags$style(css)), # (1)
br(),
useShinyjs(),
fluidRow(
column(1,actionButton("addSeries", "Add",width = '70px')),
column(1,actionButton("delSeries","Delete",width = '70px')),
column(3,h5(hidden(textOutput("delFlag"))),
class = c("nudge-right", "text-right")), # (2)
column(3,hidden(uiOutput("delSeries2")), class = "nudge-left") # (2)
)
)
Explanation
The white space you see is partly due to the width of the column and partly due to the so called padding (an additional white space around the element). To bridge this gap you can:
Right align the text. Here you can rely on the already pre-defined (by the underlying bootstrap framework) class text-right.
Further decrease the gap by removing the right padding from the text column and the left padding from the input column. In order to so, you define new classes (I called them .nudge-right and .nudge-left respectively) where you deliberately set the padding to your liking (here I removed it completely, you may want to provide a small offset though - e.g. 5px).
Then all which is left is to
Create some css with the class definitions (#0)
Load the css (#1)
Assign the classes to the columns (#2)

Related

R Shiny: Align table and sortable bucket list

I am attempting to arrange the following outputs so that each number pair is aligned perfectly.
Is there a way to change the spacing of a table beyond the options avaible e.g 'l'?
Following this, how could I vertically align the table with the bucketlist?
library(shiny)
library(sortable)
ui <- fluidPage(column(width =1,tableOutput("table")), column(width =1,
uiOutput("numbers"))
)
server <- function(input, output, session) {
output$table = renderTable( spacing = 'l',as.matrix(c(1:30)))
output$numbers <- renderUI({
bucket_list(
header = h4("Numbers", align = "center"),
group_name = "rank_Bedspace_Acuity",
orientation = "horizontal",
add_rank_list(
text = h5("Numbers", align = "center",style="color: #fff; background-color: #4080C9"),
input_id = "numbers",
labels = c(1:30)
))
})
}
shinyApp(ui, server)
Help appreciated.
Spacing of table - You will have to tweak the .css on your own.
I took your code and made the following updates to .css
Set table
width: auto; - Deleted this
padding-top: 15px; - Added this
.tr { padding-bottom: 1px }
(this is to match with the sortable height of 42px. Alternatively, you could also update the row height directly.
I assume by vertical alignment, you want the table to appear right next to the sortable widget so that you get a reference between old table vs the updated one. Applying the above .css tweaks, I get the following
Is this what you were looking for?

Adjust Padding of Shiny Table Using css

Let's say I want to reduce the padding between the left edge of the screen and the first column to maximize real estate on an iPhone. Here's the table:
library(shiny)
library(reactable)
ui <- fluidPage(
theme = "styles.css",
mainPanel(
align = "left",
reactableOutput("table")
)
)
server <- function(input, output, session) {
output$table <- renderReactable({
reactable(iris,
fullWidth = FALSE
)
})
}
shinyApp(ui, server)
And styles.css is:
.container-fluid {
padding-left: 0 !important;
}
This does not work. However, if I use Chrome Inspector to look at the gap, I can manually set padding-left: 0 and the gap narrows.
How do I narrow the gap from within R/Shiny//css?
Check in the inspector in the sources tab if the file is being correctly included. If it still does not work check if there are errors in your css file, that might be preventing the stylesheet from working. Finally, you might have to set the style inline or in the style tag. If you are using Bootstrap then you can use the ml-0 class in the container.

Distorted spacing between div elements after sorting with jqui_sortable

While building a very nice additional functionality into my shiny app where the user can reorganize the plots inside the page, I ran into 1 problem.
I noticed that the spacing between the div elements that are being relocated (sorted), changes while doing so, resulting in a misalignment of the plots afterwards.
I have tried to adjust margin values to nothing, 0 or a certain amount of pixels, but that doesn't seem to solve this.
The app that I made to test / illustrate the issue is posted below, where I left out the plots to simplify it:
require('shiny')
require('shinyjqui')
ui <- fluidPage(
div(uiOutput('multiobject'), style = 'width: 1200px')
)
server <- function(input, output, session) {
output$multiobject <- renderUI({
plot_output_list <- list();
for(i in 1:8) {
plot_output_list <- append(plot_output_list,list(
wellPanel(
actionButton('drag', label = icon('hand-point-up'), style = 'float: right; color: #339fff;'),
style = 'border-color:#339fff; border-width:1px; background-color: #fff;display: inline-block; margin:2px; width:290px; height:250px')
))
}
jqui_sortable(do.call(function(...) div(id="allplots", ...), plot_output_list), options = list(handle = '#drag', cancel = ""))
})
}
shinyApp(ui, server)
and this image shows the problem after sorting:
A second problem is the white space appearing when hovering a plot.
I tried to add the css from this "non-R-Shiny" question but could't make it work.
It is not perfect yet, but it should be better than before.
The spacing problem of the <div>s was caused by empty text knods. You can see them when inspecting the page in a browser. This means, changing the css margin arguments will not help. The empty text knods are present in the initial page and once you start dragging they disappear leading to said spacing problem. I got rid of them by not wrapping uiOutput('multiobject') in a div()-tag and instead defined its width using the .ui-sortable class in css.
Your second problem, the white space appearing when hovering a plot, can be mitigated by adding 'float: left; to the style = argument in the for loop of your plot_output_list. The css arguments from the SO post you linked won't work, since there are no classes named .sort-container and .item-wrapper this was specific to the original question. There is still a white space appearing when dragging, but it is much smaller than before.
Update I had some issues with the code, sometimes it's working sometimes not. I think there might be css confilcts. I now added !important to the changed css arguments and it seems to work. Will try it on a different machine later.
require('shiny')
require('shinyjqui')
require('stringr')
ui <- fluidPage(
# Custom CSS----------
tags$style(HTML(".ui-sortable {
width: 1200px !important;
} "
)),
uiOutput('multiobject')
)
server <- function(input, output, session) {
output$multiobject <- renderUI({
print(input$drag)
plot_output_list <- list();
for (i in 1:8) {
plot_output_list <- append(plot_output_list,list(
wellPanel(
actionButton('drag', label = icon('hand-point-up'), style = 'float: right; color: #339fff;'),
style = 'float:left !important; border-color:#339fff; border-width:1px; background-color: #fff;display: inline-block; margin:2px; width:290px; height:250px')
))
}
jqui_sortable(do.call(function(...) div(id = "allplots", ...), plot_output_list), options = list(handle = '#drag', cancel = ""))
})
}
shinyApp(ui, server)

Hide column names in shiny table

Is there a way to hide column names of a formattable? I thought about
changing an attribute in the formattable options. Didn't find something about it in the documentation or SO.
changing the font color to white for the header. I guess this may be an easy task for a CSS expert. I couldn't find the right sources to do it as a layman.
Maybe there is another option that I didn't think of? Thanks for your help in advance.
Example code below. The right table's header should be hidden.
library(shiny)
library(formattable)
df <- data.frame(A = LETTERS[1:10], B = 1:10)
server <- function(input, output) {
output$table1 <- renderFormattable({
formattable(df)
})
output$table2 <- renderFormattable({
formattable(df)
})
}
ui <- fluidPage(
fluidRow(
column(6,
h6("Table with header"),
formattableOutput("table1")
),
column(6,
h6("Table without header"),
formattableOutput("table2")
)
)
)
shinyApp(ui = ui, server = server)
Additional: If there is a way to set cell borders like in Excel for the
right table, solutions to this problem would also be appreciated.
Not exactly hiding, but here is my simple suggestion:
output$table2 <- renderFormattable({
names(df) <- c("_", ".")
formattable(df)
})
Any help to your problem?
Add this to your code:
tags$head(tags$style(type = "text/css", "#table2 th {display:none;}"))
Note that you will need to manually set the widths of your columns as they will collapse to the smallest width without text overflowing to a new line.
What I've done here is used some CSS to tap into table2's properties. I access the header properties by declaring th after stating the table's ID. Any additional css for the header can go after the ;.

Column widths in renderDataTable of a shiny app without stretching

I would like to get a DataTable (with all its ranking, search and page features) that does not stretch fully across the page, and results in large amounts of white space in each column...
... ideally with column widths similar to the "wrap" style from renderTable...
I know I can fix relative column widths, however, my table will dynamically update with different numbers of columns dependent of inputs selected. I would prefer additional columns to expand into the empty space on the right hand side and then trigger a horizontal scrollbar if it becomes wider than the browser window width.
Reproducible example of the tables in the images above...
library(shiny)
runApp(list(
ui = navbarPage(
title = 'Tables',
tabPanel('dataTableOutput', dataTableOutput('ex1')),
tabPanel('tableOutput', tableOutput('ex2'))
),
server = function(input, output) {
output$ex1 <- renderDataTable(iris)
output$ex2 <- renderTable(iris)
}
))
I think that you should use drawCallback in dataTables. Here I just changed your example a little to fix width of dataTable to 600px. you can play with possible java script function in callback function to do almost anything.
library(shiny)
runApp(list(
ui = navbarPage(
title = 'Tables',
tabPanel('dataTableOutput', dataTableOutput('ex1')),
tabPanel('tableOutput', tableOutput('ex2'))
),
server = function(input, output) {
output$ex1 <- renderDataTable( iris,
option = list( drawCallback = I("function( settings ) {document.getElementById('ex1').style.width = '600px';}")) )
output$ex2 <- renderTable(iris)
}
))
Assuming your data.frame is df, then put this code at the beginning of the reactive/renderTable block at the server side. It will wrap the column names to desirable length and therefore reducing the size of the table. You can always change the width to equal the desired width.
library(stringr)
colnames(df) = str_wrap(colnames(df),width = 10)

Resources