The R Project SVN R

Rev

Rev 68953 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
61990 ripley 1
% File src/library/grid/vignettes/plotexample.Rnw
68953 ripley 2
% Part of the R package, https://www.R-project.org
61990 ripley 3
% Copyright 2001-13 Paul Murrell and the R Core Team
4
% Distributed under GPL 2 or later
5
 
28502 murrell 6
\documentclass[a4paper]{article}
7
%\VignetteIndexEntry{Writing grid Code}
8
%\VignettePackage{grid}
49741 murrell 9
\newcommand{\code}[1]{\texttt{#1}}
49817 hornik 10
\newcommand{\pkg}[1]{{\normalfont\fontseries{b}\selectfont #1}}
11
\newcommand{\grid}{\pkg{grid}}
49741 murrell 12
\newcommand{\grob}{\code{grob}}
13
\newcommand{\gTree}{\code{gTree}}
14
\newcommand{\R}{{\sffamily R}}
85828 hornik 15
\newcommand{\I}[1]{#1}
28502 murrell 16
\setlength{\parindent}{0in}
17
\setlength{\parskip}{.1in}
28707 murrell 18
\setlength{\textwidth}{140mm}
19
\setlength{\oddsidemargin}{10mm}
28502 murrell 20
 
21
\newcommand{\aside}[1]{\begin{list}{}
22
                                   {\setlength{\leftmargin}{1in}
23
                                    \setlength{\rightmargin}{1in}
24
                                    \setlength{\itemindent}{0in}}
55298 ripley 25
                       \item \textsc{Aside:} \emph{#1}
28502 murrell 26
                       \end{list}}
27
 
28
\title{Writing \grid{} Code}
29
\author{Paul Murrell}
30
 
31
\begin{document}
32
\maketitle
33
 
28707 murrell 34
<<echo=FALSE, results=hide>>=
39581 murrell 35
library(grDevices)
36
library(stats) # for runif()
28707 murrell 37
library(grid)
38
ps.options(pointsize=12)
39
options(width=60)
55298 ripley 40
@
28707 murrell 41
 
28502 murrell 42
The \grid{} system contains a degree of complexity in order
43
to allow things like editing graphical objects, ``packing'' graphical
44
objects, and so on.  This means that many of the
45
predefined Grid graphics functions are
46
relatively complicated\footnote{Although there are exceptions;  some
49741 murrell 47
functions, such as \code{grid.show.viewport}, are purely for producing
28502 murrell 48
illustrative diagrams and remain simple and procedural.}.
49
 
55298 ripley 50
One design aim of \grid{} is to allow users to create simple graphics
51
simply and not to force them to use complicated concepts or write
52
complicated code unless they actually need to.  Along similar lines,
53
it is intended that people should be able to prototype even complex
54
graphics very simply and then refine the implementation into a more
42476 ripley 55
sophisticated form if necessary.
28502 murrell 56
 
55298 ripley 57
With the predefined graphics functions being fully-developed and
58
complicated implementations, there is a lack of examples of simple,
59
prototype code.  Furthermore, given that the aim is to allow a range
60
of ways to produce the same graphical output, there is a need for
61
examples which demonstrate the various stages, from simple to complex,
28502 murrell 62
that a piece of \grid{} code can go through.
63
 
55298 ripley 64
This document describes the construction of a scatterplot object, like
65
that shown below, going from the simplest, prototype implementation to
66
the most complex and sophisticated.  It demonstrates that if you only
67
want simple graphics output then you can do it pretty simply and
68
quickly.  It also demonstrates how to write functions that allow your
69
graphics to be used by other people.  Finally, it demonstrates how to
70
make your graphics fully interactive (or at least as interactive as
71
Grid will let you make it).
28502 murrell 72
 
73
@
74
This document should be read {\em after} the \grid{} Users'
75
Guide.  Here we are assuming that the reader has an understanding
76
of viewports, layouts, and units.  For the later sections of the
77
document, it will also be helpful to have an understanding of
49741 murrell 78
\R{}'s \code{S3} object system.
28502 murrell 79
 
80
\section*{Procedural \grid{}}
81
 
55298 ripley 82
The simplest way to produce graphical output in Grid is just like
83
producing standard R graphical output.  You simply issue a series of
84
graphics commands and each command adds more ink to the plot.  The
85
purpose of the commands is simply to produce graphics output; in
86
particular, we are not concerned with any values returned by the
87
plotting functions.  I will call this \emph{procedural graphics}.
28502 murrell 88
 
89
In order to draw a simple scatterplot, we can  issue a series
90
of commands which draw the various components of the plot.
91
 
92
Here are some random data to plot.
93
 
94
<<>>=
95
x <- runif(10)
96
y <- runif(10)
97
@
98
\noindent
99
The first step in creating the plot involves defining a ``data'' region.
100
This is a region which has sensible scales on the axes for plotting the
101
data and margins around the outside
102
for the axes to fit in, with a space for a title at the top.
103
 
104
<<datavp>>=
55298 ripley 105
data.vp <- viewport(x = unit(5, "lines"),
106
                    y = unit(4, "lines"),
107
                    width = unit(1, "npc") - unit(7, "lines"),
108
                    height = unit(1, "npc") - unit(7, "lines"),
109
                    just = c("left", "bottom"),
55315 ripley 110
                    xscale = range(x) + c(-0.05, 0.05)*diff(range(x)),
111
                    yscale = range(y) + c(-0.05, 0.05)*diff(range(y)))
28502 murrell 112
@
113
\noindent
55298 ripley 114
Now we create the data region and draw the components of the plot
115
relative to it: points, axes, labels, and a title.
28502 murrell 116
 
117
<<procplot>>=
118
pushViewport(data.vp)
119
grid.points(x, y)
120
grid.rect()
121
grid.xaxis()
122
grid.yaxis()
55298 ripley 123
grid.text("x axis", y = unit(-3, "lines"),
124
          gp = gpar(fontsize = 14))
125
grid.text("y axis", x = unit(-4, "lines"),
126
          gp = gpar(fontsize = 14), rot = 90)
42476 ripley 127
grid.text("A Simple Plot",
55298 ripley 128
          y = unit(1, "npc") + unit(1.5, "lines"),
129
          gp = gpar(fontsize = 16))
28502 murrell 130
popViewport()
131
<<fig=TRUE, echo=FALSE, results=hide>>=
132
<<procplot>>
133
@
134
\section*{Facilitating Annotation}
135
 
42476 ripley 136
Issuing a series of commands to produce a plot, like in the previous
28502 murrell 137
section, allows the user to have a great deal of flexibility.
42476 ripley 138
It is always possible to recreate viewports in order to add
28502 murrell 139
further annotations.  For example, the following code
140
recreates the data region in order to place the date
141
at the bottom right corner.
142
 
143
<<ann1>>=
144
pushViewport(data.vp)
55298 ripley 145
grid.text(date(), x = unit(1, "npc"), y = 0,
146
          just = c("right", "bottom"), gp = gpar(col="grey"))
28502 murrell 147
popViewport()
148
<<fig=TRUE, echo=FALSE, results=hide>>=
149
<<procplot>>
150
<<ann1>>
151
@
152
 
42476 ripley 153
When more complex arrangements of viewports are involved, there may be
28502 murrell 154
a bewildering array of viewports created, which may make it difficult
55298 ripley 155
for other users to revisit a particular region of a plot.  A
156
\code{lattice} plot is a good example.  In such cases, it will be more
157
cooperative to use \code{upViewport()} rather than
158
\code{popViewport()} and leave the viewports that were created during
159
the drawing of the plot.  Other users can then use \code{vpPath}s to
160
navigate to the desired region.  For example, here is a slight
161
modification of the original series of commands, where the original
162
data viewport is given a name and \code{upViewport()} is used at the
163
end.
28502 murrell 164
 
165
<<results=hide>>=
55298 ripley 166
data.vp <- viewport(name = "dataregion",
167
                    x = unit(5, "lines"),
168
                    y = unit(4, "lines"),
169
                    width = unit(1, "npc") - unit(7, "lines"),
170
                    height = unit(1, "npc") - unit(7, "lines"),
171
                    just = c("left", "bottom"),
55315 ripley 172
                    xscale = range(x) + c(-0.05, 0.05)*diff(range(x)),
173
                    yscale = range(y) + c(-0.05, 0.05)*diff(range(y)))
28502 murrell 174
pushViewport(data.vp)
175
grid.points(x, y)
176
grid.rect()
177
grid.xaxis()
178
grid.yaxis()
55298 ripley 179
grid.text("x axis", y = unit(-3, "lines"),
180
          gp = gpar(fontsize = 14))
181
grid.text("y axis", x = unit(-4, "lines"),
182
          gp = gpar(fontsize = 14), rot = 90)
42476 ripley 183
grid.text("A Simple Plot",
55298 ripley 184
          y = unit(1, "npc") + unit(1.5, "lines"),
185
          gp = gpar(fontsize = 16))
28502 murrell 186
upViewport()
187
@
188
 
55298 ripley 189
The date is now added using \code{downViewport()} to get to the data
190
region.
28502 murrell 191
 
192
<<results=hide>>=
193
downViewport("dataregion")
55298 ripley 194
grid.text(date(), x = unit(1, "npc"), y  =  0,
195
          just = c("right", "bottom"), gp = gpar(col = "grey"))
28502 murrell 196
upViewport()
197
@
198
\section*{Writing a \grid{} Function}
199
 
200
Here is the scatterplot code wrapped up as a simple function.
201
 
202
<<funcplot>>=
55298 ripley 203
splot <- function(x = runif(10), y = runif(10), title = "A Simple Plot") {
204
    data.vp <- viewport(name = "dataregion",
205
                        x = unit(5, "lines"),
206
                        y = unit(4, "lines"),
207
                        width = unit(1, "npc") - unit(7, "lines"),
208
                        height = unit(1, "npc") - unit(7, "lines"),
209
                        just = c("left", "bottom"),
210
                        xscale = range(x) + c(-.05, .05)*diff(range(x)),
211
                        yscale = range(y) + c(-.05, .05)*diff(range(y)))
212
    pushViewport(data.vp)
213
    grid.points(x, y)
214
    grid.rect()
215
    grid.xaxis()
216
    grid.yaxis()
217
    grid.text("y axis", x = unit(-4, "lines"),
218
              gp = gpar(fontsize = 14), rot = 90)
219
    grid.text(title, y = unit(1, "npc") + unit(1.5, "lines"),
220
              gp = gpar(fontsize = 16))
221
    upViewport()
28502 murrell 222
}
223
@
42476 ripley 224
There are several advantages to creating a
28502 murrell 225
function:
226
\begin{enumerate}
42476 ripley 227
\item We get the standard advantages of a function:
28502 murrell 228
we can reuse and maintain the plot code more easily.
42476 ripley 229
\item We can slightly generalise the plot.  In this case, we can use it for
28502 murrell 230
different data and have a different title.  We could
231
add more arguments to allow different margins, control over
232
the axis scales, and so on.
233
\item The plot can be embedded in other graphics output.
234
\end{enumerate}
49741 murrell 235
Here is an example which uses the \code{splot()} function to
42476 ripley 236
create a slightly modified scatterplot, embedded within
28502 murrell 237
other \grid{} output.
238
 
239
<<embed, fig=TRUE, results=hide>>=
55298 ripley 240
grid.rect(gp = gpar(fill = "grey"))
241
message <-
242
    paste("I could draw all sorts",
243
          "of stuff over here",
244
          "then create a viewport",
245
          "over there and stick",
246
          "a scatterplot in it.", sep = "\n")
247
grid.text(message, x = 0.25)
248
grid.lines(x = unit.c(unit(0.25, "npc") + 0.5*stringWidth(message) +
249
           unit(2, "mm"),
250
           unit(0.5, "npc") - unit(2, "mm")),
251
           y = 0.5,
252
           arrow = arrow(angle = 15, type = "closed"),
253
           gp = gpar(lwd = 3, fill = "black"))
254
pushViewport(viewport(x = 0.5, height = 0.5, width = 0.45, just = "left",
255
                      gp = gpar(cex = 0.5)))
256
grid.rect(gp = gpar(fill = "white"))
257
splot(1:10, 1:10, title = "An Embedded Plot")
28502 murrell 258
upViewport()
259
@
260
 
42476 ripley 261
It is still straightforward to annotate the scatterplot as long as
28502 murrell 262
we have enough information about the viewports.  In this case,
49741 murrell 263
a non-strict \code{downViewport()} will still work (though note
264
that \code{upViewport({\bf 0})} is required to get right back to the
28502 murrell 265
top level).
266
 
55298 ripley 267
<<ann2, echo = FALSE, eval=FALSE>>=
28502 murrell 268
downViewport("dataregion")
55298 ripley 269
grid.text(date(), x = unit(1, "npc"), y  =  0,
270
          just = c("right", "bottom"), gp = gpar(col = "grey"))
28502 murrell 271
upViewport(0)
272
<<echo=FALSE, results=hide>>=
273
<<embed>>
274
<<ann2>>
275
@
276
\section*{Creating \grid{} Graphical Objects}
277
 
42476 ripley 278
A \grid{} function like the one in the previous section provides
28502 murrell 279
output which is very flexible and can be annotated in arbitrary ways
280
and can be embedded within other output.  This is likely
281
to satisfy most uses.
282
 
283
However, there are some things that cannot be done (or at least would
284
be extremely hard to do) with such a function.  The output produced by
55298 ripley 285
the function cannot be addressed as a coherent whole.  It is not
286
possible, for example, to to change the \code{x} and \code{y} data
287
used in the plot and have the points and axes update automatically.
288
There is no scatterplot object to save; the individual components
289
exist, but they are not bound together as a whole.  If/when these
290
sorts of issues become important, it becomes necessary to create a
291
\grid{} graphical object (a \grob{}) to represent the plot.
28502 murrell 292
 
293
The first step is to write a function which will create a \grob{}
55240 ripley 294
-- a \emph{constructor} function.  In most cases, this will involve
28502 murrell 295
creating a special sort of \grob{} called a \gTree{};  this is just
296
a \grob{} that can have other \grob{}s as children.  Here's an example
49741 murrell 297
for creating an \code{splot} \grob{}.  I have put bits of the
42476 ripley 298
construction into separate functions, for reasons which will become
28502 murrell 299
apparent later.
300
 
301
<<>>=
302
splot.data.vp <- function(x, y) {
55298 ripley 303
  viewport(name = "dataregion",
304
           x = unit(5, "lines"),
305
           y = unit(4, "lines"),
306
           width = unit(1, "npc") - unit(7, "lines"),
307
           height = unit(1, "npc") - unit(7, "lines"),
308
           just = c("left", "bottom"),
309
           xscale = range(x) + c(-.05, .05)*diff(range(x)),
310
           yscale = range(y) + c(-.05, .05)*diff(range(y)))
28502 murrell 311
}
312
 
313
splot.title <- function(title) {
55298 ripley 314
      textGrob(title, name = "title",
315
               y = unit(1, "npc") + unit(1.5, "lines"),
316
               gp = gpar(fontsize = 16), vp = "dataregion")
28502 murrell 317
}
318
 
319
splot <- function(x, y, title, name=NULL, draw=TRUE, gp=gpar(), vp=NULL) {
55298 ripley 320
    spg <- gTree(x = x, y = y, title = title, name = name,
321
                 childrenvp  =  splot.data.vp(x, y),
322
                 children = gList(rectGrob(name = "border",
323
                                           vp = "dataregion"),
324
                 xaxisGrob(name = "xaxis", vp = "dataregion"),
325
                 yaxisGrob(name = "yaxis", vp = "dataregion"),
326
                 pointsGrob(x, y, name = "points", vp = "dataregion"),
327
                 textGrob("x axis", y = unit(-3, "lines"), name = "xlab",
328
                          gp = gpar(fontsize = 14), vp = "dataregion"),
329
                 textGrob("y axis", x = unit(-4, "lines"), name = "ylab",
330
                          gp = gpar(fontsize = 14), rot = 90,
331
                          vp = "dataregion"),
332
                 splot.title(title)),
333
                 gp = gp, vp = vp,
334
                 cl = "splot")
335
    if (draw) grid.draw(spg)
336
    spg
28502 murrell 337
}
338
@
339
 
340
There are four important additions to the argument list compared
49741 murrell 341
to the original \code{splot()} function:
28502 murrell 342
\begin{enumerate}
49741 murrell 343
\item The \code{name} argument allows a string identifier to be
55298 ripley 344
  associated with the scatterplot object we create.  This is important
345
  for being able to specify the scatterplot when we try to edit it
346
  after drawing it and/or when it is part of a larger \grob{} (see
347
  later examples).
28502 murrell 348
 
55298 ripley 349
\item The \code{draw} argument makes it possible to use the function
350
  in a procedural manner as before:
351
 
28502 murrell 352
<<splotgrob, eval=FALSE, echo=FALSE>>=
55298 ripley 353
sg <- splot(1:10, 1:10, "Same as Before", name = "splot", draw = FALSE)
28502 murrell 354
<<>>=
55298 ripley 355
splot(1:10, 1:10, "Same as Before", name = "splot")
28502 murrell 356
downViewport("dataregion")
55298 ripley 357
grid.text(date(), x = unit(1, "npc"), y = 0,
358
          just = c("right", "bottom"), gp = gpar(col = "grey"))
28502 murrell 359
upViewport(0)
360
@
49741 murrell 361
\item The \code{gp} argument allows the user to supply \code{gpar()}
55298 ripley 362
  settings for the scatterplot as a whole.
363
 
364
\item The \code{vp} argument allows the user to supply a viewport for
365
  the \code{splot} \grob{} to be drawn in.  This is especially useful
366
  for specifying a \code{vpPath} when the \code{splot} is used as a
367
  component of another \grob{} (see scatterplot matrix example below).
28502 murrell 368
\end{enumerate}
369
 
370
The important parts of the \gTree{}  definition are:
371
\begin{enumerate}
55298 ripley 372
\item The \code{children} argument provides a list of \grob{}s which
373
  are part of the scatterplot.  When the scatterplot is drawn, all
374
  children will be drawn.  Notice that instead of the procedural
375
  \code{grid.*()} functions we use \code{*Grob()} functions which just
376
  produce \grob{}s and do not perform any drawing.  Also notice that I
377
  have given each of the children a name; this will make it possible
378
  to access the components of the scatterplot (see later examples).
49741 murrell 379
\item The \code{childrenvp} argument provides a viewport (or
55298 ripley 380
  \code{vpStack}, \code{vpList}, or \code{vpTree}) which will be
381
  pushed before the children are drawn.  The difference between this
382
  argument and the \code{vp} argument common to all \grob{}s is that
383
  the \code{vp} is pushed before drawing the children and then popped
384
  after, whereas the \code{childrenvp} gets pushed \emph{and} then a
385
  call to \code{upViewport()} is made before the children are drawn.
386
  This allows the children to simply specify the viewport they should
387
  be drawn in by way of a \code{vpPath} in their \code{vp} argument.
388
  In this way, viewports remain available for further annotation such
389
  as we have already seen in procedural code.
390
\item The \code{gp} and \code{vp} arguments are automatically handled
391
  by the \gTree{} drawing methods so that \code{gpar()} settings will
392
  be enforced and the viewport will be pushed when the \code{splot} is
393
  drawn.
394
\item The \code{cl} argument means that the \grob{} created is a
395
  special sort of \grob{} called \code{splot}.  This will allow us to
396
  write methods specifically for our scatterplot (see later examples).
28502 murrell 397
\end{enumerate}
398
 
399
 
400
@
401
 
55298 ripley 402
Now that we have a \grob{}, there are some more interesting things
403
that we can do with it.  First of all, the \code{splot} \grob{}
404
provides a container for the \grob{}s which make up the scatterplot.
49741 murrell 405
If we modify the \code{splot} \grob{}, it affects all of the children.
28502 murrell 406
 
407
<<results=hide>>=
55298 ripley 408
splot(1:10, 1:10, "Same as Before", name = "splot")
409
grid.edit("splot", gp = gpar(cex=0.5))
28502 murrell 410
<<fig=TRUE, echo=FALSE, results=hide>>=
411
<<splotgrob>>
55298 ripley 412
sg <- editGrob(sg, gp = gpar(cex = 0.5))
28502 murrell 413
grid.draw(sg)
42476 ripley 414
@
28502 murrell 415
 
49741 murrell 416
We can access elements of the \code{splot} \grob{} to edit them
28502 murrell 417
individually.
418
 
419
<<results=hide>>=
55298 ripley 420
splot(1:10, 1:10, "Same as Before", name = "splot")
421
grid.edit(gPath("splot", "points"), gp = gpar(col = 1:10))
28502 murrell 422
<<fig=TRUE, echo=FALSE, results=hide>>=
423
<<splotgrob>>
55298 ripley 424
sg <- editGrob(sg, gPath = "points", gp = gpar(col = 1:10))
28502 murrell 425
grid.draw(sg)
426
 
427
@
428
 
429
With a little more work we can make the scatterplot a bit more dynamic.
49741 murrell 430
The following describes a \code{editDetails()} method for the
431
\code{splot} \grob{}.  This will be called whenever a scatterplot
28502 murrell 432
is edited and will update the components of the scatterplot.
433
 
434
<<>>=
435
editDetails.splot <- function(x, specs) {
55298 ripley 436
    if (any(c("x", "y") %in% names(specs))) {
437
        if (is.null(specs$x)) xx <- x$x else xx <- specs$x
438
        if (is.null(specs$y)) yy <- x$y else yy <- specs$y
439
        x$childrenvp <- splot.data.vp(xx, yy)
440
        x <- addGrob(x, pointsGrob(xx, yy, name = "points",
441
                                   vp = "dataregion"))
442
    }
28502 murrell 443
  x
444
}
55298 ripley 445
splot(1:10, 1:10, "Same as Before", name = "splot")
446
grid.edit("splot", x = 1:100, y = (1:100)^2)
28502 murrell 447
<<fig=TRUE, echo=FALSE, results=hide>>=
448
<<splotgrob>>
55298 ripley 449
sg <- editGrob(sg, x = 1:100, y = (1:100)^2)
28502 murrell 450
grid.draw(sg)
451
@
452
 
55298 ripley 453
The \code{splot} \grob{} can also be used in the construction of other
454
\grob{}s.  Here's a simple scatterplot matrix \grob{}\footnote{{\bf
455
    Warning:} As the number of \grob{}s in a \gTree{} gets larger the
456
  construction of the \gTree{} will get slow.  If this happens, the
457
  best solution is to just use a \grid{} function rather than a
458
  \gTree{}, and wait for me to implement some ideas for speeding
459
  things up!}.
28502 murrell 460
 
461
<<fig=TRUE>>=
55298 ripley 462
cellname <- function(i, j) paste("cell", i, j, sep = "")
28502 murrell 463
 
464
splom.vpTree <- function(n) {
55298 ripley 465
    vplist <- vector("list", n^2)
466
    for (i in 1:n)
467
        for (j in 1:n)
468
            vplist[[(i - 1)*n + j]] <-
469
              viewport(layout.pos.row = i, layout.pos.col = j,
470
                       name = cellname(i, j))
471
    vpTree(viewport(layout = grid.layout(n, n), name = "cellgrid"),
28502 murrell 472
    do.call("vpList", vplist))
473
}
42476 ripley 474
 
55298 ripley 475
cellpath <- function(i, j) vpPath("cellgrid", cellname(i, j))
28502 murrell 476
 
55298 ripley 477
splom <- function(df, name = NULL, draw = TRUE) {
478
    n <- dim(df)[2]
479
    glist <- vector("list", n*n)
480
    for (i in 1:n)
481
        for (j in 1:n) {
482
            glist[[(i - 1)*n + j]] <-if (i == j)
483
                textGrob(paste("diag", i, sep = ""),
484
                         gp = gpar(col = "grey"), vp = cellpath(i, j))
485
            else if (j > i)
486
                textGrob(cellname(i, j),
487
                         name = cellname(i, j),
488
                         gp = gpar(col = "grey"), vp = cellpath(i, j))
489
            else
490
                splot(df[,j], df[,i], "",
491
                      name = paste("plot", i, j, sep = ""),
492
                      vp = cellpath(i, j),
493
                      gp = gpar(cex = 0.5), draw = FALSE)
494
        }
495
    smg <- gTree(name = name, childrenvp = splom.vpTree(n),
496
                 children = do.call("gList", glist))
497
    if (draw) grid.draw(smg)
498
    smg
28502 murrell 499
}
500
 
55298 ripley 501
df <- data.frame(x = rnorm(10), y = rnorm(10), z = rnorm(10))
28502 murrell 502
splom(df)
503
@
504
 
505
This \grob{} can be edited as usual:
506
 
507
<<>>=
508
splom(df)
55298 ripley 509
grid.edit("plot21::xlab", label = "", redraw = FALSE)
510
grid.edit("plot32::ylab", label = "", redraw = FALSE)
511
grid.edit("plot21::xaxis", label = FALSE, redraw = FALSE)
512
grid.edit("plot32::yaxis", label = FALSE)
30260 murrell 513
<<splomgrob, eval=FALSE, echo=FALSE>>=
55298 ripley 514
smg <- splom(df, draw = FALSE)
28502 murrell 515
<<fig=TRUE, echo=FALSE, results=hide>>=
516
<<splomgrob>>
55298 ripley 517
smg <- editGrob(smg, gPath = "plot21::xaxis", label = FALSE)
518
smg <- editGrob(smg, gPath = "plot21::xlab", label = "")
519
smg <- editGrob(smg, gPath = "plot32::yaxis", label = FALSE)
520
smg <- editGrob(smg, gPath = "plot32::ylab", label = "")
28502 murrell 521
grid.draw(smg)
522
@
523
 
55298 ripley 524
But of more interest, because this is a \grob{}, is the
525
\emph{programmatic} interface.  With a \grob{} (as opposed to a
526
function) it is possible to modify the description of what is being
527
drawn via an API (as opposed to having to edit the original code).  In
528
the following, we remove one of the ``spare'' cell labels and put in
529
its place the current date.
28502 murrell 530
 
531
<<>>=
55298 ripley 532
splom(df, name = "splom")
28502 murrell 533
grid.remove("cell12")
55298 ripley 534
grid.add("splom", textGrob(date(), name = "date",
535
                           gp = gpar(fontface = "italic"),
536
                           vp = "cellgrid::cell12"))
28502 murrell 537
<<fig=TRUE, echo=FALSE, results=hide>>=
538
<<splomgrob>>
539
smg <- removeGrob(smg, "cell12")
55298 ripley 540
smg <- addGrob(smg, textGrob(date(), name = "date",
541
                             gp = gpar(fontface = "italic"),
542
                             vp = "cellgrid::cell12"))
28502 murrell 543
grid.draw(smg)
544
@
545
 
546
With the date added as a component of the scatterplot matrix, it is
547
saved as part of the matrix.  The next sequence saves the scatterplot
42476 ripley 548
matrix, loads it again, extracts the bottom-left plot and the date
28502 murrell 549
and just draws those two objects together.
550
 
551
<<>>=
55298 ripley 552
splom(df, name = "splom")
28502 murrell 553
grid.remove("cell12")
55298 ripley 554
grid.add("splom", textGrob(date(), name = "date",
555
                           gp = gpar(fontface = "italic"),
556
                           vp = "cellgrid::cell12"))
28502 murrell 557
smg <- grid.get("splom")
55298 ripley 558
save(smg, file = "splom.RData")
28502 murrell 559
load("splom.RData")
560
plot <- getGrob(smg, "plot31")
561
date <- getGrob(smg, "date")
55298 ripley 562
plot <- editGrob(plot, vp = NULL, gp = gpar(cex = 1))
563
date <- editGrob(date, y = unit(1, "npc") - unit(1, "lines"), vp = NULL)
28502 murrell 564
grid.newpage()
565
grid.draw(plot)
566
grid.draw(date)
567
 
568
<<fig=TRUE, echo=FALSE, results=hide>>=
569
<<splomgrob>>
570
smg <- removeGrob(smg, "cell12")
55298 ripley 571
smg <- addGrob(smg, textGrob(date(), name = "date",
572
                             gp = gpar(fontface = "italic"),
573
                             vp = "cellgrid::cell12"))
574
save(smg, file = "splom.RData")
28502 murrell 575
load("splom.RData")
576
plot <- getGrob(smg, "plot31")
577
date <- getGrob(smg, "date")
55298 ripley 578
plot <- editGrob(plot, vp = NULL, gp = gpar(cex = 1))
579
date <- editGrob(date, y = unit(1, "npc") - unit(1, "lines"), vp = NULL)
28502 murrell 580
grid.draw(plot)
581
grid.draw(date)
582
@
583
 
55298 ripley 584
All of this may seem a bit irrelevant to interactive use, but it does
585
provide a basis for creating an editable plot interface as used in
85828 hornik 586
\I{M.~Kondrin}'s \pkg{Rgrace} package (available on CRAN 2005--7).
28502 murrell 587
 
42476 ripley 588
\end{document}