I have several pre-made figures, which I'd like to add to a latex document that I'm preparing with knitr.
What is the best strategy to add them using something like a for loop?
Thanks a lot!
My suggestion is to build a data frame to support the meta data about the needed LaTeX figure environments and then use mapply with a custom function to build the needed output. Here is an example .Rnw file
\documentclass{article}
\usepackage{hyperref,fullpage}
\hypersetup{
colorlinks=true,
linkcolor=blue,
filecolor=magenta,
urlcolor=cyan,
}
\begin{document}
Thanks to \url{https://classroomclipart.com} for the graphics.
For displaying several pre-made figures you could write out the figure
environments yourself.
\begin{figure}[!h]
\centering
\caption{Explicit figure environment. \label{fig:00}}
\includegraphics[width=0.2\linewidth]{figs/man-working-on-a-computer-clipart-318.jpg}
\end{figure}
To create many figure environments, I would suggest building a data.frame with
captions, figure labels, options, and file paths:
<<>>=
myfigs <-
data.frame(caption = c("Bright Red Fall Foliage", "Chat 9", "Man On Computer"),
label = c("brff", "c9", "moc"),
option = c("width=0.1\\linewidth", "width=0.2\\linewidth", "width=0.3\\linewidth"),
path = c("figs/bright-red-fall-foliage-photo_8304-Edit.jpg",
"figs/chat-9-94.jpg",
"figs/man-working-on-a-computer-clipart-318.jpg"),
stringsAsFactors = FALSE)
myfigs
#
Build a function for creating a figure environment:
<<>>=
build_fig_env <- function(caption = "", label = "", option = "", path = "") {
cat(
sprintf("\\begin{figure}[!h]\n\\centering\n\\caption{%s \\label{fig:%s}}\n\\includegraphics[%s]{%s}\n\\end{figure}\n\n\n",
caption, label, option, path)
)
}
#
Now call the function using mapply. The mapply call is wrapped in a call to
invisible to suppress the irrelevant output.
<<results = "asis">>=
invisible(
mapply(build_fig_env,
caption = myfigs$caption,
label = myfigs$label,
option = myfigs$option,
path = myfigs$path,
SIMPLIFY = FALSE)
)
#
This is just one solution to your question.
\end{document}
The output looks like this:
Or you can view the pdf here
Related
There are already a few questions considering ggplots in RMarkdown but none has answered my question as how to put a ggplot into a table with kable() by knitr.
I ve tried this link:
How can I embed a plot within a RMarkdown table?
But have not had any luck so far. Any ideas?
The idea was to put all plots into a list with
a<-list(p1,p2,p3...)
and then having the table with
{r}kable(a)
Additional text should also be able to be included
b<-("x","y","z",...)
kable (c(a,b),col.names=c())
Thanks for your help
Frieder
I experimented some with this and the following is the best I could come up with. This is a complete markdown document you should be able to paste into RStudio and hit the Knit button.
Two relevant notes here.
Setting the file links directly into kable doesn't work as it is wrapped in html such that it is interpreted as text, so we need to gsub() it in. An alternative is to set kable(..., escape = FALSE), but it is a risk that other text might cause problems.
Also, the chunk option results = 'asis' is necessary to have the print(kab) return raw html.
I don't know if these are problems for the real application.
---
title: "Untitled"
author: "me"
date: "02/06/2020"
output: html_document
---
```{r, results = 'asis'}
library(ggplot2)
library(svglite)
n <- length(unique(iris$Species))
data <- split(iris, iris$Species)
# Create list of plots
plots <- lapply(data, function(df) {
ggplot(df, aes(Sepal.Width, Sepal.Length)) +
geom_point()
})
# Create temporary files
tmpfiles <- replicate(n, tempfile(fileext = ".svg"))
# Save plots as files, get HTML links
links <- mapply(function(plot, file) {
# Suit exact dimensions to your needs
ggsave(file, plot, device = "svg", width = 4, height = 3)
paste0('<figure><img src="', file, '" style = "width:100%"></figure>')
}, plot = plots, file = tmpfiles)
# Table formatting
tab <- data.frame(name = names(plots), fig = paste0("dummy", LETTERS[seq_len(n)]))
kab <- knitr::kable(tab, "html")
# Substitute dummy column for figure links
for (i in seq_len(n)) {
kab <- gsub(paste0("dummy", LETTERS[i]), links[i], kab, fixed = TRUE)
}
print(kab)
```
I have found my way around it as described in the link I posted.
I. Saved my plot as a picture
II. Used sprintf() to insert picture into table with this command from Rmarkdown:
![](path/to/file)
Poor, but it works. If anybody finds a solution, I will always be interested in smart coding.
I have a data.frame that I need as a nice PDF table for a scientific poster. While it's very easy to export plots via pdf(), I'm stuck with this table.
I know how to get a PDF table with rmarkdown, e.g.
---
output: pdf_document
---
```{r tab, echo=FALSE, results='asis'}
library(xtable)
xtable(head(mtcars))
```
But I want this output directly from the R script, e.g.
renderThisToPDF(xtable(head(mtcars), to="nicetable.pdf") # fantasy code
How would I do this?
So far I attempted this code with a indirection via writeLines
code <- "library(xtable)\nprint(xtable(head(mtcars)))"
fileConn <- file("output.Rmd")
writeLines(cat("---\noutput: pdf_document\n---\n```{r tab, echo=FALSE, results='asis'}\n",
code, "\n```\n"), fileConn)
close(fileConn)
knitr::knit('output.Rmd')
but failed with an error.
Error in writeLines(cat("---\noutput: pdf_document\n---\n```{r tab, echo=FALSE,
results='asis'}\n", :
can only write character objects
I guess there's probably an easier solution?
Here is a possibility, without rmarkdown.
library(xtable)
latex <- print.xtable(xtable(head(iris)), print.results = FALSE)
writeLines(
c(
"\\documentclass[12pt]{article}",
"\\begin{document}",
"\\thispagestyle{empty}",
latex,
"\\end{document}"
),
"table.tex"
)
tools::texi2pdf("table.tex", clean = TRUE)
Or, using the standalone document class:
latex <- print.xtable(xtable(head(iris)), print.results = FALSE,
floating = FALSE)
writeLines(
c(
"\\documentclass[12pt]{standalone}",
"\\usepackage{caption}",
"\\begin{document}",
"\\minipage{\\textwidth}",
latex,
"\\captionof{table}{My caption}",
"\\endminipage",
"\\end{document}"
),
"table.tex"
)
tools::texi2pdf("table.tex", clean = TRUE)
One Solution would be to use tableGrob from gridExtra, add the table to a grid plot and save it with ggsave
require(ggplot2)
require(gridExtra)
ds <- iris[1:10, ]
tg <- tableGrob(ds)
ggsave("test.pdf", tg)
This is quite simple but will be less convinient than a LaTeX solution for more complex tables.
Here is a one-liner using the huxtable package (disclaimer: I am the author)
huxtable::quick_pdf(iris[1:10, ])
It will automatically open the PDF in your viewer – you can disable this with auto_open=FALSE.
For prettier formatting, create a huxtable object:
library(huxtable)
ht <- as_hux(iris[1:10, ])
bold(ht)[1,] <- TRUE # or whatever else you feel like doing
quick_pdf(ht)
In R markdown, if I want to save cahce in some other directory than the file-directory. For this, in the chuck, I will specify
{r chunkName, cache=TRUE, cache.path=cache.path = "../cache_filename/"}
But how to avoid typing filename? Is there a way that it can take title name or filename without .Rmd?
knitr automatically sets the cache.path based on the input filename. If you want to do it differently, you could do something like this:
```{r}
origCache <- knitr::opts_chunk$get("cache.path")
base <- sub("_cache/.*$", "", origCache)
cat("The base of the filename is ", base)
knitr::opts_chunk$set(cache.path = paste0(base, "_new_cache"))
```
Now the cache will be set to the base part of the filename followed by "_new_cache".
I am trying to produce a "longitudinal" layout for long tables in RMarkdown with kable. For example, I would like a table to be split over two columns, like in the example below:
dd <- data.frame(state=state.abb, freq=1:50)
kable(list(state=dd[1:25,], state=dd[26:50,]))
However, this hack produces an output that looks a way worse than the normal kable output (for example the header is not in bold). Is there a "proper" way to do this using kable?
kable is a great tool, but has limits. For the type of table you're describing I would use one of two different tools depending on output wanted.
Hmisc::latex for .Rnw -> .tex -> .pdf
htmlTable::htmlTable for .Rmd -> .md -> .html
Here is an example of the latter:
dd <- data.frame(state=state.name, freq=1:50)
dd2 <- cbind(dd[1:25, ], dd[26:50, ])
library(htmlTable)
htmlTable(dd2,
cgroup = c("Set 1:25", "Set 26:50"),
n.cgroup = c(2, 2),
rnames = FALSE)
You can still use Kable with a slight modification to your code.
dd <- data.frame(state=state.abb, freq=1:50)
knitr::kable(
list(dd[1:25,], dd[26:50,]),
caption = 'Two tables placed side by side.',
booktabs = TRUE
)
This code is a modification of this. You can also find more information about tables on that page
I'm actually creating a shiny app. In that app, there is a download button which download a PDF file that depends of user's input.
So I use a .rnw file to do generate that PDF document. I just want to do a table (with tabular) which have a number of row that depends of app user's input.
So in my R chunck, i'd like to do something like that :
\begin{tabular}{c|c}
<<echo=FALSE>>=
for (index in 1:nrow(myData))
{
SomethingThatRunLaTeXCode(paste0("\hline ",
"\Sexpr{",myData[index,1],"}"," % ","\Sexpr{",myData[index,2],"}"))
}
\hline
\end{tabular}
#
As suggested by sebastian-c, a much better way to make such a table is to use the xtable package together with Knitr. To make the Knitr chunks understand TeX, use the chunk option results='asis'.
Since your data is a data.frame, it is straight-forward:
<<echo = FALSE, results = "asis">>=
## test data
set.seed(1)
df <- data.frame(Gaussian = rnorm(10), Exponential = rexp(10))
library(xtable)
cap = paste("My caption can span multiple lines and",
"can be arbitrarily long.")
xtable(df,caption = cap)
#
For full customization, use the function print.xtable on your xtable object.
<<echo = FALSE, results = "asis">>=
print.xtable(xtable(df),table.placement = "")
#