R DT Flexible Table Width - r

I would like to make a datatable using DT that does not change width when the browser window changes. The example below almost does what I am trying to do, all of the column widths are locked except the first column, which is still flexible. I would like all of the columns to be locked without specifying widths in pixels for each column.
library(DT)
library(dplyr)
datatable(mtcars,
options = list(
autowidth = TRUE
)) %>%
formatStyle(columns = 1:ncol(mtcars),
`width` = "100%")

The following Rmd document gives a fixed width of 100 pixels to the datatable
---
output: html_document
---
```{r}
shiny::div(
width = "100px",
DT::datatable(mtcars))
```
The usage in shiny is similar
shiny::shinyApp(
ui = shiny::div(
width = "100px",
DT::datatable(mtcars)),
server = function(...){}
)

Related

Resizable ggplot images in flexdashboard?

By default, flexdashboard displays all images using the same predefined size.
Hence, I want to be able to do the following two things:
be able to display the image so it occupies the full availale space (maximize it), and / or
be able to allow a user to modify image size interactively using shiny sliders.
Is that possible to do? At least the first of these tasks, which seems easier.
Below is the .Rmd code and the screenshot of what it does now. You'll note the image is cut at the bottom and I don't know how to change its size.
---
title: "Resizable ggplot images in flexdashboard"
output:
flexdashboard::flex_dashboard:
vertical_layout: fill
orientation: columns
runtime: shiny
---
## Left column ----
This dashboard shows how you can resize ggplot images in 'flexdashboard'.
## Right column, where the shiny sliders and image are displayed ---
```{r}
library(ggplot2)
# fluidPage( # This does not help
fluidRow(
column(width=4, checkboxInput("maximize_image", "Maximize image", T) ),
column(width=4, sliderInput("image_width", "Image width", 2, 6, 3) ),
column(width=4, sliderInput("image_height", "Image height ", 2, 9, 4) )
)
renderPlot(
ggplot(pressure) + geom_point (aes(temperature,pressure))
)
# )
# end of .Rmd code
The following code seems to do the trick:
library(ggplot2)
fluidRow(
# column(width=4, checkboxInput("maximize_image", "Maximize image", T) ),
column(width=4, sliderInput("image_width", "Image width", 50, 100, 50) ),
column(width=4, sliderInput("image_height", "Image height ", 50, 100, 50 ) ),
)
renderUI(
fillPage(
div(style = paste0("width: ", input$image_width, "%;", " height: ", input$image_height, "%;"),
renderPlot( ggplot(pressure) + geom_point (aes(temperature,pressure)) ) )
)
)
It's probably not the best (as it does not know the maximum visible space, so you have to manually play with slider to find out that height=87% is the one you are looking for.
Still though, I'm surprised I could not find it anywhere, because it seems super-handy.

shinyWidgets pickerInput width issue overflow off sidebar

I am using shinyWidgets pickerInput within a flexdashboard sidebar. My issue is that when the options in the pickerInput are too wide they get cut off within the width of the sidebar which makes it so you cannot read the options, see which are selected, or see the deselect all button. Is there a way to have the pickerInput dropdown overflow off of the sidebar and onto the body of the page?
As an intermediate solution I have found that you can use:
choicesOpt = list(
content = stringr::str_trunc(sort(unique(COLUMN_NAME)), width = 25))
To truncate the text in the pickerInput so that you are able to see which options are selected and all of the buttons but you are still not able to read each option fully.
Edit:
Adding reprex - Looking to have the filter drop down open over the body so that everything is visible.
---
title: "TEST"
runtime: shiny
output:
flexdashboard::flex_dashboard:
orientation: rows
---
```{r setup, include=FALSE}
library(dplyr)
library(shiny)
library(DT)
library(shinyWidgets)
Name <- c("LONNGGGGGGGGGGGGGGG TEXXTTTTTTTTTTTTTTTTTT", "Bill", "Maria", "Ben", "Tina")
Age <- c(23, 41, 32, 58, 26)
df <- data.frame(Name, Age)
```
Sidebar {.sidebar}
=======================================================================
### Filters
```{r}
pickerInput(
inputId = "name",
label = "test",
choices = sort(unique(df$Name)),
selected = sort(unique(df$Name)),
multiple = TRUE,
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(df$Name))) -1),`count-selected-text` = "All Selected")
)
```
TEST
=======================================================================
Row
-------------------------------------
```{r}
filtered_data <-
reactive ({
req(input$name)
df %>%
filter(Name %in% input$name)
})
renderDataTable(filtered_data(), class = 'cell-border stripe',
extensions = 'Buttons',
rownames = FALSE,
options = list(
columnDefs = list(list(className = 'dt-center',width = '100px', targets = "_all"))),fillContainer=TRUE)
```
This may have unintended side effects but here's a workaround to force the picker dropdown to not get cutoff.
You can add your own css class to the Sidebar section inside the {}. I used .my-class as a placeholder. Then I inserted a css chunk and added .my-class to the .section.sidebar classes from flexdashboard. If you don't do that then that css will overwrite the class. Most likely because it's loaded afterwards.
Also in the reprex provided, for whatever reason the choices were the not the actual values but instead the level positions.
So I used sort(unique(Name)) instead of sort(unique(df$Name))
```{css, echo=FALSE}
.section.sidebar.my-class {
overflow: visible;
z-index: 10;
}
```
Sidebar {.sidebar .my-class}
=======================================================================
...
Option 2: Truncate choices
The above option works as long as the height of the sidebar does not exceed the height of the browser window. Ideally you want overflow-x: visible and overflow-y: scroll. However I'm not sure if that's possible on the same div with position fixed.
Instead you could truncate your options so they fit in the window. If you want more text to be displayed you can increase the width of the sidebar.
cs = sort(unique(Name)
pickerInput(
inputId = "name",
label = "test",
choices = cs,
selected = cs,
multiple = TRUE,
options = list(
`actions-box` = TRUE,
`selected-text-format` = paste0("count > ", length(sort(unique(df$Name))) -1),`count-selected-text` = "All Selected"
),
choicesOpt = list(
content = stringr::str_trunc(cs, width = 18)
)
)

Issues with controlling width of columns in a rendered datatable Shiny

To render a datatable in a shiny app I use the following code
ui <- fluidPage(
box(width = 10, # this is to control table width
DT::DTOutput(('table'))
)
)
server <- function(input, output) {
options(shiny.maxRequestSize=10000*1024^2)
output$table <- DT::renderDataTable(
datatable(
dataset ,
options = list(dom = 'fltipr',
pageLength = 1000,
#lengthMenu = list(c(250, 500), c('250', '500')),
searchHighlight = TRUE,
autoWidth = TRUE,
columnDefs = list(list(width = '300px', targets = c(7,10)), # this is to control width of two columns
list(visible = FALSE, targets = c(2,4,6, 8,11,13,15,16,17:23)))
), filter = 'top',
selection = 'none',
editable = 'cell')
)
}
With that that setup I am trying to control the width of two of the visible columns. When I run the app, it renders fine, just as I wanted it to be rendered.
But when I try to sort the rendered datatable by one of the columns, the controls for column width (and even the whole table width) stop working. The initially controlled column that contains long sections of text now becomes so wide it does not fit on the page, and I have to scroll sideways.
In essence I would like all table to fit on page, with width of two textual columns controlled strictly not matter how I sort the rendered datatable.
Sincerely,
Maria

Incomplete CSV/Excel rows downloaded from DT buttons through RMarkdown-Shiny

I have the following RMarkdown Shiny document:
---
title: "Title"
runtime: shiny
output:
flexdashboard::flex_dashboard:
vertical_layout: scroll
theme: bootstrap
orientation: rows
---
```{r setup, include=FALSE}
library(flexdashboard)
```
Rows {data-height=400}
-----------------------------------------------------------------------
### Table
``` {r show_table}
library(DT)
library(ggplot2)
renderDataTable( {
dat <- diamonds
},
extensions = c('Scroller','Buttons'),
class = 'compact cell-border stripe', rownames = FALSE,
filter = list( position = 'top', clear = FALSE, plain =TRUE ),
options = list(
deferRender = FALSE,
scrollY = 200,
scroller = TRUE,
dom = 'Bfrtip',
buttons = c('csv', 'excel')
)
)
```
Which produces this document:
After I download the Excel file, the number of rows is just ~90 lines
not complete 53,940 entries. Why is that and how can I fix it?
By default DT uses Server-side Processing so only the visible data are sent to the browser. That is why the Excel file only contains the visible data (if you remove scrollY = 200 and scroller = TRUE this becomes very clear).
To download all data you need to disable Server-side Processing by including server = FALSE, e.g.
class = 'compact cell-border stripe', rownames = FALSE,
server = FALSE,
filter = list( position = 'top', clear = FALSE, plain =TRUE ),
Unfortunately, this makes loading and browsing the table extremely slow (on my computer at least).
BTW: Your code depends on the diamonds dataset which is part of ggplot2.

How to display multiple plots on an R flexdashboard page if using storyboard layout

I'm building an R FlexDashboard in storyboard format. I'd like to display multiple plots on a few of the storyboard pages, including a series of linked plots using crosstalk. However, when I try to display multiple plots on a page or use the bscols() function, the page looks all messed up. Are multiple plots allowed in R FlexDashboard's storyboard format? Here is an example:
---
title: "Error_example"
output:
flexdashboard::flex_dashboard:
storyboard: true
theme: bootstrap
---
###Example: Why can't won't the datatable show up below the plot in this storyboard?
```{r}
library(plotly)
library(DT)
plot1<-plot_ly(data=diamonds,x=~carat,y=~price)
table1<-datatable(diamonds)
plot1
table1
bsCols() Seems to completely override the flexdashboard CSS so I would avoid using that.
A simple solution would be to add some divs into the R chunk. Something like:
---
title: "I think this should work"
output:
flexdashboard::flex_dashboard:
storyboard: true
theme: bootstrap
---
###Example: Using divs to separate outputs
```{r}
library(shiny)
library(plotly)
library(DT)
plot1<-plot_ly(data=diamonds,x=~carat,y=~price)
table1<-datatable(diamonds)
tags$div(
tags$div(
plot1
),
tags$div(
table1
)
)
```
This example combines crosstalk, leaflet and plotly, in a way which allows for a high number of plots. The trick is to use absolutepanels with collapsable buttons. The absolutepanel sits over the leaflet map, which means the map can be full size like in superzip https://shiny.rstudio.com/gallery/superzip-example.html, while the buttons allow plots to appear on an as needs basis. So you can add as many plots and tables as youe like, link them with crosstalk, and still tell your story.
This makes a clean interface where plots are included in a way which the user has greater control over the final display. Another example is here How to combine row and column layout in flexdashboard?, but without crosstalk.
---
title: "Demo"
output:
flexdashboard::flex_dashboard:
orientation: columns
vertical_layout: fill
---
```{r setup, include=FALSE}
library(flexdashboard)
library(rmarkdown)
library(plotly)
library(shiny)
library(DT)
```
```{r}
library(crosstalk)
sd <- SharedData$new(quakes[sample(nrow(quakes), 100),])
```
Map { data-icon="fa-map-o"}
=====================================
Sidebar {.sidebar data-width=220}
--------------------------------
```{r, results='asis'}
filter_slider("mag", "Magnitude", sd, column=~mag, step=0.1, width=200)
```
Column {data-width=400}
--------------------------------
### Planet Earth
```{r}
library(leaflet)
leaflet(sd) %>% addTiles() %>% addMarkers()
```
```{r}
##########################
absolutePanel(id = "controls", class = "panel panel-default", fixed = TRUE,
draggable = TRUE, top = 70, left = "auto", right = 20, bottom = "auto",
width = '25%', height = 'auto',
style = "overflow-y:scroll; max-height: 1000px; opacity: 0.9; style = z-index: 400",
h4(strong("Plot Explorer")),
HTML('<button data-toggle="collapse" data-target="#box1" class="btn-block btn-primary">dot plot</button>'),
tags$div(id = 'box1', class="collapse in",
plot_ly(sd, x = ~depth, y = ~mag) %>% layout(height=200)
),
HTML('<button data-toggle="collapse" data-target="#box2" class="btn-block btn-warning">histogram</button>'),
tags$div(id = 'box2', class="collapse",
plot_ly(sd, x = ~depth, y = ~mag, type = "histogram", name = "Histogram") %>% layout(height=200)
),
HTML('<button data-toggle="collapse" data-target="#box3" class="btn-block btn-danger">table</button>'),
tags$div(id = 'box3', class="collapse in",
datatable(sd, extensions="Scroller", style="bootstrap", class="compact", width="100%",height = 300,
options=list(deferRender=TRUE, scrollY=300, scroller=TRUE))
)
)
```

Resources