Introduciton
As of R 4.1.0 there is built-in support for patterns in grid
graphics. There
are 3 types of pattern:
grid::linearGradient()
for linear colour gradientsgrid::radialGradient()
for radial colour gradientsgrid::pattern()
repetition of any combination of graphic objects (grobs)
This quick post summarises a few things which can be done with patterns:
- creating a pattern
- a repeating element within a pattern can be masked (another new feature of
grid
in R v4.1.0) - a pattern can itself have a pattern
- a pattern can consist of any objects you can put in a
grid::grobTree()
Reading list:
- 14 July 2020 Catching up with R Graphics Gradients, Patterns, Clipping Paths, and Masks
- 15 July 2020 New Features in the R Graphics Engine Paul Murrell
library(grid)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Ensure that images are rendered using a device which understands patterns
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
knitr::opts_chunk$set(dev.args = list(png = list(type = "cairo")))
Define the core element of the pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define a small rectangle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
small_rect <- rectGrob(
width = unit(10, 'mm'),
height = unit(10, 'mm'),
gp = gpar(
fill = 'lightblue',
col = 'blue'
)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Display the rectangle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grid.newpage()
grid.draw(small_rect)
Create a pattern by wrapping the core element in grid::pattern()
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap the core element (small_rect) inside a pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
small_rect_pattern <- grid::pattern(
small_rect,
width = unit(15, 'mm'),
height = unit(15, 'mm'),
extend = 'repeat'
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Use the pattern as a 'fill' on another shape
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
large_rect <- rectGrob(
width = 0.5,
height = 0.5,
gp = gpar(fill = small_rect_pattern)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Display the rectangle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grid.newpage()
grid.draw(large_rect)
Patterns can have masks
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create a mask
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mask <- circleGrob(
x = unit(0.5, 'npc') + unit(2.5, 'mm'),
y = unit(0.5, 'npc') + unit(2.5, 'mm'),
r = unit(4, 'mm'),
gp = gpar(fill = 'black')
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define a small rectangle with some masking
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
small_rect_with_mask <- rectGrob(
width = unit(10, 'mm'),
height = unit(10, 'mm'),
gp = gpar(
fill = 'lightblue',
col = 'blue'
),
vp = viewport(mask = mask)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Wrap the core element (small_rect_with_mask) inside a pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
small_rect_with_mask_pattern <- grid::pattern(
small_rect_with_mask,
width = unit(15, 'mm'),
height = unit(15, 'mm'),
extend = 'repeat'
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Use the pattern as a 'fill' on another shape
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
large_rect <- rectGrob(
width = 0.5,
height = 0.5,
gp = gpar(fill = small_rect_with_mask_pattern)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Display the rectangle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grid.newpage()
grid.draw(large_rect)
Pattern - Patterns can have patterns
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define an inner pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inner_pattern_element <- circleGrob(
r = unit(5, 'mm'),
gp = gpar(
fill = 'pink',
col = 'red'
)
)
inner_pattern <- grid::pattern(
inner_pattern_element,
width = unit(12, 'mm'),
height = unit(12, 'mm'),
extend = 'repeat'
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define an outer pattern which is filled with the inner pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
outer_pattern_element <- polygonGrob(
x = unit(0.5, 'npc') + unit(c(0, 20, 20) - 10, 'mm'),
y = unit(0.5, 'npc') + unit(c(0, 0, 20) - 10, 'mm'),
gp = gpar(fill = inner_pattern, col = 'blue')
)
outer_pattern <- grid::pattern(
outer_pattern_element,
width = unit(30, 'mm'),
height = unit(30, 'mm'),
extend = 'reflect'
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Fill a 'rect' with the outer pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
large_rect <- rectGrob(
width = 0.5,
height = 0.5,
gp = gpar(fill = outer_pattern)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Display the rectangle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grid.newpage()
grid.draw(large_rect)
Pattern - Patterns can contain multiple objects
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define a small rectangle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
small_rect <- rectGrob(
width = unit(10, 'mm'),
height = unit(10, 'mm'),
gp = gpar(
fill = 'lightblue',
col = 'blue'
)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define a small circle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
small_circle <- circleGrob(
x = unit(0.5, 'npc') + unit(3, 'mm'),
y = unit(0.5, 'npc') + unit(3, 'mm'),
r = unit(4, 'mm'),
gp = gpar(
fill = 'pink',
col = 'red'
)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Creat a compound pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compound_pattern <- pattern(
grobTree(small_rect, small_circle),
width = unit(15, 'mm'),
height = unit(15, 'mm'),
extend = 'repeat'
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Fill a 'rect' with the compound pattern
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
large_rect <- rectGrob(
width = 0.5,
height = 0.5,
gp = gpar(fill = compound_pattern)
)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Display the rectangle
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
grid.newpage()
grid.draw(large_rect)