skip to Main Content

I am trying to style cells in a shiny datatable into six or so column-level quantiles (except the first column, which is character). Here is a MRE of my current code, which styles cells as above or below the column mean with a rowcallback from this answer. I am not familiar with javascript.

EDIT: users can select/deselect columns, so I need a solution that applies across the columns currently in dataset.

library(shiny)
library(DT)

set.seed(123)
dataset <- data.frame(
  ID = 1:20,
  Value1 = round(rnorm(10, mean = 15, sd = 5), 1),
  Value2 = round(rnorm(10, mean = 25, sd = 8), 1))

ui <- fluidPage(
  titlePanel("Reprex for cell styling"),
  dataTableOutput("myTable"))

server <- function(input, output, session) {
  output$myTable <- renderDataTable({
    datatable(
      dataset,
      options = list(
        rowCallback = JS(paste0(
          "function(row, data) {n",
          paste(
            sapply(
              2:ncol(dataset),
              function(i) paste0("var value=data[", i, "]; if (value!==null) $(this.api().cell(row,", i, ").node()).css({'background-color':value <=", mean(dataset[[i]]), " ? '#6EACCA' : '#FFDD91'});n")
            ),
            collapse = "n"
          ),
          "}n"
        ))
      )
    )
  })
}

shinyApp(ui, server)

Most of my attempts so far have been similar to:

rowCallback = JS(paste0("function(row, data) {n",
                        "  // Iterate over columns starting from the second column (index 1)n",
                        sapply(2:ncol(dataset), function(i) {
                          paste0(
                            "  var value = data[", i, "];n",
                            "  if (value !== null) {n",
                            "    // Calculate column-level quantiles for the current columnn",
                            "    var columnData = data.map(function(row) { return row[", i, "]; });n",
                            "    var quantiles = quantile(columnData, [0, 0.2, 0.4, 0.6, 0.8, 1]);n",
                            "    var color;n",
                            "    if (value <= quantiles[1]) color = '#BFD3E6';n",  
                            "    else if (value <= quantiles[2]) color = '#8BACD6';n",
                            "    else if (value <= quantiles[3]) color = '#6382C1';n",
                            "    else if (value <= quantiles[4]) color = '#385FAD';n",
                            "    else if (value <= quantiles[5]) color = '#0D3D99';n",  
                            "    else color = ''; // Handle edge cases if neededn",
                            "    $(this.api().cell(row, ", i, ").node()).css({'background-color': color});n",
                            "  }n"
                          )
                        }), "}n"))

The closest I have gotten is styling in six quantiles but the cutoffs revert to whole-datatable values instead of column-level quantiles.

2

Answers


  1. Chosen as BEST ANSWER

    Got this working with help from @StéphaneLaurent's answers above and here. Using a list of quantiles for current columns and a styling loop:

        quantileList <- lapply(dataset[, -1, drop = FALSE], function(col) {
          quantile(col, c(0, 0.2, 0.4, 0.6, 0.8))
        })
        
        clrs <- c("red", "#BFD3E6", "#8BACD6", "#6382C1", "#385FAD", "#0D3D99")
        
        DT <- datatable(dataset)
    
        for (i in 2:ncol(dataset)) {
          brks <- quantileList[[i - 1]]
          colname <- colnames(dataset)[i]
          DT <- DT %>% formatStyle(colname, backgroundColor = styleInterval(brks, clrs))
        }
        
        DT
    

  2. You can use the DT functions formatStyle and styleInterval:

    library(DT)
    
    set.seed(123)
    dataset <- data.frame(
      ID = 1:20,
      Value1 = round(rnorm(200, mean = 15, sd = 5), 1),
      Value2 = round(rnorm(200, mean = 25, sd = 8), 1)
    )
    
    brks1 <- quantile(dataset$Value1, c(0, 0.2, 0.4, 0.6, 0.8))
    brks2 <- quantile(dataset$Value2, c(0, 0.2, 0.4, 0.6, 0.8))
    clrs <- c("red", "#BFD3E6", "#8BACD6", "#6382C1", "#385FAD", "#0D3D99")
    
    datatable(dataset) %>% 
      formatStyle("Value1", backgroundColor = styleInterval(brks1, clrs)) %>%
      formatStyle("Value2", backgroundColor = styleInterval(brks2, clrs))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search