The ‘grid’ Graphics System


The purpose of this topic is to provide a low-level view of data visualisation.

In the previous section we looked at data visualisation with the ‘ggplot2’ package, which is based on the Grammar of Graphics. That provided a high-level view of data visualisation; with the ‘ggplot2’ package, we construct a high-level description of a data visualisation and the software performs a lot of drawing for us.

In this topic, we view a data visualisation as just a specific case of drawing a picture; a data visualisation is just an arrangement of lines, shapes, and text that we draw ourselves using a selection of line types, colours, and fonts.

This topic is useful because sometimes we want to be able to draw (at least part of) a data visualisation from scratch and because sometimes we want to tweak the details of a high-level data visualisation. A low-level approach to graphics typically means more work, but greater control.

We will learn about the R package ‘grid’ as a low-level tool to produce data visualisations.

Introduction

The ‘grid’ package provides functions for drawing basic shapes.

library(grid)

We can think about a scatterplot as just a collection of shapes. For example, the data symbols are just a set of circles, the frame of the plot is just a rectangle, the tick marks are just line segments, and the axis labels are just text.

This is how we can draw a circle in ‘grid’; x = .5 means the centre of the circle is half way across the image, y = .5 means the centre of the circle is half way up the image, and r = .2 means the radius of the circle is .2 of the width/height of the image.

grid.circle(x = .5, y = .5, r = .2)

This is how we can draw a rectangle; width = .8 means .8 of the width of the image and height = .6 means .6 of the height of the image.

grid.rect(width=.8, height=.6)

The following code draws some text. The y location of the text is half way up the image, but x = 1:4/5 means that, because there are multiple x locations, we will draw four pieces of text (at x locations .2, .4, .6, and .8). label = 1:4 means that we will draw four different pieces of text (the numbers 1 to 4).

grid.text(label = 1:4, x = 1:4/5, y = .5)

The following code draws some line segments. One line segment (the horizontal one) is positioned as before, using proportions of the width or height of the image (from .2 of the width to .8 of the width and, vertically, located in the centre of the image).

However, the other call to grid.segments() introduces some new ideas: coordinate systems and the unit() function. In terms of the y-location, unit(.5, "npc") means .5 of the height of the image.

The unit() function associates a value with a coordinate system; “npc” means 0 is at the bottom and 1 is at the top. When we do not use the unit() function, we usually get “npc” by default, so .5 is the same as unit(.5, "npc").

There are other coordinate systems available, for example, unit(3, "mm") means 3mm. We can also use simple arithmetic to combine values, so unit(.5, "npc") - unit(3, "mm") means 3mm down from half way up the image.

grid.segments(x0 = .2, y0 = .5, x1 = .8, y1 = .5)
grid.segments(x0 = 1:4/5, y0 = .5,
              x1 = 1:4/5, y1 = unit(.5, "npc") - unit(3, "mm"))

We can also create our own coordinate system by creating a viewport with an x-axis scale and a y-axis scale. This is what the next code does with the viewport() function. With the viewport in place (pushViewport() “pushes” the viewport onto the image), we can position drawing relative to the “native” scale of the viewport that is defined by the xscale and yscale. In the code below, we draw a circle at position (2, 4) in “native” coordinates, which means an x location of 2 relative to the xscale (where 0 is the left edge of the image and 9 is the right edge of the image) and a y location of 4 relative to the yscale (where 0 is the bottom edge of the image and 5 is the top edge of the image).

pushViewport(viewport(xscale = c(0, 9), yscale = c(0, 5)))
grid.circle(x = unit(2, "native"), y = unit(4, "native"),
            r = unit(1.5, "mm"))
upViewport()

A viewport can have a location and size, like a rectangle. In the following code, we create a viewport that just takes up .8 of the width and height of the image (leaving margins around the outside), with an x-axis scale and a y-axis scale, and we draw circles at locations relative to the scales, a rectangle around the viewport, and tick marks and labels on the axes. In other words, a scatter plot.

Notice that all coordinate systems are relative to the viewport that we have pushed. For example, 0 (or unit(0, "npc")) is the bottom of the viewport, not the bottom of the image.

pushViewport(viewport(width = .8, height = .8, 
                      xscale = c(0, 9), yscale = c(0, 5)))
grid.rect()
grid.circle(x = unit(1:4, "native"), y = unit(1:4, "native"),
            r = unit(1.5, "mm"))
grid.segments(unit(1:8, "native"), 0,
              unit(1:8, "native"), unit(-3, "mm"))
grid.segments(0, unit(1:4, "native"), 
              unit(-3, "mm"), unit(1:4, "native"))
grid.text(1:4, unit(-6, "mm"), unit(1:4, "native"))
grid.text(1:10, unit(1:8, "native"), unit(-6, "mm"))
upViewport()

That demonstration gives a basic idea of how we can draw a data visualisation with ‘grid’ by positioning and sizing simple shapes relative to a variety of coordinate systems, including coordinate systems that we set up by pushing viewports.

The reading on The ‘grid’ Graphics Package describes these ideas in a bit more detail and introduces other important concepts like graphical parameters, navigating between viewports, graphical objects, and how to combine ‘grid’ with ‘ggplot2’ using the ‘gggrid’ package. The reading on Getting Started with ‘gggrid’ demonstrates how to work with ‘gggrid’ in a little more detail.

Make sure that you understand the meanings of the following terms:

  • Low-level graphics
  • Grobs
  • Viewports
  • Units
  • Graphical parameters

Readings

References

  • Help pages for ‘grid’ functions.

  • Chapter 5 of “R Graphics” (1st Ed).

    This is a little old, so lacks some more recent ‘grid’ features, but it still covers the fundamentals of viewports, units, and graphical parameters.

Bibliography


Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License.