【问题标题】:Is there a way in R's ggplot2 to incorporate the stat summary argument into the legend with geom_line?在 R 的 ggplot2 中有没有办法将统计摘要参数合并到带有 geom_line 的图例中?
【发布时间】:2021-03-21 15:57:29
【问题描述】:

我有一个数据集,其中包含 2008 年至 2017 年每年每个州的 SUD 治疗率。两个州接受了干预,其余的没有。我可以将每种干预状态的治疗率绘制为单独的线,并将非干预状态(使用平均值分组为一条线)绘制在同一张图上。

我想在图例中包含分组的行,但在这样做时遇到了麻烦。到目前为止,只有干预状态被标记。我粘贴了数据的子集(不完全是绘图显示的内容,但提供了对结构的洞察),并为 ggplot 代码提供了结果图。任何帮助,将不胜感激。谢谢!

structure(list(statename = c("Alabama", "Alabama", "Alabama", 
"Alabama", "Alabama", "Alabama", "Alabama", "Alabama", "Alabama", 
"Alabama", "Colorado", "Colorado", "Colorado", "Colorado", "Colorado", 
"Colorado", "Colorado", "Colorado", "Colorado", "Colorado", "Iowa", 
"Iowa", "Iowa", "Iowa", "Iowa", "Iowa", "Iowa", "Iowa", "Iowa", 
"Iowa", "Washington", "Washington", "Washington", "Washington", 
"Washington", "Washington", "Washington", "Washington", "Washington", 
"Washington"), YEAR = c(2008L, 2009L, 2010L, 2011L, 2012L, 2013L, 
2014L, 2015L, 2016L, 2017L, 2008L, 2009L, 2010L, 2011L, 2012L, 
2013L, 2014L, 2015L, 2016L, 2017L, 2008L, 2009L, 2010L, 2011L, 
2012L, 2013L, 2014L, 2015L, 2016L, 2017L, 2008L, 2009L, 2010L, 
2011L, 2012L, 2013L, 2014L, 2015L, 2016L, 2017L), RML_ever_state = c(0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 
1L, 1L, 1L, 1L, 1L, 1L, 1L), TotalAdolescent_noprior_Admissionrate = c(4.07959747971533, 
17.1095315089946, 28.605586683907, 11.488423601983, 14.9233623164375, 
13.0325736612464, 11.5686458431041, 15.2887154594351, 18.9275946907701, 
17.9164783752891, 28.9653195613967, 30.542173819128, 33.8611241088185, 
29.9657748758525, 25.214146698236, 22.847991066509, 21.975843495247, 
21.783383749025, 25.8868468603421, 23.6029880132029, 45.9863203727017, 
51.6710909784629, 61.713238062499, 48.3292305542656, 52.4339028740025, 
54.9353761700907, 50.2282357945714, 46.8358255273624, 63.8611763171622, 
63.7710085311979, 50.5294974023959, 53.0407358054702, 54.7486826331652, 
59.981622172154, 57.2193036593259, 54.5478493207391, 49.924220486418, 
41.9396870928129, 11.3163228651143, 0.258492875751707)), row.names = c(1L, 
2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 31L, 32L, 33L, 34L, 35L, 
36L, 37L, 38L, 39L, 40L, 117L, 118L, 119L, 120L, 121L, 122L, 
123L, 124L, 125L, 126L, 387L, 388L, 389L, 390L, 391L, 392L, 393L, 
394L, 395L, 396L), class = "data.frame")
ggplot(vars1, aes(x = YEAR, y = TotalAdolescent_noprior_Admissionrate, group = statename))  +
  stat_summary(
    data = ~ subset(., RML_ever_state == 0),
    aes(group = -1),
    fun.data = mean_se,
    geom = "line", size = 3, colour = "green"
  ) +
  geom_line(
    data = ~ subset(., RML_ever_state == 1),
    aes(colour = statename)
  )   + scale_x_discrete( limits=c(2008,2009,2010,2011,2012,2013,2014,2015,2016,2017))

【问题讨论】:

  • 由于图例显示state,一个想法是将非干预状态的摘要视为一个单独的状态(也许此时将列称为不同的),那么您将拥有所有 50 个州 + 不干预摘要;这会将它包含在同一个图例中。
  • 另外,最好提供一个可重现的小例子(你在这里很接近它)。您可以创建一个最小数据集并使用dput(vars1)vars1 的输出剪切/粘贴到帖子中。人们将能够通过剪切和粘贴进行复制。您可能会在几分钟内得到答案,而不是完全没有或几小时/几天。但是,我上面提供的链接可能会回答您的问题。
  • 这会帮助别人帮助你。我不知道如何使用您的方法来解决此问题,我通常通过创建一个包含原始数据和摘要数据之类的新列并拥有一个新因素来解决这个问题。所有项目都以图例结尾,但标题不同,因为我将汇总数据与非汇总数据包括在内。我并不是说这是最好的方法,只是我所做的那样查看数据。
  • 谢谢。我对 R 很陌生,并且导航 ggplot 比我想象的要复杂。我感谢您的帮助。感谢您,我了解了 dput()。
  • 我找到了一个带注释的手动解决方案,通过在ggplot末尾添加以下内容,我可以控制放置标签的位置。不是最好的解决方案,但可以解决 + annotate('text', x=2016, y=15, label = "Non-RML \n state")

标签: r ggplot2


【解决方案1】:

通过了解ggplot2 如何创建图例,可以实现一个很好的解决方案。我们将利用这一点来迫使stat_summary() 中的一个图例。在这里,我们将有效地“劫持”另一种美学,然后将这些传说挤在一起,让它看起来像是一个传说。

有两点可以帮助解释为什么最终答案有效。

传奇内创aes()

首先,ggplot2 将为在aes() 内需要区分的任何内容创建一个图例。因此,如果您在aes() 中拥有colorfillsize 之类的审美,您将开始让ggplot2 成为传奇的过程。当您aes()之外定义美学时,此过程将被覆盖。

所以这段代码生成了一个图例:

ggplot(df, aes(x,y)) + geom_point(aes(size=my_category))

但是这个没有:

ggplot(df, aes(x,y)) + geom_point(aes(size=my_category), size=3)

因此,这意味着如果您想在上面的第一个示例中定义大小,则必须采用默认的 ggplot2 或通过添加 scale_size_manual() 命令来指定实际大小:

ggplot(df, aes(x,y)) + geom_point(aes(size=my_category)) + scale_size_manual(values=3)

aes() 中引用的内容与列名

您还可以通过发送到aes() 的内容来控制图例中项目的名称。以上面的例子为例。如果我输入aes(size=my_category),则假定df 中有一个名为my_category 的列,其中包含值。如果该列是一个因子,则因子的水平将用作图例项目名称和最终图中的特定“大小”值。如果该列是字符向量,则将通过将列“强制”为一个因子来创建图例,然后将按字母数字列出项目。如果df$my_category 是一个数字向量,您将获得一个连续的大小比例。当您提供一个字符/字符串时,游戏会发生一些变化。假设df$my_category 是一个字符向量。当我发送它时:

ggplot(df, aes(x,y)) + geom_point(aes(size="my_category")...)

我将得到相同大小的所有内容,以及带有一个名为“my_category”的项目的图例。有趣的。基本上,您将在第二个示例中提供列的全部内容,其中每个项目都标记为“my_category”。有道理?我们可以将这个逻辑组合在一起形成您的解决方案。

您的问题的解决方案

现在,我将使用这些信息来创建您的情节。要将stat_summary() 分离为传奇项目,我需要选择一种美学。您可以只需指定color= 位于aes() 中,用于stat_summary,并使用一个字符来正确标记它。那可行;但是,如果您这样做,所有图例键(称为“字形”)将与 stat_summary 中的行看起来相同。如果所有行看起来都一样,那很好,但是您的摘要行“更胖”,因此您希望它与其他行不同。

在这里,我将使用size 创建一个图例,这将是与geom_line() 使用的color 不同的图例,它们可以有不同的格式而不会出现任何问题。

由于我将size 拉入aes() 以获取stat_summary,因此我需要在stat_summary 中删除aes()size outside,并将该值放入单独的scale_size_manual() 命令。其次,我使用guides() 来控制图例和一些标题的顺序。最后,我使用theme 元素来控制两个图例之间的间距,以将它们推得更近一些。最终结果:

ggplot(vars1, aes(x = YEAR, y = TotalAdolescent_noprior_Admissionrate, group = statename))  +
  stat_summary(
    data = ~ subset(., RML_ever_state == 0),
    aes(group = -1, size='Summary'),
    fun.data = mean_se,
    geom = "line", colour = "green"
  ) +
  geom_line(
    data = ~ subset(., RML_ever_state == 1),
    aes(colour = statename)
  )   +
  scale_x_discrete( limits=c(2008,2009,2010,2011,2012,2013,2014,2015,2016,2017)) +
  scale_size_manual(values=3) +
  guides(
    color=guide_legend(title='Legend', order=1),
    size=guide_legend(title=NULL, order=2)
  ) +
  theme(
    legend.margin = margin(t=0,b=0),
    legend.spacing.y = unit(0,'pt'),
    legend.title = element_text(margin=margin(b=10))
  )

【讨论】:

  • 难以置信!!非常感谢 chemdork123 。这是超越的。我希望这对以后的其他人有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-02
相关资源
最近更新 更多