R shiny datatable scrollX impacts table width - r

please I have the following example to show a layout issue I'm facing with my R shiny app. Example should be entirely reproducible:
ui <- dashboardPage(
title = "Dashboard test", # this is the name of the tab in Chrome browserr
dashboardHeader(title = "Web Portal"),
dashboardSidebar(
sidebarMenu(
menuItem('Retail', tabName = "retail", icon = icon("th"),
menuItem('Dashboard', tabName = 'retail_dashboard'))
)
),
dashboardBody(
tabItem(tabName = "retail_dashboard",
tabsetPanel(type = "tabs",
tabPanel("Dashboard",
h3("Test."),
fluidRow(column(3,
dataTableOutput("table_test1", width = '100%')),
column(3,
dataTableOutput("table_test2", width = '100%'))
)
)
)
)
)
)
server <- function(input, output, session) {
output$table_test1 <- renderDataTable({
df <- data.frame(BUCKET=c("1","2"), ITEM=c(48,53), VALUE = c(7.88, 5.12), stringsAsFactors = F)
datatable(df,
rownames= F,
#colnames = colnames_var,
filter = 'none',
extensions = 'Buttons',
caption = NULL,
options = list(scrollX = T
#, headerCallback = js_col_header # this is to show/hide column headers
, lengthChange = T
#, pagingType = "numbers" # this hides the Next and Previous buttons --> https://datatables.net/reference/option/pagingType
, paging = T # this completely hides the Next, Previous and Page number at the bottom of the table
, autoWidth = T
, pageLength = 5 # this determines how many rows we want to see per page
, dom = 'Blfrtip'
, buttons = NULL
, info = T # this will hide the "Showing 1 of 2..." at the bottom of the table --> https://stackoverflow.com/questions/51730816/remove-showing-1-to-n-of-n-entries-shiny-dt
, searching = T # this removes the search box -> https://stackoverflow.com/questions/35624413/remove-search-option-but-leave-search-columns-option
, ordering = F # https://stackoverflow.com/questions/54318475/hide-the-column-names-in-dtdatatable useful especially when we want to hide column names
))
})
output$table_test2 <- renderDataTable({
df <- data.frame(BUCKET=c("1","2"), ITEM=c(48,53), VALUE = c(7.88, 5.12), stringsAsFactors = F)
datatable(df,
rownames= F,
#colnames = colnames_var,
filter = 'none',
extensions = 'Buttons',
caption = NULL,
options = list(scrollX = F
#, headerCallback = js_col_header # this is to show/hide column headers
, lengthChange = T
#, pagingType = "numbers" # this hides the Next and Previous buttons --> https://datatables.net/reference/option/pagingType
, paging = T # this completely hides the Next, Previous and Page number at the bottom of the table
, autoWidth = T
, pageLength = 5 # this determines how many rows we want to see per page
, dom = 'Blfrtip'
, buttons = NULL
, info = T # this will hide the "Showing 1 of 2..." at the bottom of the table --> https://stackoverflow.com/questions/51730816/remove-showing-1-to-n-of-n-entries-shiny-dt
, searching = T # this removes the search box -> https://stackoverflow.com/questions/35624413/remove-search-option-but-leave-search-columns-option
, ordering = F # https://stackoverflow.com/questions/54318475/hide-the-column-names-in-dtdatatable useful especially when we want to hide column names
))
})
}
cat("\nLaunching 'shinyApp' ....")
shinyApp(ui, server)
Problem 1: if I open this app on a large screen, table_test2 is nicely taking all the expected real estate of the screen, ranging entirely within 3 columns.
However, table_test1 does not (see my screenshot).
Main difference is that table_test1 has scrollX =T vs table_test2 that has scrollX =F.
How can I keep scrollX = T and visualize table_test1 the same way I visualize table_test2 (meaning, with no empty side spaces)? (see red color in attached screenshot)
Problem 2:
How come the alignment of table_test1 is a bit messed up and column names are not aligned to table columns? (see blue color in attached screenshot)
Changing scrollX is not an option since some users have a smaller screen and with scrollX =F tables would not show up properly on some users' monitors.
Thanks

Take out the autoWidth option from datatable
datatable(
data = df,
rownames = FALSE,
filter = "none",
extensions = "Buttons",
caption = NULL,
options = list(
scrollX = TRUE,
lengthChange = TRUE,
paging = TRUE,
pageLength = 5,
dom = "Blfrtip",
buttons = NULL,
info = TRUE,
searching = TRUE,
ordering = FALSE
)
)

Related

Shinydashboard tabBox to fill mainPanel

Is there a simple way to get the following tabBox to span the entire height of the dashboardBody?
app_ui <- function() {
shinydashboard::dashboardPage(
shinydashboard::dashboardHeader(title = "Baseball Statistics"),
shinydashboard::dashboardSidebar(
width = 250
),
shinydashboard::dashboardBody(
shinydashboard::box(title = "Individual"),
shinydashboard::tabBox(title = "Stats",
shiny::tabPanel("Batting", DT::DTOutput("batting")),
shiny::tabPanel("Pitching", DT::DTOutput("pitching")),
shiny::tabPanel("Fielding", DT::DTOutput("fielding"))
)
)
)
}
I would like the datatable to occupy as much vertical screen as possible:
The following answer was not successful - Shinydashboard Tabbox Height
I attempted to integrate the above answer by:
shinydashboard::dashboardBody(
shinydashboard::box(title = "Individual"),
shinydashboard::tabBox(title = "Stats",
shiny::tags$head(
shiny::tags$style(shiny::HTML(" #tabBox { height:90vh !important; } "))
),
id="tabBox",
shiny::tabPanel("Batting", DT::DTOutput("batting")),
shiny::tabPanel("Pitching", DT::DTOutput("pitching")),
shiny::tabPanel("Fielding", DT::DTOutput("fielding"))
)
)
The output looks like:
It probably depends on the oter DT options.
When I use only scrollX options
output$batting <- renderDT(iris,
options = list( scrollX = TRUE))
I get
This is my final try, it seems the other things didn't work out, so:
output$dataset <- DT::renderDT(dataframes$df.response,
callback = JS(js),
filter = "top",
rownames = FALSE,
selection = list(target = "row+column"),
extensions = c("ColReorder"),
options = list(
# scrollX = TRUE,
# lengthMenu = c(15, 50, 100, 200, 500),
# colReorder = list(realtime = FALSE),
pageLength = 1000,
scrollY=TRUE
)
)
the pagelength element to the max rows of your data set it will show it entirely when loading. like in this screen:. Is this a possible workaround for you?

Factor Search Clearing Button in DT: shinydashboard vs. shinymaterial

I have several applications that I am attempting to port from shinydashboard to shinymaterial, due to the nice aesthetics that my users seem to enjoy. I am facing an issue with searching/filtering factors in the shinymaterial dashboards where the "x" button that normally clears factor filtering is NOT present when using shinymaterial.
shinydashboard screenshot where the "filter clearing" button for the factor column is present:
shinydashboard screenshot
shinymaterial screenshot where there is no "filter clearing" button for the factor column:
shinymaterial screenshot
Here are my reproducible code examples:
shinydashboard
library(shiny)
library(tidyverse)
library(DT)
# Shiny Dashboard or Shiny Material
library(shinydashboard)
ui <- shinydashboard::dashboardPage(
shinydashboard::dashboardHeader(
title = "Some Title",
titleWidth = 250
),
shinydashboard::dashboardSidebar(),
shinydashboard::dashboardBody(
DT::dataTableOutput("exampleDT")
)
)
server <- function(input, output, session) {
# Use MPG Data and convert manufacturer to Factor
df <- mpg %>%
mutate(manufacturer = as.factor(manufacturer))
# Create Datatable
output$exampleDT <- DT::renderDataTable({
DT::datatable(df,
class = 'cell-border stripe',
rownames = FALSE,
escape = FALSE,
extensions = c("KeyTable"),
filter = list(position = "top"),
options = list(searching = TRUE,
searchHighlight = TRUE,
scrollX = TRUE,
pageLength = 5,
autoWidth = TRUE,
keys = TRUE,
columnDefs = list(list(className = "dt-center", targets = "_all"))
)
)
})
}
shinyApp(ui = ui, server = server)
shinymaterial
library(shiny)
library(tidyverse)
library(DT)
# Shiny Dashboard or Shiny Material
library(shinymaterial)
ui <- shinymaterial::material_page(
title = "Some Title",
primary_theme_color = "grey",
shinymaterial::material_tabs(
tabs = c("Tab 1" = "tab1")
),
shinymaterial::material_tab_content(
tab_id = "tab1",
shinymaterial::material_card(
title = "",
DT::dataTableOutput("exampleDT")
)
)
)
server <- function(input, output, session) {
# Use MPG Data and convert manufacturer to Factor
df <- mpg %>%
mutate(manufacturer = as.factor(manufacturer))
# Create Datatable
output$exampleDT <- DT::renderDataTable({
DT::datatable(df,
class = 'cell-border stripe',
rownames = FALSE,
escape = FALSE,
extensions = c("KeyTable"),
filter = list(position = "top"),
options = list(searching = TRUE,
searchHighlight = TRUE,
scrollX = TRUE,
pageLength = 5,
autoWidth = TRUE,
keys = TRUE,
columnDefs = list(list(className = "dt-center", targets = "_all"))
)
)
})
}
shinyApp(ui = ui, server = server)
That's because this "button" actually is a glyphicon icon. The glyphicon icons are included in bootstrap, which is automatically loaded when you use an ordinary Shiny page, but not when you use 'shinymaterial'. So you have to add a link to bootstrap-glyphicons.css:
ui <- shinymaterial::material_page(
tags$head(
tags$link(href = "https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css", rel="stylesheet")
),
title = "Some Title",
......
This way requires to use the app online. But instead of including a link, you can download the css file and put it in the www subfolder of your app, and include it with tags$link(href = "bootstrap-glyphicons.css", rel = "stylesheet").

Hide a column in shiny datatable but keep it searchable

The DT package in Shiny produces a table with a searchbar that searches over every column in the table. I have a column of metadata which I do not want to display in the table, but I still want the rows to come up if I search with the search bar.
For example, the app below contains a column titled searchCol . This column is just letters. I want to hide this column in the actual table, and I want to be able to search for the letter b , using the DT search bar, and have the second row show up.
Is there a way to hide the column but have it still work with the search bar?
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput('tbl1'),
)
server <- function(input, output, session) {
output$tbl1 <- DT::renderDT(server = TRUE, {
datatable(
cbind(data.frame(replicate(3,sample(0:1,26,rep=TRUE))), data.frame(searchCol = letters)),
escape = FALSE,
rownames = FALSE,
filter = list(position = "top", clear = FALSE, plain = TRUE),
selection = "single",
options = list(
autoWidth = TRUE,
pageLength = 50,
lengthMenu = c(50, 100, 1000),
dom = 'Blfrtip',
buttons = c('copy', 'excel')
)
)
})
}
shinyApp(ui, server)
I've adapted the answer from here to the format you need to use in DT::datatable. You can use columnDefs to define the render options for the different columns, targets defines which column you mean. Please note that the JS library datatables starts counting columns at 0.
library(shiny)
library(DT)
ui <- fluidPage(
DTOutput('tbl1'),
)
server <- function(input, output, session) {
output$tbl1 <- DT::renderDT(server = TRUE, {
datatable(
cbind(data.frame(replicate(3,sample(0:1,26,rep=TRUE))), data.frame(searchCol = letters)),
escape = FALSE,
rownames = FALSE,
filter = list(position = "top", clear = FALSE, plain = TRUE),
selection = "single",
options = list(
autoWidth = TRUE,
pageLength = 50,
lengthMenu = c(50, 100, 1000),
dom = 'Blfrtip',
buttons = c('copy', 'excel'),
columnDefs = list(
list(
targets = 3,
searchable = TRUE,
visible = FALSE
)
)
)
)
})
}
shinyApp(ui, server)

R large datatable display in Shiny

I am trying to display a relatively large DataTable in a shiny app. The table's dimensions are 7000x30. The performance in Chrome was very very sluggish so I added the 'Scroller' extension to limit the rendering but that did not help. It seems that it is the large number of columns that is causing the issue, not the large number of rows. I also tried to used the colvis extension but the button gives a non scrollable list and with 30 columns, that wouldn't work. Also I tried to have some columns hidden using the visible option, but that didn't work.
Here is the example:
data = as_tibble(matrix(runif(200000), ncol=30))
data %>%
DT::datatable(filter = 'top', extensions = c('Buttons', 'Scroller'),
options = list(scrollY = 650,
scrollX = 500,
deferRender = TRUE,
scroller = TRUE,
# paging = TRUE,
# pageLength = 25,
buttons = list('excel',
list(extend = 'colvis', targets = 0, visible = FALSE)),
dom = 'lBfrtip',
fixedColumns = TRUE),
rownames = FALSE)
Weirdly, the Rstudio viewer shows the datatable and is fine. It's only when I Run the document as a shiny document and open it in Chrome that it becomes very sluggish. My questions are:
Why is this happening
How do I only show a limited number of columns by default and have the option to show the others
is there a better button for colvis? if the list of columns exceeds the page length, I can't access those hidden columns to toggle them on or off.
What do you mean by sluggish?
I ran it and everything looks okay to me in terms of speed.
library(shiny)
library(shinydashboard)
library(DT)
####/UI/####
header <- dashboardHeader()
sidebar <- dashboardSidebar()
body <- dashboardBody(
DT::dataTableOutput("test")
)
ui <- dashboardPage(header, sidebar, body)
####/SERVER/####
server <- function(input, output, session) {
data <- as_tibble(matrix(runif(200000), ncol=30))
output$test <- DT::renderDataTable({
DT::datatable(
data,
filter = 'top', extensions = c('Buttons', 'Scroller'),
options = list(scrollY = 650,
scrollX = 500,
deferRender = TRUE,
scroller = TRUE,
# paging = TRUE,
# pageLength = 25,
buttons = list('excel',
list(extend = 'colvis', targets = 0, visible = FALSE)),
dom = 'lBfrtip',
fixedColumns = TRUE),
rownames = FALSE)
})
}
shinyApp(ui, server)
You may want to remove 'scroller' from Options = () as with that many rows, you may want to break it up into pages. Also, you can try to make the table server processing by putting Server = TRUE in there, that will make it process every page versus the whole dataset at once.

Button extension to download all data or only visible data

With the button extension to DT package, is there a way to specify that the buttons download either (1) all the data feeding the datatable, or (2) only the data on the visible page.
Below is the example from the documentation.
datatable(
iris, extensions = 'Buttons', options = list(
dom = 'Bfrtip',
buttons = c('copy', 'csv', 'excel', 'pdf', 'print')
)
)
As #divibisan said, one option is to use the server argument of renderDT() to control whether the download button will download only the current or all rows.
That would work well if you want to have one download button. However if you want to have two buttons always appear, where one download the current page and one downloads the full dataset, you can use the following code:
library(shiny)
ui <- fluidPage(
DT::DTOutput("table")
)
server <- function(input, output, session) {
output$table <- DT::renderDT(server = FALSE, {
DT::datatable(
mtcars,
extensions = c("Buttons"),
options = list(
dom = 'Bfrtip',
buttons = list(
list(extend = "csv", text = "Download Current Page", filename = "page",
exportOptions = list(
modifier = list(page = "current")
)
),
list(extend = "csv", text = "Download Full Results", filename = "data",
exportOptions = list(
modifier = list(page = "all")
)
)
)
)
)
})
}
shinyApp(ui, server)
See this answer: Buttons: download button with scroller downloads only few rows
Whether the buttons export all data or only visible data is determined by the server argument in the DT::renderDT function call. If server=FALSE then the buttons will export all data in the table, while if server=TRUE they will only export visible data.
You could set the server argument with a variable to make this a selectable option.
output$table <- DT::renderDT(server = input$download_all, {
DT::datatable( ... )
}
The other option you might want to look at is the exportOptions: modifier: selected option that determines whether to download only selected rows (the default) or all rows. You can read about that option here: https://datatables.net/extensions/buttons/examples/print/select.html
Note that your users might run into performance and memory issues using server=FALSE if your data table is very large.
you are looking for the modifiers: page: selected. here is a working example
ui <- fluidPage(
title = "Examples of DataTables",
sidebarLayout(
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel("diamonds", DT::dataTableOutput("mytable1"))
)
)
)
)
server <- function(input, output) {
# choose columns to display
diamonds2 = diamonds[sample(nrow(diamonds), 1000), ]
output$mytable1 <- DT::renderDataTable({
DT::datatable(diamonds2,
extensions = 'Buttons',
options = list(
dom = 'Bfrtip',
buttons =
list(
list(
extend = 'csv',
buttons = c('csv'),
exportOptions = list(
modifiers = list(page = "current")
)
))
)
)
})
}
shinyApp(ui, server)
hope this helps!
If you want to include the options to download the current page and the entire dataset as both a csv or an excel file, I've managed to implement this as two separate dropdown buttons with those options, together with the copy and print buttons:
Here is the modified working code:
library(shiny)
ui <- fluidPage(
DT::dataTableOutput("table")
)
server <- function(input, output, session) {
output$table <- DT::renderDataTable(server = FALSE, {
DT::datatable(
mtcars,
extensions = "Buttons",
filter = "top",
selection = "none", #this is to avoid select rows if you click on the rows
rownames = FALSE,
options = list(
scrollX = TRUE,
autoWidth = FALSE,
dom = 'Blrtip', # the important thing is that there is the l to allow for the lengthMenu
# https://stackoverflow.com/questions/52645959/r-datatables-do-not-display-buttons-and-length-menu-simultaneously
buttons = list(
# insert buttons with copy and print
# colvis includes the button to select and view only certain columns in the output table
# from https://rstudio.github.io/DT/extensions.html
I('colvis'), 'copy', 'print',
# code for the first dropdown download button
# this will download only the current page only (depends on the number of rows selected in the lengthMenu)
# using modifier = list(page = "current")
# only the columns visible will be downloaded using the columns:":visible" option from:
# https://stackoverflow.com/questions/72317260/how-to-download-only-the-selected-columns-in-a-dataframe-using-colvis-from-dt-in/72317607#72317607
list(
extend = 'collection',
buttons = list(
list(extend = "csv", filename = "page",exportOptions = list(
columns = ":visible",modifier = list(page = "current"))
),
list(extend = 'excel', filename = "page", title = NULL,
exportOptions = list(columns = ":visible",modifier = list(page = "current")))),
text = 'Download current page'),
# code for the second dropdown download button
# this will download the entire dataset using modifier = list(page = "all")
list(
extend = 'collection',
buttons = list(
list(extend = "csv", filename = "data",exportOptions = list(
columns = ":visible",modifier = list(page = "all"))
),
list(extend = 'excel', filename = "data", title = NULL,
exportOptions = list(columns = ":visible",modifier = list(page = "all")))),
text = 'Download all data')
),
# add the option to display more rows as a length menu
lengthMenu = list(c(10, 30, 50, -1),
c('10', '30', '50', 'All'))
),
class = "display"
)
})
}
shinyApp(ui, server)

Resources