ggplot:如何在三个不同的 geom_line() 下应用 geom_area() 或类似的填充区域而不重叠每个独立填充?

ggplot: How to apply geom_area() or similar to fill area under three distinct geom_line() without overlapping each indepedent fill?

我有一个基于我的数据 nd 的图表,其中三个 geom_line() 证明了 1 年后死亡的概率:nd$y_et,3 年后:nd$y_tre 和 5 年:nd$y_fem,分别作为切除淋巴结数量的函数 nd$n_fjernet

问题:如何填充nd$y_et, y_tre, y_fem的三个geom_line()下面的每个区域,而不重叠后面的geom_line + fill?

我尝试了 geom_areageom_polygon 但没有接近正确的解决方案。

当前剧情

ggplot(nd, aes(x=n_fjernet))  +
         geom_line(aes(y=y_et)) + 
         geom_line(aes(y=y_tre)) + 
         geom_line(aes(y=y_fem)) +    scale_x_continuous(breaks = seq(0,25,5), limits=c(0,25))

应该给出预期的输出:

更新

我应用了下面提供的解决方案,得到了

ndd %>% 
  rename(X3=y_et, X2=y_tre, X1=y_fem) %>% 
  pivot_longer(values_to="N", names_to="Variable", cols=c(X1:X3)) %>%
  ggplot(aes(x=n_fjernet, y=N, fill=Variable, colour=Variable)) +
  geom_area(position=position_identity(), alpha=.15) +
  geom_line(size=3, color="white") +
  geom_line(size=.75) +
  scale_fill_manual(values=c("#2C77BF", "#E38072", "#6DBCC3")) +
  scale_colour_manual(values=c("#2C77BF", "#E38072", "#6DBCC3")) +
  scale_x_continuous(breaks = seq(0,10,5), limits=c(0,10))

随着我们越来越接近预期的情节,不幸的是仍然有重叠 fills。在red-fill后面可以看到blue-fillblue-fillred-fill 都在 green-fill 后面。

问题:如何在不重叠的情况下包含fills

我的数据nd

    nd <- structure(list(y_et = c(0.473, 0.473, 0.472, 0.471, 0.471, 0.47, 
0.47, 0.469, 0.468, 0.468, 0.467, 0.467, 0.466, 0.465, 0.465, 
0.464, 0.464, 0.463, 0.462, 0.462, 0.461, 0.461, 0.46, 0.459, 
0.459, 0.458, 0.458, 0.457, 0.456, 0.456, 0.455, 0.455, 0.454, 
0.453, 0.453, 0.452, 0.452, 0.451, 0.45, 0.45, 0.449, 0.449, 
0.448, 0.447, 0.447, 0.446, 0.446, 0.445, 0.445, 0.444, 0.443, 
0.443, 0.442, 0.442, 0.441, 0.44, 0.44, 0.439, 0.439, 0.438, 
0.438, 0.437, 0.436, 0.436, 0.435, 0.435, 0.434, 0.433, 0.433, 
0.432, 0.432, 0.431, 0.431, 0.43, 0.429, 0.429, 0.428, 0.428, 
0.427, 0.427, 0.426, 0.425, 0.425, 0.424, 0.424, 0.423, 0.423, 
0.422, 0.421, 0.421, 0.42, 0.42, 0.419, 0.419, 0.418, 0.417, 
0.417, 0.416, 0.416, 0.415), y_tre = c(0.895, 0.894, 0.894, 0.893, 
0.893, 0.893, 0.892, 0.892, 0.891, 0.891, 0.89, 0.89, 0.889, 
0.889, 0.889, 0.888, 0.888, 0.887, 0.887, 0.886, 0.886, 0.886, 
0.885, 0.885, 0.884, 0.884, 0.883, 0.883, 0.882, 0.882, 0.881, 
0.881, 0.881, 0.88, 0.88, 0.879, 0.879, 0.878, 0.878, 0.877, 
0.877, 0.876, 0.876, 0.875, 0.875, 0.875, 0.874, 0.874, 0.873, 
0.873, 0.872, 0.872, 0.871, 0.871, 0.87, 0.87, 0.869, 0.869, 
0.868, 0.868, 0.867, 0.867, 0.866, 0.866, 0.865, 0.865, 0.865, 
0.864, 0.864, 0.863, 0.863, 0.862, 0.862, 0.861, 0.861, 0.86, 
0.86, 0.859, 0.859, 0.858, 0.858, 0.857, 0.857, 0.856, 0.856, 
0.855, 0.855, 0.854, 0.854, 0.853, 0.853, 0.852, 0.852, 0.851, 
0.851, 0.85, 0.85, 0.849, 0.848, 0.848), y_fem = c(0.974, 0.974, 
0.973, 0.973, 0.973, 0.973, 0.973, 0.973, 0.972, 0.972, 0.972, 
0.972, 0.972, 0.971, 0.971, 0.971, 0.971, 0.971, 0.971, 0.97, 
0.97, 0.97, 0.97, 0.97, 0.969, 0.969, 0.969, 0.969, 0.969, 0.968, 
0.968, 0.968, 0.968, 0.968, 0.967, 0.967, 0.967, 0.967, 0.967, 
0.966, 0.966, 0.966, 0.966, 0.966, 0.965, 0.965, 0.965, 0.965, 
0.965, 0.964, 0.964, 0.964, 0.964, 0.963, 0.963, 0.963, 0.963, 
0.963, 0.962, 0.962, 0.962, 0.962, 0.961, 0.961, 0.961, 0.961, 
0.961, 0.96, 0.96, 0.96, 0.96, 0.959, 0.959, 0.959, 0.959, 0.958, 
0.958, 0.958, 0.958, 0.957, 0.957, 0.957, 0.957, 0.957, 0.956, 
0.956, 0.956, 0.956, 0.955, 0.955, 0.955, 0.955, 0.954, 0.954, 
0.954, 0.954, 0.953, 0.953, 0.953, 0.952), n_fjernet = c(0, 0.1, 
0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 
1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 
2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 
4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 
5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 
6.7, 6.8, 6.9, 7, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 
8, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 8.8, 8.9, 9, 9.1, 9.2, 
9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9)), row.names = c(NA, -100L), class = c("data.table", 
"data.frame"))
nd %>% 
  pivot_longer(values_to="N", names_to="Variable", cols=c(y_fem:y_et)) %>% 
  ggplot(aes(x=n_fjernet, y=N, fill=Variable)) + geom_area()

给予

这只是在 objective 的上下文中制作数据 tidy 的问题。在这里,您的数据不整齐,因为您的列名包含信息。

回应 OP 在下方的评论...

啊!这让事情变得有点棘手。一个geom_area中默认的positionstack,也就是说每个有颜色的区域的高度就是对应变量的高度(而栈的总高度就是个别值 - 例如,在 n_fjernet = 0, you havey_fem = 0.981,y_tre = 0.9199andy_et = 0.514 , giving a total stack height of about2.5`。查看您的原始图表,您想以其原始值绘制每条线,并填充它与下一个 lowext 伴侣之间的间隙,对吗?

原则上,这很容易。您可以在 geom_area() 中设置 position=position_identity()。但如果这将按照您希望的方式工作,您需要手动跟踪变量值的顺序。例如,根据您的数据,我们得到:

nd %>% 
  pivot_longer(values_to="N", names_to="Variable", cols=c(y_fem:y_et)) %>% 
  ggplot(aes(x=n_fjernet, y=N, fill=Variable)) + 
  geom_area(position=position_identity())

完全不是你想要的。

在这个特定实例中,获得正确结果的一种非常古怪的方法是

nd %>% 
  rename(X3=y_et, X2=y_tre, X1=y_fem) %>% 
  pivot_longer(values_to="N", names_to="Variable", cols=c(X1:X3)) %>% 
  ggplot(aes(x=n_fjernet, y=N, fill=Variable)) +   
  geom_area(position=position_identity())

您还可以通过自定义用于创建填充的比例来控制绘制区域的顺序,如 here 所述。

另一种选择是使用 geom_ribbon 而不是 geom_area。但是无论您使用哪种方法,如果不手动控制创建填充的顺序,我都不知道如何做到这一点。这似乎是想要在绝对位置绘制值并填充下方区域的必然结果。我能想到的唯一可能性是为每个填充设置一个小于 1 的 alpha 值。但是,就我个人而言,我认为这看起来很难看:

nd %>% 
  pivot_longer(values_to="N", names_to="Variable", cols=c(y_fem:y_et)) %>% 
  ggplot(aes(x=n_fjernet, y=N, fill=Variable)) + 
  geom_area(position=position_identity(), alpha=0.4)

如果变量的顺序在您沿 x 轴移动时发生变化,您会怎么做?就个人而言,我会放弃填充,只使用不同颜色的线条。但这是你的决定。

如果有人有更好的选择,我很想看看。

* 编辑 2 * 回答 OP 关于手动控制颜色的问题:

nd %>% 
  rename(X3=y_et, X2=y_tre, X1=y_fem) %>% 
  pivot_longer(values_to="N", names_to="Variable", cols=c(X1:X3)) %>% 
  ggplot(aes(x=n_fjernet, y=N, fill=Variable, colour=Variable)) + 
  geom_area(position=position_identity()) +
  geom_line() +
  scale_fill_manual(values=c("pink", "darkseagreen2", "steelblue2")) +
  scale_colour_manual(values=c("red", "green4", "blue"))

给我

据我所知,我的代码与您的代码非常相似,所以我不确定为什么它对我有用而不对您有用。 [你记得把colour=Variable放在aes()里面吗?]

我的颜色来自 here

您在评论中提到了 geom_point。是打错了吗?

顺便说一句,我们不需要全部 200 个数据点来解决这个问题。半打就足够了。最多十几个。也许下次……;)