如何在ggplot中模糊部分情节?

Posted

技术标签:

【中文标题】如何在ggplot中模糊部分情节?【英文标题】:How to blur part of a plot in ggplot? 【发布时间】:2021-07-22 09:59:18 【问题描述】:

有没有办法模糊ggplot 中的某个情节?

例如,考虑以下情节:

library(ggplot2)
library(magrittr)

p <- 
  mtcars %>%
  ggplot(aes(x = disp, y = mpg)) +
  geom_line() +
  theme_minimal() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        panel.background = element_blank()) 

p +
  annotate("rect", xmin = 100, xmax = 200, ymin = 15, ymax = 30,
           alpha = .1,fill = "red") 

由reprex package (v2.0.0) 于 2021-07-22 创建


所需输出

我想在p 中当前存在红色矩形的区域上应用模糊效果。 我正在寻找的演示:

这可能吗?


参考:Similar question (and answer) in python。

【问题讨论】:

您可能想查看ggfx 包 我会将需要模糊的数据绘制为单独的图层,然后将模糊应用于该图层 目前自己在测试,但想法是我们有 2 个数据集,一个普通的 geom_line(d1),第二个数据集被包装到 with_blur(geom_line(d2)) 为什么不让你的第一次尝试得到更好的可见性的答案,也让问题/答案的事情更清楚一点。也有人可以支持这一尝试。这是应得的。 从您的示例中获取它,我可能会使用您的模糊补丁生成一个 theme_void 图,并将其叠加到第一个带有牛图或拼凑而成的图上。但我真的还没有开始研究那个看起来很邪恶的 ggfx 包。 【参考方案1】:

您可以使用带有geom_rect() 的ggfx 蒙版来确定应用效果的区域。示例如下:

library(ggplot2)
library(magrittr)
library(ggfx)

# Plot without line
p <- 
  mtcars %>%
  ggplot(aes(x = disp, y = mpg)) +
  theme_minimal() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        panel.background = element_blank()) 

# Add mask as a reference
p + 
  as_reference(
    geom_rect(
      aes(xmin = 100, xmax = 200, ymin = 15, ymax = 30),
      inherit.aes = FALSE
    ),
    id = "draw_area" # <- set some name
  ) +
  # Plot blurry part with mask
  with_mask(
    with_blur(geom_line(), sigma = 5),
    mask = ch_alpha("draw_area")
  ) +
  # Plot crisp part with inverted mask
  with_mask(
    geom_line(),
    mask = ch_alpha("draw_area"),
    invert = TRUE
  )

由reprex package (v1.0.0) 于 2021 年 7 月 22 日创建

如果你打算经常使用它,你可以像这样制作一个包装函数:

# trbl: Top, Right, Bottom, Left
area_effect <- function(layer, effect = with_blur, ..., trbl) 
  id <- rlang::hash(trbl)
  ref <- as_reference(
    annotate(
      "rect", xmin = trbl[4], xmax = trbl[2], ymin = trbl[3], ymax = trbl[1]
    ),
    id = id
  )
  mask1 <- with_mask(
    effect(layer, ...),
    mask = ch_alpha(id)
  )
  mask2 <- with_mask(
    layer, mask = ch_alpha(id), invert = TRUE
  )
  list(
    ref, mask1, mask2
  )


p +
  area_effect(geom_line(), trbl = c(30, 200, 15, 100), sigma = 5)

【讨论】:

因为我确实打算经常使用它,所以我对您的area_effect() 感到非常兴奋。但是,在不同的绘图上尝试此操作会导致不希望的图形失真。 p_mpg &lt;- mpg %&gt;% ggplot(aes(x = manufacturer, y = cty)) + geom_line() ; p_mpg_with_blur &lt;- p_mpg + area_effect(geom_line(), trbl = c(20, 6, 10, 0.5), sigma = 5)。你可以看到herep_mpg_with_blur,模糊区域外的线条变得奇怪了。 其实你的第一种方法也会出现同样的问题。所以可能是ggfx 的问题? 同意,我认为这可能是在引擎盖下发生的转换为栅格/png 的人工制品。线条一般较粗。右侧的线条看起来很奇怪,因为过度绘制并因此堆叠了透明度值。【参考方案2】:

我们可以将数据一分为二:普通绘图数据,模糊数据:

library(ggplot2)
library(ggfx)

d1 <- mtcars
d1 <- d2 <- d1[ order(d1$disp), ]

ix1 <- range(which(d1$disp > 100 & d1$disp < 200)) + c(1, -1)
ix2 <- which(d1$disp < 100 | d1$disp > 200)

d1[ ix1[ 1 ]:ix1[ 2 ], "mpg" ] <- NA
d2[ ix2, "mpg" ] <- NA

ggplot() +
  geom_line(aes(x = disp, y = mpg), d1) +
  with_blur(
    geom_line(aes(x = disp, y = mpg), d2),
    sigma = unit(1, 'mm')
  )

【讨论】:

【参考方案3】:

这是我的第一次尝试,使用 ggfx 库,但仍然不是理想的输出

library(ggplot2)
library(magrittr)
library(ggfx)

p_all_blurry <- 
  mtcars %>%
  ggplot(aes(x = disp, y = mpg)) +
  with_blur(
    geom_line(),
    sigma = unit(1, 'mm')
  )+
  theme_minimal() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        panel.background = element_blank()) 

p_all_blurry

由reprex package (v2.0.0) 于 2021 年 7 月 22 日创建

如何将模糊区域限制在红色矩形(问题中)所在的位置?

【讨论】:

以上是关于如何在ggplot中模糊部分情节?的主要内容,如果未能解决你的问题,请参考以下文章

如何将剪贴蒙版应用于ggplot中的geom?

如何让ggplot线跑到边缘?

如何在绘图标题或标签中为文本加下划线? (ggplot2)

避免使用 facet_wrap 从 ggplot 进行情节转换中的图例重复

如何将ggplot的符号和颜色用于LaTeX中的图形标题?

如何在ggplot2的图例中斜体化一个类别