【问题标题】:Add image background to ggplot barplot so that image is only visible inside of bars将图像背景添加到 ggplot barplot 以便图像仅在条形图内可见
【发布时间】:2019-05-29 16:10:42
【问题描述】:

我想使用 ggplot2 在 R 中创建一个条形图,这样条形图是透明的,允许背景图像可见,而绘图的其余部分是不透明的并覆盖背景图像。

我可以将图像添加到背景中,如下所示,但我找不到仅在条形图中显示背景图像的方法。从本质上讲,我希望创造出与我在这里所拥有的相反的东西。

library(ggplot2)
library(jpeg)
library(grid)
library(scales)

montage <- readJPEG("AcanthMontage.jpg")
mont <- rasterGrob(montage, 
                   width = unit(1,"npc"), 
                   height = unit(1,"npc"))

montplot <- ggplot(frequencyDF, aes(x=depth, y= perLiter)) + 
  annotation_custom(mont, -Inf, Inf, -Inf, Inf) +
  scale_fill_continuous(guide = FALSE) +
  geom_bar(stat = "identity", color="black", fill="white", alpha=0.5) + 
  coord_flip() + 
  scale_y_continuous(limits= c(0,1.25), expand = c(0, 0)) + 
  scale_x_continuous(limits= c(-1000,0), expand = c(0,0)) + 
  theme_bw() + 
  theme(text=element_text(size=16)) + 
  xlab("Depth (m)") + 
  ylab("Cells per Liter")

montplot

【问题讨论】:

  • 有趣。在前面,我不知道该怎么做,但作为情节的制造者和消费者,我不得不评论说这是非常忙碌和分散注意力的,甚至可能是反Tufte。你想要这个布局有什么特别的原因吗? (我确实理解你的意思是相反,但还是有点奇怪......我想我的眼睛会尝试为条形图中的某些模式分配意义。)
  • @r2evans 感谢您的评论!我同意情节变得太忙了。蒙太奇中的图像是为创建“每升细胞”计数而计算的实际细胞。我认为将细胞排列在条内可能看起来不错,就像象形文字一样,但是,由于每个条内的细胞数量与每升的细胞数量没有直接关系,我知道这会产生误导.从本质上讲,我试图为海报增添趣味,并在更小的空间中包含更多信息——细胞是什么样子的,有多少。
  • 我明白了。 “海报”表示你的用法,虽然它可能仍然很忙,但它更有意义。

标签: r ggplot2 geom-bar


【解决方案1】:

这让我想起了一个类似的问题here,其中公认的解决方案使用geom_ribbon() 来提供遮罩层。

以类似的方式进行,因为在这种情况下,蒙版需要围绕单个条,我们正在寻求创建一个可以优雅地处理孔的多边形层。最后我检查了一下,geom_polygon 并没有那么好,但是来自 ggpolypath 包的 geom_polypath 可以。

可重现的示例,使用 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")

附言古老的格言“仅仅因为你可以,并不意味着你应该”在这里可能适用......

【讨论】:

  • 谢谢@Z.Lin!这完美地解决了这个问题。我同意这可能不是从美学角度显示信息的最佳方式。最初的想法是,通过在条形图中显示细胞的密度,可以节省空间,并可能在科学海报上具有视觉吸引力——有点像象形文字。我会继续考虑最好的数字,但同时感谢您的帮助!
【解决方案2】:

相当有趣的问题。我和@r2evans 一起担心这可能会产生一个令人困惑的情节,这可能会用条形图内的模式传达错误的解释。

如果这是一个图像编辑问题,您正在寻找一个遮罩 - 其中的条是过滤背景图像的遮罩。 raster 包有这个功能,但我不确定如何将它与 ggplot2 结合起来。

ggplot2 使用grid 包将元素渲染到图形设备(即屏幕、窗口、pdf 等)上。在这里,您可以将rasterGrob 与每个条的视口结合起来,以创建遮罩效果。第一站是从你的 ggplot2 对象渲染一个ggplotGrob 对象(实际上是ggplotGrob(p),其中p &lt;- ggplot(...) + ...)。

有关视口的更多信息,请参阅Zhou 2010Murell 2018

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-18
    • 2013-02-16
    • 2015-08-14
    • 2012-07-14
    相关资源
    最近更新 更多