Search code examples
rdataframeflextable

Width of flextable in pdf do not show in full the column names


I have the following rmarkdown document in R that generates a flextable object.

My problem is that the two columns 4 and 5 the header names do not show in full and the last letters are hidden.


---
title: "flex_width_issue"
output: pdf_document
date: "2025-02-08"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)


library(tidyverse)
library(officer)
library(flextable)

ft3 = structure(list("Project Number" = c(4107L, 1770L, 1979L, 9252L, 
2581L, 8360L, 6290L, 1002L, 7300L, 2925L), "Client Company" = c("Dynamic Build Concept Agency", 
"Nova", "Alpha Corp", "Global Innovations", "Core Metrics", "Vision Group for Property Holdings", 
"United Firm for Urban Growth Projects", "Eastern Gate Real Estate Investment Group (EGRIG)", 
"Eastern Gate Real Estate Investment Group (EGRIG)", "Eastern Gate Real Estate Investment Group (EGRIG)"
), `organizational growth planning` = c(5, 5, 4.83, 4.67, 4.17, 
4, 3.83, 3.67, 3.5, 2.83), competency = c(5, 5, 4.83, 4.67, 4.27, 
4.08, 4.25, 4, 3.5, 3.25), compression = c(5, 5, 5, 4.67, 4.38, 
4.67, 4.67, 4, 3.67, 3), `International development project` = c(5, 
4.57, 4.43, 4.43, 3.83, 4.17, 3.57, 3.14, 2.71, 2.71), `Team spirit` = c(5, 
5, 5, 4.5, 4.21, 4.5, 4.5, 3.5, 3.5, 3), Plan = c(5, 5, 4, 4, 
3.6, 2, 3, 4, 3, 3), PIR = c(5, 5, 4.17, 4.67, 4.07, 4.17, 4.33, 
3.67, 3.67, 3.33), Success = c(5, 5, 4, 4, 4.08, 5, 3, 4, 2.67, 
3), plant = c(100, 98.92, 90.65, 89.03, 81.6, 81.48, 77.88, 74.95, 
65.55, 60.3)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", 
"data.frame"))

map_color2 = function(value) {
  case_when(
    value >= 1   & value <  1.5  ~ "#ed2e1c",    # [1–1.5[
    value >= 1.5 & value <= 2.5  ~ "#e09c95", # [1.5–2.5]
    value > 2.5  & value <  3.5  ~ "#85c1e9",   # ]2.5–3.5[
    value >= 3.5 & value <= 4.5 ~ "#7FF98B", # [3.5–4.5]
    value > 4.5  & value <=   5  ~ "#04B431",    # ]4.5–5]
    TRUE ~ "white"  # Default color for values outside the range
  )
}

colors2 = ft3 %>%
  select(3:(ncol(.) - 1)) %>%
  mutate(across(everything(), ~ map_color2(.)))  # Apply map_color column-wise


ft4 = ft3%>%
  flextable::flextable()

# Apply map_color to columns from 3 to the second-to-last column
ft4%>%
  border_outer(part = "all") %>%
  border_inner(part = "all") %>%
  bg(part = "header", bg = "grey") %>%
  bold(part = "header") %>%
  align(align = "center", part = "header") %>%         
  theme_zebra()%>%
  bg(bg = "grey", part = "header")%>% 
  align(align="center", part="all")%>%
  fit_to_width(max_width = 7)%>% 
  fontsize(size=7, part="all")%>%
  flextable::bg(i = rep(1:nrow(ft3)), 
                j = rep(3:(ncol(ft3) - 1)), 
                bg = unlist(colors2))%>%
  align(j = 2, align = "center", part = "all")




can anyone help me with this ? 

How this can fit in width and show all the header columns names clearly in full ? 



Solution

  • You can use a function to autoscale your table, even though it would be best to choose a landscape for wide tables. It's not perfect, but it works for now. Maybe use abbreviations in your headers.

    out

    ---
    title: "flex_width_issue"
    output:
      pdf_document: default
      html_document:
        df_print: paged
    date: "2025-02-08"
    ---
    
    ```{r setup, include=F, warning=F}
    knitr::opts_chunk$set(echo = FALSE)
    library(tidyverse)
    library(officer)
    library(flextable)
    
    ft3 = structure(list("Project Number" = c(4107L, 1770L, 1979L, 9252L, 
    2581L, 8360L, 6290L, 1002L, 7300L, 2925L), "Client Company" = c("Dynamic Build Concept Agency", 
    "Nova", "Alpha Corp", "Global Innovations", "Core Metrics", "Vision Group for Property Holdings", 
    "United Firm for Urban Growth Projects", "Eastern Gate Real Estate Investment Group (EGRIG)", 
    "Eastern Gate Real Estate Investment Group (EGRIG)", "Eastern Gate Real Estate Investment Group (EGRIG)"
    ), `organizational growth planning` = c(5, 5, 4.83, 4.67, 4.17, 
    4, 3.83, 3.67, 3.5, 2.83), competency = c(5, 5, 4.83, 4.67, 4.27, 
    4.08, 4.25, 4, 3.5, 3.25), compression = c(5, 5, 5, 4.67, 4.38, 
    4.67, 4.67, 4, 3.67, 3), `International development project` = c(5, 
    4.57, 4.43, 4.43, 3.83, 4.17, 3.57, 3.14, 2.71, 2.71), `Team spirit` = c(5, 
    5, 5, 4.5, 4.21, 4.5, 4.5, 3.5, 3.5, 3), Plan = c(5, 5, 4, 4, 
    3.6, 2, 3, 4, 3, 3), PIR = c(5, 5, 4.17, 4.67, 4.07, 4.17, 4.33, 
    3.67, 3.67, 3.33), Success = c(5, 5, 4, 4, 4.08, 5, 3, 4, 2.67, 
    3), plant = c(100, 98.92, 90.65, 89.03, 81.6, 81.48, 77.88, 74.95, 
    65.55, 60.3)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", 
    "data.frame"))
    
    ```
    
    
    
    ```{r cars,  warning=F}
    map_color2 = function(value) {
      case_when(
        value >= 1   & value <  1.5  ~ "#ed2e1c",    # [1–1.5[
        value >= 1.5 & value <= 2.5  ~ "#e09c95", # [1.5–2.5]
        value > 2.5  & value <  3.5  ~ "#85c1e9",   # ]2.5–3.5[
        value >= 3.5 & value <= 4.5 ~ "#7FF98B", # [3.5–4.5]
        value > 4.5  & value <=   5  ~ "#04B431",    # ]4.5–5]
        TRUE ~ "white"  # Default color for values outside the range
      )
    }
    
    colors2 = ft3 %>%
      select(3:(ncol(.) - 1)) %>%
      mutate(across(everything(), ~ map_color2(.)))  # Apply map_color column-wise
    
    FitFlextableToPage <- function(ft, pgwidth = 6){
      
      ft_out <- ft %>% autofit()
    
      ft_out <- width(ft_out, width = dim(ft_out)$widths*pgwidth /(flextable_dim(ft_out)$widths))
      
      return(ft_out)
    }
    
    # Apply map_color to columns from 3 to the second-to-last column
    ft <- ft3 %>%
      flextable::flextable() %>%
      # Apply your existing formatting
      border_outer(part = "all") %>%
      border_inner(part = "all") %>%
      bg(part = "header", bg = "grey") %>%
      bold(part = "header") %>%
      align(align = "center", part = "header") %>%         
      theme_zebra() %>%
      bg(bg = "grey", part = "header") %>% 
      align(align = "center", part = "all") %>%
      fontsize(size = 8, part = "all") %>%
      flextable::bg(
        i = rep(1:nrow(ft3)), 
        j = rep(3:(ncol(ft3) - 1)), 
        bg = unlist(colors2)
      ) %>%
      align(j = 2, align = "center", part = "all") 
    
    
    FitFlextableToPage(ft,6.2)
    
    ```
    

    You can even improve the space usage by only wrapping headers which exceed the max length of nchars in their cols.

    ---
    title: "flex_width_issue"
    output:
      pdf_document: default
      html_document:
        df_print: paged
    date: "2025-02-08"
    ---
    
    ```{r setup, include=F, warning=F}
    knitr::opts_chunk$set(echo = FALSE)
    library(tidyverse)
    library(officer)
    library(flextable)
    
    ft3 = structure(list("Project Number" = c(4107L, 1770L, 1979L, 9252L, 
    2581L, 8360L, 6290L, 1002L, 7300L, 2925L), "Client Company" = c("Dynamic Build Concept Agency", 
    "Nova", "Alpha Corp", "Global Innovations", "Core Metrics", "Vision Group for Property Holdings", 
    "United Firm for Urban Growth Projects", "Eastern Gate Real Estate Investment Group (EGRIG)", 
    "Eastern Gate Real Estate Investment Group (EGRIG)", "Eastern Gate Real Estate Investment Group (EGRIG)"
    ), `organizational growth planning` = c(5, 5, 4.83, 4.67, 4.17, 
    4, 3.83, 3.67, 3.5, 2.83), competency = c(5, 5, 4.83, 4.67, 4.27, 
    4.08, 4.25, 4, 3.5, 3.25), compression = c(5, 5, 5, 4.67, 4.38, 
    4.67, 4.67, 4, 3.67, 3), `International development project` = c(5, 
    4.57, 4.43, 4.43, 3.83, 4.17, 3.57, 3.14, 2.71, 2.71), `Team spirit` = c(5, 
    5, 5, 4.5, 4.21, 4.5, 4.5, 3.5, 3.5, 3), Plan = c(5, 5, 4, 4, 
    3.6, 2, 3, 4, 3, 3), PIR = c(5, 5, 4.17, 4.67, 4.07, 4.17, 4.33, 
    3.67, 3.67, 3.33), Success = c(5, 5, 4, 4, 4.08, 5, 3, 4, 2.67, 
    3), plant = c(100, 98.92, 90.65, 89.03, 81.6, 81.48, 77.88, 74.95, 
    65.55, 60.3)), row.names = c(NA, -10L), class = c("tbl_df", "tbl", 
    "data.frame"))
    
    wrap_long_headers <- function(df, wrap_at = 7) {
      new_colnames <- sapply(names(df), function(col) {
        max_val_length <- max(nchar(as.character(df[[col]])), na.rm = TRUE)
        col_length <- nchar(col)
        
        # Apply wrapping only if the column name is longer than max value length
        if (col_length > max_val_length) {
          return(gsub(paste0("(.{", wrap_at, "})"), '\\1-\n', col, perl = TRUE))
        } else {
          return(col)  # Keep as is
        }
      })
      
      colnames(df) <- new_colnames
      return(df)
    }
    
    # Apply function
    ft3 <- wrap_long_headers(ft3)
    
    ```
    
    
    
    ```{r cars,  warning=F}
    map_color2 = function(value) {
      case_when(
        value >= 1   & value <  1.5  ~ "#ed2e1c",    # [1–1.5[
        value >= 1.5 & value <= 2.5  ~ "#e09c95", # [1.5–2.5]
        value > 2.5  & value <  3.5  ~ "#85c1e9",   # ]2.5–3.5[
        value >= 3.5 & value <= 4.5 ~ "#7FF98B", # [3.5–4.5]
        value > 4.5  & value <=   5  ~ "#04B431",    # ]4.5–5]
        TRUE ~ "white"  # Default color for values outside the range
      )
    }
    
    colors2 = ft3 %>%
      select(3:(ncol(.) - 1)) %>%
      mutate(across(everything(), ~ map_color2(.)))  # Apply map_color column-wise
    
    FitFlextableToPage <- function(ft, pgwidth = 6){
      
      ft_out <- ft %>% autofit()
    
      ft_out <- width(ft_out, width = dim(ft_out)$widths*pgwidth /(flextable_dim(ft_out)$widths))
      
      return(ft_out)
    }
    
    # Apply map_color to columns from 3 to the second-to-last column
    ft <- ft3 %>%
      flextable::flextable() %>%
      # Apply your existing formatting
      border_outer(part = "all") %>%
      border_inner(part = "all") %>%
      bg(part = "header", bg = "grey") %>%
      bold(part = "header") %>%
      align(align = "center", part = "header") %>%         
      theme_zebra() %>%
      bg(bg = "grey", part = "header") %>% 
      align(align = "center", part = "all") %>%
      fontsize(size = 8, part = "all") %>%
      flextable::bg(
        i = rep(1:nrow(ft3)), 
        j = rep(3:(ncol(ft3) - 1)), 
        bg = unlist(colors2)
      ) %>%
      align(j = 2, align = "center", part = "all") 
    
    
    FitFlextableToPage(ft,6.2)
    
    ```
    

    out2