Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a layered plot step by step using grid in knitr?

Tags:

r

knitr

For an online tutorial accompanying a workshop, I would like to highlight the use of the grid package (especially how to work with viewports). For this, I would like to build a plot step by step (i.e. chunk by chunk). Between each of the steps/chunks I would like to include some ordinary text in order to explain each of the steps in more detail.

How can I tell knitr to not evaluate a chunk separately, but to start the evaluation where the previous chunk ended? Basically, rather than a new evaluation of the chunk I want to add to the result of the previous chunk.

In the below code what happens is that I get 2 plots in the .html output when knitting to html. The first one showing the resutls of the first chunk (a pink rectangle and some text) and the second showing the results of the second chunk (a blue rectangle). What I would like to achieve is two plots - the first one showing the results of the first chunk (as above) and the second plot showing the results of the first chunk + the results of the second chunk (the blue rectangle within the pink rectangle). Basically, I would like to reproduce the behavior of the two code chunks when run in the R console. The blue rectangle should be placed in the pink rectangle and not be plotted separately.

Here's the first chunk

```{r grid first vp, tidy = FALSE}
library(grid)
grid.newpage()

## draw a rectangle around the root vp and provide some text
grid.rect()
grid.text("this is the root vp", x = 0.5, y = 1, just = c("centre", "top"))

vp <- viewport(x = 0.5, y = 0.5, 
               height = 0.5, width = 0.5,
               just = c("centre", "centre"))

pushViewport(vp)

grid.rect(gp = gpar(fill = "pink"))
grid.text("this is our first vp", x = 0.5, y = 1, just = c("centre", "top"))
```

Then some explanatory text in between:

"Ok, so now we have created a viewport in the middle of the root viewport at x = 0.5 and y = 0.5 - just = c("centre", "centre") that is half the height and half the width of the original viewport - height = 0.5 and width = 0.5.

Afterwards we navigated into this viewport - pushViewport(vp) and then we have drawn a rectangle that fills the entire viewport and filled it in pink colour - grid.rect(gp = gpar(fill = "pink"))

Note that we didn't leave the viewport yet. This means, whatever we do now, will happen in the currently active viewport (the pink one). To illustrate this, we will simply repeat the exact same code from above once more (we're only going to change the fill colour so we see the change better)."

And here's the second chunk

```{r grid second vp, tidy = FALSE}

vp <- viewport(x = 0.5, y = 0.5, 
               height = 0.5, width = 0.5,
               just = c("centre", "centre"))

pushViewport(vp)

grid.rect(gp = gpar(fill = "cornflowerblue"))
```

Any ideas how I could tell knitr to 'keep' whatever has been done in previous chunks and take this as the 'starting point' for the current chunk evaluation?

like image 608
TimSalabim Avatar asked Jul 06 '13 10:07

TimSalabim


1 Answers

It is not documented, but this feature has been there for almost a year. To keep a graphical device open throughout the compilation, you can set

opts_knit$set(global.device = TRUE)

I thought it would be very rare for anybody to use this feature, but it seems I was wrong.

like image 141
Yihui Xie Avatar answered Oct 23 '22 06:10

Yihui Xie