subfigures stacked vertically with knitr - r

I am trying to put two subfigures stacked vertically rather than side-by-side using knitr in a Latex document. In Latex, I usually do this by putting a '\par' command between two subfloats that need to be stacked op top of one another, but I don't know how to pass that command on to knitr.
I've only been able to find one topic on this, Subfigures or Subcaptions with knitr?. The example given by Yihui puts the figures side by side. The final answer in that thread achieves my goal, but using quite a bit of hacking, so I'm wondering whether there's a simple way to pass this command to knitr directly?
MWE:
\documentclass[a4paper]{article}
\usepackage[font=footnotesize]{subfig}
\begin{document}
<<GeneratePlot>>=
library(ggplot2)
library(tikzDevice)
P1 <- ggplot(data=mpg, aes(x=displ, y=hwy, colour=factor(cyl)))+
geom_line()
P2 <- ggplot(data=mpg, aes(x=displ, y=hwy, colour=factor(cyl)))+
geom_point()
#
<<fig1,eval=TRUE,echo=FALSE,dev='tikz', fig.width=6, fig.height=3, out.width='1\\textwidth', fig.cap='Two figures', fig.subcap=c('Top','Bottom'), fig.show='asis', fig.pos='!htpb', fig.align='center', dependson='GeneratePlot'>>=
P1
P2
#
\end{document}
I've also tried creating the plot object in the same chunk as the output, but that yields the same result and in my original document the plot objects are generated as part of a larger chunk, so it will have the same structure as the MWE.

You can do that with the non-CRAN package oaReporting.
\documentclass[a4paper]{article}
\usepackage{float}
\usepackage{subcaption}
\begin{document}
<<setup, include=FALSE>>=
knitr::opts_chunk$set(fig.path="figures/")
library(oaReporting)
#
<<GeneratePlot>>=
library(ggplot2)
P1 <- ggplot(data=mpg, aes(x=displ, y=hwy, colour=factor(cyl)))+
geom_line()
P2 <- ggplot(data=mpg, aes(x=displ, y=hwy, colour=factor(cyl)))+
geom_point()
path1 <- createPlot(P1, file="./figures/P1.pdf")
path2 <- createPlot(P2, file="./figures/P2.pdf")
captions <- c("P1", "P2")
#
<<results="asis", fig.keep="none">>=
insertFigures(paths = c(path1, path2), captions=captions,
generalCaption = "P1 and P2",
generalLabel = "fig:P1andP2",
posMultipleFig = "H",
nCol = 1,
width = 0.7)
#
\end{document}

This has been officially supported in knitr 1.17.19 (current on Github). To add \par between the two subfigures, you can use the chunk option fig.sep = '\\par', e.g.,
\documentclass[a4paper]{article}
\usepackage[font=footnotesize]{subfig}
\begin{document}
<<GeneratePlot>>=
library(ggplot2)
library(tikzDevice)
P1 <- ggplot(data=mpg, aes(x=displ, y=hwy, colour=factor(cyl)))+
geom_line()
P2 <- ggplot(data=mpg, aes(x=displ, y=hwy, colour=factor(cyl)))+
geom_point()
#
<<fig1, echo=FALSE,dev='tikz', fig.width=6, fig.height=3, out.width='1\\textwidth', fig.cap='Two figures', fig.subcap=c('Top','Bottom'), fig.show='asis', fig.pos='!htpb', fig.sep='\\par'>>=
P1
P2
#
\end{document}
Output:

Related

Stop ## quartz_off_screen showing in HTML report

My R Markdown files contain code to save PDF files e.g.
pdf(paste0("plots/filtering/", exp_name, "_umap.pdf"))
walk(list(p4, p5, p6, p7), print)
dev.off()
When I knit to HTML, I get the following printed as part of the HTML.
## quartz_off_screen
## 2
Is there a way to prevent this? I already have the knitr chunk options message and warning set to FALSE.
Best wishes,
Lucy
Wrap the the call to dev.off with invisible(...).
MWE
---
title: "Test"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(ggplot2)
library(purrr)
```
## R Markdown
```{r}
p1 <- ggplot(mtcars, aes(mpg, disp)) + geom_point()
p2 <- ggplot(mtcars, aes(mpg, disp, color = factor(vs))) + geom_point()
```
```{r}
pdf("mtcars.pdf")
walk(list(p1, p2), print)
invisible(dev.off())
```

Force empty plot to show up with `patchwork` with pdf_output R Markdown

I would like to display a single plot that takes up half of my page (to appear like it is taking up one column), using the patchwork library and the plot_spacer() function. The thing is, I can't get the "empty plot" to take up half the space! No matter what I do, the first plot seems to take up most of the page. I'm looking for the equivalent of p1 + p2 below, except I'd want p2 to be white space.
Reproducible example and output
---
title: " "
author: " "
date: " "
output: pdf_document
geometry: paperheight=8.5in,paperwidth=5.5in,left=0.4in, right=0.4in, top=0.25in, bottom=0.25in
header-includes:
- \pagenumbering{gobble}
---
{r, fig.height = 1.5}
library(ggplot2)
library(patchwork)
p1 <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) + geom_point()
p2 <- ggplot() + geom_blank()
p3 <- p2 + theme_void()
p1 + plot_spacer()
p1 + p1
p1 + p2
p1 + p3
Also note that the plots appear to work in my R session but not when output to pdf:
Finally, I also tried another suggestion to use plot_layout:
design <- "
1#
"
p1 + plot_layout(design = design)
This also seems to work in the session but not in pdf_output.
If I understand you correctly, you should set out.height="50%" in your code chunk. This means that the plots will take 50% of the page. To create a white space plot, I used a theme with white background. You can see this in the code below:
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
\newpage
```{r, out.height="50%"}
library(ggplot2)
library(patchwork)
p1 <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) + geom_point()
p2 <- ggplot() + geom_blank() + theme(panel.background = element_rect(fill = 'white', colour = 'white'))
p3 <- p2 + theme_void()
p1 + plot_spacer()
p1 + p1
p1 + p2
p1 + p3
```
In the pdf document you will see that the plots will plot 50% of the page. The output of p1 + plot_spacer() looks like this:
Output of p1 + p1 and p1 + p2:
And finally the output of p1 + p3:
As you can see from the images, the plots are half of the pages in a one column.

How can I suppress and capture knitr chunk ouput?

In a knitr document, I am calling an external code chunk which generates a ggplot2 object similar to the following:
# file.R
# ---- create_plot ----
library(ggplot2)
data(mtcars)
gg <- ggplot(mtcars, aes(mpg, cyl)) + geom_point()
gg
In my document (Flexdashboard Rmd, specifically):
# dashboard.Rmd
```{r setup}
knitr::read_chunk("plot.R")
```
```{r create_plot}
```
I would like to call this chunk and suppress the printing of the gg object, allowing me to do some tweaks to the object (title, colors, etc.) and display the plot later in my document. I've tried results='hide' when calling the chunk with no success. My desired document would be something like:
# dashboard.Rmd
```{r setup}
knitr::read_chunk("plot.R")
```
```{r create_plot, results='hide'}
```
```{r display_plot}
gg <- gg + labs(title = "Custom title")
gg
```
Is this possible without editing the external chunk to omit the final gg call?
You'll need to include = FALSE in the chunk option. This way, the code will run but not be included. I often do this when I run batch code using source(). Anyhow, give this a try:
```{r display_plot, include = FALSE}
gg <- gg + labs(title = "Custom title")
gg
```

Why can't i use fig.cap - Latex through Sweave + Knitr

I'm very new to Latex, and I'm trying my way on creating a graph with a figure caption.
Now when I try to add fig.cap in the chunk heading (second chunk) I get the error
Latex error: Not in outer par mode
My code
<<echo = FALSE>>=
source("analysis.R")
repoData <- readRDS("data/repoData.rds")
a4width<- 8.3
a4height<- 11.7
#
\begin{figure}[h]
<<echo = FALSE, fig.width= a4width, fig.height=0.35*a4height>>=
G2(repoData)
#
\end{figure}
## ---- G2 ----
G2 <- function(df) {
# For inflation graph
plot <- ggplot(df, aes(x = Month, y = Percent)) +
geom_line(colour = "firebrick") +
xlab("") +
ylab("Repo rate") +
theme_classic() +
theme(axis.title.y = element_text(vjust = 1))
return(plot)
}
Why does this happen and how can this be resolved?
You should omit the \begin{figure} (not shown in your MWE) and \end{figure} from your Sweave file; when you specify fig.cap they are generated automatically by knitr (and redundantly, in the case of your MWE, leading to the error).
If you need to specify other LaTeX figure options, see the "Plot" section of the knitr chunk options documentation: in particular, if you want to use position "h", use fig.pos="h" in your chunk options, as indicated by
fig.pos: (''; character) a character string for the figure position arrangement to be used in \begin{figure}[fig.pos]

grid.layout in ggplot

I'm using the following code to create three sets of plots in the amazing package ggplot2:
w<-rnorm(100)
x<-rnorm(100)
y<-rnorm(100)
z<-rnorm(100)
g<-rep(factor(LETTERS[1:4]), 25)
d<-data.frame(g,w,x,y,z)
library(ggplot2)
pw<-ggplot(d, aes(w, y))
px<-ggplot(d, aes(x, y))
pz<-ggplot(d, aes(z, y))
pw+geom_point()+facet_grid(.~g, scales='fixed')+coord_equal()+stat_smooth(method='lm')
px+geom_point()+facet_grid(.~g, scales='fixed')+coord_equal()+stat_smooth(method='lm')
pz+geom_point()+facet_grid(.~g, scales='fixed')+coord_equal()+stat_smooth(method='lm')
I would make a PDF file that has each of these three sets of plots printed on the same page. My understanding is thatsplit.screen(c(3,1))andpar(mfrow=c(3,1))won't work with ggplot2 graphics, but thatgrid.layout()from the grid package would work so I tried:
pdf(file="test.pdf")
pushViewport(viewport(layout=grid.layout(3,1)))
print(pw+geom_point()+facet_grid(.~g, scales='fixed')+coord_equal()+stat_smooth(method='lm'))
print(px+geom_point()+facet_grid(.~g, scales='fixed')+coord_equal()+stat_smooth(method='lm'))
print(pz+geom_point()+facet_grid(.~g, scales='fixed')+coord_equal()+stat_smooth(method='lm'))
dev.off()
but this ends up being a four page PDF file with the first page being blank and each set of figures following one per page and the x-axis label way down at the bottom. Is there a way to make a PDF file with all the sets of figures on the same page (and without a blank page leading!)?
You'll probably have a better time using grid.arrange(), from the gridExtra package:
p1 <- pw + geom_point() + facet_grid(.~g, scales='fixed') + coord_equal() +
stat_smooth(method='lm')
p2 <- px + geom_point() + facet_grid(.~g, scales='fixed') + coord_equal() +
stat_smooth(method='lm')
p3 <- pz + geom_point() + facet_grid(.~g, scales='fixed') + coord_equal() +
stat_smooth(method='lm')
grid.arrange(p1, p2, p3, ncol=1)
You can also use the multiplot() function, which could be customized to suite your needs: http://www.cookbook-r.com/Graphs/Multiple_graphs_on_one_page_(ggplot2)/
If you use markdown, use fig.height in each code chunk for each plot:
```{r pw, fig.height = 2.66, echo = F}
pw
```
```{r px, fig.height = 2.66, echo = F}
px
```
```{r pz, fig.height = 2.66, echo = F}
pz
```

Resources