1% File src/library/grid/vignettes/grobs.Rnw
2% Part of the R package, https://www.R-project.org
3% Copyright 2001-13 Paul Murrell and the R Core Team
4% Distributed under GPL 2 or later
5
6\documentclass[a4paper]{article}
7
8\usepackage{Rd}
9
10% \VignetteIndexEntry{Working with grid grobs}
11% \VignettePackage{grid}
12
13\newcommand{\grid}{\pkg{grid}}
14\newcommand{\grob}{\code{grob}}
15\newcommand{\gTree}{\code{gTree}}
16\newcommand{\gPath}{\code{gPath}}
17\newcommand{\lattice}{\CRANpkg{lattice}}
18
19\setlength{\parindent}{0in}
20\setlength{\parskip}{.1in}
21\setlength{\textwidth}{140mm}
22\setlength{\oddsidemargin}{10mm}
23
24\title{Modifying \grid{} \code{grob}s}
25\author{Paul Murrell}
26
27\begin{document}
28\maketitle
29
30<<echo=FALSE, results=hide>>=
31library(grDevices)
32library(grid)
33ps.options(pointsize = 12)
34options(width = 60)
35@
36There is a distinction between \grob{}s which are just stored
37in user-level \R{} objects and \grob{}s which represent
38drawn output (i.e., \grob{}s on the \grid{} display list).
39There is a naming convention that \code{grid.*()}  functions are
40(mainly) used for their side-effect of producing output or
41modifying existing output (they create/affect \grob{}s on the display list).
42Functions of the form \code{*Grob()} are used for their return value;
43the \grob{} that they create/modify.
44For example, the following creates a \grob{} and then modifies it, but
45performs absolutely no drawing;  this is purely manipulating a
46description of a graphical object.
47
48<<>>=
49gl <- linesGrob()
50gl <- editGrob(gl, gp = gpar(col = "green"))
51@
52
53The next example produces output.  A \grob{} is returned,
54but that \grob{} is just a description of the output that was drawn
55and has no direct link to the output.  It is possible to access the
56grob representing the output by
57using the \grob{}'s \code{name}.  In order to access a \grob{}
58which represents drawn output (i.e., a \grob{} on the display list),
59you must specify a \gPath{}.  The \gPath{} should be created using the
60\code{gPath()} function for writing scripts, but in interactive use, it
61is possible to specify the \gPath{} directly as a string.  The code below
62shows both approaches.
63
64<<results=hide>>=
65grid.newpage()
66grid.lines(name = "lines")
67grid.edit(gPath("lines"), gp = gpar(col = "pink"))
68grid.edit("lines", gp = gpar(col = "red"))
69@
70
71Complex graphical objects are provided by the \gTree{} class.  A
72\gTree{} is a \grob{} which may have other \grob{}s as children.  The
73\code{xaxis} and \code{yaxis} \grob{}s provided by \grid{} are
74examples of \gTree{}s; the children of an axis include a lines \grob{}
75for the tick-marks and a text \grob{} for the tick-mark labels.  The
76function \code{childNames()} can be used to list the names of the
77children of a \gTree{}.  When dealing with these hierarchical objects,
78more complex \gPath{}s can be used to access children of a \gTree{}.
79In the following example, an x-axis is drawn, then the xaxis itself is
80edited to modify the locations of the tick-marks, then the xaxis's
81text child is edited to modify the location of the labels on the
82tick-marks.
83
84<<results=hide>>=
85grid.newpage()
86pushViewport(viewport(w = .5, h = .5))
87grid.rect(gp = gpar(col = "grey"))
88grid.xaxis(name = "myxaxis")
89grid.edit("myxaxis", at = 1:4/5)
90grid.edit(gPath("myxaxis", "labels"), y = unit(-1, "lines"))
91
92@
93
94This next example extends the idea a step further to edit the child of
95a child of a \gTree{}.  It also shows the use of the \gTree{} function
96to construct a simple \gTree{} (this is just creating an instance of
97the \gTree{} class -- it is also possible to extend the \gTree{} class
98in order to provide specialised behaviour for drawing and other
99things; more on this later).  Finally, the example demonstrates how
100\gPath{}s of depth greater than 1 can be specified directly as a
101string.
102
103<<results=hide>>=
104grid.newpage()
105pushViewport(viewport(w = .5, h = .5))
106myplot <-
107    gTree(name = "myplot",
108          children = gList(rectGrob(name = "box", gp = gpar(col = "grey")),
109                           xaxisGrob(name = "xaxis")))
110grid.draw(myplot)
111grid.edit("myplot::xaxis", at = 1:10/11)
112grid.edit("myplot::xaxis::labels", label = round(1:10/11, 2))
113grid.edit("myplot::xaxis::labels", y = unit(-1, "lines"))
114@
115\code{"grobwidth"} units require a \grob{} to give the width of.
116There are two ways to specify the \grob{}.  The following example
117shows the most obvious method of simply supplying a \grob{}.  Notice
118that if you modify \code{gt} it will have no effect on the width of
119the drawn rectangle.
120
121<<results=hide>>=
122grid.newpage()
123gt <- grid.text("Hi there")
124grid.rect(width = unit(1, "grobwidth", gt))
125@
126In order to allow a \code{"grobwidth"} unit to track changes in the
127\grob{}, it is possible to specify a \gPath{} rather than a \grob{} as
128the data for a \code{"grobwidth"} unit.  The following example
129modifies the previous example to use a \gPath{}.  Now, the width of
130the rectangle changes when the width of the underlying \grob{}
131changes.
132
133<<results=hide>>=
134grid.newpage()
135gt <- grid.text("Hi there", name = "sometext")
136grid.rect(width = unit(1, "grobwidth", "sometext"))
137grid.edit("sometext", label = "Something different")
138@
139
140One issue in the evaluation of \code{"grobwidth"} units involves
141establishing the correct ``context'' for a \grob{} when determining its width
142(if a \grob{} has a viewport in its \code{vp} slot then that viewport gets
143pushed before the \grob{} is drawn;  that viewport should also be pushed
144when determining the width
145of the \grob{}).
146To achieve this there are
147\code{preDrawDetails()},  \code{drawDetails()}, and \code{postDrawDetails()}
148generic functions.
149(suggestions for better names welcome!).  The idea is that
150pushing and popping of viewports should occur in the \code{pre} and
151\code{post} generics, and any actual drawing happens in the main
152\code{drawDetails()} generic.  This allows the code that calculates a
153\grob{} width to call the \code{preDrawDetails()} in order to establish
154the context in which the \grob{} would be drawn before calculating its
155width.  The following example shows a test case;  a \grob{} is created
156(extending to a new class to allow specific methods to be written),
157and methods are provided which establish a particular context
158for drawing the \grob{}.  These methods are used both in the drawing
159of the \grob{} and in the calculation of the \grob{}'s width (when
160drawing a bounding rectangle).
161
162<<results=hide>>=
163grid.newpage()
164mygrob <- grob(name = "mygrob", cl = "mygrob")
165preDrawDetails.mygrob <- function(x)
166    pushViewport(viewport(gp = gpar(fontsize = 20)))
167
168drawDetails.mygrob <- function(x, recording = TRUE)
169    grid.draw(textGrob("hi there"), recording = FALSE)
170
171postDrawDetails.mygrob <- function(x) popViewport()
172
173widthDetails.mygrob <- function(x) unit(1, "strwidth", "hi there")
174
175grid.draw(mygrob)
176grid.rect(width = unit(1, "grobwidth", mygrob))
177@
178
179This next example shows a slightly different test case where the
180standard \code{preDrawDetails()} and \code{postDrawDetails()} methods
181are used, but the \grob{} does have a \code{vp} slot so these methods
182do something.  Another interesting feature of this example is the
183slightly more complex \gTree{} that is created.  The \gTree{} has a
184\code{childrenvp} specified.  When the \gTree{} is drawn, this
185viewport is pushed and then ``up''ed before the children of the
186\gTree{} are drawn.  This means that the children of the \gTree{} can
187specify a \code{vpPath} to the viewport they should be in.  This
188allows the parent \gTree{} to create a suite of viewports and then
189children of the \gTree{} select which one they want -- this can be
190more efficient than having each child push and pop the viewports it
191needs, especially if several children are drawn within the same
192viewport.  Another, more realistic example of this is given later.
193
194<<results=hide>>=
195grid.newpage()
196mygtree <- gTree(name = "mygrob",
197                 childrenvp = viewport(name = "labelvp",
198                                       gp = gpar(fontsize = 20)),
199                 children = gList(textGrob("hi there", name = "label",
200                   vp = "labelvp")),
201                 cl = "mygtree")
202widthDetails.mygtree <- function(x)
203    unit(1, "grobwidth", getGrob(x, "label"))
204
205grid.draw(mygtree)
206grid.rect(width = unit(1, "grobwidth", mygtree))
207@
208
209Constructing a description of a \code{frame} \grob{} must be
210done via \code{packGrob()} and \code{placeGrob()}.  The following example
211shows the construction of a simple frame consisting of two
212equal-size columns.
213
214<<results = hide>>=
215grid.newpage()
216fg <- frameGrob(layout = grid.layout(1, 2))
217fg <- placeGrob(fg, textGrob("Hi there"), col = 1)
218fg <- placeGrob(fg, rectGrob(), col = 2)
219grid.draw(fg)
220@
221
222This next example constructs a slightly fancier frame using packing.
223
224<<results=hide>>=
225grid.newpage()
226pushViewport(viewport(layout = grid.layout(2, 2)))
227drawIt <- function(row, col) {
228    pushViewport(viewport(layout.pos.col = col, layout.pos.row = row))
229    grid.rect(gp = gpar(col = "grey"))
230    grid.draw(fg)
231    upViewport()
232}
233fg <- frameGrob()
234fg <- packGrob(fg, textGrob("Hi there"))
235fg <- placeGrob(fg, rectGrob())
236drawIt(1, 1)
237fg <- packGrob(fg, textGrob("Hello again"), side = "right")
238drawIt(1, 2)
239fg <- packGrob(fg, rectGrob(), side = "right", width = unit(1, "null"))
240drawIt(2, 2)
241@
242
243In order to allow frames to update when the objects packed within them
244are modified, there is a \code{dynamic} argument to \code{packGrob()}
245(and \code{grid.pack()}).  The following extends the previous example
246to show how this might be used.  Another feature of this example is
247the demonstration of ``non-strict'' searching that occurs in the
248\code{grid.edit()} call; the \grob{} called \code{"midtext"} is not at
249the top-level, but is still found.  Something like
250\code{grid.get("midtext", strict = TRUE)} would fail.
251
252<<results=hide>>=
253grid.newpage()
254fg <- frameGrob()
255fg <- packGrob(fg, textGrob("Hi there"))
256fg <- placeGrob(fg, rectGrob())
257fg <- packGrob(fg, textGrob("Hello again", name = "midtext"),
258               side = "right", dynamic = TRUE)
259fg <- packGrob(fg, rectGrob(), side = "right", width = unit(1, "null"))
260grid.draw(fg)
261grid.edit("midtext", label = "something much longer")
262@
263
264There have been a few examples already which have involved creating a
265\gTree{}.  This next example explicitly demonstrates this technique.
266A \gTree{} is created with two important components.  The
267\code{childrenvp} is a \code{vpTree} consisting of a
268\code{"plotRegion"} viewport to provide margins around a plot and a
269\code{"dataRegion"} viewport to provide x- and y-scales.  The
270\code{"dataRegion"} gets pushed within the \code{"plotRegion"} and
271both are pushed and then ``up''ed before the children are drawn.  The
272\code{children} of the \gTree{} are an \code{xaxis} and a \code{yaxis}
273both drawn within the \code{"dataRegion"}, and a \code{rect} drawn
274around the border of the \code{"plotRegion"}.  A further feature of
275this example is the use of the \code{addGrob()} and
276\code{removeGrob()} functions to modify the \gTree{}.  The first
277modification involves adding a new child to the \gTree{} which is a
278set of points drawn within the \code{"dataRegion"}.  The second
279modification involves adding another set of points with a different
280symbol (NOTE that this second set of points is given a name so that it
281is easy to identify this set amongst the children of the \gTree{}).
282The final modification is to remove the second set of points from the
283\gTree{}.
284
285<<results=hide>>=
286grid.newpage()
287pushViewport(viewport(layout = grid.layout(2, 2)))
288drawIt <- function(row, col) {
289    pushViewport(viewport(layout.pos.col = col, layout.pos.row = row))
290    grid.rect(gp = gpar(col = "grey"))
291    grid.draw(gplot)
292    upViewport()
293}
294gplot <- gTree(x = NULL, y = NULL,
295               childrenvp = vpTree(
296                 plotViewport(c(5, 4, 4, 2), name = "plotRegion"),
297                 vpList(viewport(name = "dataRegion"))),
298               children = gList(
299                 xaxisGrob(vp = "plotRegion::dataRegion"),
300                 yaxisGrob(vp = "plotRegion::dataRegion"),
301                 rectGrob(vp = "plotRegion")))
302drawIt(1, 1)
303gplot <- addGrob(gplot, pointsGrob(vp = "plotRegion::dataRegion"))
304drawIt(1, 2)
305gplot <- addGrob(gplot, pointsGrob(name = "data1", pch = 2,
306                                   vp = "plotRegion::dataRegion"))
307drawIt(2, 1)
308gplot <- removeGrob(gplot, "data1")
309drawIt(2, 2)
310@
311
312This next example provides a simple demonstration of saving and
313loading \grid{} \grob{}s.  It is also a nice demonstration that
314\grob{}s copy like normal \R{} objects.
315
316<<results=hide>>=
317gplot <- gTree(x = NULL, y = NULL,
318               childrenvp = vpTree(
319                 plotViewport(c(5, 4, 4, 2), name = "plotRegion"),
320                   vpList(viewport(name = "dataRegion"))),
321               children = gList(
322                 xaxisGrob(vp = "plotRegion::dataRegion"),
323                 yaxisGrob(vp = "plotRegion::dataRegion"),
324                 rectGrob(vp = "plotRegion")))
325save(gplot, file = "gplot1")
326gplot <- addGrob(gplot, pointsGrob(vp = "plotRegion::dataRegion"))
327save(gplot, file = "gplot2")
328grid.newpage()
329pushViewport(viewport(layout = grid.layout(1, 2)))
330pushViewport(viewport(layout.pos.col = 1))
331load("gplot1")
332grid.draw(gplot)
333popViewport()
334pushViewport(viewport(layout.pos.col = 2))
335load("gplot2")
336grid.draw(gplot)
337popViewport()
338@
339
340This next example just demonstrates that it is possible to use a
341\gPath{} to access the children of a \gTree{} when editing.  This is
342the \code{editGrob()} equivalent of an earlier example that used
343\code{grid.edit()}.  One useful application of this API is the ability
344to modify the appearance of quite precise elements of a large, complex
345graphical object by editing the \code{gp} slot of a child (of a child
346\ldots{}) of a \gTree{}.
347
348<<results = hide>>=
349myplot <- gTree(name = "myplot",
350                children = gList(
351                  rectGrob(name = "box", gp = gpar(col = "grey")),
352                  xaxisGrob(name = "xaxis")))
353myplot <- editGrob(myplot, gPath = "xaxis", at = 1:10/11)
354myplot <- editGrob(myplot, gPath = "xaxis::labels", label = round(1:10/11, 2))
355myplot <- editGrob(myplot, gPath = "xaxis::labels", y = unit(-1, "lines"))
356grid.newpage()
357pushViewport(viewport(w = .5, h = .5))
358grid.draw(myplot)
359
360@
361The following example demonstrates
362the use of the \code{getGrob()} and \code{grid.get()} (along with
363\gPath{}s) to access \grob{}s.
364
365<<results = hide>>=
366myplot <- gTree(name = "myplot",
367                children = gList(
368                  rectGrob(name = "box", gp = gpar(col = "grey")),
369                  xaxisGrob(name = "xaxis")))
370getGrob(myplot, "xaxis")
371myplot <- editGrob(myplot, gPath="xaxis", at=1:10/11)
372getGrob(myplot, "xaxis::labels")
373grid.newpage()
374pushViewport(viewport(w=.5, h=.5))
375grid.draw(myplot)
376grid.get("myplot")
377grid.get("myplot::xaxis")
378grid.get("myplot::xaxis::labels")
379@
380
381There is also an API for (re)setting children of a \gTree{}
382or any drawn \grob{}.  This is not intended for general user use,
383but provides a simple way for developers to perform modifications
384to the structure of a \gTree{} by doing something like \ldots{}
385
386\begin{verbatim}
387grob <- getGrob(<spec>)
388<modify grob>
389setGrob(<spec>, grob)
390\end{verbatim}
391
392This approach is used in the implementation of packing and placing grobs.
393The following example shows some simple usage of the
394\code{setGrob()} and \code{grid.set()} functions to replace
395children of a \gTree{} with different \grob{}s.  NOTE that currently
396such replacement can only occur if the name of the new \grob{}
397is the same as the name of the old \grob{}.
398
399<<results=hide>>=
400myplot <- gTree(name = "myplot",
401                children = gList(rectGrob(name = "box", gp = gpar(col = "grey")),
402                  xaxisGrob(name = "xaxis")))
403myplot <- setGrob(myplot, "xaxis", rectGrob(name = "xaxis"))
404grid.newpage()
405pushViewport(viewport(w = .5, h = .5))
406grid.draw(myplot)
407grid.set("myplot::xaxis", xaxisGrob(name = "xaxis", at = 1:3/4))
408grid.set("myplot::xaxis::labels",
409         textGrob(name = "labels", x = unit(1:3/4, "native"),
410                  y = unit(-1, "lines"), label = letters[1:3]))
411myplot <- setGrob(grid.get("myplot"), "xaxis::labels",
412                  circleGrob(name = "labels"))
413grid.newpage()
414pushViewport(viewport(w = .5, h = .5))
415grid.draw(myplot)
416@
417
418This next example just shows more complex use of the add/remove
419facilities for modifying \grob{}s.  Again, \code{addGrob()} and
420\code{removeGrob()} are for constructing descriptions of graphical
421objects and \code{grid.add()} and \code{grid.remove()} are for
422modifying drawn output.  Of particular note are the last two lines
423involving \code{grid.remove()}.  The first point is that there are
424multiple \grob{}s on the display list with the same name.  The example
425only affects the first one it finds; this could easily be extended to
426affect the display list ``globally'' (for children of \gTree{}s, there
427cannot be multiple children with the same name so the issue does not
428arise).  The last line is interesting because it actually erases the
429\grob{} named \code{"plot1"} from the display list altogether (well,
430the first instance on the display list of a \grob{} called
431\code{"plot1"} anyway).
432
433<<results=hide>>=
434drawIt <- function(row, col) {
435  pushViewport(viewport(layout.pos.col = col, layout.pos.row = row))
436  grid.rect(gp = gpar(col = "grey"))
437  grid.draw(gplot)
438  upViewport()
439}
440gplot <- gTree(name = "plot1",
441               childrenvp = vpTree(
442                 plotViewport(c(5, 4, 4, 2), name = "plotRegion"),
443                 vpList(viewport(name = "dataRegion"))),
444               children = gList(
445                 xaxisGrob(name = "xaxis", vp = "plotRegion::dataRegion"),
446                 yaxisGrob(name = "yaxis", vp = "plotRegion::dataRegion"),
447                 rectGrob(name = "box", vp = "plotRegion")))
448grid.newpage()
449pushViewport(viewport(layout = grid.layout(2, 2)))
450drawIt(1, 1)
451grid.add("plot1", pointsGrob(0.5, 0.5, name = "data1",
452                             vp = "plotRegion::dataRegion"))
453grid.add("plot1::xaxis",
454         textGrob("X Axis", y = unit(-2, "lines"), name = "xlab"))
455grid.edit("plot1::xaxis::xlab", y = unit(-3, "lines"))
456gplot <- grid.get("plot1")
457gplot <- addGrob(gplot, gPath = "yaxis",
458                 textGrob("Y Axis", x = unit(-3, "lines"), rot = 90,
459                          name = "ylab"))
460drawIt(1, 2)
461gplot <- removeGrob(gplot, "xaxis::xlab")
462drawIt(2, 1)
463grid.remove("plot1::data1")
464grid.remove("plot1")
465@
466
467The next example is just a \code{grid.place()} and \code{grid.pack()}
468equivalent of an earlier example involving
469\code{placeGrob()} and \code{packGrob()}.  The interesting feature is
470that each action is reflected in the output as it occurs.
471
472<<results=hide>>=
473grid.newpage()
474grid.frame(name = "myframe", layout = grid.layout(1, 2))
475grid.place("myframe", textGrob("Hi there"), col = 1)
476grid.place("myframe", rectGrob(), col = 2)
477grid.newpage()
478grid.frame(name = "frame2")
479grid.pack("frame2", textGrob("Hi there"))
480grid.place("frame2", rectGrob())
481grid.pack("frame2", textGrob("Hello again"), side = "right")
482grid.pack("frame2", rectGrob(), side = "right", width = unit(1, "null"))
483@
484\end{document}
485
486
487
488