How to ref stargazer tables in RMarkdown? - r

It seems that stargazer tables cannot be referenced in RMarkdown anymore.
I have unsuccessfully tried to implement the workarounds posted on the github page that refer to this problem https://github.com/rstudio/bookdown/issues/175
---
title: "Ref Stargazer Test"
output:
bookdown::html_document2: default
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r results='asis'}
m1 <- lm(mpg ~ cyl + disp, mtcars)
stargazer::stargazer(m1, type = "html", label = "tab:model")
```
Table \#ref(tab:model) should show something on cars.
```{r mytab, results="asis"}
stargazer::stargazer(attitude,
type=ifelse(knitr::is_latex_output(),"latex","html"),
label=knitr::opts_current$get("label"),
title="Stargazer <3 Bookdown")
```
As Table \#ref(tab:mytab) shows, relationships may be hard work but love finds a way.
The referencing does not work as of July 2021 (rmarkdown 2.9, bookdown 0.22, stargazer 5.2.2).
Is there another workaround that works?

I don't know how to achieve this with stargazer. I will note that bookdown cross-references are a pretty recent feature, and that stargazer has not been updated in over 3 years, so issues are bound to arise.
One more modern alternative is the modelsummary package (disclaimer: I am the maintainer). In my biased opinion, this package is more flexible and robust, but YMMV.
Below I paste a minimal example of Rmarkdown document with cross-references. A couple things to note:
modelsummary detects the output format automatically, so you only need to specify LaTeX or HTML in the YAML header at the very top of your Rmarkdown document. No need to use the output argument of modelsummary (but check out the documentation anyway!).
The table label is set by the name of the chunk. Here, it is called "model", so we use tab:model as a cross-reference.
Your table needs a title, otherwise cross-references won't show up consistently.
---
title: "modelsummary cross-reference test"
output:
bookdown::html_document2: default
---
```{r model}
library(modelsummary)
m1 <- lm(mpg ~ cyl + disp, mtcars)
modelsummary(m1, title = "A table title")
```
Table \#ref(tab:model) should show something on cars.

I have found a solution myself that works for LaTeX and HTML.
---
title: "Ref Stargazer Test"
output:
bookdown::html_document2: default
---
Table \#ref(tab:mytable) is the referenced table.
```{r mytable, results='asis', fig.cap="This is my table."}
m1 <- lm(mpg ~ cyl + disp, mtcars)
# Use title caption from fig.cap
tit <- knitr::opts_current$get("fig.cap")
# Adding caption for html output
tit_html <- paste0('<span id="tab:',
knitr::opts_current$get("label"),
'">(#tab:',
knitr::opts_current$get("label"),
')</span>',
tit)
stargazer::stargazer(m1,
label = paste0("tab:", knitr::opts_current$get("label")),
title = ifelse(knitr::is_latex_output(), tit, tit_html),
type = ifelse(knitr::is_latex_output(),"latex","html"),
header = F
)
```
You can now also use the fig.cap argument in the chunk header to write the title you want to have for your table. For referencing, you have to refer to the chunk label (in this case "mytable"). The title argument in stargazer creates the <caption> element, this is why the html title is inserted there.

A simple way of solving this is by adding manually your table's name on stargazer.
label = "tab:table4"
So your code should look something like this:
stargazer(m1, label = "tab:mytable")
And now you will be able to cross reference as usual in Rmarkdown \ref{tab:mytable}

Related

How do I get Bookdown to properly knit a PDF with multiple code chunks?

I am transitioning to Bookdown from Markdown. Although it seems as though this should be straightforward I am getting an unexpected knit failure once I have added the 3rd (usually) code chunk in a chapter (not index.rmd) file. I have tried using code from the example code by Allaire and Xie with the same result. The problem does not occur if all the markdown code is in one file i.e. no chapters. Here is the sample code from the index and 1st chapter files. Sorry about the formatting; I'm not sure how to format markdown code in stackoverflow so the 3 back tics consistently show.
---
classoption: openany # Removes blank pages (Arrgh!!)
site: "bookdown::bookdown_site"
output:
bookdown::tufte_book2:
latex_engine: xelatex
---
```{r setup, include=FALSE}
library(ggplot2)
# invalidate cache when the tufte version changes
knitr::opts_chunk$set(tidy = FALSE, cache.extra = packageVersion("tufte"))
```
And this is the first chapter code:
# Figures
## Margin Figures
Images and graphics play an integral role in Tufte's work. To place figures in the margin you can use the **knitr** chunk option `fig.margin = TRUE`. For example:
```{r fig-margin, fig.margin = TRUE, fig.cap = "MPG vs horsepower, colored by transmission.", fig.width=3.5, fig.height=3.5, cache=TRUE, message=FALSE}
library(ggplot2)
mtcars2 <- mtcars
mtcars2$am <- factor(
mtcars$am, labels = c('automatic', 'manual')
)
ggplot(mtcars2, aes(hp, mpg, color = am)) +
geom_point() + geom_smooth() +
theme(legend.position = 'bottom')
```
In fact, you can include anything in the margin using the **knitr** engine named `marginfigure`. Unlike R code chunks ```` ```{r} ````, you write a chunk starting with ```` ```{marginfigure} ```` instead, then put the content in the chunk. See an example on the right about the first fundamental theorem of calculus.
```{marginfigure}
We know from _the first fundamental theorem of calculus_ that for $x$ in $[a, b]$:
$$\frac{d}{dx}\left( \int_{a}^{x} f(u)\,du\right)=f(x).$$
```
It fails here
knitr::kable(
mtcars[1:6, 1:6], caption = 'A subset of mtcars.'
)
Deleting the code after "It fails here" makes it knit properly for me.
Dropbox link with scripts, log, and pdf's.

Cross-referencing a table or figure in rmarkdown in the caption of another figure or table

I am producing a rmarkdown document, knitting to PDF and have a figure (figure 1) and a table (table 1) where the table explains the figure in more detail. I have no issue giving either of them a standard caption but I would like to change the table caption to be "Explanation of Figure 1". Is there any way of doing this?
The code chunks are listed below, please let me know if I need to provide more information:
YAML:
- \usepackage{caption} #and several others
output:
bookdown::pdf_document2:
keep_tex: no
latex_engine: xelatex
Code Chunks:
Figure 1:
```{r figure-1, fig.cap="Figure"}
ggplot()
```
Table 1:
```{r table, fig.cap="Explanation of Figure \#ref(fig:figure-1)"}
knitr
kableExtra::kable(caption = "Explanation of Figure \#ref(fig:figure-1)")
```
The main error message with one backslash is "Error: '#' is an unrecognized escape in character string" and suggests I forgot to quote character options, which is not true.
With two backslashes the document knits but produces the caption "Explanation of Figure reffig:table"
3 backslashes: the same error as with 1.
4 backslashes: the error is "pandoc-citeproc: reference ref not found. ! Package caption Error: \caption outside float."
Appreciate any suggestions!
Just a workaround, but may helps.
The \\#ref(fig:xxx) option works well when knitting to a html_document2.
To me pdf - creation worked fine when using pandoc in the terminal.
E.g.:
---
title: "Cross ref"
output:
bookdown::html_document2:
collapsed: no
theme: readable
toc: yes
link-citations: yes
---
```{r firstplot, fig.cap = "A plot with points." }
library(ggplot2)
plot_A = ggplot(data = data.frame(x = c(1:10),
y = seq(3, 8, length.out = 10)),
aes(x = x, y =y))+
geom_point()
plot_A
```
Now a second plot with a reference to Fig.: \#ref(fig:firstplot).
```{r secondplot, fig.cap = "This is the same as Fig.: \\#ref(fig:firstplot)
but now with a red line." }
library(ggplot2)
plot_A + geom_line(alpha = .75,col = "red")
```
after knitting just move to the folder containing the html and using pandoc
pandoc mini_ex-crossref.html -o mini_ex.pdf
I tried many different approaches text references, chunk captions, caption argument in the kable function and I´m sure there is a clever solution somewhere, so here is just a workaround with pure Latex.
Add a latex chunk with a label before the chunk with the figure:
```{=latex}
\begin{figure}
\caption{Figure 1}
\label{Fig-1}
```
```{r figure-1, echo = FALSE}
ggplot(mtcars) +
geom_point(aes(cyl, gear))
```
```{=latex}
\end{figure}
```
Now you can refer to Fig-1 in your latex-caption for the table with normal latex code \ref{Fig-1}:
```{=latex}
\begin{table}
\caption{Explanation of Figure \ref{Fig-1}}
```
```{r table}
kableExtra::kable(x = mtcars)
```
```{=latex}
\end{table}
```
Notes:
* In my opinion this is just a workaround.
* It´s not possible to use the chunk option fig.cap = "" and the latex code in parallel
J_F referenced Yihui Xie's excellent explanation of using text references in RMarkdown (https://bookdown.org/yihui/bookdown/markdown-extensions-by-bookdown.html#text-references), which you can use for figure and table captions that require more complicated things than plain text (e.g., formatting, cross-references, etc.). This may be a more flexible solution overall than remembering to escape the backslash in Robert's answer, and does not require a workaround with LaTeX.
As Yihui explains, all you need to do is define a text reference on a single line in markdown and reference that in the chunk option "fig.cap" or the "caption" parameter in knitr::kable(). Just be careful to make sure that each text reference is one paragraph that does not end in a white space.
Here's a basic example.
---
title: "Cross-referencing figures and tables within captions."
output: bookdown::pdf_document2
editor_options:
chunk_output_type: console
---
```{r load-packages}
library(knitr)
library(flextable)
```
(ref:first-fig-caption) Here's a complicated figure caption for the first figure, which can include complicated text styling like $m^2$ and references to other elements in the document, like Table \#ref(tab:mtcars) or Fig. \#ref(fig:cars).
```{r pressure, fig.cap = '(ref:first-fig-caption)'}
plot(pressure)
```
(ref:second-fig-caption) Here's a second complicated figure caption, also referencing Table \#ref(tab:mtcars).
```{r cars, fig.cap = '(ref:second-fig-caption)'}
plot(cars)
```
(ref:caption-table1) A caption for the first table. Check out this cross reference to Fig. \#ref(fig:pressure).
```{r mtcars}
mtcars |>
head() |>
kable(caption = '(ref:caption-table1)')
```

P-values significance not showed in stargazer html regression table

I am having trouble with the Notes significance (asterisks) not appearing when using stargazer to format html tables. The result is ok when using latex.
Here is my source file "teste.Rmd"
---
title: "Untitled"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r data}
#some data
set.seed(123)
X = rnorm(500,10,3)
Y = 10+ 3*I(X^1.2) + rnorm(500)
# models
m1 = lm(Y~X)
m2 = lm(Y~X+I(X^2))
```
```{r res,warning=FALSE,message=FALSE,results='asis'}
library(stargazer)
stargazer(m1,m2,type = 'html',title = 'Models' )
```
The result is below
The same with latex produces this
As you can see the asterisks in Notes are formatted correctly with latex but not with html option. How to get the same behavior with html?
Maybe it is a bug as #jaySf said in the comments to the original question. But based on #tmfmnk's answer and htmltools package I ended with a workaround. This is the updated relevant part of the source file.
```{r res,warning=FALSE,message=FALSE,results='hide'}
library(stargazer)
stargazer(m1,m2,type = 'html',title = 'Models', out = "table1.html")
```
```{r, echo=FALSE}
htmltools::includeHTML("table1.html")
```
Now I got the desired result
Try adding customized notes using notes and notes.append parameters as follows:
stargazer(m1,m2,type='html',notes="<span>***</span>: p<0.01; <span>**</span>: p<0.05; <span>*</span>: p<0.1",notes.append=F)
I originally thought that using backslash to escape * will work, e.g. notes="\\*\\*\\*: p<0.01; \\*\\*: p<0.05; \\*: p<0.1". Unfortunately, it doesn't. I also tried to use the HTML code of *, i.e. *, e.g. notes="***: p<0.01; **: p<0.05; *: p<0.1". Still it doesn't work.
However, surrounding * with an HTML tag works. It doesn't have to be <span></span>. I tried <b></b>, etc. and they worked.
When exported through out it is working fine:
stargazer(m1,m2,type = 'html',
title = 'Models',
out = "/path/table.html")

How to show significance stars in R Markdown (rmarkdown) html output notes?

I want to show regression outputs in HTML documents using R Markdown. I tried the texreg and stargazerpackages. My problem is now, that in the notes I can't bring the significance stars to life. Due to automatic generation it seems I can't escape them. I've been puzzling around with this and this but with no success. What am I missing? Thanks a lot!!
Here's some code:
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r data}
library(car)
lm1 <- lm(prestige ~ income + education, data=Duncan)
```
## with STARGAZER
```{r table1, results = "asis", message=FALSE}
library(stargazer)
stargazer(lm1, type="html", notes="stargazer html 1") # nothing
stargazer(lm1, type="html", notes="stargazer html 2", star.char = "\\*") # nothing, even gone in table
```
## with TEXREG
```{r table2, results = "asis", message=FALSE}
library(texreg)
htmlreg(lm1, custom.note="%stars. htmlreg") # nothing
htmlreg(lm1, custom.note="%stars. htmlreg", star.symbol = "\\*") # still nothing!
```
Note: Question was a former sub-question I have now splitted.
Use the HTML entity for the asterisk:
star.symbol='*'
See http://www.ascii.cl/htmlcodes.htm.
You could also add the "legend" manually:
stargazer(lm1, type="html", notes = "<em>*p<0.1;**p<0.05;***p<0.01</em>", notes.append = F)

Print RMarkdown captions from a loop

I am creating a series of plots from within a loop in an RMarkdown document, then knitting this to a PDF. I can do this without any problem, but I would like the caption to reflect the change between each plot. A MWE is shown below:
---
title: "Caption loop"
output: pdf_document
---
```{r, echo=FALSE}
library(tidyverse)
p <-
map(names(mtcars), ~ggplot(mtcars) +
geom_point(aes_string(x = 'mpg', y = .))) %>%
set_names(names(mtcars))
```
```{r loops, fig.cap=paste(for(i in seq_along(p)) print(names(p)[[i]])), echo=FALSE}
for(i in seq_along(p)) p[[i]] %>% print
```
I have made a first attempt at capturing the plots and storing in a variable p, and trying to use that to generate the captions, but this isn't working. I haven't found too much about this on SO, despite this surely being something many people would need to do. I did find this question, but it looks so complicated that I was wondering if there is a clear and simple solution that I am missing.
I wondered if it has something to do with eval.after, as with this question, but that does not involve plots generated within a loop.
many thanks for your help!
It seems that knitr is smart enough to do the task automatically. By adding names(mtcars) to the figure caption, knitr iterates through these in turn to produce the correct caption. The only problem now is how to stop all of the list indexes from printing in the document...
---
title: "Caption loop"
output: pdf_document
---
```{r loops, fig.cap=paste("Graph of mpg vs.", names(mtcars)), message=FALSE, echo=FALSE, warning=FALSE}
library(tidyverse)
map(
names(mtcars),
~ ggplot(mtcars) +
geom_point(aes_string(x = 'mpg', y = .))
)
```
In case this might be useful to somebody. Here is an adaptation of Jonny's solution for captions without printing list indices. This can be achieved by using purrr::walk instead of purrr::map. Also included is a latex fig label and text that references each plot.
---
title: "Loop figures with captions"
output:
pdf_document
---
```{r loops, fig.cap=paste(sprintf("\\label{%s}", names(mtcars)), "Graph of mpg vs.", names(mtcars)),results='asis', message=FALSE, echo=FALSE, warning=FALSE}
library(tidyverse)
library(stringi)
walk(names(mtcars),
~{
p <- ggplot(mtcars) +
geom_point(aes_string(x = 'mpg', y = .))
#print plot
cat('\n\n')
print(p)
#print text with refernce to plot
cat('\n\n')
cat(sprintf("Figure \\ref{%s} is a Graph of mpg vs. %s. %s \n\n", ., .,
stri_rand_lipsum(1)))
cat("\\clearpage")
})
```

Resources