Search code examples
rr-markdownknitrflextable

How to knit_print flextable with loop in a rmd file


I am trying to produce mutltiple tables using the flextable and kable packages. When I want to output some table iteratively, I found knit_print of flextable is not working in loop. Below is a minimal example:

---
output: word_document
---

```{r}
library(flextable)
library(knitr)
```

```{r}
 data(cars)
     speed<-unique(cars$speed)
for (v in 1:length(speed)) {
  carspd<-cars[which(cars$speed==speed[v]),]
  tb<-regulartable(carspd)
knit_print(tb)
}
knit_print(tb)
```

Just the last knit_print can print the result to the word_document with the .Rmd file.


Now I find the difference of them in .md which is output by the pandoc process file with ultraedit, the right table:

```{=openxml}
<w:tbl xmlns:w=".......

the wrong table:

鈥媊``{=openxml}
<w:tbl xmlns:w="

In hexadecimal there are extra content:"E2 80 8B", someone call they Zero-Width Space? But I am not figure out how to avoid it.


Solution

  • This is a limitation of one of the functions that flextable uses in its knit_print method: knitr::asis_output() can't be used in a loop. A couple of solutions are described here: https://github.com/yihui/knitr/issues/1137.

    This one works for me in HTML output, just collecting all the output into one big vector and printing it at the end. I have modified the code to also insert some text before the table and a figure after it. I don't use Word, but I'd assume it will also work there:

    ---
    output: html_document
    ---
    
    ```{r}
    library(flextable)
    library(knitr)
    ```
    
    ```{r}
    data(cars)
    speed <- unique(cars$speed)
    results <- character()
    for (v in 1:length(speed)) {
      carspd <- cars[which(cars$speed == speed[v]),]
      tb <- regulartable(carspd)
    
      # Generate a figure in a temporary file
      filename <- tempfile(fileext = ".png")
      png(filename)
      hist(carspd$dist)
      dev.off()
    
      # Put everything into the results vector
      results <- c(results, "\n\nThis is the table for v =", v,
                            knit_print(tb),
                            knitr:::wrap(include_graphics(filename)))
    
    }
    asis_output(results)
    knit_print(tb)
    ```
    

    A couple of notes:

    • The \n\n in the text seems to be necessary to insert a line break.
    • The knitr:::wrap() function is an undocumented internal function in knitr, so there might be limitations that I don't know about, and this might fail in some future version of knitr.