Search code examples
rshinydtreactable

Unable to fix the first column using renderDT in R Shiny?


In the example that I posted below, I have a df with 100 rows and 100 columns with numeric values (except the first column) that I would like to print with sequential color scale on the main panel in Shiny. Since all columns don’t fit in a single window, I would like to use horizontal scrolling while keeping the first column fixed. Here is my attempt at it. Not sure where I am going wrong. As you can see, I am using DT package. I would appreciate if someone can also show me the solution with reactable package.

library(shiny)
library(tidyverse)
df <- matrix(runif(100*100,0,1000) %>% floor(),nrow = 100,ncol = 100) %>% as_tibble() %>% 
    mutate(V1=rep_len(letters,length.out = 100))
# Define UI for application that draws a histogram
ui <- fluidPage(
    # Application title
    titlePanel("Table"),
    sidebarLayout(
        # Show the table
        sidebarPanel(),
        mainPanel(
           DT::DTOutput("table")
        )
    )
)
# Define server logic
server <- function(input, output) {
    output$table <- DT::renderDT({
        #splitting values into quantiles
        brks <- quantile(df %>% select(-1), probs = seq(0,1,length.out = 39), na.rm = TRUE)
        #creating a blue palette
        clr_plt_blue_func <- colorRampPalette(c("white","lightblue","skyblue","royalblue","navyblue"))
        clr_plt_blue <- clr_plt_blue_func(40)
        DT::datatable(df,options = list(pageLength=20,
                                        class= 'cell-border stripe',
                                        searching=TRUE,
                                        extensions='FixedColumns',
                                        scrollX = TRUE,
                                        fixedColumns=list(leftColumns=2)
        )
        ) %>% 
            DT::formatStyle(columns =  names(df)[-1], 
                            backgroundColor = DT::styleInterval(brks, clr_plt_blue),
                            color = 'red',
                            fontWeight = 'bold')
    })
}
# Run the application 
shinyApp(ui = ui, server = server)

Solution

  • DT

    In DT extensions='FixedColumns' needs to be a direct argument in datatable not in options.

    DT::datatable(df,options = list(pageLength=20,
                                        class= 'cell-border stripe',
                                        searching=TRUE,
                                        scrollX = TRUE,
                                        fixedColumns = list(leftColumns = 2)),
                      extensions='FixedColumns'
                      
                      
        ) %>% 
          DT::formatStyle(columns =  names(df)[-1], 
                          backgroundColor = DT::styleInterval(brks, clr_plt_blue),
                          color = 'red',
                          fontWeight = 'bold')
    

    Reactable

    Here is an example for reactable. Fixed column is shown in browser, probably not in R's Viewer tab.

    pal <- function(x) rgb(colorRamp(c("white","lightblue","skyblue","royalblue","navyblue"))(x), maxColorValue = 255)
    
    reactable(
      df,
      #x and y scrollable
      pagination = FALSE,
      height = 500,
      #define style for 2:100 column
      defaultColDef = colDef(
        style = function(value) {
          if (!is.numeric(value)) return()
          normalized <- (value - min(df[, -1])) / (max(df[, -1]) - min(df[, -1]))
          color <- pal(normalized)
          list(background = color, color = "red")
        },
        minWidth = 50
      ),
      rownames = TRUE,
      #fix first column and rownames
      columns = list(
        V1 = colDef(
          style = list(position = "sticky",
                       left = "50px", 
                       background = "#fff", 
                       zIndex = 1),
          headerStyle = list(position = "sticky", 
                             left = "50px",
                             background = "#fff", 
                             zIndex = 1)
        ),
        .rownames = colDef(
          style = list(position = "sticky",
                       left = 0,
                       background = "#fff", 
                       color = "black"),
          headerStyle = list(position = "sticky", 
                             left = 0,
                             background = "#fff", 
                             zIndex = 1)
        )
      )
    )