4

I'm writing an explanation of a plot where I'll basically create the plot in a first chunk, then describe that output, and add an axis in a second chunk.

However, it seems each chunk forces a new plotting environment, so we get an error when trying to run a chunk with axis alone. Observe:

---
output: html_document
---

```{r first}
plot(1:10, 1:10, xaxt = "n")
```

Look, no x axis!

```{r second}
axis(side = 1, at = 1:10)
```

Error in axis(side = 1, at = 1:10) : plot.new has not been called yet Calls: <Anonymous> ... withCallingHandlers -> withVisible -> eval -> eval -> axis Execution halted

Obviously this is a valid workaround that has identical output:

---
output: html_document
---

```{r first}
plot(1:10, 1:10, xaxt = "n")
```

Look, no x axis!

```{r second, eval = FALSE}
axis(side = 1, at = 1:10)
```
 ```{r second_invisible, echo = FALSE}
plot(1:10, 1:10, xaxt = "n")
axis(side = 1, at = 1:10)
```

But this is less than ideal (duplicated code, having to evaluate the plot twice, etc.)

This question is related -- e.g., we could exclude the second chunk and set echo = -1 on the second_invisible chunk (this also wouldn't work in my application, but I don't want to over-complicate things here)

Is there no option like dev.hold that we can send to the first chunk?

Community
  • 1
  • 1
MichaelChirico
  • 33,841
  • 14
  • 113
  • 198
  • It seems that in the first code block, you are trying to add the axis to an already existing plot (only one plot), where in the second block you are adding the axis to a new duplicated plot (i.e. you have two versions of the plot, one without the axes and one with, which is what you really want). In other words, you are expecting / hoping that in the second chunk, it will automatically duplicate the plot for you (they really are two separate versions of the plot). The related question doesn't seem to be trying to create more than one plot. – steveb May 12 '16 at 14:59
  • In Sweave/noweb syntax you can use <> to insert the code from the first chunk in a later one, but I don't know of an equivalent in Markdown syntax. – user2554330 May 12 '16 at 16:40
  • @user2554330 hmm, sounds somewhat promising. I still see the problem that the code will have to be evaluated twice, however. – MichaelChirico May 12 '16 at 16:55

2 Answers2

2

You might look into using recordPlot

---
output: html_document
---

```{r first}
plot(1:10, 1:10, xaxt = "n")
x<-recordPlot()
```

Look, no x axis!

```{r second}
replayPlot(x)
axis(side = 1, at = 1:10)

```

sources:

R: Saving a plot in an object

R plot without showing the graphic window

https://stat.ethz.ch/R-manual/R-devel/library/grDevices/html/recordplot.html <- note the disclaimer about ggplot2 here

Community
  • 1
  • 1
user5359531
  • 3,217
  • 6
  • 30
  • 55
  • This won't produce the _exact_ output of above. You'll need `echo = -2` in `first` and `echo = -1` in `second`. But I think you're onto something. – MichaelChirico May 12 '16 at 17:51
  • I'm not familar with `echo=-2`,etc., that's a knitr parameter right? I tried adding it and couldn't immediately see the difference. If you are worried about the plot splitting up the code chunk, a simple (but obviously limited) solution might be to put the code in one line: `plot(1:10, 1:10, xaxt = "n"); x<-recordPlot()` – user5359531 May 12 '16 at 17:57
  • It's more that I don't want my output to include `x <- recordPlot` or `replayPlot` -- I'd like to obscure that from my users since it's not relevant to what I'm trying to show (it's only an artifact of the workaround we're coming up with). `echo = -2` should print only the first line of code (excluding the second). – MichaelChirico May 12 '16 at 17:58
  • Understood. Though it might be argued that if the goal is to teach others how to use R, more transparency might be helpful to the end user even if it makes the code less pretty. The other method I was thinking about was to create the plot in a different environment (such as a function) and export the `x<-recordPlot()` object. But that is starting to get too complicated for such a simple issue and I am not sure if it will actually work. – user5359531 May 12 '16 at 18:05
2

You can set an option global.device to open a persistent graphical device:

---
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_knit$set(global.device = TRUE)
```

```{r first}
plot(1:10, 1:10, xaxt = "n")
```

Look, no x axis!

```{r second}
axis(side = 1, at = 1:10)
```
Yihui Xie
  • 28,913
  • 23
  • 193
  • 419