如何在同一个散点图上使用 geom_vline() 和 geom_hline 避免图例中的交叉效应?

Posted

技术标签:

【中文标题】如何在同一个散点图上使用 geom_vline() 和 geom_hline 避免图例中的交叉效应?【英文标题】:How to avoid the crossing effect in legend with geom_vline() and geom_hline on the same scatter plot? 【发布时间】:2021-04-24 03:34:08 【问题描述】:

我用geom_hline()geom_vline() 创建了一个散点图,该图很好,但图例条目不是我想让它们出现的方式。 vline(恢复)和hline(阈值)在图例中相互交叉,令人困惑。我希望恢复图例条目为橙色垂直线,阈值图例条目为水平黑线。

我尝试了其他帖子中建议的几件事,使用 guide_legend(override.aes())show.legend = F 但要么它更改了上面“类型”部分的图例条目(它删除了线条并保留了彩色圆圈),要么它只是删除了其中一行的图例条目。

这是我当前的代码:

ggplot(data = tst_formule[tst_formule$River != "Roya",], aes(x=Year, y = BRI_adi_moy_transect, shape = River, col = Type)) +  
  geom_point(size = 3) +   
  geom_errorbar(aes(ymin = BRI_adi_moy_transect - SD_transect, ymax = BRI_adi_moy_transect + SD_transect), width = 0.4) + 
  scale_shape_manual(values = c(15, 16, 17)) +
  scale_colour_manual(values = c("chocolate1", "darkcyan")) +  
  geom_vline(aes(xintercept = Restauration_year, linetype = "Restoration"), colour = "chocolate1") + 
  geom_hline(aes(yintercept = 0.004, linetype = "Threshold"), colour= 'black') + 
  scale_linetype_manual(name = NULL, values = c(4, 5)) + 
  scale_y_continuous("BRI*", limits = c(min(tst_formule$BRI_adi_moy_transect - tst_formule$SD_transect),
                                        max(tst_formule$BRI_adi_moy_transect + tst_formule$SD_transect))) +
  scale_x_continuous(limits = c(min(tst_formule$Year - 1),max(tst_formule$Year + 1)), breaks = scales::breaks_pretty(n = 6)) + 
  theme_bw() + 
  facet_wrap(vars(River))

这是我的dput 数据:

structure(list(River = c("Durance", "Durance", "Durance", "Durance", 
"Roya", "Var"), Reach = c("La Brillanne", "Les Mées", "La Brillanne", 
"Les Mées", "Basse vallée", "Basse vallée"), Type = c("restaured", 
"target", "restaured", "target", "witness", "restaured"), Year = c(2017, 
2017, 2012, 2012, 2018, 2011), Restauration_year = c(2013, 2013, 
2013, 2013, 2000, 2009), BRI_adi_moy_transect = c(0.0028, 0.0017, 
0.0033, 0.0018, 0.009, 0.0045), SD_transect = c(0.00128472161839638, 
0.000477209421076879, 0.00204050725984513, 0.000472466654940182, 
0.00780731734792112, 0.00310039904793707)), row.names = c(NA, 
6L), class = "data.frame")

知道如何让它做我想做的事吗?

【问题讨论】:

【参考方案1】:

这是本期https://github.com/tidyverse/ggplot2/issues/2483中记录的一个已知问题

那里没有提供任何答案,除了自定义绘制的图例键,我认为这是不可能的

【讨论】:

【参考方案2】:

我找到了一个令人难以置信的不可概括的解决方法,但我想我还是会分享。解决方法是编写键字形函数,根据线型有条件地输出键。这有点硬编码,所以我不知道如何概括这一点。下面是两个函数:

glyph_vline <- function(data, params, size) 
  if (data$linetype == 4) 
    draw_key_vline(data, params, size)
   else 
    zeroGrob()
  


glyph_hline <- function(data, params, size) 
  if (data$linetype == 5) 
    draw_key_path(data, params, size)
   else 
    zeroGrob()
  

您需要将这些输入到 vline/hline 层的 key_glyph 参数中。像这样:

ggplot(data = tst_formule[tst_formule$River != "Roya",], aes(x=Year, y = BRI_adi_moy_transect, shape = River, col = Type)) +  
  geom_point(size = 3) +   
  geom_errorbar(aes(ymin = BRI_adi_moy_transect - SD_transect, ymax = BRI_adi_moy_transect + SD_transect), width = 0.4) + 
  scale_shape_manual(values = c(15, 16, 17)) +
  scale_colour_manual(values = c("chocolate1", "darkcyan")) +  
  geom_vline(aes(xintercept = Restauration_year, linetype = "Restoration"), 
             colour = "chocolate1", key_glyph = glyph_vline) + 
  geom_hline(aes(yintercept = 0.004, linetype = "Threshold"), 
             colour= 'black', key_glyph = glyph_hline) + 
  scale_linetype_manual(name = NULL, values = c(4, 5)) + 
  scale_y_continuous("BRI*", limits = c(min(tst_formule$BRI_adi_moy_transect - tst_formule$SD_transect),
                                        max(tst_formule$BRI_adi_moy_transect + tst_formule$SD_transect))) +
  scale_x_continuous(limits = c(min(tst_formule$Year - 1),max(tst_formule$Year + 1)), breaks = scales::breaks_pretty(n = 6)) + 
  theme_bw() + 
  facet_wrap(vars(River))

【讨论】:

【参考方案3】:

创建两个线型比例。我已将 vline/hline 调用置于底部以获得更好的可见性。

library(tidyverse)
library(ggnewscale)

ggplot(data = tst_formule[tst_formule$River != "Roya",], aes(x=Year, y = BRI_adi_moy_transect, shape = River, col = Type)) +  
  geom_point(size = 3) +   
  geom_errorbar(aes(ymin = BRI_adi_moy_transect - SD_transect, ymax = BRI_adi_moy_transect + SD_transect), width = 0.4) + 
  scale_shape_manual(values = c(15, 16, 17)) +
  scale_colour_manual(values = c("chocolate1", "darkcyan")) +  
  scale_y_continuous("BRI*", limits = c(min(tst_formule$BRI_adi_moy_transect - tst_formule$SD_transect),
                                        max(tst_formule$BRI_adi_moy_transect + tst_formule$SD_transect))) +
  scale_x_continuous(limits = c(min(tst_formule$Year - 1),max(tst_formule$Year + 1)), breaks = scales::breaks_pretty(n = 6)) + 
  theme_bw() + 
  facet_wrap(vars(River)) +
# here starts the trick 
  geom_vline(aes(xintercept = Restauration_year, linetype = "Restauration"), colour = "chocolate1") + 
  scale_linetype_manual(name = NULL, values = 4) +
# ggnewscale is an amazing package
  new_scale("linetype") +
# now do the same for geom_hline
  geom_hline(aes(yintercept = 0.004, linetype = "Threshold"), colour= 'black') + 
  scale_linetype_manual(name = NULL, values = 5) 
  

【讨论】:

谢谢@tjebo!那很完美!知道为什么 vlinehline 的图例条目现在位于图例的顶部吗?有没有办法让它们保持在全局图例的底部,并使它们之间的空间更小? @Jude 我原以为你会问这个问题......在这种情况下很棘手。我想很难改变只有这两个传说项目之间的距离而不弄乱grobs。图例间距可能是一个相当大的挑战。 ***.com/questions/11366964/… 可能会有所帮助。至于订单***.com/q/11393123/7941188 这可能值得一个后续问题,例如“更改仅选定图例之间的间距”左右,我认为之前已经问过,但我没有在快速搜索中找到它。跨度> 我设法通过theme(legend.spacing.y())guides() 实现了我想要的形状、颜色和线条,因此效果很好。感谢您的帮助!

以上是关于如何在同一个散点图上使用 geom_vline() 和 geom_hline 避免图例中的交叉效应?的主要内容,如果未能解决你的问题,请参考以下文章

Plotly 散点图趋势线出现在散点下方。如何让趋势线出现在散点图上? [Python]

如何将数据椭圆叠加在 ggplot2 散点图上?

如何在 3d 散点图上自动化注释

如何在 ggplot2 散点图上覆盖 lm 对象的线

如何用R标记散点图上的点?

散点图上的颜色线 - R [重复]