How to render a dataTable with definite row height? - r

I've been struggling for a few hours with such a task:
in R Shiny I need to display a table which contains of a single column of integers with the definite (relatively large) spacing between rows.
There is the spacing argument in the renderTable() function, but even setting it to the biggest value 'l' is still not enough for my purpose.
I've tried to do that using xtable and taking into account the example from Adjust row height xtable R , but with no result (I don't know CSS).
The most natural way I've found in the web is to use DT package along with the Scroller extension, but the following code still gives no results
ui.R:
fluidPage(
sidebarLayout(
sidebarPanel(
dataTableOutput('dtable', width = '50%') # argument 'height' does not work here
),
mainPanel()
)
)
server.R:
library(shiny)
library(DT)
function(input, output) {
output$dtable <- DT::renderDataTable({
data.frame(SSD = c(2, 17, 19, 35))
},
extensions = 'Scroller',
options = list(
dom = 't',
ordering = FALSE,
scroller = list(rowHeight = 100)
)
)
}
The output of that gives only column name (what is wrong??), but without Scroller extensions it displays the expected table - of course with too small spacing...

You want to use the rowCallback option and attach a style to each row:
server.R
library(shiny)
library(DT)
function(input, output) {
output$dtable <- DT::renderDataTable({
data.frame(SSD = c(2, 17, 19, 35))
},
options = list(
dom = 't',
ordering = FALSE,
rowCallback = JS("function(r,d) {$(r).attr('height', '100px')}")
)
)
}
Note that this may result in increased render time as the number of rows raises

Related

R shiny RenderDT format specific cell in table output

I am trying to format a SPECIFIC cell in a R shiny dashboard data table (using renderDT).
In the UI I use the following line of code:
DTOutput('dt_vols')
I also include this line in the UI as I dont want to display column names (not sure if that is relevant to the problem)
tags$head(tags$style(type = "text/css", "#dt_vols th {display:none;}")),
In the server code, I first create the following reactive 2x2 matrix (called dt_vols) - I've simplified the matrix in the example
dt_vols <- reactive({
mtx_vols <- matrix(1:4, nrow = 2, ncol = 2)
return(mtx_vols)
})
Then I render the DT table as follows:
output$dt_vols = renderDT(
dt_vols(), options = list(pageLength = 4, dom = 't', autoWidth = FALSE), rownames= FALSE,
formatStyle(dt_vols(), columns = 1, border = '1px solid #ddd')
)
It works until I add the formatstyle line. I am not sure how to get this line right and to get it pointing a specific cell (for example row1, column2). It seems to have a problem with the column argument. If i run the below I get the following error:
Warning: Error in : $ operator is invalid for atomic vectors
formatStyle expects a table object created from datatable() as input - you passed a matrix, which results in the error.
Please check the following:
library(shiny)
library(DT)
ui <- fluidPage(DTOutput('dt_vols'),
tags$head(tags$style(type = "text/css", "#dt_vols th {display:none;}")))
server <- function(input, output, session) {
dt_vols <- reactive({
mtx_vols <- matrix(1:4, nrow = 2, ncol = 2)
return(mtx_vols)
})
output$dt_vols = renderDT({
myTable <- datatable(dt_vols(),
options = list(pageLength = 4, dom = 't', autoWidth = FALSE),
rownames = FALSE
)
formatStyle(myTable, columns = 1, border = '10px solid #ddd')
})
}
shinyApp(ui, server)

Use backgroundColor in DT package to change a complete row instead of a single value

The answer is probably obvious but i've been looking into using the backgroundColor attribute in the DT package to change the color of the full row instead of only the value that i use to select the row and I didn't manage to do it.
So basically in my Shiny app, I have a DataTable output in my server file where i wrote this :
output$tableMO <- DT::renderDataTable({
datatable(DFSurvieMO,
options =
list( displayStart= numerMO()-2,
pageLength = 15,
lengthChange = FALSE, searching =FALSE),rownames= FALSE) %>% formatStyle(
c(1:2),
backgroundColor =
if(numerMO()>1) {
styleInterval(c(DFSurvieMO[,1][numerMO()-1],DFSurvieMO[,1][numerMO()]), c('blank','lightblue', 'blank'))
}
else {
styleInterval(DFSurvieMO[,1][numerMO()], c('lightblue', 'blank'))}
)
})
And what i get in my app is a DataTable with only a single cell colored. I tried using target = 'row' but either I didn't put it in the right place or it does not work. So how can i get it to color the whole row ?
Thank You.
You can write some custom JS function using rowCallback. Below I have written a reactive which will listen to the slider and if the slider values in the mtcars dataset are bigger than your value it will repaint the row. Note that the aData[1] is the column called cyl within the mtcars dataset.
Apologies for not using your code as I wanted to make a more generic example
rm(list = ls())
library(shiny)
library(DT)
ui <- basicPage(
sliderInput("trigger", "Trigger",min = 0, max = 10, value = 6, step= 1),
mainPanel(DT::dataTableOutput('my_table'))
)
server <- function(input, output,session) {
my_callback <- reactive({
my_callback <- 'function(nRow, aData, iDisplayIndex, iDisplayIndexFull) {if (parseFloat(aData[1]) >= TRIGGER)$("td", nRow).css("background-color", "#9BF59B");}'
my_callback <- sub("TRIGGER",input$trigger,my_callback)
my_callback
})
output$my_table = DT::renderDataTable(
datatable(mtcars,options = list(
rowCallback = JS(my_callback()),searching = FALSE,paging = FALSE),rownames = FALSE)
)
}
runApp(list(ui = ui, server = server))

Controlling table width in Shiny dataTableOutput

I am unable to control the width of a datatable I have added to a shiny app using the function dataTableOutput(). I've tried to use the width parameter within the function but it changes nothing in the output and there is no error ~ it's not telling me that it's ignoring the width parameter.
library(shiny)
library(shinythemes)
ui <- fluidPage(theme = shinytheme("Spacelab"),
fluidRow(
column(6,dataTableOutput(outputId = "table")),
column(6,p(textOutput("para")))
)
)
server <- function(input, output){
df <- as.data.frame(matrix(0, ncol = 15, nrow = 20))
output$table <- renderDataTable({df})
output$para <- renderText({
text <- rep(x = "Hello World",1000)
})
}
shinyApp(ui = ui,server = server)
dataTableOutput does not have an argument width. You can use column within a fluidRow with argument width, supplying an integer between 1 and 12.
library(shinythemes)
ui <- fluidPage(theme = shinytheme("Spacelab"),
fluidRow(
column(
dataTableOutput(outputId = "table"), width = 6)
)
)
server <- function(input, output){
df <- as.data.frame(matrix(0, ncol = 20, nrow = 5))
output$table <- renderDataTable({df},
options = list(scrollX = TRUE))
}
shinyApp(ui = ui,server = server)
Options from the JavaScript library DataTable can be passed directly via renderDataTable argument options. For example, setting scrollX to be true allows tables to scroll.
If you use the "DT" R package, and the respective DT::dataTableOutput and DT::renderDataTable, you can use a "width" option with those calls, which apparently can be either a % (e.g. width = "100%") or pixels (width = 300) which should get you the control you want.
See:
https://rstudio.github.io/DT/shiny.html
Note from that page:
Important: Be sure to use the DT:: prefix when calling dataTableOutput
and renderDataTable so that the DT versions of these functions are
guaranteed to be called, instead of the deprecated Shiny versions. If
you make sure to library(DT) after library(shiny), normally the DT
versions should just override the shiny versions if you do not use the
DT:: prefix (when in doubt, use this prefix, until we completely
remove these functions from shiny)

Freezing header and first column using data.table in Shiny

I have a Shiny app that yields a data table, but I can't freeze the first column and the headers, so the table is hard to read as you go down or across. Is there anyway to freeze the panes? I've tried searching but have found nothing.
Interesting question and now thanks to the recent update of Shiny to data.tables 1.10.2
it is alot easier to use the various plug-ins and extensions. For your question the FixedHeader extension seems ideal. To add this extension we need to include the relevant JavaScript and CSS file (see http://cdn.datatables.net/):
tagList(
singleton(tags$head(tags$script(src='//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js',type='text/javascript'))),
singleton(tags$head(tags$link(href='//cdn.datatables.net/fixedheader/2.1.2/css/dataTables.fixedHeader.css',rel='stylesheet',type='text/css')))
)
data.tables has an option initComplete which allows us to stipulate a callback once table is drawn etc.
function(settings, json) {
new $.fn.dataTable.FixedHeader(this, {
left: true,
right: true
} );
}
We will use a modified version of the iris data set adding an index and some random data at the end to show left to right scrolling:
library(shiny)
myData <- cbind(list(index = row.names(iris)), iris
, rep(list(row.names(iris)), 10))
names(myData)[7:16] <- paste0("randomData", 1:10)
runApp(
list(ui = fluidPage(
tagList(
singleton(tags$head(tags$script(src='//cdn.datatables.net/fixedheader/2.1.2/js/dataTables.fixedHeader.min.js',type='text/javascript'))),
singleton(tags$head(tags$link(href='//cdn.datatables.net/fixedheader/2.1.2/css/dataTables.fixedHeader.css',rel='stylesheet',type='text/css')))
),
dataTableOutput("mytable")
)
, server = function(input, output, session){
output$mytable <- renderDataTable(myData,
options = list(
pageLength = 50,
initComplete = I("function(settings, json){
new $.fn.dataTable.FixedHeader(this, {
left: true,
right: true
} );
}")
)
)
})
)
so in the image we can see we are scrolled down to record 8 and across some ways but the header and the first column (our added index column) are still visible.
FixedHeader is now (2021) compatible with FixedColumns. See table
library(shiny)
library(DT)
runApp(
list(ui = fluidPage(
dataTableOutput("mytable")
)
, server = function(input, output, session){
Rows <- c(1:30)
for (y in 1:15){
x<-y-1
assign(letters[x+1],runif(5, 0, 1))
}
x <- data.frame(Rows, mget(letters[1:15]), row.names=NULL)
x<- x[2:15]
output$mytable <- renderDataTable(
DT::datatable(x, rownames=FALSE,extensions = c('FixedColumns',"FixedHeader"),
options = list(dom = 't',
scrollX = TRUE,
paging=FALSE,
fixedHeader=TRUE,
fixedColumns = list(leftColumns = 1, rightColumns = 0))
)
)
}
)
)
Implemented:
2021-09-10: FixedColumns 4.0.0

Filter Shiny DataTable on Multiple Conditions

The following is a direct replication of the datatable demo provided on the rstudio shiny website. It is quite easy to filter the dataset (e.g. Ideal on the diamond, or setosa on the iris), however is there a way to filter multiple conditions such as 'Ideal' and 'Fair' in the diamond dataset? I have tried the basic 'AND' and '&' syntax, spaces, nothing seems to work. This seems like it should be possible but is this even possible or does it require some roundabout approach?
require(shiny)
runApp(
list(ui = fluidPage(
title = 'Examples of DataTables',
sidebarLayout(
sidebarPanel(
conditionalPanel(
'input.dataset === "diamonds"',
checkboxGroupInput('show_vars', 'Columns in diamonds to show:',
names(diamonds), selected = names(diamonds))
)
),
mainPanel(
tabsetPanel(
id = 'dataset',
tabPanel('diamonds', dataTableOutput('mytable1'))
)
)
)
),
server = shinyServer(function(input, output) {
# a large table, reative to input$show_vars
output$mytable1 <- renderDataTable({
library(ggplot2)
diamonds[, input$show_vars, drop = FALSE]
})
})
)
)
After some further search, I suspect I should be able to use the jquery column filter plugin. To simplify this question, here is a more stripped down version of the above code:
library(shiny)
runApp(
list(ui = basicPage(
h1('Diamonds DataTable with TableTools'),
# added column filter plugin
singleton(tags$head(tags$script(src='https://code.google.com/p/jquery-datatables-column-filter/source/browse/trunk/media/js/jquery.dataTables.columnFilter.js',
type='text/javascript'))),
dataTableOutput("mytable")
)
,server = function(input, output) {
output$mytable = renderDataTable({
diamonds[,1:6]
}, options = list(
pageLength = 10,
columnDefs = I('[{"targets": [0,1],
"searchable": true}]')
)
)
}
))
However, I cannot seem to get the columnFilter plugin to work. The columnDefs statement (commented out) works fine but when I try to do the columnFilter statement, I get only get the table header and filter search boxes. I suspect some syntax must be off to get this to work. As an example of the functionality, please see this website. Please note, this is also using the most recent version of shiny from the rstudio github
Turn off regex escaping
By default, DataTables escapes regex characters in search terms. However, since DataTables 1.10, there's an option to disable the escaping and allow regex searches. We can use options to pass the option to datatable, like this:
library(DT)
datatable(mtcars,
options = list(search = list(regex = TRUE)))
Now your seaches can use regular expressions. For example, to filter the table for Mazda or Chrysler, you could search Mazda|Chrysler.
Here's the official RStudio page on the matter.
Example app
library(shiny)
library(DT)
ui <- fluidPage(
fluidRow(
column(width = 9,
br(),
DT::dataTableOutput("dt")
),
column(width = 3,
br(),
radioButtons("regex", "Enable Regex?", choices = c("yes", "no"), inline = T))
)
)
server <- function(input, output, session) {
output$dt <- DT::renderDataTable({
value <- ifelse(input$regex == "yes", TRUE, FALSE)
datatable(mtcars,
options = list(search = list(regex = value))
)
})
}
shinyApp(ui, server)

Resources