Rmarkdown automatically use function on plots - r

I'm producing an RMarkdown document where each chunk produces a plot.
For each of these plots, I'd like to apply a special formatting function that adjusts the way the title appears.
Is there a way to tell knitr/rmarkdown to apply this special function to each chunk's plot? For example, maybe there's a chunk option like {r, fig.function = adjust_title_position}?
The motivation is that I don't want to have to retype the function call separately for each plot (e.g. adjust_title_position(plot_42)) and, at the same time, I don't want to use something like lapply(my_plots, adjust_title_position) which would require all the plots to be defined in one place.
Below is a minimal example of the RMarkdown file to which this could be applied.
---
title: "RMD_Example"
output: html_document
---
```{r setup, include=FALSE}
# Load ggplot2
library(ggplot2)
# Define helper function
adjust_title_position <- function(p) {
# Shift the horizontal position of the plot title
p_built <- invisible(ggplot2::ggplot_build(p))
gt <- invisible(ggplot2::ggplot_gtable(p_built))
gt$layout[which(gt$layout$name == "title"), c("l", "r")] <- c(2, max(gt$layout$r))
# Prints the plot to the current graphical device
gridExtra::grid.arrange(gt, newpage = TRUE)
# Invisibly return the gtable object
invisible(gt)
}
```
```{r plot_1}
ggplot(mtcars) + geom_point(aes(x = wt, y = mpg)) +
labs(title = "Weights and miles-per-gallon")
```
```{r plot_2}
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) + geom_point() +
labs(title = "Sepal length and width")
```

You could reregister the print-method for ggplot-objects.
# Define helper function
adjusted_title_position <- function(p) {
# Shift the horizontal position of the plot title
p_built <- invisible(ggplot2::ggplot_build(p))
gt <- invisible(ggplot2::ggplot_gtable(p_built))
gt$layout[which(gt$layout$name == "title"), c("l", "r")] <- c(2, max(gt$layout$r))
# Prints the plot to the current graphical device
gridExtra::grid.arrange(gt, newpage = TRUE)
}
# Reregister print.ggplot
assignInNamespace("print.ggplot", adjusted_title_position, asNamespace("ggplot2"))

Related

Displaying the plots stored in a list, suppressing the names and indices from printing into console

I have a few ggplot2 plots stored in a named list, plt_list, and I would like to display the plots in R or Rmarkdown, without the names or list indices (e.g. [[1]]) to be displayed; just the plots. I have tried unname(plt_list), but the indices are printed into the console (or in Rmarkdown document, before each plot). With invisible nothing is displayed. Is there any way to do this in R?
We can use walk from purrr to display in Rmarkdown
---
title: "Title"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
```{r plot_create, echo = FALSE}
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(purrr))
p1 <- ggplot(iris, aes(x = Species, y = Sepal.Length)) + geom_col()
plt_lst <- list(p1 = p1, p2 = p1, p3 = p1)
```
```{r plots, echo = FALSE, results = 'asis'}
walk(plt_lst, print)
```
-output
If we are trying this in R console, a for loop should also work
for(i in seq_along(plt_lst)) plt_lst[[i]]

R: Align Text Ouput Next to Plot Output in html knitr File

I'd like to align some text output next to a plot output from plotly in an html knitr file. For example, I'd like the output of the functions below to appear side by side in the document.
---
title: 'untitled'
output: html_document
---
```{r}
pacman::p_load(ggplot2, plotly, grid, gridExtra)
p1 <- ggplot(df, aes(y = var1, x =
var2, color = p_c)) + geom_point(aes(text = subjID)) +
geom_smooth(method = "lm")
ggplotly(p1, tooltip = "text")
cor.test(var1, var2)
```
I've fooled around with Grobs (i.e. grobText) and the grid/gridExtra packages - but those don't seem compatible with plotly. For example:
```{r}
pacman::p_load(ggplot2, plotly, grid, gridExtra)
p1 <- ggplot(df, aes(y = var1, x =
var2, color = p_c)) + geom_point(aes(text = subjID)) +
geom_smooth(method = "lm")
p1 <- ggplotly(p1, tooltip = "text")
text1 <- cor.test(var1, var2)
text1 <- textGrob(text1)
grid.arrange(p1, text1, ncol = 2)
```
This returns the error: Error in gList(list(x = list(data = list(list(x = c(-28, 1689, 1122, 284, : only 'grobs' allowed in "gList"
I've also considered flexdashboard, but I don't want the output to appear in a separate html page from the rest of the report.
Any thoughts are appreciated, especially if there's a way to get the row formatting of flexdashboard to be inserted into the middle of a standard html rmarkdown file.

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]

Raw HTML and plots in a (knitr) loop

I am putting together a Knitr script to generate a report. The content of the report is determined dynamically at runtime, where sections of the report are generated via a loop. Ideally I would like to do both of the following in each iteration of the loop:
generate some raw HTML output and
generate a plot.
However, I am battling to get both of these working at the same time.
If I use the following chunk options, then I get the plots but the HTML code is formatted in a "pre" environment.
```{r echo=FALSE, fig.keep = "all", fig.show = "asis"}
for (i in 1:3) {
cat("<h2>Heading</h2>")
print(ggplot(data.frame(x = 1:10, y = 1:10), aes(x = x, y = y)) + geom_point())
}
```
If I change the chunk options then I get the raw HTML but the plots disappear, being replaced by a short text snippet indicating the path to the plot.
```{r results="asis", echo=FALSE}
for (i in 1:3) {
cat("<h2>Heading</h2>")
print(ggplot(data.frame(x = 1:10, y = 1:10), aes(x = x, y = y)) + geom_point())
}
```
Is it possible to get both working at once?
This is my first attempt to do anything remotely non-trivial with Knitr, so I am sure that there is a simple answer to this question.
Best regards,
Andrew.
This seems to work at my end:
```{r results='asis', echo=F, fig.keep='all'}
for (i in 1:3) {
cat("<h2>Heading</h2>")
pl <- ggplot(data.frame(x = 1:10, y = 1:10), aes(x = x, y = y)) + geom_point()
print(pl)
}```

Formatting output with Knitr, ggplot2 and xtable

I am trying to achieve the following task with Knitr, ggplot2 and xtables:
Generate several annotated plots of beta-distributions with ggplot2
Write the output in a layout such that I have a plot, and a corresponding summary Stats table following it, for every plot.
Write the code such that both PDF and HTML reports can be a generated in a presentable way
Here is my attempt at this task (Rnw file):
\documentclass{article}
\begin{document}
Test for ggplot2 with Knitr
<<Initialize, echo=FALSE>>=
library(ggplot2)
library(ggthemes)
library(data.table)
library(grid)
library(xtable)
library (plyr)
pltlist <- list()
statlist <- list()
#
The libraries are loaded. Now run the main loop
<<plotloop, echo=FALSE>>=
for (k in seq(1,7)){
x <- data.table(rbeta(100000,1.6,14+k))
xmean <- mean(x$V1, na.rm=T)
xqtl <- quantile(x$V1, probs = c(0.995), names=F)
xdiff <- xqtl - xmean
dens <- density(x$V1)
xscale <- (max(dens$x, na.rm=T) - min(dens$x, na.rm=T))/100
yscale <- (max(dens$y, na.rm=T))/100
y_max <- max(dens$y, na.rm=T)
y_intercept <- y_max-(10*yscale)
data <- data.frame(x)
y <- ggplot(data, aes(x=V1)) + geom_density(colour="darkgreen", size=2, fill="green",alpha=.3) +
geom_vline(xintercept = xmean, colour="blue", linetype = "longdash") +
geom_vline(xintercept = xqtl, colour="red", linetype = "longdash") +
geom_segment(aes(x=xmean, xend=xqtl, y=y_intercept, yend=y_intercept), colour="red", linetype = "solid", arrow = arrow(length = unit(0.2, "cm"), ends = "both", type = "closed")) +
annotate("text", x = xmean+xscale, y = y_max, label = paste("Val1:",round(xmean,4)), hjust=0) +
annotate("text", x = xqtl+xscale, y = y_max, label = paste("Val2:",round(xqtl,4))) +
annotate("text", x = xmean+10*xscale, y = y_max-15*yscale, label = paste("Val3:",round(xdiff,4))) +
xlim(min(dens$x, na.rm=T), xqtl + 9*xscale) +
xlab("Values") +
ggtitle("Beta Distribution") +
theme_bw() +
theme(plot.title = element_text(hjust = 0, vjust=2))
pltlist[[k]] <- y
statlist[[k]] <- list(mean=xmean, quantile=xqtl)
}
stats <- ldply(statlist, data.frame)
#
Plots are ready. Now Plot them
<<PrintPlots, warning=FALSE, results='asis', echo=FALSE, cache=TRUE, fig.height=3.5>>=
for (k in seq(1,7)){
print(pltlist[[k]])
print(xtable(stats[k,], caption="Summary Statistics", digits=6))
}
#
Plotting Finished.
\end{document}
I am faced with several issues after running this code.
When I run this code just as R code, Once I try to print the plots in the list, the horizontal line from the geom_segment part starts to move all over the place. However if I plot the figures individually, without putting them in a list, the figures are fine, as I would expect them to be.
Only the last plot is as I would expect the output to be, in all the other plots, the geom_segment line moves around randomly.
I am also unable to put a separate caption for the Plots as I can for the Tables.
Points to note :
I am storing the beta-random numbers in data.table since in our actual code, we are using data.table. However for the purposes of testing ggplot2 in this way, I convert the data.table into a data.frame, as ggplot2 requires.
I also need to generate the random numbers within the loop and generate the plots per iteration (so something like first generating the random numbers and then using melt would not work here), since generating the random numbers is emulating a complex database call per iteration of the loop.
I am using RStudio Version 0.98.1091 and
R version 3.1.2 (2014-10-31) on Windows 8.1
This is the expected Plot:
This is the plot I am getting when plotting from the list:
My output in PDF form :
PDF Output
Please advice if there are any ideas for solutions.
Thank you,
SG
I don't know why the horizontal line in geom_segment is "moving around" from plot to plot, rather than spanning xmean to xqtl. However, I was able to get the horizontal line in the correct location by getting the value from the stats data frame, rather than from direct calculation of the mean and quantile. You just have to create the stats data frame before the loop, rather than after, so that you can use it in the loop.
stats <- ldply(statlist, data.frame)
for (k in seq(1,7)){
...
y <- ggplot(data, aes(x=V1)) +
...
geom_segment(aes(x=stats[k,1], xend=stats[k,2], y=y_intercept, yend=y_intercept),
colour="red", linetype = "solid",
arrow = arrow(length = unit(0.2, "cm"), ends = "both", type = "closed")) +
...
pltlist[[k]] <- y
statlist[[k]] <- list(mean=xmean, quantile=xqtl)
}
Hopefully, someone else will be able to explain the anomalous behavior, but at least this seems to fix the problem.
For the figure caption, you can add a fig.cap argument to the chunk where you plot the figures, although this results in the same caption for each figure and causes the figures and tables to be plotted in separate groups, rather than interleaved:
<<PrintPlots, warning=FALSE, results='asis', echo=FALSE, cache=TRUE, fig.cap="Caption", fig.height=3.5>>=
for (k in seq(1,7)){
print(pltlist[[k]])
print(xtable(stats[k,], caption="Summary Statistics", digits=6))
}
You might want to use R Markdown and knitr which is easier than using LaTeX and R (as also zhaoy suggested).
You might also want to check out the ReporteRs package. I think it is actually easier to use than knitr. However, you cannot generate PDFs with it. But you can use pandoc to convert them into PDFs.

Resources