Skip to content

Commit 4069ea7

Browse files
committed
feat: 'pattern_units' aesthetic
* {ggpattern} now supports the `pattern_units` aesthetic (#81). Supported by most "geometry" patterns. It sets the `grid::unit()` used by the `pattern_spacing`, `pattern_xoffset`, `pattern_yoffset`, and (for the "wave" pattern) the `pattern_frequency` aesthetics. Default is "snpc" while "cm" and "inches" are likely alternatives. closes #81
1 parent e8cebf7 commit 4069ea7

16 files changed

+424
-304
lines changed

DESCRIPTION

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Package: ggpattern
22
Type: Package
33
Title: 'ggplot2' Pattern Geoms
4-
Version: 1.1.0-8
4+
Version: 1.1.0-9
55
Authors@R: c(person("Mike", "FC", role = "aut"),
66
person("Trevor L.", "Davis", role = c("aut", "cre"),
77
email = "trevor.l.davis@gmail.com",
@@ -19,7 +19,7 @@ Imports:
1919
ggplot2 (>= 3.5.1),
2020
glue,
2121
grid,
22-
gridpattern (>= 1.2.0-4),
22+
gridpattern (>= 1.2.0-6),
2323
lifecycle,
2424
rlang (>= 1.1.3),
2525
scales,

NAMESPACE

+4
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ export(scale_pattern_type_continuous)
185185
export(scale_pattern_type_discrete)
186186
export(scale_pattern_type_identity)
187187
export(scale_pattern_type_manual)
188+
export(scale_pattern_units_continuous)
189+
export(scale_pattern_units_discrete)
190+
export(scale_pattern_units_identity)
191+
export(scale_pattern_units_manual)
188192
export(scale_pattern_xoffset_continuous)
189193
export(scale_pattern_xoffset_discrete)
190194
export(scale_pattern_xoffset_identity)

NEWS.md

+6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@
3939
(in addition to color strings) (#112).
4040
Note using gradient/pattern fills will require R (>= 4.2) and a graphics device with support for the gradient/pattern fill feature.
4141
Use of just color fills should continue to work on a wider variety of R versions and graphics devices.
42+
* {ggpattern} now supports the `pattern_units` aesthetic (#81).
43+
Supported by most "geometry" patterns.
44+
It sets the `grid::unit()` used by the `pattern_spacing`, `pattern_xoffset`, `pattern_yoffset`,
45+
and (for the "wave" pattern) the `pattern_frequency` aesthetics.
46+
Default is "snpc" while "cm" and "inches" are likely alternatives.
47+
4248
* `geom_bin_2d_pattern()` is now an alias for `geom_bin2d_pattern()`.
4349
This matches `{ggplot2}` which has both `geom_bin_2d()` and `geom_bin2d()`.
4450

R/geom-.R

+44-39
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ pattern_aesthetics <- aes(
4040

4141
pattern_grid = 'square',
4242
pattern_rot = 0,
43-
pattern_res = getOption("ggpattern_res", NA)
43+
pattern_res = getOption("ggpattern_res", NA),
44+
pattern_units = 'snpc'
4445
)
4546

4647
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -57,47 +58,51 @@ create_key_pattern_grob <- function(data, params, size, aspect_ratio, boundary_d
5758
data$size <- data$linewidth %||% data$size %||% 0.5
5859
lwd <- min(data$size, min(size) / 4) * .pt
5960

60-
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61-
# Convert the width/height of the key into npc sizes
62-
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63-
key_native_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'native')))
64-
key_native_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'native')))
65-
66-
vp <- grid::current.viewport()
67-
vp_native_x <- abs(diff(vp$xscale))
68-
vp_native_y <- abs(diff(vp$yscale))
69-
70-
71-
key_npc_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'npc')))
72-
key_npc_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'npc')))
73-
74-
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
75-
# What's the overall scale_factor?
76-
# The legend is actually drawn in its own viewport with an area of 1x1 npc.
77-
# I have to do some fancy scaling to draw the current pattern in this
78-
# scaled viewport as currently appears in the full viewport of the plot.
79-
# i.e. I need to make the pattern in the legend look like the pattern in the
80-
# plot.
81-
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
82-
83-
denom <- sqrt(2) * (1/aspect_ratio) * 9/8
84-
85-
if (vp_native_x/vp_native_y < aspect_ratio) {
86-
scale_factor <- 1/key_npc_x / aspect_ratio / denom
61+
if (data$pattern_units == "snpc") {
62+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63+
# Convert the width/height of the key into npc sizes
64+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65+
key_native_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'native')))
66+
key_native_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'native')))
67+
68+
vp <- grid::current.viewport()
69+
vp_native_x <- abs(diff(vp$xscale))
70+
vp_native_y <- abs(diff(vp$yscale))
71+
72+
73+
key_npc_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'npc')))
74+
key_npc_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'npc')))
75+
76+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77+
# What's the overall scale_factor?
78+
# The legend is actually drawn in its own viewport with an area of 1x1 npc.
79+
# I have to do some fancy scaling to draw the current pattern in this
80+
# scaled viewport as currently appears in the full viewport of the plot.
81+
# i.e. I need to make the pattern in the legend look like the pattern in the
82+
# plot.
83+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
84+
85+
denom <- sqrt(2) * (1/aspect_ratio) * 9/8
86+
87+
if (vp_native_x/vp_native_y < aspect_ratio) {
88+
scale_factor <- 1/key_npc_x / aspect_ratio / denom
89+
} else {
90+
scale_factor <- 1/key_npc_y/denom
91+
}
92+
93+
scale_factor <- scale_factor * data$pattern_key_scale_factor
94+
95+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
96+
# Compensate for box the key is rendered in being different aspect ratios
97+
# i.e. theme(legend.key.width = unit(2, 'cm'),
98+
# legend.key.height = unit(3, 'cm')
99+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100+
key_aspect_ratio <- key_native_x/key_native_y
101+
scale_factor <- scale_factor / key_aspect_ratio
87102
} else {
88-
scale_factor <- 1/key_npc_y/denom
103+
scale_factor <- 1.00 * data$pattern_key_scale_factor
89104
}
90105

91-
scale_factor <- scale_factor * data$pattern_key_scale_factor
92-
93-
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94-
# Compensate for box the key is rendered in being different aspect ratios
95-
# i.e. theme(legend.key.width = unit(2, 'cm'),
96-
# legend.key.height = unit(3, 'cm')
97-
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98-
key_aspect_ratio <- key_native_x/key_native_y
99-
scale_factor <- scale_factor / key_aspect_ratio
100-
101106
this_params <- fill_default_params(data)
102107

103108
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

R/scale-pattern-auto.R

+78
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,64 @@ scale_pattern_rot_discrete <- function(..., range = c(0, 360)) {
11281128
...
11291129
)
11301130
}
1131+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1132+
#' @rdname scale_discrete
1133+
#' @export
1134+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1135+
scale_pattern_units_continuous <- function(name = waiver(),
1136+
breaks = waiver(),
1137+
labels = waiver(),
1138+
limits = NULL,
1139+
choices = c('snpc', 'cm', 'inches'),
1140+
trans = deprecated(),
1141+
guide = 'legend',
1142+
...,
1143+
transform = 'identity') {
1144+
1145+
if (is.null(choices)) {
1146+
abort('scale_pattern_units_continuous(): must specify "choices" argument')
1147+
}
1148+
if (lifecycle::is_present(trans)) {
1149+
lifecycle::deprecate_warn('1.1.1',
1150+
'scale_pattern_units_continuous(trans)',
1151+
'scale_pattern_units_continuous(transform)')
1152+
transform <- trans
1153+
}
1154+
1155+
ggplot2::continuous_scale(
1156+
aesthetics = 'pattern_units',
1157+
palette = function(x) choices[as.integer(x * (length(choices) - 1) + 1)],
1158+
name = name,
1159+
breaks = breaks,
1160+
labels = labels,
1161+
limits = limits,
1162+
transform = transform,
1163+
guide = guide,
1164+
...)
1165+
}
1166+
1167+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1168+
#' @rdname scale_discrete
1169+
#' @importFrom utils head
1170+
#' @export
1171+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1172+
scale_pattern_units_discrete <- function(..., choices = c('snpc', 'cm', 'inches'), guide = 'legend') {
1173+
force(range)
1174+
1175+
if (is.null(choices)) {
1176+
abort('scale_pattern_units_discrete(): must specify "choices" argument')
1177+
}
1178+
1179+
ggplot2::discrete_scale(
1180+
aesthetics = 'pattern_units',
1181+
palette = function(n) {
1182+
idx <- cut(seq(n), length(choices), labels = FALSE, include.lowest = TRUE)
1183+
choices[idx]
1184+
},
1185+
guide = guide,
1186+
...
1187+
)
1188+
}
11311189
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11321190
#' Create your own discrete scale
11331191
#'
@@ -1342,6 +1400,13 @@ scale_pattern_rot_manual <- function(..., values, breaks = waiver()) {
13421400
manual_scale('pattern_rot', values, breaks, ...)
13431401
}
13441402
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1403+
#' @rdname scale_pattern_manual
1404+
#' @export
1405+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1406+
scale_pattern_units_manual <- function(..., values, breaks = waiver()) {
1407+
manual_scale('pattern_units', values, breaks, ...)
1408+
}
1409+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13451410
#' Use values without scaling
13461411
#'
13471412
#' @param ...,guide See \code{ggplot2} for documentation on identity scales.
@@ -1711,3 +1776,16 @@ scale_pattern_rot_identity <- function(..., guide = 'none') {
17111776
super = ScaleContinuousIdentity
17121777
)
17131778
}
1779+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1780+
#' @rdname scale_pattern_identity
1781+
#' @export
1782+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1783+
scale_pattern_units_identity <- function(..., guide = 'none') {
1784+
discrete_scale(
1785+
aesthetics = 'pattern_units',
1786+
palette = identity_pal(),
1787+
...,
1788+
guide = guide,
1789+
super = ScaleDiscreteIdentity
1790+
)
1791+
}

data-raw/config.R

+1
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ pattern_frequency | | continuous | NULL
3232
pattern_grid | | discrete | c('square', 'hex')
3333
pattern_res | | continuous | NULL
3434
pattern_rot | | continuous | c(0, 360)
35+
pattern_units | | discrete | c('snpc', 'cm', 'inches')
3536
", trim_ws = TRUE, delim = "|")

man/scale_discrete.Rd

+20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_pattern_identity.Rd

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/scale_pattern_manual.Rd

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/_snaps/geom/density.svg

+220-224
Loading

0 commit comments

Comments
 (0)