The R Project SVN R

Rev

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