Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

flextable won't work with quarto files (.qmd) after rendering to html #385

Closed
dax44 opened this issue Mar 12, 2022 · 15 comments
Closed

flextable won't work with quarto files (.qmd) after rendering to html #385

dax44 opened this issue Mar 12, 2022 · 15 comments

Comments

@dax44
Copy link

dax44 commented Mar 12, 2022

flextable function won't show tables after rendering qmd files to html, but for pdf and docx works. If I write the following code

library(flextable)
mtcars |> 
  head() |> 
  flextable()

in qmd file and compile it, I've got this
Zrzut ekranu 2022-03-12 o 22 03 56

If I compile file to pdf and docx function works.
Can you help me?

@jjallaire
Copy link

I've been investigating this and can't quite discern what the problem is. I do notice that there is quite a bit of custom detection logic in the knitr_print method for flextable (detecting pandoc version, whether bookdown is running, etc.). My best guess is that some of this logic is preventing all of the flextable output from being included. @davidgohel note that Quarto does set rmarkdown.pandoc.to for compatibility, so there is something else causing this. Any help you can provide is much appreciated!

@davidgohel
Copy link
Owner

davidgohel commented Mar 13, 2022

I found something that may be the reason,

HTML output is using shadow dom by default with flextable and the content is in a tag <template></template>.

It seems the content of these tag is removed in the HTML result with quarto.
It can be reproduced without using flextable:

---
format: html
---

```{r}
#| results: asis
#| echo: false
cat("<template><div>zzz</div></template>")
```

```{r}
#| results: asis
#| echo: false
cat("<div>zzz</div>")
```

Generated HTML fragment with quarto

<main class="content" id="quarto-document-content">
<template></template><p></p>
<div>
zzz
</div>
</main>

@davidgohel
Copy link
Owner

@dax44

You can set knitr chunk option ft.shadow=FALSE as a workaround (but there may be styles issues if some css has been defined for tables).

---
format: html
---

```{r}
#| include: false
library(flextable)
knitr::opts_chunk$set("ft.shadow" = FALSE)
use_df_printer()
```

```{r}
head(iris)
```

```{r}
head(mtcars)
```

@jjallaire
Copy link

It does indeed look like our DOM post-processor mauls the <template> tag: b-fuze/deno-dom#18. Sounds like a fix for this is coming relatively soon. @davidgohel If in the meantime Quarto pre-set the chunk option ft.shadow=FALSE is that a satisfactory workaround or are there significant side effects of this that users would find problematic?

@davidgohel
Copy link
Owner

@jjallaire

There are side effects. In the following example, I voluntarily added a CSS definition that conflicts with one of those of flextable because the result is not encapsulated in a shadow-dom.

---
format: html
---


```{css}
#| echo: false
table tr:last-child td {
  border-bottom-width: 5px;
  border-bottom-color: red;
}
table td, table th {
  border-left: none;
  border-right: none;
}
```



```{r}
#| include: false
library(flextable)
library(dplyr)
knitr::opts_chunk$set("ft.shadow" = FALSE)
```


```{r}
#| echo: false
n_format <- function(z){
  x <- sprintf("%.0f", z)
  x[is.na(z)] <- "-"
  x
}

set_flextable_defaults(digits = 2, border.color = "gray")

dat <- group_by(warpbreaks, wool, tension) %>% 
  summarise(breaks = mean(breaks), .groups = "drop")

cft_1 <- tabulator(
  x = dat, rows = "wool",
  columns = "tension",
  `mean` = as_paragraph(as_chunk(breaks)),
  `(N)` = as_paragraph(
    as_chunk(length(breaks), formatter = n_format ))
)

ft_1 <- as_flextable(cft_1)
ft_1
```

Expected result is:

Capture d’écran 2022-03-13 à 23 45 17

Quarto result is:

Capture d’écran 2022-03-13 à 23 45 00

I am ok with the fix you proposed, but I think it would be easier if I could do it. For example, is there a way to know if running quarto (sorry I am totally new to quarto and am a bit lost in the repo for now)? If yes, I can now switch to ft.shadow=FALSE when HTML and quarto, and could then easily switch to ft.shadow=TRUE when the fix will be available?

@jjallaire
Copy link

That sounds good. Here is where we set various opts_knit so that packages can detect what's going on:

https://github.com/quarto-dev/quarto-cli/blob/main/src/resources/rmd/execute.R#L179-L185

Another Quarto related item to check on is handling of table cross-references and captions. AFAIK is should work fine (we can target raw HTML, looking for the <caption> tag and adding one if it's not there). See docs here: https://quarto.org/docs/authoring/cross-references.html#computations-1

@jjallaire
Copy link

jjallaire commented Mar 14, 2022

I was thinking it might be better if I put the temporary workaround into Quarto for a couple of reasons:

  1. This will work with all versions of flextable currently in the field rather than requiring an update
  2. I can remove it the instant that our DOM parser supports <template>

Here is my patch to Quarto: quarto-dev/quarto-cli@d2b4ea2 (it just sets ft.shadow to FALSE by default for all Quarto renders -- users can override this within the setup chunk or within an individual chunk). If you disagree w/ this approach LMK and I'll revert my fix (or make it conditional on older versions of flextable that don't have your change)

@dax44
Copy link
Author

dax44 commented Mar 14, 2022

Thank you guys for help... Now all works fine after Quarto patch.

@davidgohel
Copy link
Owner

@jjallaire it's ok for me, thanks for the fix, it's great.

Also, thanks for the pointer to caption and cross-ref, I'll explore that soon and will try to give feedback.

@jjallaire
Copy link

In terms of labels for table cross refs, in Quarto they are included within the table caption. So for example here is a raw HTML table that is reference-able:

<table class="table">
<caption>Simple Table {#tbl-simple}</caption>
<thead>
  <tr class="header">
    <th>Col1</th>
    <th>Col2</th>
  </tr>
</thead>
<tbody>
  <tr class="odd">
    <td>A</td>
    <td>B</td>
  </tr>
</tbody>
</table>

See @tbl-simple for details.

So its certainly possible for crossrefs to work straight away w/ flextable if users explicitly specify the caption (I believe that's how it currently works w/ bookdown).

In addition, we wanted to make it possible to specify the caption and label as cell options (for consistency w/ figures). That would look something like this:

```{r}
#| label: tbl-simple
#| tbl-cap: "Simple Table"

library(flextable)
mtcars |> 
  head() |> 
  flextable()
```

In this case we look at the raw HTML and see if we can modify an existing caption (or inject a new one). We do that here: https://github.com/quarto-dev/quarto-cli/blob/main/src/resources/filters/quarto-pre/table-captions.lua#L165-L185. If you want to play w/ getting this to work for flextable its pretty straightforward:

  1. Install the development version as described here: https://github.com/quarto-dev/quarto-cli#development-version
  2. Edit the table-captions.lua file as required and render (the updates will be seen right away w/o any rebuild step).

Note that it's not entirely imperative that this work w/ flextable (as manually specifying a caption is still supported) but it is nice ergonomically for the cell options to work as they do w/ figures and other computationally created tables.

@dax44
Copy link
Author

dax44 commented May 8, 2022

Unfortunately captions for flextables still don't work.

#| label: tbl-knitr
#| tbl-cap: "Caption 1"

library(knitr)
kable(head(mtcars))

and I've got

image

but when I code in the same file

#| label: tbl-flextable
#| tbl-cap: "Caption 2"
library(flextable)
flextable(head(mtcars))

I've got

image

What I done wrong?

Remark: I have the latest RStudio version which should fix this problem!

@jjallaire
Copy link

It looks like flextable creates two separate html outputs so we are missing them in our code. Here I've merged adjacent raw HTML cells that have tables (which in turn makes the example above work as expected): quarto-dev/quarto-cli@9e9f7b3

@leeroyaus
Copy link

This issue seems to still occur when rendering in Word:

flextable_quarto_docx

Is this expected, or can a fix be applied for rendering in Word too?

quarto check

[>] Checking Quarto installation......OK
      Version: 0.9.649
      Path: C:\Program Files\Quarto\bin\
      CodePage: 1252

[>] Checking basic markdown render....OK

[>] Checking Python 3 installation....(None)

      Unable to locate an installed version of Python 3.
      Install Python 3 from https://www.python.org/downloads/

[>] Checking R installation...........OK
      Version: 4.2.0
      Path: C:/PROGRA~1/R/R-42~1.0
      rmarkdown: 2.14

[>] Checking Knitr engine render......OK

@davidgohel
Copy link
Owner

It should be OK now, not yet on CRAN (next week probably). Note I am using the dev version of Quarto, captions in Word were the big deal, and it may change in the future, we will adapt if necessary. :)

@github-actions
Copy link

This old thread has been automatically locked. If you think you have found something related to this, please open a new issue and link to this old issue if necessary.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 16, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants