4.2 Manipulating Existing Plots

Another application of grid is to manipulate an existing plot object. You may have noted that our version of the 2-dimensional density scatter plot produced with lattice lacks a color key. Looking at the ggplot2 version of the density scatter, by contrast, we see that this one already has a color key which is placed to the right of the main plot.

As regards the lattice version, a color key can be easily added using grid. Since lattice is built upon grid, it produces a lot of viewports in the creation of the plots (like our scatter plot). After these have been set up, we can navigate to each of them and edit (or delete) them or add new stuff. Given that we have five panels, we actually have some ‘white’ space left in the bottom-right corner that we could use for the color key placement, thus making better use of the available space…

In order to do so, we need to know into which of the viewports we need to navigate. Luckily, lattice provides a structured naming convention for its viewports, which makes navigating between single viewports rather easy. Since we are interested in the area covered by the main figure only, we will use trellis.vpname("figure") to extract the name of the corresponding viewport and pass this on to downViewport() in order to navigate to it. You will notice that this is very similar to pushViewport(), except for the target viewport being already there.

Like that, we can set up a new viewport in the main plotting area (the ‘figure’ viewport) to make use of the existing white space. Remember that the default units of grid range from 0 to 1. This means that we can easily calculate the necessary viewport dimensions. Let’s see how this is done (note that we are actually creating two new viewports in the figure area, one for the color key and another one for the color key label).

my_theme <- trellis.par.get()
my_theme$strip.background$col <- "grey80"
my_theme$plot.symbol$pch <- 16
my_theme$plot.symbol$col <- "grey60"
my_theme$plot.polygon$col <- "grey90"

scatter_lattice <- xyplot(price ~ carat | cut, 
                          data = diamonds, 
                          panel = function(x, y, ...) {
                            panel.xyplot(x, y, ...)
                            lm1 <- lm(y ~ x)
                            lm1sum <- summary(lm1)
                            r2 <- lm1sum$adj.r.squared
                            panel.text(labels = 
                                         bquote(italic(R)^2 == 
                                                  .(format(r2, 
                                                           digits = 3))),
                                       x = 4, y = 1000)
                            panel.smoother(x, y, method = "lm", 
                                           col = "black", 
                                           col.se = "black",
                                           alpha.se = 0.3)
                            },
                          xscale.components = xscale.components.subticks,
                          yscale.components = yscale.components.subticks,
                          as.table = TRUE)

l_sc <- update(scatter_lattice, par.settings = my_theme)
xy <- kde2d(x = diamonds$carat, y = diamonds$price, n = 100) 
xy_tr <- con2tr(xy)
offset <- max(xy_tr$z) * 0.2
z_range <- seq(min(xy_tr$z), max(xy_tr$z) + offset, offset * 0.01)

l_sc <- update(scatter_lattice, aspect = 1, par.settings = my_theme, 
               between = list(x = 0.3, y = 0.3),
               panel=function(x,y) {
                 xy <- kde2d(x,y, n = 100) 
                 xy_tr <- con2tr(xy)                 
                 panel.levelplot(xy_tr$x, xy_tr$y, xy_tr$z, asp = 1,
                                 subscripts = seq(nrow(xy_tr)), 
                                 contour = FALSE, region = TRUE, 
                                 col.regions = c("white", 
                                                 rev(clrs_hcl(10000))),
                                 at = z_range)
                 lm1 <- lm(y ~ x)
                 lm1sum <- summary(lm1)
                 r2 <- lm1sum$adj.r.squared
                 panel.abline(a = lm1$coefficients[1], 
                              b = lm1$coefficients[2])
                 panel.text(labels = 
                              bquote(italic(R)^2 == 
                                       .(format(r2, digits = 3))),
                            x = 4, y = 1000)
                 #panel.xyplot(x,y) 
                 } 
               ) 


grid.newpage()
#grid.rect()
print(l_sc, newpage = FALSE)
#grid.rect()
downViewport(trellis.vpname(name = "figure"))
#grid.rect()
vp1 <- viewport(x = 1, y = 0, 
                height = 0.5, width = 0.3,
                just = c("right", "bottom"),
                name = "legend.vp")

pushViewport(vp1)
#grid.rect()

vp1_1 <- viewport(x = 0.2, y = 0.5, 
                  height = 0.7, width = 0.5,
                  just = c("left", "centre"),
                  name = "legend.key")

pushViewport(vp1_1)
#grid.rect()

key <- draw.colorkey(key = list(col = c("white", rev(clrs_hcl(10000))),
                                at = z_range), draw = TRUE)

seekViewport("legend.vp")
#grid.rect()
vp1_2 <- viewport(x = 1, y = 0.5, 
                  height = 1, width = 0.3,
                  just = c("right", "centre"),
                  name = "legend.text", angle = 0)

pushViewport(vp1_2)
#grid.rect()

grid.text("estimated point density", 
          x = 0, y = 0.5, rot = 270, 
          just = c("centre", "bottom"))

upViewport(3)
Using **grid** to add a color key to an existing **lattice** plot object.

Figure 4.6: Using grid to add a color key to an existing lattice plot object.

Not too complicated, is it? And, in comparison to the ggplot2 version, we are utilizing the available space a bit more efficiently. Though, obviously, we could also manipulate the ggplot2 density scatter plot (or any other plot) in a similar manner. In general, we hope that it has become clear just how useful grid can be and how it provides us with tools which enable us to produce individual graphics that satisfy our needs.

So far, we have put our efforts into plot creation and learned about a variety of tools that can help us achieve what we want. As a next logical step, let’s see how we can save our graphics to our hard drive.