rstudio / pagedown

Paginate the HTML Output of R Markdown with CSS for Print
https://pagedown.rbind.io
Other
895 stars 127 forks source link

No entry in LoT when kable(..., format='html') is given. #191

Open markanewman opened 4 years ago

markanewman commented 4 years ago

When I use the format = 'html' argument in Kable(), my entry for that table in the List of Tables is removed. This is problematic because things like library(kableExtra) set options(knitr.table.format = 'html') on load. As a workaround, options(knitr.table.format = NULL) is useful, but that causes its own challenges.

Example:

---
title: "foo"
lot: true
output:
  pagedown::html_paged:
      toc: true
---

# Iris {.chapter}

Does not have an entry in LoT

```{r}
knitr::kable(head(iris[, -5]), caption = 'An example table 1.', format = 'html')

Has an entry in LoT

knitr::kable(head(iris[, -5]), caption = 'An example table 2.')

![lot](https://user-images.githubusercontent.com/17315237/96186502-824ae200-0f09-11eb-9496-3b4e1ac597fd.jpg)
cderv commented 4 years ago

Yes currently the List of Table is only built for table written in Markdown in the document with a caption, and thus seen as table by Pandoc. (https://pandoc.org/MANUAL.html#tables)

The LOFT is built with a Lua filter that apply on the AST for Table element. A table in HTML is seen as Raw HTML by Pandoc and thus not scan for the reference to link to.

We would need to see how the Lua filter can be improve to support such tables.

RLesur commented 4 years ago

Another option would be to replace the LOFT Pandoc filter with a Paged.js hook.

cderv commented 4 years ago

Oh yes. could be easier maybe ? And JS easier to maintain than Lua filter ? 😅

vidonne commented 3 years ago

Same issue for our unhcr-report that we plan to use organization wide for reproductible analysis and reporting. We need to apply some classes to the tables them following our brand style but then they don't show up in the LoT. knitr::kable(ref_idp_table, table.attr = "class=\"table\"", format = "html")

cderv commented 3 years ago

@vidonne thanks for sharing. This is something we indeed need to support more easily.

One thing is that Pandoc supports attributes for tables, but currently the Markdown syntax does not support it (https://github.com/jgm/pandoc/issues/6317).

On R Markdown side, knitr::kable with format HTML is indeed the easiest to add classes but currently as a limitation of pagedown, it won't be picked up in the LOT.

As a work around for now, I think it can be done with post processing using Javascript or maybe a Lua filter to add the class you need to the tables. Using Fenced divs to help identify the div with tables.

Or maybe just wrap the table in fenced divs and modify the css. as example

---
title: "R Notebook"
output: 
  html_document: default
---

::: table-striped-blue
```{r, echo = FALSE}
knitr::kable(mtcars, caption = "A table")

:::

div.table-striped-blue > table > tbody > tr:nth-of-type(odd) {
  color: red;
}


Sorry for this limitation. We plan to fix that in the future.
atusy commented 3 years ago

@vidonne

If you use pandoc 2.10.1 or later, you can add classes to tables by lua filters

Example Rmd ```` --- title: "Untitled" output: pagedown::html_paged: pandoc_args: null - --lua-filter - class_table.lua --- # Tables automatically gains the `table` classes ```{r, results='asis', echo=FALSE} knitr::kable(mtcars[1, 1:2]) ``` # Table gains inherit classes from wrapping Div ```{r, results='asis', echo=FALSE} cat("::: {.special}") knitr::kable(mtcars[1, 1:2]) cat(":::") ``` # Lua filters Remove the first function if you do not want to add the `table` class to all the tables. Instead, you wrap a table with a Div element with the `table` class. ```{cat, engine.opts=list(file = "class_table.lua"), eval = TRUE} -- add table class to tables function Table(elem) table.insert(elem.attr.classes, "table") return elem end -- add arbitrary classes to tables function Div(elem) local content = elem.content if (#content == 1) and (content[1].tag == "Table") then for _,class in ipairs(elem.classes) do table.insert(content[1].attr.classes, class) end return content[1] end end ``` ````
vidonne commented 3 years ago

@cderv Thanks fixed it with some fenced div.

markanewman commented 2 years ago

Further refining @cderv's comment, the below hack might work for others until a proper lua/JS solution is found. It puts a no-row table directly above the real table. This seems to keep the LoT working, keep bookdown's @references working, keep bookdown's auto numbering working, and allows for the use of kableExtra in most cases.

---
title: "foo"
lot: true
output:
  pagedown::html_paged
---

```{css, echo = FALSE}
table {
  width: 100%;
}
div.table-norow > table {
  border-top: 0px;
  border-bottom: 0px;
}
add_lot_link <- function(caption) {
  t1 <- data.frame(x = c(1))
  t1 <- knitr::kable(t1[F,], caption = caption, format = 'pipe', col.names = c(' '))
  t1 <- c('::: table-norow', '', t1, '', ':::')
  attributes(t1) <- list(format = 'pipe', class = 'knitr_kable')
  t1
}

Iris {.chapter}

Has an entry in LoT

Reference to Tables \@ref(tab:table1) and \@ref(tab:table2).

add_lot_link(caption = 'An example table 1.')
knitr::kable(head(iris[, -5]), format = 'html')

\newpage

knitr::kable(head(iris[, -5]), caption = 'An example table 2.', format = 'pipe')