A data visualisation consists of data symbols, guides, and labels.
We produce data symbols by mapping data values to the visual features of a shape.
Which visual feature we choose depends on:
The effectiveness of a data visualisation also depends on coordination between different elements.
There may also be a justification for elements that do not map directly to data values.
With {ggplot2} we are able to specify a high-level description of a data visualisation.
This topic explores a different approach to producing a data visualisation.
There are some things that are hard to do with {ggplot2}.
The {grid} package
Integrating {grid} with {ggplot2}
Integrating {ggplot2} with {grid}
The {grid} Package
With the {ggplot2} package, we describe a data visualisation in terms of higher-level concepts, such as mappings from data to aesthetics.
With the {grid} package, we just draw shapes.
grid.rect()
draws rectangles
gpar()
controls graphical settings like (border)
col
our and fill
colour.
grid.segments()
draws line segments.
gpar(lwd)
controls line width.
Positions are proportions of the page (by default)
(0 =
left/bottom, 1 = right/top)
These are "npc"
(normalised parent) coordinates.
Shapes can be based on data!
[1] 0.2995225 0.7004775
[1] "#F8766D" "#00BFC4"
Shapes can be based on data!
Drawing is always relative to a viewport.
Drawing is always relative to a viewport.
Drawing is always relative to a coordinate system.
vp(xscale, yscale)
define "native"
coordinates.
"npc"
coordinates are also still available.
Drawing is always relative to a coordinate system.
default.units
selects the default coordinates.
Drawing is always relative to a coordinate system.
pushViewport(vp)
grid.rect(gp=gpar(col=NA, fill="grey90"))
grid.segments(0, .5, 1, .5, gp=gpar(col="white"))
grid.segments(0:4/4, 0, 0:4/4, 1, gp=gpar(col="white"),
default.units="native")
grid.rect(c(1, 0), width=crimeGenderTotal$prop, height=.8,
hjust=c(1, 0), gp=gpar(col=NA, fill=fills),
default.units="native")
unit()
associates values with a coordinate
system.
There are "mm"
and "in"
coordinates
available.
"npc"
and "native"
are still also
available.
unit()
associates values with a coordinate
system.
pushViewport(vp)
grid.rect(gp=gpar(col=NA, fill="grey90"))
grid.segments(0, .5, 1, .5, gp=gpar(col="white"))
grid.segments(0:4/4, 0, 0:4/4, 1, gp=gpar(col="white"),
default.units="native")
grid.rect(c(1, 0), width=crimeGenderTotal$prop, height=.8,
hjust=c(1, 0), gp=gpar(col=NA, fill=fills),
default.units="native")
grid.segments(0:4/4, 0, 0:4/4, -twoMM, default.units="native")
grid.text()
draws text.
pushViewport(vp)
grid.rect(gp=gpar(col=NA, fill="grey90"))
grid.segments(0, .5, 1, .5, gp=gpar(col="white"))
grid.segments(0:4/4, 0, 0:4/4, 1, gp=gpar(col="white"),
default.units="native")
grid.rect(c(1, 0), width=crimeGenderTotal$prop, height=.8,
hjust=c(1, 0), gp=gpar(col=NA, fill=fills),
default.units="native")
grid.segments(0:4/4, 0, 0:4/4, -twoMM, default.units="native")
grid.text(0:4/4, unit(0:4/4, "native"), unit(-1, "lines"))
gpar()
Settings{grid} means more work, but you get complete control.
{grid} means more work, but you get complete control.
{grid} means more work, but you get complete control.
{grid} means more work, but you get complete control.
{grid} means more work, but you get complete control.
Integrating {grid} with {ggplot2}
The pets
data frame contains an estimate of the
number of pet cats and dogs globally.
pet count
1 dog 471
2 cat 373
The raster images cat
and dog
depict
silhouettes of a cat and a dog.
Instead of drawing {grid} output directly, we can create a grob (graphical objects), but draw nothing, and then draw the grob later.
We can combine grobs into a single gTree (grob Tree).
The {gggrid} package allows us to mix {grid} drawing with a {ggplot2} plot.
The grid_panel()
function draws a grob on a
{ggplot2} plot.
grid_panel()
also accepts a function that calculates
what to draw.
The function is called with data
and
coords
(transformed data) for the {ggplot2} plot
panel.
The function returns a grob or gTree for {ggplot2} to draw.
grid_panel()
also accepts a function that calculates
what to draw.
The function is called with data
and
coords
(transformed data) for the {ggplot2} plot panel.
x y PANEL group
1 471 2 1 2
2 373 1 1 1
x y PANEL group
1 0.9545455 0.7272727 1 2
2 0.7653928 0.2727273 1 1
grid_panel()
also accepts a function that calculates
what to draw.
The function returns a grob or gTree for {ggplot2} to draw.
{gggrid} means greater control, at the cost of more effort.
Integrating {ggplot2} with {grid}
A {ggplot2} plot is “just” {grid} drawing in the end.
A {ggplot2} plot is “just” {grid} drawing in the end.
layout
background.1-13-16-1
plot.background..rect.462
panel.9-7-9-7
panel-1.gTree.428
grill.gTree.426
panel.background..rect.419
panel.grid.minor.x..polyline.421
panel.grid.major.y..polyline.423
panel.grid.major.x..polyline.425
NULL
geom_rect.rect.415
NULL
panel.border..zeroGrob.416
We can draw a {ggplot2} plot within a {grid} viewport.
This allows us to draw other content alongside.
The crimeYear
data frame contains the number of
offenders per year.
We can see changes more easily by directly visualising changes.
We can answer more questions if we have both views of the data.
gg1 <- ggplot(crimeYear) +
geom_line(aes(x=year, y=total)) +
scale_x_continuous(limits=c(2010, 2022),
expand=expansion(c(0, 0)),
breaks=seq(2010, 2020, 2))
gg2 <- ggplot(crimeYear) +
geom_col(aes(x=year, y=change)) +
scale_x_continuous(limits=c(2010, 2022),
expand=expansion(c(0, 0)),
breaks=seq(2010, 2020, 2))
Summary
Exercises
Can you use {grid} to draw any of these diagrams?
The male()
function creates a male symbol grob.
The female()
function creates a female symbol
grob.
Can you use the male()
and female()
functions (and the crimeGenderTotal
data frame) to produce
the data visualisation below?