kable produces malformed reference links within lapply function in blogdown - r

I am using blogdown to to create a blogpost that has a series of tables. Creating a single table using the kable function works fine. If you do
blogdown::new_site()
blogdown::new_post("test", ext = ".rmd")
A new rmd file will be created within the content/post directory of the project. If you open that file and create a single table by doing
```{r test1}
library(knitr)
library(magrittr)
library(shiny)
data.frame(a= c(1,2,3)) %>% kable(caption = 'test',format = 'html')
```
A correctly formatted table will be generated. The caption will read "
Table 1: test" If you look at the code of the generated site, the caption will look like this.
<caption>
<span id="tab:test1">Table 1: </span>test
</caption>
Ideally I don't have any desire to label the table as Table 1 in the first place but that is another question. If formatting of captions by kable can be disabled entirely, I'd also be happy.
However if I use lapply to generate 2 tables instead
```{r test2}
lapply(1:2,function(x){
data.frame(a= c(1,2,3)) %>% kable(caption = 'test2',format = 'html') %>% HTML()
}) -> tables
tables[[1]]
tables[[2]]
```
The captions will have the prefix \#tab:test2. If you look at the caption of these tables, you'll see
<caption>(\#tab:test2)test2</caption>
The question is, why kable behaves differently when its called from a lapply compared to its behaviour outside? Note that both of these behaviours are different that its behaviour when simply knitting the file as an html_document.
I did some digging into the kable's code and found that the caption link is created by the knitr:::create_label function. Looking into this function, I saw the part that is responsible for the wrong behaviour seen with the multiple tables.
if (isTRUE(opts_knit$get("bookdown.internal.label"))) {
lab1 = "(\\#"
lab2 = ")"
}
I could not find the code, responsible for the "correct" behaviour with the single table but it seems like knitr internal options are responsible.
Ultimately the behaviour that I want is simply
<caption>test</caption>
which is the behaviour when simply knitting an html document. But I am yet to find a way to set the relevant knitr options and why are they different within the same document.
Edit: Further examination suggests that the issue isn't lapply specific. It can be replicated using a for loop or even { by itself. A complete post with all the problematic examples can be acquired from this issue on knitr's github page. This github repo includes the basic blogdown site that replicates the issue

Turns out the responsible party is not the lapply call but the HTML call at the end. It seems like the regular process by knitr in blogdown and bookdown is to have a temporary marker for the table references in the form of (\#tab:label) and replace it with the appropriate syntax later in the processing.
I was using the HTML call to be able to use the tags object in shiny/htmltools to bind the tables together. This approach seems to make the process of replacing the temporary marker impossible for reasons outside my understanding. For my own purposes I was able to remove the temporary marker all together to get rid of both malformed captions and the working-as-intended table numbers by doing
remove_table_numbers = function(table){
old_attributes = attributes(table)
table %<>% as.character() %>% gsub("\\(\\\\#tab:.*?\\)","",.)
attributes(table) = old_attributes
return(table)
}
data.frame(a= c(1,2,3)) %>% kable(caption = 'test',format = 'html') %>% remove_table_numbers
This question still would benefit from a proper explanation of the reference link placement process and if its possible to apply it to tables in HTML calls as well. But for know this solves my issue. I'll gladly switch the accepted answer if a more complete explanation appears

Related

Create a carousel in Rmarkdown?

Is there any quick and easy way to create a simple carousel in an Rmarkdown doc?
What I know so far
I found slickr but run into errors setting options and knitting (the errors could be specific to me / mac - I am not sure at this point).
I believe it would be possible to hard code html/javascript into the RMarkdown doc i.e. the same way a carousel would be done in any other (regular) html document (i.e. using the html code here)- but I wonder if there's a native (R) way?
Example use
In my particular use case, I'm trying to display multiple complicated ggplots which are each sufficiently complex to make them require their own space (i.e. not faceted or grid.arrange as the size of each plot will get too small to read
Notes
Here is the slickr code I tried
library(texPreview)
library(slickR)
objpath <- file.path(getwd(),"slickr_files/figure-html")
if(!dir.exists(objpath)) { dir.create(objpath,recursive = TRUE) }
tex_opts$set(
fileDir = objpath, # path to save output
returnType = 'html', # return images ready for html
imgFormat = 'png' # return png images
)
knitr::kable(mtcars,'latex') %>%
texPreview::tex_preview(stem = 'kable-1')
# ! LaTeX Error: File `standalone.cls' not found.
A side note, if there's a better way of providing many (e.g. > 3) large, detailed plots that doesn't involve faceting, grid.arrange, or (my current preferred option) tabbing, please give a suggestion as a comment
The example works fine for me. Be sure to save your plots in the folder slickr_files/figure-html.
Then run:
```{r}
slickR::slickR(
list.files(objpath,full.names = TRUE,pattern = 'png'),
height = 200,
width = '95%')
```

Generating a table in word from rmarkdown using the flextable package error

I have been trying to generate a table in R Markdown with output to word looking like this (a very common table format for chemical sciences):
I started with kable using markdown syntax to get the subscripts etc (eg. [FeBr~2~(dpbz)~2~]) which worked in the word document file. However, i could not modify the table design and most importantly i could not figure out how to get the headings to display properly. So i moved on using the flextable package. Here is my code so far (still work in progress):
```{r DipUVvis,echo=FALSE, anchor='Table S', tab.cap="Summary of catalytic reactions monitored with *in situ* UV-Vis spectroscopy."}
df<-data.frame(Entry=c('AMM 51^*a*^','AMM 52^*a*^','AMM 53^*a*^','AMM 54^*a*^','AMM 57^*b*^','AMM 58^*c*^','AMM 59^*d*^'),
Precat=c('[FeBr~2~(dpbz)~2~] (4.00)','[FeBr~2~(dpbz)~2~] (2.00)','[FeBr~2~(dpbz)~2~] (1.00)','[FeBr~2~(dpbz)~2~] (0.50)','[FeBr~2~(dpbz)~2~] (2.00)','[FeBr(dpbz)~2~] (1.00)','[FeBr~2~(dpbz)~2~] (2.00)'),
Nucl=c('Zn(4-tolyl)~2~/2 MgBr~2~ (100)','Zn(4-tolyl)~2~/2 MgBr~2~ (100)','Zn(4-tolyl)~2~/2 MgBr~2~ (100)','Zn(4-tolyl)~2~/2 MgBr~2~ (100)','Zn(4-tolyl)~2~/2 MgBr~2~ (100)','Zn(4-tolyl)~2~/2 MgBr~2~ (100)','Zn(4-tolyl)~2~/2 MgBr~2~ (100)'),
BnBr=c(0,0,0,0,'42 + 42',42,42))
tbl<-regulartable(df)
tbl<-set_header_labels(tbl,Entry='Entry',Precat='Pre-catalyst (mM)',Nucl='Nucleophile (mM)',BnBr='BnBr (mM)')
tbl <- align( tbl, align = "center", part = "all" )
tbl<-autofit(tbl)
tbl
```
This took care of the headers and with a bit of setting the rest parameters i think i can get the table to look like in the picture above. The resulting table looks fine in the Rstudio console from a formatting perspective:
However, there are two major issues:
1) The subscripts/superscripts are not being translated.
2) When i Knit to word, instead of a table i get 5 pages of code, which from my understanding must be the html code?
After many hours of trying to sort this out, i found that one possible cause is R studio using an old version of pandoc (https://github.com/davidgohel/flextable/issues/34). Indeed that was the case for me so i changed it by moving the new installed files of pandoc in the correct directory (where r studio is looking) and renaming. This must have worked now (see second figure console section). However it didnt change anything. Then i tried adding in my code:
knit_print(tbl)
This keeps giving an error:
Error in knit_print.flextable(tbl) : render_flextable needs to be used as a renderer for a knitr/rmarkdown R code chunk (render by rmarkdown).
Interestingly, when i removed the last line from the r chunk in R studio (tbl) and added the following below the r chunk (not in it):
`r tbl`
The table was generated in word (of course i still didnt get the subscripts and superscripts right). It also had the Figure caption on the top and not the bottom as a desirable side effect of generating the table after the main r chunk.
Any ideas of what is going on and how can i get the correct table output in word? Really confused here, so thank you in advance for your help.
UPDATE: If i remove the anchor = 'Table S' from the chunk header the table comes out ok (still without the subscripts or superscripts though) but then i cant automatically number the tables (i have used this: https://gist.github.com/benmarwick/f3e0cafe668f3d6ff6e5 for autonumbering and cross referencing).

Which knitr hooks are invoked when a DiagrammeR graph is rendered in rmarkdown?

I have an RMarkdown document where I use data.tree and DiagrammeR to generate models. I then display these using a set-up similar to the one used in How to include DiagrammeR/mermaid flowchart in a Rmarkdown file
For example:
```{r fig.cap="Structureel model bij enkelvoudige regressie.", fig.with=4, fig.height=1}
drawStructuralModel <- function(covariates, criterion) {
### Create tree
res <- Node$new(criterion);
for (covariate in covariates) {
res$AddChild(covariate);
}
### Set display settings
SetEdgeStyle(res, dir='back');
res <- ToDiagrammeRGraph(res, direction = "descend");
res <- add_global_graph_attrs(res, "layout", "dot", "graph");
res <- add_global_graph_attrs(res, "rankdir", "RL", "graph");
### Draw and return tree
render_graph(res);
}
drawStructuralModel("X", "Y");
```
So far so good. The caption text is added, which is what you'd expect.
Except :-)
Above, in the 'setup' knitr chunk, I used setFigCapNumbering from userfriendlyscience (see https://github.com/Matherion/userfriendlyscience/blob/master/R/setFigCapNumbering.R). This function uses knit_hooks$set to set a hook for plots, so that the captions are automatically numbered.
But this numbering isn't applied to the DiagrammeR output.
I guess that makes sense, since it's not actually a plot, rather an HTML widget or some SVG or so. I would still like it to be numbered as a figure, though.
But how do I find out which hook knitr invokes when DiagrammeR output is generated?
I could always resort to using the more generic 'automatic caption' function setCaptionNumbering (https://github.com/Matherion/userfriendlyscience/blob/master/R/setCaptionNumbering.R), and tell it to use the same counter option as the figure caption thingy uses. That would sidestep the issue, but I'd prefer to modify the appropriate knitr hook.
And since this problem (figuring out which hook knitr uses for output produced by a given function) probably occurs more often, I thought it would be worth opening an SA question.
Does anybody know how you can find this out?
knitr calls knit_print on the output produced by a given chunk. This then calls the appropriate method based on the class of the output. You can find out what methods are available by running methods("knit_print"), then see if any of those match the class of the output from DiagrammeR.
Looking at your example, I'm guessing the class of your output is "DiagrammeR" "htmlwidget", so knitr is calling knit_print.htmlwidget.
Digging into that source code, it calls htmltools::knit_print.html, which wraps the tags and then outputs asis. So to answer your question, it uses the default hooks for asis output in whatever output format you're using.

Source code from Rmd file within another Rmd

I'm attempting to make my code more modular: data loading and cleaning in one script, analysis in another, etc. If I were using R scripts, this would be a simple matter of calling source on data_setup.R inside analysis.R, but I'd like to document the decisions I'm making in an Rmarkdown document for both data setup and analysis. So I'm trying to write some sort of source_rmd function that will allow me to source the code from data_setup.Rmd into analysis.Rmd.
What I've tried so far:
The answer to How to source R Markdown file like `source('myfile.r')`? doesn't work if there are any repeated chunk names (a problem since the chunk named setup has special behavior in Rstudio's notebook handling). How to combine two RMarkdown (.Rmd) files into a single output? wants to combine entire documents, not just the code from one, and also requires unique chunk names. I've tried using knit_expand as recommended in Generate Dynamic R Markdown Blocks, but I have to name chunks with variables in double curly-braces, and I'd really like a way to make this easy for my colaborators to use as well. And using knit_child as recommended in How to nest knit calls to fix duplicate chunk label errors? still gives me duplicate label errors.
After some further searching, I've found a solution. There is a package option in knitr that can be set to change the behavior for handling duplicate chunks, appending a number after their label rather than failing with an error. See https://github.com/yihui/knitr/issues/957.
To set this option, use options(knitr.duplicate.label = 'allow').
For the sake of completeness, the full code for the function I've written is
source_rmd <- function(file, local = FALSE, ...){
options(knitr.duplicate.label = 'allow')
tempR <- tempfile(tmpdir = ".", fileext = ".R")
on.exit(unlink(tempR))
knitr::purl(file, output=tempR, quiet = TRUE)
envir <- globalenv()
source(tempR, local = envir, ...)
}

Add native knitr print methods

I'm looking for a way to adjust functions which usually show html tables in the viewer or browser in a way that they automatically insert the html in knitr documents like rnotebooks when called.
Specifically I want to change the way functions in the package sjPlot behave. At the moment they return an object with a $knitr attribute that has to be inserted manually and then produce an html table in the viewer:
`r sjt.frq(efc$e42dep, no.output=TRUE)$knitr`
One of these functions is sjt.frq. Is there a way to do this?
From knit_print:
library(knitr)
a = 42
class(a) = "my_class"
knit_print.my_class = function(x,...){
res = paste("{{", x,"}}")
asis_output(res)
}
a
It works when I knit document but doesn't work with RNotebooks and doesn't work with sjt.frq. However with RNotebook works the following statement:
library(sjPlot)
library(sjmisc)
library(knitr)
data(efc)
asis_output(sjt.frq(efc$e42dep, no.output=TRUE)$knitr)

Resources