diff --git a/DESCRIPTION b/DESCRIPTION index d592f31..795d8ea 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: ggpattern Type: Package Title: 'ggplot2' Pattern Geoms -Version: 1.1.0-8 +Version: 1.1.0-9 Authors@R: c(person("Mike", "FC", role = "aut"), person("Trevor L.", "Davis", role = c("aut", "cre"), email = "trevor.l.davis@gmail.com", @@ -19,7 +19,7 @@ Imports: ggplot2 (>= 3.5.1), glue, grid, - gridpattern (>= 1.2.0-4), + gridpattern (>= 1.2.0-6), lifecycle, rlang (>= 1.1.3), scales, diff --git a/NAMESPACE b/NAMESPACE index 4deca73..0dd3b6b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -185,6 +185,10 @@ export(scale_pattern_type_continuous) export(scale_pattern_type_discrete) export(scale_pattern_type_identity) export(scale_pattern_type_manual) +export(scale_pattern_units_continuous) +export(scale_pattern_units_discrete) +export(scale_pattern_units_identity) +export(scale_pattern_units_manual) export(scale_pattern_xoffset_continuous) export(scale_pattern_xoffset_discrete) export(scale_pattern_xoffset_identity) diff --git a/NEWS.md b/NEWS.md index 2614481..30da591 100644 --- a/NEWS.md +++ b/NEWS.md @@ -39,6 +39,12 @@ (in addition to color strings) (#112). Note using gradient/pattern fills will require R (>= 4.2) and a graphics device with support for the gradient/pattern fill feature. Use of just color fills should continue to work on a wider variety of R versions and graphics devices. +* {ggpattern} now supports the `pattern_units` aesthetic (#80). + 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. + * `geom_bin_2d_pattern()` is now an alias for `geom_bin2d_pattern()`. This matches `{ggplot2}` which has both `geom_bin_2d()` and `geom_bin2d()`. diff --git a/R/geom-.R b/R/geom-.R index fd212be..fa7f8c4 100644 --- a/R/geom-.R +++ b/R/geom-.R @@ -40,7 +40,8 @@ pattern_aesthetics <- aes( pattern_grid = 'square', pattern_rot = 0, - pattern_res = getOption("ggpattern_res", NA) + pattern_res = getOption("ggpattern_res", NA), + pattern_units = 'snpc' ) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -57,47 +58,51 @@ create_key_pattern_grob <- function(data, params, size, aspect_ratio, boundary_d data$size <- data$linewidth %||% data$size %||% 0.5 lwd <- min(data$size, min(size) / 4) * .pt - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # Convert the width/height of the key into npc sizes - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - key_native_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'native'))) - key_native_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'native'))) - - vp <- grid::current.viewport() - vp_native_x <- abs(diff(vp$xscale)) - vp_native_y <- abs(diff(vp$yscale)) - - - key_npc_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'npc'))) - key_npc_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'npc'))) - - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # What's the overall scale_factor? - # The legend is actually drawn in its own viewport with an area of 1x1 npc. - # I have to do some fancy scaling to draw the current pattern in this - # scaled viewport as currently appears in the full viewport of the plot. - # i.e. I need to make the pattern in the legend look like the pattern in the - # plot. - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - denom <- sqrt(2) * (1/aspect_ratio) * 9/8 - - if (vp_native_x/vp_native_y < aspect_ratio) { - scale_factor <- 1/key_npc_x / aspect_ratio / denom + if (data$pattern_units == "snpc") { + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # Convert the width/height of the key into npc sizes + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + key_native_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'native'))) + key_native_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'native'))) + + vp <- grid::current.viewport() + vp_native_x <- abs(diff(vp$xscale)) + vp_native_y <- abs(diff(vp$yscale)) + + + key_npc_x <- abs(as.numeric(grid::convertWidth (unit(size[1], 'mm'), 'npc'))) + key_npc_y <- abs(as.numeric(grid::convertHeight(unit(size[2], 'mm'), 'npc'))) + + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # What's the overall scale_factor? + # The legend is actually drawn in its own viewport with an area of 1x1 npc. + # I have to do some fancy scaling to draw the current pattern in this + # scaled viewport as currently appears in the full viewport of the plot. + # i.e. I need to make the pattern in the legend look like the pattern in the + # plot. + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + denom <- sqrt(2) * (1/aspect_ratio) * 9/8 + + if (vp_native_x/vp_native_y < aspect_ratio) { + scale_factor <- 1/key_npc_x / aspect_ratio / denom + } else { + scale_factor <- 1/key_npc_y/denom + } + + scale_factor <- scale_factor * data$pattern_key_scale_factor + + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # Compensate for box the key is rendered in being different aspect ratios + # i.e. theme(legend.key.width = unit(2, 'cm'), + # legend.key.height = unit(3, 'cm') + #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + key_aspect_ratio <- key_native_x/key_native_y + scale_factor <- scale_factor / key_aspect_ratio } else { - scale_factor <- 1/key_npc_y/denom + scale_factor <- 1.00 * data$pattern_key_scale_factor } - scale_factor <- scale_factor * data$pattern_key_scale_factor - - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # Compensate for box the key is rendered in being different aspect ratios - # i.e. theme(legend.key.width = unit(2, 'cm'), - # legend.key.height = unit(3, 'cm') - #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - key_aspect_ratio <- key_native_x/key_native_y - scale_factor <- scale_factor / key_aspect_ratio - this_params <- fill_default_params(data) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/R/scale-pattern-auto.R b/R/scale-pattern-auto.R index f3f8bc3..b3952fc 100644 --- a/R/scale-pattern-auto.R +++ b/R/scale-pattern-auto.R @@ -1128,6 +1128,64 @@ scale_pattern_rot_discrete <- function(..., range = c(0, 360)) { ... ) } +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#' @rdname scale_discrete +#' @export +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +scale_pattern_units_continuous <- function(name = waiver(), + breaks = waiver(), + labels = waiver(), + limits = NULL, + choices = c('snpc', 'cm', 'inches'), + trans = deprecated(), + guide = 'legend', + ..., + transform = 'identity') { + + if (is.null(choices)) { + abort('scale_pattern_units_continuous(): must specify "choices" argument') + } + if (lifecycle::is_present(trans)) { + lifecycle::deprecate_warn('1.1.1', + 'scale_pattern_units_continuous(trans)', + 'scale_pattern_units_continuous(transform)') + transform <- trans + } + + ggplot2::continuous_scale( + aesthetics = 'pattern_units', + palette = function(x) choices[as.integer(x * (length(choices) - 1) + 1)], + name = name, + breaks = breaks, + labels = labels, + limits = limits, + transform = transform, + guide = guide, + ...) +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#' @rdname scale_discrete +#' @importFrom utils head +#' @export +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +scale_pattern_units_discrete <- function(..., choices = c('snpc', 'cm', 'inches'), guide = 'legend') { + force(range) + + if (is.null(choices)) { + abort('scale_pattern_units_discrete(): must specify "choices" argument') + } + + ggplot2::discrete_scale( + aesthetics = 'pattern_units', + palette = function(n) { + idx <- cut(seq(n), length(choices), labels = FALSE, include.lowest = TRUE) + choices[idx] + }, + guide = guide, + ... + ) +} #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #' Create your own discrete scale #' @@ -1342,6 +1400,13 @@ scale_pattern_rot_manual <- function(..., values, breaks = waiver()) { manual_scale('pattern_rot', values, breaks, ...) } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#' @rdname scale_pattern_manual +#' @export +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +scale_pattern_units_manual <- function(..., values, breaks = waiver()) { + manual_scale('pattern_units', values, breaks, ...) +} +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #' Use values without scaling #' #' @param ...,guide See \code{ggplot2} for documentation on identity scales. @@ -1711,3 +1776,16 @@ scale_pattern_rot_identity <- function(..., guide = 'none') { super = ScaleContinuousIdentity ) } +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#' @rdname scale_pattern_identity +#' @export +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +scale_pattern_units_identity <- function(..., guide = 'none') { + discrete_scale( + aesthetics = 'pattern_units', + palette = identity_pal(), + ..., + guide = guide, + super = ScaleDiscreteIdentity + ) +} diff --git a/data-raw/config.R b/data-raw/config.R index 5b7cb26..a2240ce 100644 --- a/data-raw/config.R +++ b/data-raw/config.R @@ -32,4 +32,5 @@ pattern_frequency | | continuous | NULL pattern_grid | | discrete | c('square', 'hex') pattern_res | | continuous | NULL pattern_rot | | continuous | c(0, 360) +pattern_units | | discrete | c('snpc', 'cm', 'inches') ", trim_ws = TRUE, delim = "|") diff --git a/man/scale_discrete.Rd b/man/scale_discrete.Rd index c8e86f3..43c0e06 100644 --- a/man/scale_discrete.Rd +++ b/man/scale_discrete.Rd @@ -16,6 +16,8 @@ \alias{scale_pattern_orientation_discrete} \alias{scale_pattern_grid_continuous} \alias{scale_pattern_grid_discrete} +\alias{scale_pattern_units_continuous} +\alias{scale_pattern_units_discrete} \alias{scale_pattern_continuous} \alias{scale_pattern_discrete} \title{Scales for discrete pattern aesthetics} @@ -136,6 +138,24 @@ scale_pattern_grid_discrete( guide = "legend" ) +scale_pattern_units_continuous( + name = waiver(), + breaks = waiver(), + labels = waiver(), + limits = NULL, + choices = c("snpc", "cm", "inches"), + trans = deprecated(), + guide = "legend", + ..., + transform = "identity" +) + +scale_pattern_units_discrete( + ..., + choices = c("snpc", "cm", "inches"), + guide = "legend" +) + scale_pattern_continuous( name = waiver(), breaks = waiver(), diff --git a/man/scale_pattern_identity.Rd b/man/scale_pattern_identity.Rd index 7c1477d..15e069c 100644 --- a/man/scale_pattern_identity.Rd +++ b/man/scale_pattern_identity.Rd @@ -29,6 +29,7 @@ \alias{scale_pattern_grid_identity} \alias{scale_pattern_res_identity} \alias{scale_pattern_rot_identity} +\alias{scale_pattern_units_identity} \alias{scale_pattern_color_identity} \title{Use values without scaling} \usage{ @@ -84,6 +85,8 @@ scale_pattern_res_identity(..., guide = "none") scale_pattern_rot_identity(..., guide = "none") +scale_pattern_units_identity(..., guide = "none") + scale_pattern_identity(..., guide = "none") } \arguments{ diff --git a/man/scale_pattern_manual.Rd b/man/scale_pattern_manual.Rd index 9b17c8e..c5151e7 100644 --- a/man/scale_pattern_manual.Rd +++ b/man/scale_pattern_manual.Rd @@ -29,6 +29,7 @@ \alias{scale_pattern_grid_manual} \alias{scale_pattern_res_manual} \alias{scale_pattern_rot_manual} +\alias{scale_pattern_units_manual} \alias{scale_pattern_color_manual} \title{Create your own discrete scale} \usage{ @@ -84,6 +85,8 @@ scale_pattern_res_manual(..., values, breaks = waiver()) scale_pattern_rot_manual(..., values, breaks = waiver()) +scale_pattern_units_manual(..., values, breaks = waiver()) + scale_pattern_manual(..., values, breaks = waiver(), na.value = "none") } \arguments{ diff --git a/tests/testthat/_snaps/geom/density.svg b/tests/testthat/_snaps/geom/density.svg index c159f7c..3c094eb 100644 --- a/tests/testthat/_snaps/geom/density.svg +++ b/tests/testthat/_snaps/geom/density.svg @@ -20,241 +20,237 @@ - - + + - - + + - - + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -0.00 -0.05 -0.10 -0.15 -0.20 -0.25 - - - - - - - - - - - - -10 -15 -20 -25 -30 -35 +0.00 +0.05 +0.10 +0.15 +0.20 +0.25 + + + + + + + + + + + + +10 +15 +20 +25 +30 +35 mpg -density - -as.factor(cyl) - - - - - - - - - - - - - - - - - - - - - - - -4 -6 -8 -ggpattern::geom_density_pattern() +density + +as.factor(cyl) + + + + + + + + + + + + + + + + + + + + + + + +4 +6 +8 +ggpattern::geom_density_pattern() diff --git a/tests/testthat/_snaps/geom/violin.svg b/tests/testthat/_snaps/geom/violin.svg index e1757af..6c18817 100644 --- a/tests/testthat/_snaps/geom/violin.svg +++ b/tests/testthat/_snaps/geom/violin.svg @@ -50,35 +50,35 @@ - + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - + + + + - - - - + + + + @@ -106,11 +106,11 @@ - + - - - + + + diff --git a/tests/testthat/test-geom.R b/tests/testthat/test-geom.R index 052f5f5..e155db9 100644 --- a/tests/testthat/test-geom.R +++ b/tests/testthat/test-geom.R @@ -116,7 +116,7 @@ test_that("geometry patterns work as expected", { }) expect_doppelganger("histogram", { - ggplot(diamonds, aes(carat)) + + ggplot(ggplot2::diamonds, aes(carat)) + geom_histogram_pattern(pattern = "stripe", bins = 30) }) diff --git a/vignettes/developing-patterns.Rmd b/vignettes/developing-patterns.Rmd index 8fa390a..f47e486 100644 --- a/vignettes/developing-patterns.Rmd +++ b/vignettes/developing-patterns.Rmd @@ -90,11 +90,12 @@ so may make your pattern more useful for others: | `pattern_scale` | Scale | 1 | Multiplier | | `pattern_shape` | Plotting shape | 1 | shapes | | `pattern_size` | Stroke linewidth | 1 | linewidth | -| `pattern_spacing` | Spacing between repetitions of pattern | 0.05 | value in range [0, 1] (snpc units) | +| `pattern_spacing` | Spacing between repetitions of pattern | 0.05 | value in `pattern_units` grid units | | `pattern_subtype` | Generic control option | NA | pattern-dependent | | `pattern_type` | Generic control option | NA | pattern-dependent | -| `pattern_xoffset` | Shift pattern along x axis | 0 | value in range [0, 1] (snpc units) | -| `pattern_yoffset` | Shift pattern along y axis | 0 | value in range [0, 1] (snpc units) | +| `pattern_units` | Pattern grid unit | 'snpc' | `grid::unit()` unit i.e. 'snpc', 'cm', and 'inches' | +| `pattern_xoffset` | Shift pattern along x axis | 0 | value in `pattern_units` grid units | +| `pattern_yoffset` | Shift pattern along y axis | 0 | value in `pattern_units` grid units | diff --git a/vignettes/patterns-points.Rmd b/vignettes/patterns-points.Rmd index d1c7d8b..f6b6951 100644 --- a/vignettes/patterns-points.Rmd +++ b/vignettes/patterns-points.Rmd @@ -47,9 +47,10 @@ suppressPackageStartupMessages({ | pattern\_fill | Fill colour | 'grey80' | colour | | pattern\_angle | Rotation angle | 30 | angle in degrees | | pattern\_density | Approx. fraction of area the pattern fills | 0.2 | value in range [0, 1] (fraction) | -| pattern\_spacing | Spacing between repetitions of pattern | 0.05 | value in range [0, 1] (snpc units) | -| pattern\_xoffset | Shift pattern along x axis | 0 | value in range [0, 1] (snpc units) | -| pattern\_yoffset | Shift pattern along y axis | 0 | value in range [0, 1] (snpc units) | +| pattern\_spacing | Spacing between repetitions of pattern | 0.05 | value in `pattern_units` grid units | +| pattern\_xoffset | Shift pattern along x axis | 0 | value in `pattern_units` grid units | +| pattern\_yoffset | Shift pattern along y axis | 0 | value in `pattern_units` grid units | +| pattern\_units | Pattern grid unit | 'snpc' | `grid::unit()` unit i.e. 'snpc', 'cm', and 'inches' | | pattern\_alpha | Alpha | NA | value in range [0, 1] or NA | | pattern\_linetype | Stroke linetype | 1 | linetype | | pattern\_size | Stroke linewidth | 1 | linewidth | diff --git a/vignettes/patterns-stripes.Rmd b/vignettes/patterns-stripes.Rmd index 314feaa..9490ce4 100644 --- a/vignettes/patterns-stripes.Rmd +++ b/vignettes/patterns-stripes.Rmd @@ -47,9 +47,10 @@ suppressPackageStartupMessages({ | pattern\_fill | Fill colour | 'grey80' | colour | | pattern\_angle | Rotation angle | 30 | angle in degrees | | pattern\_density | Approx. fraction of area the pattern fills | 0.2 | value in range [0, 1] (fraction) | -| pattern\_spacing | Spacing between repetitions of pattern | 0.05 | value in range [0, 1] (snpc units) | -| pattern\_xoffset | Shift pattern along x axis | 0 | value in range [0, 1] (snpc units) | -| pattern\_yoffset | Shift pattern along y axis | 0 | value in range [0, 1] (snpc units) | +| pattern\_spacing | Spacing between repetitions of pattern | 0.05 | value in `pattern_units` grid units | +| pattern\_xoffset | Shift pattern along x axis | 0 | value in `pattern_units` grid units | +| pattern\_yoffset | Shift pattern along y axis | 0 | value in `pattern_units` grid units | +| pattern\_units | Pattern grid unit | 'snpc' | `grid::unit()` unit i.e. 'snpc', 'cm', and 'inches' | | pattern\_alpha | Alpha | NA | value in range [0, 1] or NA | | pattern\_linetype | Stroke linetype | 1 | linetype | | pattern\_size | Stroke linewidth | 1 | linewidth | diff --git a/vignettes/patterns-tilings.Rmd b/vignettes/patterns-tilings.Rmd index 647bbc4..09c5428 100644 --- a/vignettes/patterns-tilings.Rmd +++ b/vignettes/patterns-tilings.Rmd @@ -189,9 +189,10 @@ ggplot(df2, aes(x="", y = value, pattern_angle = group))+ | pattern\_colour | Stroke colour | 'grey20' | colour | | pattern\_fill | Fill colour | 'grey80' | colour | | pattern\_angle | Rotation angle | 30 | angle in degrees | -| pattern\_spacing | Spacing between repetitions of pattern | 0.05 | value in range [0, 1] (snpc units) | -| pattern\_xoffset | Shift pattern along x axis | 0 | value in range [0, 1] (snpc units) | -| pattern\_yoffset | Shift pattern along y axis | 0 | value in range [0, 1] (snpc units) | +| pattern\_spacing | Spacing between repetitions of pattern | 0.05 | value in `pattern_units` grid units | +| pattern\_xoffset | Shift pattern along x axis | 0 | value in `pattern_units` grid units | +| pattern\_yoffset | Shift pattern along y axis | 0 | value in `pattern_units` grid units | +| pattern\_units | Pattern grid unit | 'snpc' | `grid::unit()` unit i.e. 'snpc', 'cm', and 'inches' | | pattern\_alpha | Alpha | NA | value in range [0, 1] or NA | | pattern\_linetype | Stroke linetype | 1 | linetype | | pattern\_size | Stroke linewidth | 1 | linewidth |