Skip to contents

register_pattern() registers a pattern so it can be used by grid.pattern() / patternGrob() (and {ggpattern}). unregister_pattern() removes a pattern previously registered by the same owner (as determined by env); it never removes patterns registered by other packages or the builtin {gridpattern} patterns.

Usage

register_pattern(
  name,
  fn,
  kind = c("geometry", "array"),
  defaults = list(),
  env = caller_env()
)

unregister_pattern(name, env = caller_env())

Arguments

name

Pattern name. Must not contain ":".

fn

Pattern function. Its required signature depends on kind:

geometry

function(params, boundary_df, aspect_ratio, legend) returning a grid grob that lies within the boundary (e.g. clipped to it). params is a list of (prefixed) pattern parameters e.g. params$pattern_fill, boundary_df is a data frame with x, y, and id columns describing the boundary polygon(s) in “npc” coordinates, aspect_ratio is the (best guess) aspect ratio of the viewport, and legend is whether the pattern is being drawn in a {ggpattern} legend key.

array

function(width, height, params, legend) returning a 3D array of RGBA values (all values in the range [0, 1]) which {gridpattern} will mask to the boundary. width and height are the dimensions (in pixels) of the boundary's bounding box and params and legend are as for geometry patterns.

See the “Developing Patterns” vignette vignette("developing-patterns", package = "gridpattern") for more details and examples.

kind

Either "geometry" or "array".

defaults

A named list of pattern-specific default parameter values (without the pattern_ prefix) e.g. list(type = "running", spacing = 0.1). Values may be constants or functions of the form function(params, gp) where params is the list of (prefixed) pattern parameters filled in so far and gp is the grob's grid::gpar() object e.g. list(amplitude = function(params, gp) 0.5 * params$pattern_spacing). These replace the generic defaults for parameters that weren't supplied. Note {ggpattern} supplies its own (generic) defaults for most of its pattern aesthetics so these will mainly be used with grid.pattern() / patternGrob().

env

The environment used to determine the “owner” of the pattern. If writing a function that registers patterns on behalf of its caller add an env = rlang::caller_env() argument to that function and pass it on.

Value

register_pattern() and unregister_pattern() invisibly return the previous registration (a list) or NULL if there wasn't one.

Details

Each pattern is “owned” by either the package that registered it or by the user (if registered from the global environment e.g. in a script or at the console). Patterns may always be referred to by their qualified name "owner::name" e.g. "gridpattern::stripe", "pkg::name", or "R_GlobalEnv::name". A bare pattern name like "stripe" is resolved as follows:

  1. If the user has set a preference with prefer_pattern() then the preferred pattern.

  2. If exactly one owner (the user, {gridpattern}, or a loaded package) has a pattern with that name then that pattern. Patterns set by the user with the (legacy) ggpattern_geometry_funcs / ggpattern_array_funcs options are owned by the user. If the user has more than one pattern with that name (from register_pattern() and/or the options) an error is thrown asking them to remove all but one of them (since they share the same qualified name "R_GlobalEnv::name" a preference can't choose between them).

  3. Otherwise there is a conflict and an error is thrown, asking for either a qualified "owner::name" or a prefer_pattern() preference. In particular, a user pattern with the same name as a builtin {gridpattern} pattern does not mask the builtin pattern without a preference.

conflicting_patterns() lists the patterns whose bare names are shared by more than one pattern.

patternGrob() resolves the pattern name when the grob is created (if the pattern is registered) so redrawing the grob (e.g. when resizing an interactive graphics device) still works even if the pattern is later unregistered or conflicted (e.g. by local_pattern() going out of scope). Changing the grob's pattern with grid::editGrob() resolves the new pattern name when drawn.

Packages should register their patterns in their .onLoad() function. We recommend wrapping the registration in rlang::on_package_load() so the pattern is registered whenever {gridpattern} is loaded (allowing {gridpattern} to be in Suggests and surviving {gridpattern} being reloaded). Since a Suggests version requirement isn't enforced when installing or loading packages, also check that the installed {gridpattern} has register_pattern() (and otherwise fall back to setting the legacy ggpattern_geometry_funcs option):

.onLoad <- function(libname, pkgname) {
  rlang::on_package_load("gridpattern", {
    if (exists("register_pattern", envir = asNamespace("gridpattern"), inherits = FALSE)) {
      gridpattern::register_pattern("brick", create_pattern_brick)
    } else {
      funcs <- getOption("ggpattern_geometry_funcs", list())
      funcs[["brick"]] <- create_pattern_brick
      options(ggpattern_geometry_funcs = funcs)
    }
  })
}

Package code that relies on a particular pattern should use its qualified name (e.g. "gridpattern::stripe") since other packages (or users) may register patterns with the same bare name.

See also

registered_patterns() and has_pattern() to list available patterns. local_pattern() to temporarily register a pattern. prefer_pattern() and conflicting_patterns() to resolve pattern name conflicts.

Examples

create_pattern_polygon <- function(params, boundary_df, aspect_ratio, legend = FALSE) {
  grid::polygonGrob(boundary_df$x, boundary_df$y, boundary_df$id,
                    gp = grid::gpar(fill = params$pattern_fill))
}
x_hex <- 0.5 + 0.5 * cos(seq(2 * pi / 4, by = 2 * pi / 6, length.out = 6))
y_hex <- 0.5 + 0.5 * sin(seq(2 * pi / 4, by = 2 * pi / 6, length.out = 6))
# don't clobber any pre-existing "polygon" pattern
if (!has_pattern("polygon")) {
  register_pattern("polygon", create_pattern_polygon)
  grid::grid.newpage()
  grid.pattern("polygon", x_hex, y_hex, fill = "blue")
  unregister_pattern("polygon")
}