flextable autofit in a Rmarkdown to word doc causes table to go outside page margins
Asked Answered
F

3

22

Hi I am trying to use flextable in an Rmarkdown .doc document to format my tables. I like the simple formatting options that flextable gives (but open to other similar packages) but have found something that I thought should be a basic function doesn't always work.

I want to fit the table to the width of the word document so that if required text will wrap within a column to fit, but if there is free space available on the page columns will be made wider, but not to the extent that the column is so wide that not all data is shown.

I have made an example below to show my problem. By default all columns are the same width and text is wrapped to fit, but there is therefore space wasted. I want to fit columns to the data (using autofit) but this then makes the columns so wide they go off the screen. I'm hoping for a happy-medium with mpg, vs and carb wider but some text wrapping still happening. E.g. I want this:

Desired output

Obviously I can manually change widths using flextable::width but my table is made through an automated process so I don't know how wide I want each column to be.

Here is my example which shows the problems either with or eithout autofit

---
title: "TestTable"
output: word_document
---

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


suppressWarnings(suppressPackageStartupMessages({library(knitr)
  library(pander)
  library(flextable)
  library(tidyverse)
library(flextable)}))
```

## Normal Table
Without extra formatting, wraps text so that it fits on the page, but there is no need for column widths to be equal and could be wider on the page

```{r, echo=FALSE, results = 'asis' }
mydata <- mtcars %>% head(3) %>% select(mpg, cyl, hp,vs, gear, carb) %>%
  mutate(mpg = paste0(mpg, "with extra stuff to make long"),
         vs = paste0(vs, "+ extra stuff"),
         carb = paste0(carb, "also with extra stuff to make longer"))

mytable <- mydata  %>% flextable(theme_fun = theme_box)

mytable

```
## Table With autofit  
But table with autofit goes off the edges of the page


```{r, echo=FALSE, results = 'asis' }

mytable %>% autofit()

```


## Table With autofit and manual breaks
And if manual breaks are inserted into the column autofit makes the columns too wide an they still go off the edges of the page

```{r, echo=FALSE, results = 'asis' }

mydataWithBreaks <- mtcars %>% head() %>% select(mpg, cyl, hp,vs, gear, carb) %>%
  mutate(mpg = paste0(mpg, "\nwith extra stuff\n to make long"),
         vs = paste0(vs, "+\n extra stuff"),
         carb = paste0(carb, "\nalso with extra stuff\n to make longer"))

mydataWithBreaks  %>% flextable(theme_fun = theme_box)%>% autofit()



```
Ferocity answered 24/7, 2019 at 4:37 Comment(0)
F
44

I have written a function to fit the table to the page which works well for now, although I'm still a bit surprised that there is no built in function to do this which would (for example) know the width of the page itself, so if any one knows any still keen to hear.

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)
}
Ferocity answered 25/7, 2019 at 3:46 Comment(2)
I wish I had found this answer ages ago, as it's the only solution that's worked consistently for me.Shopping
The same here. Best solution ever.Fess
C
12

FYI - I ran into this same problem today and used your code (thank you). But it still was bothering me because I couldn't get it quite right. I noticed on the Officedown package website (same author; https://github.com/davidgohel/officedown) they used set_table_properties(layout = "autofit") so I tried that. For whatever reason it worked as expected when doing that! I also was using officedown with default settings, so maybe the two worked well together.

Cardholder answered 21/5, 2020 at 20:14 Comment(2)
Welcome to StackOverflow; Is this an answer or a comment? have a look at the SO guidance How to AnswerKegler
In my opinion this should be the accepted answer as it is built-in and does not require defining an extra function.Hallowed
D
12

I had a similar issue using the autofit() function. When I add the function fit_to_width() to the end of the pipe, it solves the issue.

Using part of your example from above, the following line of code would autofit the columns, then resize to fit the max table width in inches given as the second argument (here I am going for 1/2 inch doc margins):


mytable %>% autofit() %>% fit_to_width(7.5)

One caveat of this is that for some of my tables, adding the fit_to_width() function slowed the rendering process considerably. For those tables, I used @bumbledore's suggested set_table_properties(layout = "autofit") and it worked great (and for the record, I am also using officedown with default settings).

Detrition answered 16/9, 2020 at 22:53 Comment(1)
fit_to_width() will scale font sizes, set_table_properties(layout = "autofit") will wrap the text so that it fits.Myrilla

© 2022 - 2024 — McMap. All rights reserved.