How do I define number format for datatable in Shiny? I would like to display 2 decimal digits only for some columns, but do not understand where it should be defined in my application. In server.R or ui.R? In server.R, this what I have in renderDataTable:
output$woeTable <- renderDataTable({
input$tryTree
input$threshold
# The following returns data frame with numeric columns
get(input$dfDescr)[['variables']][[input$columns]][['woe']]
},
options=list(
paging = FALSE,
searching = FALSE)
)
How do I format 2nd and 3rd column to display only two decimal digits?
just use round command:
output$woeTable <- renderDataTable({
input$tryTree
input$threshold
# The following returns data frame with numeric columns
A = get(input$dfDescr)[['variables']][[input$columns]][['woe']]
A[,2] = round(x = A[,2],digits = 2)
A[,3] = round(x = A[,3],digits = 2)
A
},
options=list(
paging = FALSE,
searching = FALSE)
)
you can also use fnRowCallback option in renderDataTable function if you insist to keep data with more digit and just change representation in output:
output$woeTable <- renderDataTable({
input$tryTree
input$threshold
# The following returns data frame with numeric columns
get(input$dfDescr)[['variables']][[input$columns]][['woe']]
},
options=list(
paging = FALSE,
searching = FALSE,
fnRowCallback = I("function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {ind = 2; $('td:eq('+ind+')', nRow).html( (aData[ind]).toFixed(2) );}"))
)
update for DT 1.1:
you should change
fnRowCallback = I("function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {ind = 2; $('td:eq('+ind+')', nRow).html( (aData[ind]).toFixed(2) );}"))
to
rowCallback = I("function( nRow, aData) {ind = 2; $('td:eq('+ind+')', nRow).html( parseFloat(aData[ind]).toFixed(2) );}"))
Related
I have a column 'R/Y/G' that should contain three colors Green, Yellow or Red based on values from three different columns R, Y and G. The condition is that if the value of column 'R' is greater than 2.5 million, the color of the corresponding cell in 'R/Y/G' is Red. If the value of column 'Y' is between 2 and 2.5 mil, the color of the corresponding cell in 'R/Y/G' is Yellow. If the value of column 'G' is less than 2 mil, the color of the corresponding cell in 'R/Y/G' is Green. Here the condition :
d9$tcolor <- ifelse(d9$R > 2500000, 2,
ifelse(d9$Y > 2000000 & d9$Y <= 2500000, 1,
ifelse(d9$G <= 2000000, 0)))
dt_d9=datatable(isolate(d9), editable = 'cell', rownames = FALSE, extensions = 'Buttons', options = list(dom = 'Bfrtip', buttons = I('colvis'))) %>% formatStyle(
'R/Y/G', 'tcolor',
backgroundColor = styleEqual(c(0,1,2), c('green', 'yellow', 'red')),fontWeight = 'bold'
)
tcolor is a column I've created to track the three columns ('R', 'Y' and 'G') and the color for column 'R/Y/G' will be dependent on tcolor based on what values I input in 'R', 'Y' and 'G'
Here's where it is implemented in actual code :
cmp_data1 <- dbGetQuery(qr,sql)
saveRDS(cmp_data1, 'q1.rds')
dt_output = function(title, id) {
fluidRow(column(
12, h1(paste0(title)),
hr(), DTOutput(id)
))
}
render_dt = function(data, editable = 'cell', server = TRUE, ...) {
renderDT(data,selection = 'none', server = server, editable = editable, ...)
}
ui = fluidPage(
downloadButton("mcp_csv", "Download as CSV", class="but"),
dt_output('Report', 'x9')
)
server = function(input, output, session) {
if(!file.exists("cm.rds")){
d9 = cmp_data1
d9['R/Y/G'] <- NA
d9['R'] <- NA
d9['Y'] <- NA
d9['G'] <- NA
d9['tcolor'] <- NA
}
else{
cmp <- readRDS("cm.rds")
d9 = cbind(cmp_data1, cmp[,(ncol(cmp)-4):ncol(cmp)])
}
rv <- reactiveValues()
observe({
rv$d9 <- d9
})
dt_d9=datatable(isolate(d9), editable = 'cell', rownames = FALSE, extensions = 'Buttons', options = list(dom = 'Bfrtip', buttons = I('colvis'))) %>% formatStyle(
'R/Y/G', 'tcolor',
backgroundColor = styleEqual(c(0,1,2), c('green', 'yellow', 'red')),fontWeight = 'bold'
)
output$x9 = render_dt(dt_d9)
proxy = dataTableProxy('x9')
observe({
DT::replaceData(proxy, rv$d9, rownames = FALSE, resetPaging = FALSE)
})
observeEvent(input$x9_cell_edit, {
rv$d9 <<- editData(rv$d9, input$x9_cell_edit, 'x9', rownames = FALSE)
d9 <- rv$d9
d9$tcolor <- ifelse(d9$R > 2500000, 2,
ifelse(d9$Y > 2000000 & d9$Y <= 2500000, 1,
ifelse(d9$G <= 2000000, 0)))
rv$d9 <<- d9
saveRDS(d9, 'cm.rds')
})
But this doesn't seem to work. The colors don't show up.
The created empty columns get character type instead of numeric, so you must create the empty columns with numeric type like this:
d9['R/Y/G'] <- numeric()
d9['R'] <- numeric()
d9['Y'] <- numeric()
d9['G'] <- numeric()
d9['tcolor'] <- numeric()
Learn how to debug Shiny apps by inserting breakpoints to check the type of your objects/columns.
By the way, you don't handle the case when d9$G > 2000000.
Edit: if you need some default color to be displayed before the user enters any value, you should set some default value for the tcolor column, e.g. for green:
d9['tcolor'] <- 1
To get your desired behavior of cascading conditions and not be bothered by NA values (when no value is entered in a column), you can use the case_when() function from the dplyrpackage (see this post):
d9$tcolor <- dplyr::case_when(d9$R > 2500000 ~ 2,
d9$Y > 2000000 & d9$Y <= 2500000 ~ 0,
d9$G < 2000000 ~ 1)
I am trying to create an html table using the datatable function in the DT package so that when I sort the data in R markdown, missing rows are sorted after the highest number.
For example, in the following table, when I sort by "age" in the markdown file, I would like the row with NA to be listed last so that the order is 14,15,21,NA.
dat <- data.frame("Age" = c(21,15,NA,14),
"Name" = c("John","Dora", "Max", "Sam"),
"Gender" = c("M","F","M",NA))
DT::datatable(dat, filter = c("top"))
I have tried using "na.last = TRUE" and this works when the datatable initially prints, however when clicking the column to sort, NA is still before 14.
Any help would be much appreciated!
With the render columnwise option, you can set the value of the missing values during the sorting:
library(DT)
dat <- data.frame("Age" = c(21,15,NA,14),
"Name" = c("John","Dora", "Max", "Sam"),
"Gender" = c("M","F","M",NA))
render <- JS(
"function(data, type, row) {",
" if(type === 'sort' && data === null) {",
" return 999999;",
" }",
" return data;",
"}"
)
datatable(
dat,
filter = "top",
options = list(
columnDefs = list(
list(targets = 1, render = render)
)
)
)
I wish to implement formatCurrency() and formatPercentage() (both from DT package) across multiple columns simultaneously in a shiny dashboard. I am using shinymaterial for the given example.
I am currently doing the following:
# The packages to load.
required_packages <- c("shiny", "shinymaterial", "DT", "tidyverse")
# This function will load in all the packages needed.
lapply(required_packages, require, character.only = TRUE)
# A table example.
ui <- material_page(
title = "Example table",
tags$h1("Table example"),
material_card(
title = "Table",
material_row(
DT::dataTableOutput("data_table_example")
),
depth = 1
)
)
server <- function(input, output) {
data_table_example_data = tibble(
Person = paste0("Person ", c(1:100)),
`Price $` = rnorm(100, 50000, 500),
`Cost $` = rnorm(100, 30000, 300),
`Probability %` = rnorm(100, 0.6, 0.1),
`Win %` = rnorm(100, 0.5, 0.2)
)
# This will create an output summary table
output$data_table_example = renderDataTable({
result = datatable(data_table_example_data, options = list(pageLength = 100, scrollX = TRUE),
class = 'cell-border stripe compact', rownames = FALSE) %>%
formatCurrency("Price $") %>%
formatCurrency("Cost $") %>%
formatPercentage("Probability %", digits = 1) %>%
formatPercentage("Win %", digits = 1)
})
}
shinyApp(ui = ui, server = server)
However, what I wish to do is, within the renderDataTable() function, to simplify the format functions into fewer lines. For example, implement formatCurrency() in any column with a "$" and formatPercentage() in any column with a "%".
I have done a fair bit of searching for an appropriate but could not find a solution, but I assume I am just missing a fairly simple solution.
Something like:
# This will create an output summary table
output$data_table_example = renderDataTable({
result = datatable(data_table_example_data, options = list(pageLength = 100, scrollX = TRUE),
class = 'cell-border stripe compact', rownames = FALSE) %>%
formatCurrency(grepl("$", colnames()) %>%
formatPercentage(grepl("%", colnames()), digits = 1)
})
A few additional points:
The tibble will actually be a reactive
This example is a very trivial version of a rather more complex table and set of reactives
I do not want to implement the formatting in the reactive part since I find this then messes with the DT sorting function, since it assumes the column is a character string
Any help will be greatly appreciated
Try:
# This will create an output summary table
output$data_table_example = renderDataTable({
result = datatable(data_table_example_data, options = list(pageLength = 100, scrollX = TRUE),
class = 'cell-border stripe compact', rownames = FALSE) %>%
formatCurrency(grepl("$", colnames(data_table_example_data)) %>%
formatPercentage(grepl("%", colnames(data_table_example_data)), digits = 1)
})
It seems you need to be explicit with the data so colnames() doesn't work - you need colnames(data_table_example_data).
I noticed during testing if you use grepl with rownames = TRUE that rownames becomes the first column name which means all the formatting is out by one. grep seems to not have this issue.
I have below code:
t_af_ts_outcomes <- datatable( data = cars
, options = list( bFilter = 0
, bLengthChange = 0
, paging = F
, info = F
)
)
output$v_af_ts_outcomes <- renderDataTable( t_af_ts_outcomes )
And it gives below output:
Is there anyway I can remove the row numbers?
Set argument rownames = FALSE inside datatable() function.
I am trying to select the cell in the DataTable and show the corresponding position/value.
But it seems not working... I ran the code from the example cell code from Yihui but still showing the same error as I got from my code:
Warning: Error in match.arg: 'arg' must be NULL or a character vector
Stack trace (innermost first):
76: match.arg
75: datatable
74: widgetFunc
73: func
72: renderFunc
71: output$x16
4:
3: do.call
2: print.shiny.appobj
1:
Below are part of my code.
biTableMatrix function - It assign the values to a certain position in the matrix/df by the xpos (row) and ypos (column). Firstly it returned a matrix, but I thought the error might be caused by the object type (matrix instead of data.frame from the example), so I convert it to data.frame - not much help thou...
# The following are in helper.R
travelMeans <- c('02', '04')
prepareTwoMeans <- function(travelMeans) {
listx <- subset(geodata[geodata$MeanCode==travelMeans[1],], select = -c( AreaFull,MeanName,MeanFull))
listx <- listx[order(listx$Percentage),]
listy <- subset(geodata[geodata$MeanCode==travelMeans[2],], select = -c( AreaFull,MeanName,MeanFull,AreaCode))
listy <- listy[order(listy$Percentage),]
listx$xpos <- seq(length=nrow(listx))
listy$ypos <- seq(length=nrow(listy))
listx <- merge(listx, listy, by.x = c("AreaName"), by.y = c("AreaName"), all=TRUE)
return(listx)
}
# This function generates the two-way table of two travel means
biTableMatrix <- function(travelMeans) {
fullList <- prepareTwoMeans(travelMeans)
len <- length(fullList$AreaName)
biTableMat <- matrix(data = "", nrow = len, ncol = len, dimnames = list(seq(length = len), seq(length = len)))#,
for (n in 1:len) {
x <- fullList$xpos[n]
y <- fullList$ypos[n]
biTableMat[x,y] <- as.character(fullList$AreaName[n]) #fullList$AreaCode[n]
}
return(as.data.frame(biTableMat) )
}
# The following are in server.R
biTable <- reactive({
return(biTableMatrix(input$travelMeans))
})
output$biTable <- DT::renderDataTable({
DT::datatable(
biTable()
, selection = list(mode = "single", target = "cell")
, extensions = list("Scroller", "RowReorder")
, options = list(
scrollX = 500
, scrollY = 700
, rowReorder = FALSE
)
)}
, options = list(
searchHighlight = TRUE
)
)
output$biTableText <- renderPrint(input$biTable_cells_selected$value)
For reference, here is my ui.R
#Definte UI for the application
ui <- fluidPage(
sidebarPanel(
# The following part is groupCheckBox format for the travelMeans
checkboxGroupInput(
"travelMeans"
, label = "Select the mean below:"
, choices = meanChoices
, selected = NULL
)
, br()
),
#Show the map
mainPanel(
tabsetPanel(#type = "tabs",
tabPanel("Single-Mean Table", DT::dataTableOutput("onetable"), hr())
, tabPanel("Two-way table", DT::dataTableOutput("biTable"), hr(), verbatimTextOutput("biTableText"))
)
, position="center"
, height= "auto"
)
)
Any help would be much appreciated!!
Thanks!!
devtools::install_github('rstudio/DT')
Do not use the cran DT.