Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'facet_grid(space="free")' with aesthetics defined in 'snpc' units #81

Closed
Tracked by #104
ncrnalab opened this issue Jun 1, 2022 · 4 comments · Fixed by #120
Closed
Tracked by #104

'facet_grid(space="free")' with aesthetics defined in 'snpc' units #81

ncrnalab opened this issue Jun 1, 2022 · 4 comments · Fixed by #120
Assignees

Comments

@ncrnalab
Copy link

ncrnalab commented Jun 1, 2022

Bug description

Problems with pattern when combined with facet_grid (~facet, scales="free_x", space="free")

Minimal, reproducible example

# R code for minimal, reproducible example goes here

library (tidyverse)
library (ggpattern)

df <- data.frame (x=as.character (1:15),
                  y=rep (c(1, 3, -5), 5),
                  pattern = rep (c("a", "b", "b"), 5),
                  fill = rep (c("a", "b", "a"), 5),
                  facet = c(rep("x", 10), rep("y", 2), rep("z", 3)))

ggplot (df, aes (x=x, y=y, fill=fill, pattern = pattern)) + 
  geom_col_pattern (color = "black", 
                    pattern_fill = "black",
                    pattern_angle = 45,
                    pattern_density = 0.1,
                    pattern_spacing = 0.01,
                    pattern_key_scale_factor = 0.6) +
  facet_grid (~facet, scales="free_x", space="free")

Session info

R version 4.1.2 (2021-11-01)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19044), RStudio 2022.2.0.443

Locale:
  LC_COLLATE=English_Denmark.1252  LC_CTYPE=English_Denmark.1252    LC_MONETARY=English_Denmark.1252
  LC_NUMERIC=C                     LC_TIME=English_Denmark.1252    

Package version:
  cachem_1.0.6       class_7.3.20       classInt_0.4.3     cli_3.2.0          colorspace_2.0.3  
  crayon_1.5.1       DBI_1.1.2          digest_0.6.29      e1071_1.7.9        ellipsis_0.3.2    
  fansi_1.0.2        farver_2.1.0       fastmap_1.1.0      ggpattern_0.4.2    ggplot2_3.3.6     
  glue_1.6.2         graphics_4.1.2     grDevices_4.1.2    grid_4.1.2         gridpattern_0.5.3 
  gtable_0.3.0       isoband_0.2.5      KernSmooth_2.23.20 labeling_0.4.2     lattice_0.20.45   
  lifecycle_1.0.1    magrittr_2.0.2     MASS_7.3.57        Matrix_1.4.1       memoise_2.0.1     
  methods_4.1.2      mgcv_1.8.40        munsell_0.5.0      nlme_3.1.157       pillar_1.7.0      
  pkgconfig_2.0.3    png_0.1.7          proxy_0.4.26       R6_2.5.1           RColorBrewer_1.1.3
  Rcpp_1.0.8.3       rlang_1.0.1        s2_1.0.7           scales_1.2.0       sf_1.0.7          
  splines_4.1.2      stats_4.1.2        tibble_3.1.6       tools_4.1.2        units_0.8.0       
  utf8_1.2.2         utils_4.1.2        vctrs_0.3.8        viridisLite_0.4.0  withr_2.5.0       
  wk_0.6.0 

Rplot

@trevorld
Copy link
Owner

trevorld commented Jun 1, 2022

  • The pattern_spacing aesthetic used by many "geometry" pattern is in {grid} "snpc" units
  • It seems each separate "free" facet is being drawn in a {grid} viewport of different width so that these {grid} "snpc" units are being converted into different physical sizes
  • One can manually adjust pattern_spacing values to fix this (or use/write patterns that don't depend on "snpc" units):
library (tidyverse)
library (ggpattern)

df <- data.frame (x=as.character (1:15),
                  y=rep (c(1, 3, -5), 5),
                  pattern = rep (c("n", "s", "s"), 5),
                  fill = rep (c("r", "b", "r"), 5),
                  facet = c(rep("x", 10), rep("y", 2), rep("z", 3)))

ggplot (df, aes (x=x, y=y, fill=fill, pattern = pattern)) + 
  geom_col_pattern (color = "black", 
                    pattern_fill = "black",
                    pattern_angle = 45,
                    pattern_density = 0.1,
                    pattern_spacing = c(rep(0.08, 10), rep(0.32, 2), rep(0.24, 3)),
                    pattern_key_scale_factor = 0.6) +
  facet_grid (~facet, scales="free_x", space="free") +
  scale_fill_manual(values = c("red", "blue")) +
  scale_pattern_manual(values = c("none", "stripe"))

free_space

@trevorld trevorld changed the title [BUG] ggpattern and facet_grid with space="free [BUG] ggpattern and facet_grid with space="free" Jun 1, 2022
@trevorld trevorld changed the title [BUG] ggpattern and facet_grid with space="free" 'facet_grid(space="free")' with aesthetics defined in 'snpc' units Jun 20, 2022
@trevorld
Copy link
Owner

trevorld commented Jun 24, 2022

Here is an example of "custom" circle/stripe patterns that use "cm" units instead of "snpc" units:

library("grid")
library("ggpattern")
library("ggplot2")

cm2snpc <- function(cm) {
    max(convertX(unit(cm, "cm"), "npc", valueOnly = TRUE),
        convertY(unit(cm, "cm"), "npc", valueOnly = TRUE))
}

cm_pattern <- function(params, boundary_df, aspect_ratio, legend = FALSE) {
    args <- as.list(params)

    pattern <- gsub("_cm", "", args$pattern)
    args <- args[grep("^pattern_", names(args))]

    args$pattern <- pattern
    if (legend)
        args$pattern_spacing <- cm2snpc(0.5)
    else
        args$pattern_spacing <- cm2snpc(args$pattern_spacing)
    args$pattern_xoffset <- cm2snpc(args$pattern_xoffset)
    args$pattern_yoffset <- cm2snpc(args$pattern_yoffset)

    args$x <- boundary_df$x
    args$y <- boundary_df$y
    args$id <- boundary_df$id
    args$prefix <- ""

    do.call(gridpattern::patternGrob, args)
}

options(ggpattern_geometry_funcs = list(circle_cm = cm_pattern,
                                        stripe_cm = cm_pattern))

df <- data.frame (x=as.character (1:15),
                  y=rep (c(1, 3, -5), 5),
                  pattern = rep (c("a", "b", "b"), 5),
                  fill = rep (c("a", "b", "a"), 5),
                  facet = c(rep("x", 10), rep("y", 2), rep("z", 3)))

ggplot (df, aes (x=x, y=y, fill=fill, pattern=pattern)) +
  geom_col_pattern (color = "black",
                    pattern_fill = "black",
                    pattern_angle = 45,
                    pattern_density = 0.1,
                    pattern_spacing = 0.5) +
  facet_grid (~facet, scales="free_x", space="free") +
  scale_pattern_manual(values = c("stripe_cm", "circle_cm"))

cm_pattern

@trevorld
Copy link
Owner

Possible "solutions" for when facet_grid(space="free"):

  • Use "cm" or "in" instead of "snpc" units as default

    • "snpc" units are nice since they "scale" when enlarging/shrinking a plot
    • Such a change wouldn't be reverse compatible
  • Keep "snpc" as "default" but let users use a grid::unit() to set a different "unit"

    • Although straightforward to do in {gridpattern} but in {ggplot2} coerces aesthetics to a data frame and attempting to coerce grid::unit() columns causes an error...
  • New aesthetics to set different unit defaults

    • Makes API more complex and we already have a lot of aesthetics to manage...
  • Build variant patterns in {gridpattern} that use "cm" or "in" instead as default for pattern_spacing, pattern_xoffset, and pattern_yoffset

    • But {gridpattern} pattern functions are more flexible when used directly and could simply be a single "pattern" (before the {ggplot2} coercion to a data frame makes things "hard")...
  • Build a collection of variant patterns in a new package (perhaps called something like {gridpatternExtra}) that aren't really "new" patterns but are variants that users could optionally bring in using the custom pattern extension mechanism to avoid issues with {ggplot2} aesthetic limitations

    • Perhaps "cm" and "in" variants of the "geometry" patterns
    • Perhaps the 3-color polygon tiling pattern as well?
  • Do nothing (let users manually figure out good "snpc" values or write their own custom pattern functions)


Seems to me like a new package of pattern variants may be the "best" "solution"

@trevorld
Copy link
Owner

  • With feat: 'pattern_units' aesthetic #120 we'll be able to use the new pattern_units aesthetic so that pattern_spacing is interpreted as centimeters or inches instead of the default "snpc" units.
  • The default pattern_spacing of 0.05 is almost surely too small if you aren't using the default "snpc" units...
  • The bug report example "fixed" using the new aesthetic without needing to manually compute spacing values or use a custom pattern function (but we do need to adjust pattern_spacing to a higher value):
library(ggplot2)
library (ggpattern)

df <- data.frame (x=as.character (1:15),
                  y=rep (c(1, 3, -5), 5),
                  pattern = rep (c("a", "b", "b"), 5),
                  fill = rep (c("a", "b", "a"), 5),
                  facet = c(rep("x", 10), rep("y", 2), rep("z", 3)))

ggplot (df, aes (x=x, y=y, fill=fill, pattern = pattern)) + 
  geom_col_pattern (color = "black", 
                    pattern_fill = "black",
                    pattern_angle = 45,
                    pattern_density = 0.1,
                    pattern_spacing = 0.20, pattern_units = "in",
                    pattern_key_scale_factor = 1.0) +
  facet_grid (~facet, scales="free_x", space="free")

image

trevorld added a commit that referenced this issue Apr 29, 2024
* {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
trevorld added a commit that referenced this issue Apr 30, 2024
* {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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants