rr-flextable

Method to set minimum column width in flextable


I'm looking for a way to apply autofit() only to columns that are too small.

This is my current method but I'm looking for a better way to do it:

library(flextable)
library(magrittr)

### Ex. Tbls
vendor <- data.frame("Vendor" = rep("Acme", 4),
"Sales" = c(20,30,12,32))
vendor <- data.frame("Vendor" = rep("A long Company Name", 4),
"Sales" = c(21,23,43,12))
vendor <- data.frame("Vendor" = rep("A longer Company Name", 4),
"Sales" = c(1e20,2e20,3e20,4e20))

### Current Method:
desiredWidths <- c(.5,.5)

flextable(vendor) %>%
  autofit() %>% 
  width(j = which(dim(.)$widths < desiredWidths), desiredWidths[which(dim(.)$widths < desiredWidths)])

Ideally I would like something like this:

flextable(vendor) %>%
  width(width = desiredWidths) %>%
  autofit(--Only expands columns that are too narrow--)

Is something like this possible?


Solution

  • If I understand you correctly, you want to set a minimal column width for each column and autosize the column in case any content inside exceeds this width, so that no text is wrapped.

    For this, you can use strwidth in this case for Arial point 11, and measure the maximum text widths of each column, if it's below your minWidths, set it to minWidths using pmax() + width. This is a manual way of autosizing with a lower threshold. You need to adjust this, should you use another font / fontsize.

    ---
    title: "flextabelWidth"
    output:
      pdf_document: default
      html_document:
        df_print: paged
    ---
    
    ```{r flexTables, echo=FALSE, warning=FALSE, ft.align="right"}
    library(flextable)
    ### Ex. Tbls
    vendor1 <- data.frame("Vendor" = rep("Acme", 4),"Sales" = c(20,30,12,32))
    vendor2 <- data.frame("Vendor" = rep("A long Company Name", 4),"Sales" = c(21,23,43,12))
    vendor3 <- data.frame("Vendor" = rep("A longer Company Name", 4),"Sales" = c(1e20,2e20,3e20,4e20))
    
    autosize_min_width <- function(data, minWidths){
    
      flextable(data) |> width(width = pmax(sapply(seq_along(names(
        data
      )), \(i) max(
        strwidth(
          format(data[, i], scientific = FALSE, trim = TRUE),
          font = 11,
          units = 'in'
        )
      )), minWidths))   
    }
    
    desiredWidths <- c(.5,.5)
    autosize_min_width(vendor1, desiredWidths)
    autosize_min_width(vendor2, desiredWidths)
    autosize_min_width(vendor3, desiredWidths)
    ```
    

    giving you the minimal width you wanted

    out

    whereas your code

    flextable(vendor) %>%
      autofit() %>% 
      width(j = which(dim(.)$widths < desiredWidths), desiredWidths[which(dim(.)$widths < desiredWidths)])
    

    gives out2

    which I guess is not what you want? In your code, you compare desiredWidths with the widths already falsely set by autofit to 0.75 inches, which seems to be the minimum width set by autofit.