Search code examples
rshinyr-markdownhuxtable

How do I automatically split huxtables across multiple pages?


Goal:
In the Shiny app I'm working on, the users can upload a .csv file, which is converted to a huxtable, gets formatted and can finally be downloaded as a .pdf. Since the users can upload their own dataset, I don't know in advance how many rows it will contain and if the table will need to be split across multiple pages. Therefore, it would be handy if the table would be automatically split if it is longer than one page in the .pdf file. I know I could achieve this with other packages like flextable, but flextable does not support padding when rendered to pdf.

Problem:
If the table becomes too long, it will be pushed to the next page and anything longer than the page will not be displayed.
I know the function split_across(), but I could not solve my problem with it.
If I set a fixed value for example a split after every twentieth row and then a cell contains a lot of text and the text is wrapped and thus takes more space, I have the same problem again.

Reprex:

---
output: 
  pdf_document
---

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

library(huxtable)
```

# Title Text

```{r}
faithful[1, 1] <- paste0(
  "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod ",
  "tempor incididunt ut, labore et dolore magna aliqua."
)

as_hux(faithful) |>
  set_wrap(everywhere, everywhere, TRUE) |>
  set_width(0.8)
```

Solution

  • Your idea with split_across is actually the right approach. You need to:

    1. Split your table in multiple with split_across.
    2. This will return a list(!) of huxtables.
    3. You can use to_latex to render them.
    4. As you are rendering them by hand, you need to make sure that the required LaTeX packages are added.
    5. Some syntactic sugar to make sure the labels are set properly.
    ---
    output: 
      pdf_document:
        extra_dependencies: ["array","adjustbox","threeparttable","tabularx","colortbl","hhline","calc"]
    ---
    
    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = FALSE)
    
    library(huxtable)
    library(magrittr)
    library(purrr)
    ```
    
    # Title Text
    
    ```{r, results = "asis"}
    faithful[1, 1] <- paste0(
      "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod ",
      "tempor incididunt ut, labore et dolore magna aliqua."
    )
    ## just to see if all rows are added
    faithful <- cbind(row_nr = 1:nrow(faithful), faithful) 
    
    rows_first_page <- 20L
    max_rows_per_page <- 23L
    
    hux_list <- as_hux(faithful) %>%
      set_wrap(everywhere, everywhere, TRUE) %>%
      set_width(0.8) %>% 
      split_across(., after = seq(rows_first_page , nrow(.), by = max_rows_per_page))
    
    
    hux_lat <- imap_chr(hux_list, 
                        ~ .x %>% 
                          set_label(
                            paste0("tab:", 
                                   knitr::opts_current$get("label"), "-", .y)) %>% 
                          to_latex()) %>% 
      paste(collapse = "\n\n")
    
    cat(hux_lat)
    ```