library(grid)
library(ggplot2)
library(ggpattern)
#>
#> Attaching package: 'ggpattern'
#> The following objects are masked from 'package:ggplot2':
#>
#> flip_data, flipped_names, gg_dep, has_flipped_aes, remove_missing,
#> should_stop, waiver
While developing {ggpattern}
, two different methods of creating patterned areas were explored:
{sf}
objects and treat the “cutting out” of the pattern as a spatial intersection operation. The pattern would then be converted from {sf}
back to grid grobs and included in the plot.{grid}
objects and use gridGeometry::polyclipGrob
to create a special type of intersection grob (grid graphics object).gridGeometry::polyclipGrob
The two boxes are clearly seen to be just overlapping rectangles.
horizontal_box <- rectGrob(
x = 0.5,
y = 0.5,
width = 0.5,
height = 0.1,
gp = gpar(fill = 'black', alpha = 0.5)
)
vertical_box <- rectGrob(
x = 0.5,
y = 0.5,
width = 0.1,
height = 0.5,
gp = gpar(fill = 'black', alpha = 0.5)
)
cross <- grobTree(horizontal_box, vertical_box)
plot.new()
grid.draw(cross)
polyclipGrob
does funky things with the overlap at the centre.This looks like the renderer is applying the even-odd rule and determining that in the centre of the cross there are an even number of crossings, so it must lie outside the drawn shape.
boundary <- rectGrob(
x = 0.5,
y = 0.5,
width = 0.3,
height = 0.3
)
intersection_grob <- gridGeometry::polyclipGrob(
boundary, cross,
gp = gpar(
fill = 'black'
)
)
plot.new()
grid.draw(intersection_grob)
polyclipGrob
By using a union operation, the two boxes actually become a single entity
cross <- gridGeometry::polyclipGrob(
horizontal_box, vertical_box,
op = 'union',
gp = gpar(fill = 'black', alpha = 0.5)
)
plot.new()
grid.draw(cross)
polyclipGrob
now does correct intersection operationintersection_grob <- gridGeometry::polyclipGrob(
boundary, cross,
gp = gpar(
fill = 'black',
alpha = 0.5
)
)
plot.new()
grid.draw(intersection_grob)
union
operation in polyclipGrob
The great thing about polyclipGrob
is that it gives the correct result.
But main problem with using it is that it is very slow for my use case.
In the following 2 plots, both an {sf}
solution and a {grid}
solution are presented.
{sf}
solution is approximately 20x faster
{sf}
behaviour at the crossover between two lines is different from the {grid}
solution.{sf}
based intersectiondf <- data.frame(trt = c("a", "b", "c"), outcome = c(2.3, 1.9, 3.2))
p <- ggplot(df, aes(trt, outcome)) +
geom_col_pattern(pattern = 'crosshatch', fill='white', colour='black', pattern_spacing = 0.025, pattern_alpha = 0.5) +
theme_bw() +
labs(title = "ggpattern::geom_col_pattern()") +
theme(legend.key.size = unit(1.5, 'cm')) +
coord_fixed(ratio = 1/2)
outfile <- tempfile(fileext = ".png")
system.time({
png(outfile, width=800, height=600)
print(p)
dev.off()
})
#> user system elapsed
#> 0.267 0.020 0.311
# knitr::include_graphics(outfile)
p
{grid}
based union and intersection via pattern = 'crosshatch2'
df <- data.frame(trt = c("a", "b", "c"), outcome = c(2.3, 1.9, 3.2))
p <- ggplot(df, aes(trt, outcome)) +
geom_col_pattern(pattern = 'crosshatch2', fill='white', colour='black', pattern_spacing = 0.025, pattern_alpha = 0.5) +
theme_bw() +
labs(title = "ggpattern::geom_col_pattern()") +
theme(legend.key.size = unit(1.5, 'cm')) +
coord_fixed(ratio = 1/2)
outfile <- tempfile(fileext = ".png")
system.time({
png(outfile, width=800, height=600)
print(p)
dev.off()
})
#> Warning: create_pattern_grobs() - pattern not supported:
#> Warning: create_pattern_grobs() - pattern not supported:
#> Warning: create_pattern_grobs() - pattern not supported:
#> user system elapsed
#> 0.116 0.014 0.149
# knitr::include_graphics(outfile)
p
#> Warning: create_pattern_grobs() - pattern not supported:
#> Warning: create_pattern_grobs() - pattern not supported:
#> Warning: create_pattern_grobs() - pattern not supported: