haozhu233 / kableExtra

Construct Complex Table with knitr::kable() + pipe.
https://haozhu233.github.io/kableExtra/
Other
688 stars 147 forks source link

kable_classic now creates HTML when kbl format is "pipe" #824

Closed joshuaulrich closed 7 months ago

joshuaulrich commented 7 months ago

In version 1.3.4 kable_classic created a pipe-delimited text table when the knitr_kable object's format is "pipe". It creates a HTML table in version 1.4.0. I'm not sure if this is a regression or an intended change.

library(kableExtra, lib.loc = .libPaths()[1])
packageVersion("kableExtra")
## [1] '1.3.4'

stats <- structure(list(Full = c(0.065, 0.084, 0.779, -0.227)),
       row.names = c("Annualized Return",  "Annualized Std Dev",
                     "Annualized Sharpe (Rf=0%)", "Worst Drawdown"),
       class = "data.frame")

tbl <- kbl(stats,
           format = "pipe",
           linesep = "",
           escape = TRUE)
kable_classic(tbl, full_width = FALSE) 

## |                          |   Full|
## |:-------------------------|------:|
## |Annualized Return         |  0.065|
## |Annualized Std Dev        |  0.084|
## |Annualized Sharpe (Rf=0%) |  0.779|
## |Worst Drawdown            | -0.227|

detach("package:kableExtra")
library(kableExtra, lib.loc = .libPaths()[3])
packageVersion("kableExtra")
## [1] '1.4.0'

kable_classic(tbl, full_width = FALSE) 

## <table class=" lightable-classic" style='font-family: "Arial Narrow", "Source Sans Pro", sans-serif; width: auto !important; margin-left:     auto; margin-right: auto;'>
##  <thead>
##   <tr>
##    <th style="text-align:left;">  </th>
##    <th style="text-align:right;"> Full </th>
##   </tr>
##  </thead>
## <tbody>
##   <tr>
##    <td style="text-align:left;"> Annualized Return </td>
##    <td style="text-align:right;"> 0.065 </td>
##   </tr>
##   <tr>
##    <td style="text-align:left;"> Annualized Std Dev </td>
##    <td style="text-align:right;"> 0.084 </td>
##   </tr>
##   <tr>
##    <td style="text-align:left;"> Annualized Sharpe (Rf=0%) </td>
##    <td style="text-align:right;"> 0.779 </td>
##   </tr>
##   <tr>
##    <td style="text-align:left;"> Worst Drawdown </td>
##    <td style="text-align:right;"> -0.227 </td>
##   </tr>
## </tbody>
## </table>

This matters for me because I knit the same document as PDF (to send to others for feedback) and markdown (for Hugo). The call to kable_classic() throws an error when rendering markdown because I use md_document(preserve_yaml = TRUE, pandoc_args = c("--to=markdown_strict+[other args]")) when creating the markdown document for Hugo.

I use this command to knit:

Rscript -e 'rmarkdown::render("input.Rmd", rmarkdown::md_document(preserve_yaml = TRUE, pandoc_args = c("--to=markdown_strict+all_symbols_escapable+backtick_code_blocks+fenced_code_blocks+space_in_atx_header+intraword_underscores+lists_without_preceding_blankline+shortcut_reference_links+pipe_tables+strikeout+autolink_bare_uris+task_lists+definition_lists+footnotes+smart+tex_math_dollars", "--wrap=none")), "output.md")'

The error is:

Error: Functions that produce HTML output found in document targeting markdown_strict-yaml_metadata_block output. Please change the output type of this document to HTML. If your aiming to have some HTML widgets shown in non-HTML format as a screenshot, please install webshot or webshot2 R package for knitr to do the screenshot. Alternatively, you can allow HTML output in non-HTML formats by adding this option to the YAML front-matter of your rmarkdown file:

always_allow_html: true

Note however that the HTML output will not be visible in non-HTML formats.

I can't us always_allow_html: true because then the tables do not appear in output.md. Here's my full Rmd:

---
title: kable_classic 
author: Joshua Ulrich
output: md_document
---

Please knit this document with the following command:

Rscript -e 'rmarkdown::render("input.Rmd", rmarkdown::md_document(preserve_yaml = TRUE, pandoc_args = c("--to=markdown_strict+all_symbols_escapable+backtick_code_blocks+fenced_code_blocks+space_in_atx_header+intraword_underscores+lists_without_preceding_blankline+shortcut_reference_links+pipe_tables+strikeout+autolink_bare_uris+task_lists+definition_lists+footnotes+smart+tex_math_dollars", "--wrap=none")), "output.md")'


This produces a pipe-delimited markdown table in kableExtra_1.3.4

```{r kbl_1.3.4, eval=TRUE}
library(kableExtra, lib.loc = .libPaths()[1])
packageVersion("kableExtra")

stats <- structure(list(Full = c(0.065, 0.084, 0.779, -0.227)),
       row.names = c("Annualized Return",  "Annualized Std Dev",
                     "Annualized Sharpe (Rf=0%)", "Worst Drawdown"),
       class = "data.frame")

tbl <- kbl(stats,
           format = "pipe",
           linesep = "",
           escape = TRUE)

kable_classic(tbl, full_width = FALSE)

...but creates an HTML table in kableExtra_1.4.0.

detach("package:kableExtra")
library(kableExtra, lib.loc = .libPaths()[3])
packageVersion("kableExtra")

# produces HTML table (and errors, but not in try() for some reason)
#error <- try({
    kable_classic(tbl, full_width = FALSE)
#})
#print(error)
dmurdoch commented 7 months ago

kable_classic() is documented to be a way to obtain an alternate HTML theme, so it makes sense that the output should be HTML.

To do what you want, I think you'll have to write your own wrapper, something like this:

old_kable_classic <- function(kable_input, ...) {
  if (attr(kable_input, "format") == "pipe") kable_input else kable_classic(kable_input, ...)
}
joshuaulrich commented 7 months ago

Thanks for the quick reply! I figured it was a bug fix based on the documentation, but wanted to report it in case kable_classic() was supposed to do what your wrapper does.