【问题标题】:How to create a corresponding and merged legend in ggplot?如何在ggplot中创建对应并合并的图例?
【发布时间】:2026-02-15 00:15:01
【问题描述】:

我用ggplot 创建了这个散点图,正如你所见,我没有设法为该图创建相应的图例:

  • 正方形应为深灰色,其文本应为“Méthode par transects”
  • 三角形应为浅灰色,其文本应为“Methode par sous-transects”。

如果可能的话,我也希望将虚线“Seuil”的图例靠近这些点。

这是我的代码:

ggplot(tst_formule, aes(x=nom_graph, y = value, shape = BRI_type, col = factor(BRI_type))) + 
  geom_point(size = 4) + 
  scale_shape_manual("", values = c( 15, 17)) +
  scale_colour_manual(values=c("grey20", "gray54"),  # légende
                      name  ="Légende",
                      breaks=c("BRI_adi_moy_guide", "BRI_adi_moy_Sandrine"),
                      labels=c("Méthode par transects", "Méthode par sous-transects")) +
  geom_text(aes(label = value, vjust = -0.5, hjust= -0.1), show.legend = FALSE) + # etiquettes
  geom_hline(aes(yintercept = 0.004, linetype = "Seuil"), colour= 'black') + 
  scale_linetype_manual("", values = c(2),  guide = guide_legend(override.aes = list(color = c("black")))) + 
  scale_x_discrete("\nTronçons\n") + 
  scale_y_continuous("\nValeur du BRI*\n", limits = c(0,0.025)) + 
  theme(axis.text.x = element_text(size = 11),
        axis.text.y = element_text(size = 11),
        legend.text = element_text(size = 11),
        plot.margin = unit(c(0.2,0.2,0.2,0.2), "cm"))

我阅读了几篇文章并尝试了不同的解决方案,但它不起作用,我还是 ggplot 的新手,我认为我的语法可能与图例不符......

这是我的数据的dput()

structure(list(Riviere = c("Durance", "Durance", "Roya", "Drac", 
"Drac", "Durance", "Durance", "Roya", "Drac", "Drac"), Troncon = c("La Brillanne", 
"Les Mées", "Basse vallée", "St Bonnet", "St Bonnet", "La Brillanne", 
"Les Mées", "Basse vallée", "St Bonnet", "St Bonnet"), Annee = c(2017, 
2017, 2018, 2011, 2018, 2017, 2017, 2018, 2011, 2018), nom_graph = c("La Brillane 2017 \nDurance", 
"Les Mées 2017 \nDurance", "Roya 2018", "St Bonnet 2011 \nDrac", 
"St Bonnet 2018 \nDrac", "La Brillane 2017 \nDurance", "Les Mées 2017 \nDurance", 
"Roya 2018", "St Bonnet 2011 \nDrac", "St Bonnet 2018 \nDrac"
), BRI_type = c("BRI_adi_moy_Sandrine", "BRI_adi_moy_Sandrine", 
"BRI_adi_moy_Sandrine", "BRI_adi_moy_Sandrine", "BRI_adi_moy_Sandrine", 
"BRI_adi_moy_guide", "BRI_adi_moy_guide", "BRI_adi_moy_guide", 
"BRI_adi_moy_guide", "BRI_adi_moy_guide"), value = c(0.0037, 
0.0024, 0.0013, 0.0239, 0.0038, 0.0028, 0.0017, 0.0009, 0.02, 
0.0031)), row.names = c(NA, -10L), class = "data.frame")

欢迎任何帮助!

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    首先:非常感谢您通过dput 发布您的数据集。这真的有助于回答您的问题,非常感谢。

    基本思想是让ggplot 创建和组合图例,它试图智能地做到这一点。首先,要创建图例,您将参数放入美学 (aes()) 中,您已经完成了。在您的情况下,您希望结合 shape=color= 美学。

    首先,确保他们指向正确的东西。在您的情况下,引用不一样(shape= BRI_type,而color= factor(BRI_type)),但对于ggplot,这是一回事。字符向量tst_formule$BRI_type 将在创建绘图期间转换为一个因子,以便根据该因子的级别分隔shape=。最重要的是,您可以删除 factor(BRI_type) 并使用 BRI_type;但是,最终结果是一样的。这只是更好的做法。

    还记得我提到ggplot 尝试自动组合图例吗?好吧,由于color=shape= 指向相同的因子(BRI_type,它在绘图之前得到因子),默认情况下,您将获得一个组合图例。您可以通过从原始代码中删除 scale_color_manualscale_shape_manual 来亲自查看:

    ggplot(tst_formule, aes(x=nom_graph, y = value, shape = BRI_type, col = BRI_type)) + 
      geom_point(size = 4) + 
      geom_text(aes(label = value, vjust = -0.5, hjust= -0.1), show.legend = FALSE) + # etiquettes
      geom_hline(aes(yintercept = 0.004, linetype = "Seuil"), colour= 'black') + 
      scale_linetype_manual("", values = c(2),  guide = guide_legend(override.aes = list(color = c("black")))) + 
      scale_x_discrete("\nTronçons\n") + 
      scale_y_continuous("\nValeur du BRI*\n", limits = c(0,0.025)) + 
      theme(axis.text.x = element_text(size = 11),
            axis.text.y = element_text(size = 11),
            legend.text = element_text(size = 11),
            plot.margin = unit(c(0.2,0.2,0.2,0.2), "cm"))
    

    一般规则是为了保留图例组合,如果您更改一个图例的一个方面,您必须同时对另一个图例进行相同的更改。这个概念is demonstrated well in this post。所以在解决方案中,我将同时更改两个图例。

    此外,您会看到我已完成以下操作以调整图例的间距:

    • 更改了 scale_shape_scale_color_ 调用以对 name=labels= 使用相同的参数。两者的 values= 参数都会发送一个 list 项目,其中包含来自您的数据的同名 labels,但具有不同的值。请注意,如果您更改其中任何一个参数,您将获得两个图例,因此同时更改所有参数非常重要。

    • legend.spacing.y用于调整shape/colorlinetype图例之间的间距

    • legend.margin 用于设置每个图例周围的边距(允许它们靠近而不剪裁)。

    • legend.title 缩小间距的结果是标题在键附近被“压扁”。我为她添加了一个边距,以确保图例标题和键之间有空格。

    • 我将linetype 图例的name= 设置为NULL,而不是""。如果你使用"",它是空白的,但它仍然是一个字符,所以仍然占用空间。这意味着当您将图例向上移动时,您会开始使用上方的图例剪切 ""。最好将其设置为 NULL 将其完全删除。

    这是代码和结果图:

    ggplot(tst_formule, aes(x=nom_graph, y = value, shape = BRI_type, col = BRI_type)) + 
      geom_point(size = 4) + 
      scale_shape_manual(
        values=list("BRI_adi_moy_guide"=15, "BRI_adi_moy_Sandrine"=17),
        name  ="Légende",
        labels=c("Méthode par transects", "Méthode par sous-transects")) +
      scale_colour_manual(
        values=list("BRI_adi_moy_guide"="grey20", "BRI_adi_moy_Sandrine"="gray54"),
        name  ="Légende",
        labels=c("Méthode par transects", "Méthode par sous-transects")) +
      geom_text(aes(label = value, vjust = -0.5, hjust= -0.1), show.legend = FALSE) + # etiquettes
      geom_hline(aes(yintercept = 0.004, linetype = "Seuil"), colour= 'black') + 
      scale_linetype_manual(
        name=NULL, values = c(2),
        guide = guide_legend(override.aes = list(color = c("black")))) + 
      scale_x_discrete("\nTronçons\n") + 
      scale_y_continuous("\nValeur du BRI*\n", limits = c(0,0.025)) + 
      theme(axis.text.x = element_text(size = 11),
            axis.text.y = element_text(size = 11),
            legend.text = element_text(size = 11),
            plot.margin = unit(c(0.2,0.2,0.2,0.2), "cm"),
            legend.spacing.y = unit(0.1, 'cm'),
            legend.margin = margin(0,0,0,0, 'pt'),
            legend.title = element_text(margin=margin(0,0,0.1,0, 'cm'))
      )
    

    【讨论】: