forked from hadley/ggplot2-book
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpolishing.rmd
372 lines (285 loc) · 26.4 KB
/
polishing.rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
---
title: polishing
output: bookdown::html_chapter
bibliography: references.bib
---
```{r polishing, echo=FALSE}
library("ggplot2")
library("plyr")
library("grid")
options(digits = 2, width = 60)
```
# Polishing your plots for publication {#cha:polishing}
In this chapter you will learn how to prepare polished plots for publication. Most of this chapter focusses on the theming capability of `ggplot` which allows you to control many non-data aspects of plot appearance, but you will also learn how to adjust geom, stat and scale defaults, and the best way to save plots for inclusion into other software packages. Together with the next chapter, manipulating plot rendering with **grid**, you will learn how to control every visual aspect of the plot to get exactly the appearance that you want. \index{Publication!polishing plots for}
The visual appearance of the plot is determined by both data and non-data related components. [Themes](#sec:themes) introduces the theme system which controls all aspects of non-data display. By now you should be familiar with the many ways that you can alter the data-related components of the plot---layers and scales---to visualise your data and change the appearance of the plot. In [customising scales and geoms](#sec:theme-scale-geom) you will learn how you can change the defaults for these, so that you do not need to repeat the same parameters again and again.
[Saving your output](#sec:saving) discusses the chapter with a discussion about how to get your graphics out of R and into LaTeX, Word or other presentation or word-processing software. [Multiple plots on the same page](#sec:grid-layout) concludes with a discussion of how to lay out multiple plots on a single page.
<!--
% Need cross-refs here to changing axis, legend and plot titles
% And guide breaks and legends
-->
## Themes {#sec:themes}
The appearance of non-data elements of the plot is controlled by the theme system. The theme system does not affect how the data is rendered by geoms, or how it is transformed by scales. Themes don't change the perceptual properties of the plot, but they do help you make the plot aesthetically pleasing or match existing style guides. Themes give you control over things like the fonts in all parts of the plot: the title, axis labels, axis tick labels, strips, legend labels and legend key labels; and the colour of ticks, grid lines and backgrounds (panel, plot, strip and legend). \index{Themes} \index{Publication!themes}
This separation of control into data and non-data parts is quite different than base and lattice graphics. In base and lattice graphics, most functions take a large number of arguments that specify both data and non-data appearance, which makes the functions complicated and hard to learn. ggplot takes a different approach: when creating the plot you determine how the data is displayed, then *after* it has been created you can edit every detail of the rendering, using the theming system. Some of the effects of changing the theme of a plot are shown in Figure \ref{fig:themes}. The two plots show the two themes included by default in ggplot.
```{r themes, fig.cap="The effect of changing themes. (Left) The default grey theme with grey background and white gridlines. (Right) the alternative black and white theme with white background and grey gridlines. Notice how the bars, data elements, are identical in both plots.", echo=FALSE}
qplot(rating, data = movies, binwidth = 1)
last_plot() + theme_bw()
```
Like many other areas of `ggplot`, themes can be controlled on multiple levels from coarse to fine. You can:
* Use a built-in theme. This affects every element of the plot in a visually consistent manner. The default theme uses a grey panel background with white gridlines; however, there are built-in alternatives such as `theme_bw()` which uses a white background with grey gridlines ([link to section](#sec:built-in)).
* Modify a single element of a built-in theme. Each theme is made up of multiple elements. The theme system comes with a number of built-in element rendering functions with a limited set of parameters. By adjusting these parameters you can control things like text size and colour, background and grid line colours and text orientation. By combining multiple elements you can create your own theme ([link to section](#sec:theme-elements)).
<!--
* Write a custom element function with grid, as described in [](#sec:theme-elements). This allows you to completely customise the appearance of any element; you are not restricted to a fixed set of drawing options.
-->
Generally each of these theme settings can be applied globally, to all plots, or locally to a single plot. How to do this is described in each section.
### Built-in themes {#sec:built-in}
There are two built-in themes. \index{Themes!built-in} The default, `theme_gray()`, uses a very light grey background with white gridlines. This follows from the advice of [@tufte:2006; @tufte:1990; @tufte:2001; @tufte:1997] and [@brewer:1994; @carr:2002; @carr:1994; @carr:1999]. We can still see the gridlines to aid in the judgement of position [@cleveland:1993a], but they have little visual impact and we can easily 'tune' them out. The grey background gives the plot a similar colour (in a typographical sense) to the remainder of the text, ensuring that the graphics fit in with the flow of a text without jumping out with a bright white background. Finally, the grey background creates a continuous field of colour which ensures that the plot is perceived as a single visual entity. \indexf{theme_grey}
The other built-in theme, `theme_bw()`, has a more traditional white background with dark grey gridlines. Figure \ref{fig:themes} shows some of the difference between these themes. \index{White background} \index{Themes!white background} \indexf{theme_bw}
Both themes have a single parameter, `base_size`, which controls the base font size. The base font size is the size that the axis titles use: the plot title is 20% bigger, and the tick and strip labels are 20% smaller. If you want to control these sizes separately, you'll need to modify the individual elements as described in the following section.
You can apply themes in two ways:
* Globally, affecting all plots when they are drawn: `theme_set(theme_grey())` or `theme_set(theme_bw())`. `theme_set()` returns the previous theme so that you can restore it later if you want. \indexf{theme_set}
* Locally, for an individual plot: `qplot(...) + theme_grey()`. A locally applied theme will override the global default.
The following example shows a few of these combinations:
```{r hgram, prompt=TRUE, fig.show='asis', fig.align='left'}
hgram <- qplot(rating, data = movies, binwidth = 1)
# Themes affect the plot when they are drawn,
# not when they are created
hgram
previous_theme <- theme_set(theme_bw())
hgram
# You can override the theme for a single plot by adding
# the theme to the plot. Here we apply the original theme
hgram + previous_theme
# Permanently restore the original theme
theme_set(previous_theme)
```
### Theme elements and element functions {#sec:theme-elements}
A theme is made up of multiple *elements* which control the appearance of a single item on the plot, as listed in Table~\ref{tbl:elements}. There are three elements that have individual `x` and `y` settings: `axis.text`, `axis.title` and `strip.text`. Having a different setting for the horizontal and vertical elements allows you to control how text should appear in different orientations. The appearance of each element is controlled by an *element function*. \index{Themes!elements}
<!--
\input{tbls/elements}
-->
There are four basic types of built-in element functions: text, lines and segments, rectangles and blank. Each element function has a set of parameters that control the appearance as described below:
* `element_text()` draws labels and headings. You can control the font `family`, `face`, `colour`, `size`, `hjust`, `vjust`, `angle` and `lineheight`. \index{Themes!labels} \indexf{element_text}
The following code shows the effect of changing these parameters on the plot title. The results are shown in Figure \ref{fig:theme-text}. Changing the angle is probably more useful for tick labels. When changing the angle you will probably also need to change `hjust` to 0 or 1.
```{r theme-text, out.width="0.32\\linewidth", fig.cap="Changing the appearance of the plot title."}
hgramt <- hgram + labs(title = "This is a histogram")
hgramt
hgramt + theme(plot.title = element_text(size = 20))
hgramt + theme(plot.title =
element_text(size = 20, colour = "red"))
hgramt + theme(plot.title =
element_text(size = 20, hjust = 0))
hgramt + theme(plot.title =
element_text(size = 20, face = "bold"))
hgramt + theme(plot.title =
element_text(size = 20, angle = 180))
```
* `element_line()` draws lines with the same options but in a slightly different way. Make sure you match the appropriate type or you will get strange grid errors. For these element functions you can control the `colour`, `size` and `linetype`. These options are illustrated with the code and the results are shown in Figure \ref{fig:theme-line}. \indexf{element_line}
```{r theme-line, out.width="0.32\\linewidth", fig.cap="Changing the appearance of lines and segments in the plot."}
hgram + theme(panel.grid.major = element_line(colour = "red"))
hgram + theme(panel.grid.major = element_line(size = 2))
hgram + theme(panel.grid.major = element_line(linetype = "dotted"))
hgram + theme(axis.line = element_line())
hgram + theme(axis.line = element_line(colour = "red"))
hgram + theme(axis.line = element_line(size = 0.5, linetype = "dashed"))
```
* `element_rect()` draws rectangles, mostly used for backgrounds, you can control the `fill` colour and border `colour`, `size` and `linetype`. Examples shown in Figure \ref{fig:theme-background} are created with the code below: \index{Background} \index{Themes!background} \indexf{theme_rect}
```{r theme-background, out.width="0.32\\linewidth", fig.cap="Changing the appearance of the plot and panel background"}
hgram + theme(plot.background = element_rect(fill = "grey80", colour = NA))
hgram + theme(plot.background = element_rect(size = 2))
hgram + theme(plot.background = element_rect(colour = "red"))
hgram + theme(panel.background = element_rect())
hgram + theme(panel.background = element_rect(colour = NA))
hgram + theme(panel.background = element_rect(linetype = "dotted"))
```
* `element_blank()` draws nothing. Use this element type if you don't want anything drawn, and no space allocated for that element. The following example uses `element_blank()` to progressively suppress the appearance of elements we're not interested in. The results are shown in Figure \ref{fig:theme-blank}. Notice how the plot automatically reclaims the space previously used by these elements: if you don't want this to happen (perhaps because they need to line up with other plots on the page), use `colour = NA, fill = NA` as parameter to create invisible elements that still take up space. \indexf{element_blank}
```{r theme-blank, out.width="0.32\\linewidth", fig.cap="Progressively removing non-data elements from a plot with \\texttt{element\\_blank}."}
hgramt
last_plot() + theme(panel.grid.minor = element_blank())
last_plot() + theme(panel.grid.major = element_blank())
last_plot() + theme(panel.background = element_blank())
last_plot() +
theme(axis.title.x = element_blank(),
axis.title.y = element_blank())
last_plot() + theme(axis.line = element_line())
```
You can see the settings for the current theme with `theme_get()`. The output isn't included here because it takes up several pages. You can modify the elements locally for a single plot with `theme()` (as seen above), or globally for all future plots with `theme_update`. Figure \ref{fig:theme-update} shows the results of pulling together multiple theme settings with the following code. \index{Themes!updating} \indexf{theme_get} \indexf{theme}
```{r theme-update, fig.cap="A bar chart and scatterplot created after a new visually consistent (if ugly!) theme has been applied."}
old_theme <- theme_update(
plot.background = element_rect(fill = "#3366FF"),
panel.background = element_rect(fill = "#003DF5"),
axis.text.x = element_text(colour = "#CCFF33"),
axis.text.y = element_text(colour = "#CCFF33", hjust = 1),
axis.title.x = element_text(colour = "#CCFF33", face = "bold"),
axis.title.y = element_text(colour = "#CCFF33", face = "bold",
angle = 90)
)
qplot(cut, data = diamonds, geom="bar")
qplot(cty, hwy, data = mpg)
theme_set(old_theme)
```
There is some duplication in this example because we have to specify the x and y elements separately. This is a necessary evil so that you can have total control over the appearance of the elements. If you are writing your own theme, you would probably want to write a function to minimise this repetition.
<!--
% \subsection{Custom element functions}
% \label{sub:custom-elements}
%
% To see how to write custom element functions, it's good to start by seeing how the built-in element functions work:
%
% % INTERWEAVE
% %
% % str(args(element_text()))
% % str(args(element_rect()))
% % str(args(element_line()))
% \input{_include/b9b6e26b5f4fc7e2bb7c9847fb6cd634.tex}
% % END
%
% You'll notice that these are very similar to the arguments to \f{textGrob}, \f{rectGrob} and \f{polylineGrob} and these are exactly the functions that they are based on. All that the element function do is set up some defaults.
%
% If you want to write your own, you need to copy this basic idea: take position arguments, and return a grid grob. For example, let's say we'd like to give the strips a 3d appearance. We can do this by drawing a rectangle, and then drawing highlights on the top-right and low-lights (shadows) on the bottom-left.
-->
## Customising scales and geoms {#sec:theme-scale-geom}
When producing a consistent theme, you may also want to tune some of the scale and geom defaults. Rather than having to manually specify the changes every time you add the scale or geom, you can use the following functions to alter the default settings for scales and geoms.
### Scales {#sub:customise-scales}
To change the default scale associated with an aesthetic, you can override the default by assigning a custom function to the appropriate default function (See Table~\ref{tbl:default-scales} for the defaults). The following example sets up continuous colour and fill scales for black-and-white printing: \index{Scales!customising defaults} \indexf{set_default_scale}
```{r eval=FALSE, echo=FALSE}
scale_colour_gradient2 <- function(...)
scale_colour_gradient2(..., low = "white", high = "black")
scale_fill_gradient <- function(...)
scale_fill_gradient(..., low = "white", high = "black")
```
This example sets up discrete colour and fill scales to use ColorBrewer.
```{r eval=FALSE, echo=FALSE}
scale_colour_discrete <- function(...)
scale_colour_brewer(..., palette = "Set1")
scale_fill_discrete <- function(...)
scale_fill_brewer(..., palette = "Set1")
```
### Geoms and stats {#sub:geoms-and-stats}
You can customise geoms and stats in a similar way with `update_geom_defaults()` and `update_stat_defaults()`. Unlike the other theme settings these will only affect plots *created* after the setting has been changed, not all plots drawn after the setting has been changed. The following example demonstrates changing the default point colour and changing the default histogram to a density ('true') histogram. \index{Geoms!customising defaults} \index{Scales!customising defaults} \indexf{update_geom_defaults}
```{r defaults, eval=FALSE}
update_geom_defaults("point", aes(colour = "darkblue"))
qplot(mpg, wt, data = mtcars)
update_stat_defaults("bin", aes(y = ..density..))
qplot(rating, data = movies, geom = "histogram", binwidth = 1)
```
Table~\ref{tbl:geom-defaults} lists all of the common aesthetic defaults. If you change the defaults for one geom, it's a good idea to change all the defaults for all the other geoms that you commonly use so that your plots look consistent. If you are unsure on what makes for a valid colour, line type, shape or size, [Specifications](#cha:specifications) gives the details. \index{Aesthetics!defaults}
<!--
\input{tbls/geom-defaults}
-->
## Saving your output {#sec:saving}
You have two basic choices of output: raster or vector. Vector graphics are procedural. This means that they are essentially 'infinitely' zoomable; there is no loss of detail. Raster graphics are stored as an array of pixels and have a fixed optimal viewing size. Figure \ref{fig:vector-raster} illustrates the basic differences for a basic circle. A good description is available at <http://tinyurl.com/rstrvctr>. \index{Saving} \index{Exporting} \index{Publication!saving output}
Generally, vector output is more desirable, but for complex graphics containing thousands of graphical objects it can be slow to render. In this case, it may be better to switch to raster output. For printed use, a high-resolution (e.g., 600 dpi) graphic may be an acceptable compromise, but may be large.
\begin{figure}[htbp]
\centering
\includegraphics[width= 0.5\linewidth]{diagrams/vector-raster}
\caption{The schematic difference between raster (left) and vector (right) graphics. }
\label{fig:vector-raster}
\end{figure}
To save your output, you can use the typical R way with disk-based graphics devices, which works for all packages, or a special function from `ggplot` that saves the current plot: `ggsave()`. `ggsave()` is optimised for interactive use and has the following important arguments: \indexf{ggsave}
* The `path` specifies the path where the image should be saved. The file extension will be used to automatically select the correct graphics device.
* Three arguments control output size. If left blank, the size of the current on-screen graphics device will be used. `width` and `height` can be used to specify the absolute size, or `scale` to specify the size of the plot relative to the on-screen display. When creating the final versions of graphics it's a good idea to set `width` and `height` so you know exactly what size output you're going to get.
* For raster graphics, the `dpi` argument controls the resolution of the plot. It defaults to 300, which is appropriate for most printers, but you may want to use 600 for particularly high-resolution output, or 72 for on-screen (e.g., web) display.
The following code shows these two methods. If you want to save multiple plots to a single file, you will need to explicitly open a disk-based graphics device (like `png()` or `pdf()`), print the plots and then close it with `dev.off()`.
```{r ggsave, eval=FALSE}
qplot(mpg, wt, data = mtcars)
ggsave(file = "output.pdf")
pdf(file = "output.pdf", width = 6, height = 6)
# If inside a script, you will need to explicitly print() plots
qplot(mpg, wt, data = mtcars)
qplot(wt, mpg, data = mtcars)
dev.off()
```
Table~\ref{tbl:graphic-recommendation} lists recommended graphic formats for various tasks. R output generally works best as part of a linux development tool chain: using png or pdf output in LaTeX documents. With Microsoft Office it is easiest to use a high-resolution (`dpi = 600`) png file. You can use vector output, but neither Windows meta files nor postscript supports transparency, and while postscript prints fine, it is only shown on screen if you add a preview in another software package. Transparency is used to show confidence intervals with the points showing through. If you copy and paste a graph into Word, and see that the confidence interval bands have vanished, that is the cause. The same advice holds for OpenOffice. \index{Exporting!to Word} \index{Exporting!to Powerpoint}
If you are using LaTeX, I recommend including `\DeclareGraphicsExtensions{.png,.pdf}` in the preamble. Then you don't need to specify the file extension in `\includegraphics{}` commands, but LaTeX will pick png files in preference to pdf. \index{Exporting!to Latex} I choose this order because you can produce all your files in pdf, and then go back and re-render any big ones as png. Another useful command is `\graphicspath{}` which specifies a path in which to look for graphics, allowing you to keep graphics in a separate directory to the text.
\begin{table}
\begin{center}
\begin{tabular}{lll}
\toprule
Software & Recommended graphics device \\
\midrule
Illustrator & svg \\
latex & ps \\
MS Office & png (600 dpi) \\
Open Office & png (600 dpi) \\
pdflatex & pdf, png (600 dpi) \\
web & png (72 dpi) \\
\bottomrule
\end{tabular}
\end{center}
\caption{Recommended graphic output for different purposes.}
\label{tbl:graphic-recommendation}
\end{table}
## Multiple plots on the same page {#sec:grid-layout}
If you want to arrange multiple plots on a single page, you'll need to learn a little bit of grid, the underlying graphics system used by `ggplot`. The key concept you'll need to learn about is a viewport: a rectangular subregion of the display. The default viewport takes up the entire plotting region, and by customising the viewport you can arrange a set of plots in just about any way you can imagine. \index{Layout} \index{Publication!multiple plots on the same page}
To begin, let's create three plots that we can experiment with. When arranging multiple plots on a page, it will usually be easiest to create them, assign them to variables and then plot them. This makes it easier to experiment with plot placement independent of content. The plots created by the code below are shown in Figure \ref{fig:layout}.
```{r layout, out.width="0.32\\linewidth", fig.cap="Three simple graphics we'll use to experiment with sophisticated plot layouts."}
(a <- qplot(date, unemploy, data = economics, geom = "line"))
(b <- qplot(uempmed, unemploy, data = economics) +
geom_smooth(se = F))
(c <- qplot(uempmed, unemploy, data = economics, geom="path"))
```
### Subplots
One common layout is to have a small subplot drawn on top of the main plot. To achieve this effect, we first plot the main plot, and then draw the subplot in a smaller viewport. Viewports are created with (surprise!) the `viewport()` function, with parameters `x`, `y`, `width` and `height` to control the size and position of the viewport. By default, the measurements are given in 'npc' units, which range from 0 to 1. The location (0, 0) is the bottom left, (1, 1) the top right and (0.5, 0.5) the centre of viewport. If these relative units don't work for your needs, you can also use absolute units, like `unit(2, "cm")` or `unit(1, "inch")`. \index{Sub-figures} \index{Subplots}
```{r viewports}
# A viewport that takes up the entire plot device
vp1 <- viewport(width = 1, height = 1, x = 0.5, y = 0.5)
vp1 <- viewport()
# A viewport that takes up half the width and half the height,
# located in the middle of the plot.
vp2 <- viewport(width = 0.5, height = 0.5, x = 0.5, y = 0.5)
vp2 <- viewport(width = 0.5, height = 0.5)
# A viewport that is 2cm x 3cm located in the center
vp3 <- viewport(width = unit(2, "cm"), height = unit(3, "cm"))
```
By default, the x and y parameters control the location of the centre of the viewport. When positioning the plot in other locations, you may need to use the `just` parameter to control which corner of the plot you are positioning. The following code gives some examples.
```{r viewport2}
# A viewport in the top right
vp4 <- viewport(x = 1, y = 1, just = c("right", "top"))
# Bottom left
vp5 <- viewport(x = 0, y = 0, just = c("right", "bottom"))
```
To draw the plot in our new viewport, we use the `vp` argument of the `ggplot.print()` method. This method is normally called automatically whenever you evaluate something on the command line, but because we want to customise the viewport, we need to call it ourselves. The result of this is shown in Figure \ref{fig:subplot-1}.
```{r polish, results='hide'}
pdf("figures/polishing-subplot-1.pdf", width = 4, height = 4)
subvp <- viewport(width = 0.4, height = 0.4, x = 0.75, y = 0.35)
b
print(c, vp = subvp)
dev.off()
```
This gives us what we want, but we need to make a few tweaks to the appearance: the text should be smaller, we want to remove the axis labels and shrink the plot margins. The result is shown in Figure \ref{fig:subplot-2}.
```{r polish2, results='hide'}
csmall <- c +
theme_gray(9) +
labs(x = NULL, y = NULL) +
theme(plot.margin = unit(c(1/4, 0, 0, 0), "lines"))
pdf("figures/polishing-subplot-2.pdf", width = 4, height = 4)
b
print(csmall, vp = subvp)
dev.off()
```
\begin{figure}[htbp]
\centering
\subfigure[Figure with subplot.]{
\includegraphics[width=0.5\textwidth]{figures/polishing-subplot-1}
\label{fig:subplot-1}
}%
\subfigure[Subplot tweaked for better display.]{
\includegraphics[width=0.5\textwidth]{figures/polishing-subplot-2}
\label{fig:subplot-2}
}
\caption{Two examples of a figure with subplot. It will usually be necessary to tweak the theme settings of the subplot for optimum display.}
\label{fig:subplot}
\end{figure}
Note we need to use `pdf()` (or `png()` etc.) to save the plots to disk because `ggsave()` only saves a single plot.
### Rectangular grids
A more complicated scenario is when you want to arrange a number of plots in a rectangular grid. Of course you could create a series of viewports and use what you've learned above, but doing all the calculations by hand is cumbersome. A better approach is to use `grid.layout()`, which sets up a regular grid of viewports with arbitrary heights and widths. You still need to create each viewport, but instead of explicitly specifying the position and size, you can specify the row and column of the layout.
The following example shows how this work. We first create the layout, here a 2 by 2 grid, then assign it to a viewport and push that viewport on to the plotting device. Now we are ready to draw each plot into its own position on the grid. We create a small function to save some typing, and then draw each plot in the desired place on the grid. You can supply a vector of rows or columns to span a plot over multiple cells. The results are shown in Figure \ref{fig:layout-2}.
```{r layout-2, out.width="\\linewidth", fig.cap="Three plots laid out in a grid using \\texttt{grid.layout()}."}
grid.newpage()
pushViewport(viewport(layout = grid.layout(2, 2)))
vplayout <- function(x, y)
viewport(layout.pos.row = x, layout.pos.col = y)
print(a, vp = vplayout(1, 1:2))
print(b, vp = vplayout(2, 1))
print(c, vp = vplayout(2, 2))
```
By default `grid.layout()` makes each cell the same size, but you can use the `widths` and `heights` arguments to make them different sizes. See the documentation for `grid.layout()` for more examples.