Ad

How To Set Independent Table Column Widths Using RenderTable()?

- 1 answer

In the code below, I'm trying to adjust column widths independently (where the "Period...", "Col A", and "Col B" can each have their own unique widths) for the output table rendered in the "Sum the data table columns:" section at the bottom. Also, whatever formatting I've achieved with the below statement columnDefs = list(list(width = '100px', targets = "_all")) is wiped out once the user clicks on the "By period 2" radio button.

Any suggestions on how to adjust column widths in a rendered table?

As I've researched this, I've been surprised by the lack of clarity/consistency on this. At a minimum, it would be useful in my case to be able to adjust the width of the left-most column for "Period...", and be able to adjust the widths uniformly for all other columns to the right of "Period..", if it's not possible to independently adjust the width of each column.

Code:

library(dplyr)
library(DT)
library(shiny)
library(shinyWidgets)
library(tidyverse)

ui <-
  fluidPage(
    fluidRow(
      column(width = 8,
          h3("Data table:"),
          tableOutput("data"),
          h3("Sum the data table columns:"),
          radioButtons(
            inputId = "grouping",
            label = NULL,
            choiceNames = c("By period 1", "By period 2"),
            choiceValues = c("Period_1", "Period_2"),
            selected = "Period_1",
            inline = TRUE
          ),
          DT::dataTableOutput("sums")
      )
    )
  )

server <- function(input, output, session) {
  data <- reactive({
    data.frame(
      Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
      Period_2 = c(1, 2, 3, 3, 1, 2),
      ColA = c(1000.01, 20, 30, 40, 50, 60),
      ColB = c(15.06, 25, 35, 45, 55, 65)
      )
  })
  
  colNames <- reactive({c(stringr::str_replace(input$grouping, fixed("_"), " "), "Col A", "Col B") })
  
  summed_data <- reactive({
    data() %>%
      group_by(!!sym(input$grouping)) %>%
      select("ColA","ColB") %>%
      summarise(across(everything(), sum))
  })
  
  output$data <- renderTable(data())

  output$sums <- renderDT({
    summed_data() %>% 
      datatable(
        rownames = FALSE,
        colnames=colNames(), 
        options = list(
          autoWidth = TRUE,
          columnDefs = list(list(width = '100px', targets = "_all"))
          )
        )
  })
  
}

shinyApp(ui, server)
Ad

Answer

You need to first set autoWidth to FALSE and then you can specify different width for different columns by using the targets option. The first column is indexed as 0.

library(dplyr)
library(DT)
library(shiny)
library(shinyWidgets)
library(tidyverse)

ui <-
  fluidPage(
    fluidRow(
      column(width = 8,
             h3("Data table:"),
             tableOutput("data"),
             h3("Sum the data table columns:"),
             radioButtons(
               inputId = "grouping",
               label = NULL,
               choiceNames = c("By period 1", "By period 2"),
               choiceValues = c("Period_1", "Period_2"),
               selected = "Period_1",
               inline = TRUE
             ),
             DT::dataTableOutput("sums")
      )
    )
  )

server <- function(input, output, session) {
  data <- reactive({
    data.frame(
      Period_1 = c("2020-01", "2020-02", "2020-03", "2020-01", "2020-02", "2020-03"),
      Period_2 = c(1, 2, 3, 3, 1, 2),
      ColA = c(1000.01, 20, 30, 40, 50, 60),
      ColB = c(15.06, 25, 35, 45, 55, 65)
    )
  })
  
  colNames <- reactive({c(stringr::str_replace(input$grouping, fixed("_"), " "), "Col A", "Col B") })
  
  summed_data <- reactive({
    data() %>%
      group_by(!!sym(input$grouping)) %>%
      select("ColA","ColB") %>%
      summarise(across(everything(), sum))
  })
  
  output$data <- renderTable(data())
  
  output$sums <- renderDT({
    summed_data() %>% 
      datatable(
        rownames = FALSE,
        colnames=colNames(), 
        options = list(
          autoWidth = FALSE,
          columnDefs = list(
            list(width = '35px', targets = c(0)),
            list(width = '150px', targets = c(1,2)))
        )
      )
  })
  
}

shinyApp(ui, server)
Ad
source: stackoverflow.com
Ad