I create an Rmarkdown document where I would like to create a plot at the start of the document, and then print it at the end of the document.
I thought the best way to achieve this would be to save the plot in the environment and then recall it later, I save this as follows:
plot(1:5, 1:5) ; plot1 <- recordPlot() # I create a plot and save it as plot1
This plot is saved under "Data" in the environment.
If I enter plot1 into the console, my plot is reproduced, but when I try to display it directly in Rmarkdown as follows I get the following error:
plot(plot1)
Error in xy.coords(x, y, xlabel, ylabel, log) :
'x' is a list, but does not have components 'x' and 'y'
How I can take the plot that I saved into Data and print it anywhere I would like in my Rmarkdown document?
p.s. I know it's tempting to say to repeat the plot again later in the document, but the parameters that build the plot are subsequently altered for another part of my analysis.
Re-producible example:
x = 1
plot_later <- function() {
plot(x)
}
plot_later()
x = -10
plot_later()
X starts at 1 then changes to -10 on the Y axis, I want it to stay at the initial value of 1.
Solution based on https://bookdown.org/yihui/rmarkdown-cookbook/reuse-chunks.html :
---
title: plot now, render later
output: html_document
---
We put some plot expression here to evaluate it later:
```{r, deja-vu, eval=FALSE}
x = 1
plot(x)
```
Here we change `x` - but only within the corresponding chunk's scope:
```{r}
x = 10
```
... moving on
Here, we evaluate and plot the expression defined earlier; x is taken from that chunk's scope, so it still evaluates to `1`:
```{r, deja-vu, eval=TRUE}
```
One option could be saving the plot as grob object using as.grob function from ggplotify and then print it elsewhere.
---
title: "Saving A Plot"
output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
## R Markdown
```{r}
library(ggplotify)
library(grid)
show_captured_plot <- function(grb) {
grid::grid.newpage()
grid::grid.draw(grb)
}
```
```{r}
x <- 1
p <- as.grob(~plot(x))
```
Now we can plot the figure here.
```{r}
x <- 10
show_captured_plot(p)
```
here, check out this link: https://bookdown.org/yihui/rmarkdown-cookbook/fig-chunk.html
It has a lot of instructions on how to get started with rmarkdown.
Specifically answering your question:
We generate a plot in this code chunk but do not show it:
```{r cars-plot, dev='png', fig.show='hide'}
plot(cars)
```
After another paragraph, we introduce the plot:
![A nice plot.](`r knitr::fig_chunk('cars-plot', 'png')`)
Basically you have to save your graph as a variable and then call on it using the knitr::fig_chunk() function.
Related
I'm analyzing some data and would like to do a Simpsons paradox on R. I've installed the Simpsons package and loaded the library. Here is an example based on the package documentation:
---
output: html_document
---
```{r}
library(Simpsons)
#generating data
Coffee1=rnorm(100,100,15)
Neuroticism1=(Coffee1*.8)+rnorm(100,15,8)
g1=cbind(Coffee1, Neuroticism1)
Coffee2=rnorm(100,170,15)
Neuroticism2=(300-(Coffee2*.8)+rnorm(100,15,8))
g2=cbind(Coffee2, Neuroticism2)
Coffee3=rnorm(100,140,15)
Neuroticism3=(200-(Coffee3*.8)+rnorm(100,15,8))
g3=cbind(Coffee3, Neuroticism3)
data2=data.frame(rbind(g1,g2,g3))
colnames(data2) <- c("Coffee","Neuroticism")
example <- Simpsons(Coffee,Neuroticism,data=data2)
plot(example)
```
This is returning a plot with 3 clusters (exactly what I need). However, when I Knit the Rmd file to HTML, I'm getting a lot of equals signs (======) with a percentage next to it like a loading grid which I would like to remove from my final output.
You can suppress any output messages in R by setting the knitr chunk option. If we wish to hide all code output other than plots, we can use the following solution:
---
output: html_document
---
```{r echo=FALSE, results='hide', fig.keep='all', message = FALSE}
library(Simpsons)
#generating data
Coffee1=rnorm(100,100,15)
Neuroticism1=(Coffee1*.8)+rnorm(100,15,8)
g1=cbind(Coffee1, Neuroticism1)
Coffee2=rnorm(100,170,15)
Neuroticism2=(300-(Coffee2*.8)+rnorm(100,15,8))
g2=cbind(Coffee2, Neuroticism2)
Coffee3=rnorm(100,140,15)
Neuroticism3=(200-(Coffee3*.8)+rnorm(100,15,8))
g3=cbind(Coffee3, Neuroticism3)
data2=data.frame(rbind(g1,g2,g3))
colnames(data2) <- c("Coffee","Neuroticism")
example <- Simpsons(Coffee,Neuroticism,data=data2)
plot(example)
```
I would note that this package seems to print out a lot more content that most packages, and therefore the combination of options are quite long.
An easier method would probably be to move the plot to a separate chunk and have all the analysis run before it. The include argument can be used to suppress all outputs, but this includes plots, hence why we must use two chunks:
```{r, include = FALSE}
# your code to build model
```
```{r}
plot(example)
```
Check out the full list of knitr chunk options here
I am using the knitr package for R to produce a LaTeX document combining text with embedded R plots and output.
It is common to write something like this:
We plot y vs x in a scatter plot and add the least squares line:
<<scatterplot>>=
plot(x, y)
fit <- lm(y~x)
abline(fit)
#
which works fine.
(For those not familiar with knitr or Sweave, this echos the code and output in a LaTeX verbatim environment and also adds the completed plot as a figure in the LaTeX document.)
But now I would like to write more detailed line-by-line commentary like:
First we plot y vs x with a scatterplot:
<<scatterplot>>=
plot(x, y)
#
Then we regress y on x and add the least squares line to the plot:
<<addline>>=
fit <- lm(y~x)
abline(fit)
#
The problem is that there are now two knitr code chunks for the same plot. The second code chunk addline fails because the plot frame created in the first code chunk scatterplot is not visible to the code in the second code chunk. The plotting window doesn't seem to be persistent from one code chunk to the next.
Is there any way that I can tell knit() to keep the plot window created by plot() active for the second code chunk?
If that is not possible, how else might I achieve LaTeX-style commentary on code lines that add to existing plots?
One Day Later
I can now see that essentially the same question has been asked before, see:
How to build a layered plot step by step using grid in knitr? from 2013 and
Splitting a plot call over multiple chunks from 2016.
Another question from 2013 is also very similar:
How to add elements to a plot using a knitr chunk without original markdown output?
You can set knitr::opts_knit$set(global.device = TRUE), which means all code chunks share the same global graphical device. A full example:
\documentclass{article}
\begin{document}
<<setup, include=FALSE>>=
knitr::opts_knit$set(global.device = TRUE)
#
First we plot y vs x with a scatterplot:
<<scatterplot>>=
x = rnorm(10); y = rnorm(10)
plot(x, y)
#
Then we regression y and x and add the least square line to the plot:
<<addline>>=
fit <- lm(y~x)
abline(fit)
#
\end{document}
You can show code without evaluating it by adding the chunk option eval=FALSE. If you only want to show the final version of the plot with the regression line added, then use eval=FALSE for the first plot(x,y).
Then we add two chunks for the regression line: One is the complete code needed to render the plot, but we don't want to display this code, because we don't want to repeat the plot(x,y) call. So we add a second chunk that we echo, to display the code, but don't evaluate.
---
output: pdf_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```
```{r data}
set.seed(10)
x=rnorm(10)
y=rnorm(10)
```
First we plot y vs x with a scatterplot:
```{r scatterplot, eval=FALSE}
plot(x, y)
```
Then we regress y on x and add the least squares line to the plot:
```{r addline, eval=FALSE}
fit <- lm(y~x)
abline(fit)
```
```{r echo=FALSE}
plot(x,y)
fit <- lm(y~x)
abline(fit)
```
Here's what the output document looks like:
Say I have the following code in knitr. How can I run it multiple times with different values of i?
```{r, echo=FALSE}
i<-0.1
```
### X,Y plot of Y=X+e where e is a standard normal distro: mean=0, sd=`r i`
```{r, echo=FALSE}
r<-rnorm(100,mean=0,sd=i)
x<-seq(0,1,length.out=100)
y<-x+r
plot(x,y)
```
EDIT:
As has been suggested ... I tried to do something like this: start a loop in an R code block, have a template in between and then close the loop -- R throws and error.
```{r, echo=FALSE}
for (i in 1:4) {
```
# bla
```{r, echo=FALSE}
}
```
What makes this question tricky is that not only the chunk content (the plot) must be repeated, but the heading as well. That's why we can neither simply reuse the chunk nor just loop over the plot command like
for (i in 1:3) { plot(rnorm(100, sd = i)) }
But it's almost that simple: We loop over the code that produces the plot and output the heading from inside the loop. This requires the chunk option results="asis" and cat to get verbatim markdown output:
```{r, echo=FALSE, results = "asis"}
sdVec <- c(0.1, 0.2, 0.3)
for (sd in sdVec) {
cat(sprintf("\n### X,Y plot of Y=X+e where e ~ N(0, %s)", sd))
r<-rnorm(100,mean=0,sd=sd)
x<-seq(0,1,length.out=100)
y<-x+r
plot(x,y)
}
```
See this answer for related issues.
I would like to generate a pdf document, using R markdown, to display a series of plots made using ggplot in a for loop. Is it possible to control number of plots on each page so there is, for example, a 2 X 2 grid of plots per page?
I'd like to maintain the flexibility so that I can change the total number of graphs, so that it splits across the appropriate number of pages.
My attempt using ggplot2 and gridExtra packages is below, but I can't control the number of graphs per page, it seems to want to squeeze them on to a sinlge page only. I've tried changing the ncol,nrow,heights,widths arguments in grid.arrange but it doesn't seem to help.
---
title: "ggplot Layout"
output: pdf_document
---
```{r,figure2 fig.height=8, fig.width=6,echo=FALSE,message=FALSE}
library(ggplot2)
library(gridExtra)
graphlist<-list()
count <- 1
colnums<-c(1,5,6,7,8,9,10)
for (i in colnums) {
plot.x.name<-names(diamonds[i])
p <- ggplot(data=diamonds,aes_string(x = plot.x.name)) + geom_histogram()
graphlist[[count]]<-p
count <- count+1
}
do.call("grid.arrange",c(graphlist,ncol=2))
```
The type of thing I'm looking for is demonstrated by this code (adapted from
http://kbroman.github.io/knitr_knutshell/pages/figs_tables.html), but this doesn't work with ggplot, unfortunately.
---
title: "Example Layout"
output: pdf_document
---
```{r bunch_o_figs,fig.height=8, fig.width=6, message=FALSE,echo=FALSE}
n <- 100
x <- rnorm(n)
par(mfrow=c(2,2), las=1)
for(i in 1:20) {
y <- i*x + rnorm(n)
plot(x, y, main=i)
}
``
You could try marrangeGrob
---
title: "ggplot Layout"
output: pdf_document
---
```{r figure2 , fig.height=8, fig.width=6,echo=FALSE,message=FALSE}
library(ggplot2)
library(gridExtra)
graphlist <- replicate(10, qplot(1,1), simplify = FALSE)
do.call("marrangeGrob",c(graphlist,ncol=2,nrow=2))
```
I am trying to use the R-Markdown feature in R Studio where I was trying to print plots which are generated inside a function. This is a basic run down example of what I am trying to do.
**Test printing plots generated in a function**
================================================
``` {r fig.width=8, fig.height=4, warning=FALSE, eval=TRUE, message=FALSE, tidy=TRUE, dev='png', echo=FALSE, fig.show='hold', fig.align='center'}
dat <- data.frame(x=c(1:10),y=c(11:20),z=c(21:30),name=rep(c("a","b"),each=5))
library(ggplot2)
ex <- function(data){
plot(data[,1],data[,2])
plot(data[,1],data[,3])
}
for (i in 1:10){
t1 <- rbind(i,ex(dat))
}
t1
```
Those testing this code, please make sure to save it as ".Rmd" file and then run the knithtml() in RStudio toolbar. This code above works absolutely fine with the kind of html output I desire. However when I replace the base plotting function by ggplot based code, I cannot get the knithtml() to produce the ggplot output of the 10 plots that I got like before. The base plot code above is now replaced by the following code
p1 <- ggplot(data=data, aes(x=data[,1],y=data[,2]))
p1 <- p1+geom_point()
p1
Am I missing something very simple here.
VJ
There are two problems in your code:
ggplot doesn't recognize the data x and y data, bacause it works inside the data environment. You should give it the column names directly.
The code in yur loop doesn't make sense. You can't mix a plot with an index... (the reason it works with the base plot is through a side-effect) I've replaced it with the simple plot command.
The following will work:
**Test printing plots generated in a function**
================================================
``` {r fig.width=8, fig.height=4, warning=FALSE, eval=TRUE, message=FALSE, tidy=TRUE, dev='png', echo=FALSE, fig.show='hold', fig.align='center'}
dat <- data.frame(x=c(1:10),y=c(11:20),z=c(21:30),name=rep(c("a","b"),each=5))
library(ggplot2)
ex <- function(data){
p1 <- ggplot(data=data, aes(x=x,y=y))
p1 <- p1+geom_point()
return(p1)
}
for (i in 1:2){
plot(ex(dat))
}
```