Это напоминает мне о подобной проблеме здесь , где принятое решение использовало geom_ribbon()
для обеспечения маскирующего слоя.
В том же духе, поскольку в этом случае маска должна окружать отдельные стержни, мы стремимся создать слой многоугольника, который изящно обрабатывает отверстия. Последнее, что я проверил, geom_polygon
делает не так здорово, но geom_polypath
из пакета ggpolypath делает.
Воспроизводимый пример с использованием логотипа R в качестве образца изображения и встроенного фрейма данных:
library(ggplot2)
library(grid)
library(jpeg)
montage <- readJPEG(system.file("img", "Rlogo.jpg", package="jpeg"))
mont <- rasterGrob(montage, width = unit(1,"npc"),
height = unit(1,"npc"))
p <- ggplot(mpg, aes(x = class)) +
annotation_custom(mont, -Inf, Inf, -Inf, Inf) +
geom_bar(color = "black", fill = NA) +
coord_flip() +
theme_bw()
p
Создание фрейма данных координат для маскирующего слоя:
library(dplyr)
library(tidyr)
# convert the xmin/xmax/ymin/ymax values for each bar into
# x/y coordinates for a hole in a large polygon,
# then add coordinates for the large polygon
new.data <- layer_data(p, 2L) %>%
select(ymin, ymax, xmin, xmax) %>%
mutate(group = seq(1, n())) %>%
group_by(group) %>%
summarise(coords = list(data.frame(x = c(xmin, xmax, xmax, xmin),
y = c(ymin, ymin, ymax, ymax),
order = seq(1, 4)))) %>%
ungroup() %>%
unnest() %>%
rbind(data.frame(group = 0,
x = c(-Inf, Inf, Inf, -Inf),
y = c(-Inf, -Inf, Inf, Inf),
order = seq(1, 4)))
> new.data
# A tibble: 32 x 4
group x y order
<dbl> <dbl> <dbl> <int>
1 1 0.55 0 1
2 1 1.45 0 2
3 1 1.45 5 3
4 1 0.55 5 4
5 2 1.55 0 1
6 2 2.45 0 2
7 2 2.45 47 3
8 2 1.55 47 4
9 3 2.55 0 1
10 3 3.45 0 2
# ... with 22 more rows
Добавьте маскирующий слой:
library(ggpolypath)
p +
geom_polypath(data = new.data,
aes(x = x, y = y, group = group),
inherit.aes = FALSE,
rule = "evenodd",
fill = "white", color = "black")
p.s. Старая поговорка «только потому, что вы можете, не значит, что вы должны», вероятно, применима здесь ...