【问题标题】:How to fill the area under/above the curve with different colors above and below 0?如何用0上下不同的颜色填充曲线下方/上方的区域?
【发布时间】:2021-06-23 12:17:16
【问题描述】:

我想绘制标准化降水指数 (SPI) 的时间序列。通常这看起来有点像这样:

您可以看到曲线下方/上方的区域以蓝色/红色着色。这也是我想绘制的。

我知道有类似的问题,比如thisthat 一个。这可能会更进一步,但不幸的是还没有达到最终结果。

为了便于理解,这里有一些代码供大家复现:

library(data.table)
library(ggplot2)

vec1 <- 1:310
vec2 <- c(1.78, 1.88,  1.10,  0.42,  0.73,  1.35,  1.34,  0.54,  0.20,  0.72,  1.29,  1.78,  1.30,  1.37, -0.13,  0.64, -0.13,  0.87,  0.47, -0.26, -0.27,
          -0.81, -0.54, -0.77, -0.29, -0.22, -0.05,  0.41,  0.45,  0.91, -0.31,  0.67,  0.28,  0.93,  0.43, -0.04, -0.80, -1.20, -0.73, -0.98,  0.47, -0.01,
          1.30,  1.45,  0.72, -0.59, -1.14, -0.33,  0.22,  0.49,  0.58,  0.36,  0.66,  0.64,  0.47, -0.60,  1.01,  1.50,  1.18,  0.82,  0.02,  0.57,  0.25, 
          1.20,  1.19,  0.71, -0.30, -1.37, -1.50, -1.03, -0.77, -1.08, -1.92, -2.32, -2.46, -1.61, -0.39,  0.67,  0.38,  0.62, -0.34,  0.01, -0.55, -0.74,
          -1.95, -1.18, -0.96,  0.36, -0.96, -1.28, -2.29, -2.67, -0.65, -0.13,  0.61,  0.21,  0.57,  0.11,  0.37,  0.20, -0.14, -0.87, -0.84,  0.87,  1.33,
          0.45, -0.76, -1.27, -0.65, -0.29,  0.54,  0.14, -0.55, -0.94, -0.98, -0.44, -0.37,  0.72,  0.70,  0.95,  0.89,  1.10,  1.51,  1.11,  1.77,  1.20,
          1.23, -0.72, -1.43, -2.11, -1.37, -0.80, -0.34, -0.14,  0.22, -0.65, -0.44, -0.86, -0.46, -0.67, -0.91, -0.40, -0.09,  0.22,  0.96,  0.71,  0.51,
          -1.61, -1.62, -1.43, -0.27,  1.08,  1.76,  1.30,  0.78,  1.02,  1.01,  0.56, -0.32,  0.37,  0.31,  1.36,  1.49,  1.42,  0.78, -0.19,  0.64,  0.39,
          0.47, -1.13, -1.45, -0.52,  0.43, -0.19, -0.97, -0.27,  0.63,  1.01,  1.01,  0.83, -0.56, -1.71, -0.29,  1.06,  1.82,  1.28,  0.88,  1.08,  1.78,
          1.47,  0.74, -0.34,  0.14,  1.09,  1.49,  1.30,  0.28, -0.25,  0.24, -0.33,  0.05, -0.86, -0.69, -1.03, -0.59,  0.32,  0.61,  0.84, -0.18, -0.67,
          0.46,  0.31, -0.72, -2.26, -2.85, -0.69, -0.77,  0.64, -1.49, -1.69, -1.55, -0.28, -0.80, -1.15, -0.38,  0.31,  0.18, -0.27, -0.84, -0.94, -1.23,
          -0.53, -1.52, -0.73, -0.93,  0.25, -0.11,  0.38,  0.48,  0.10, -0.02,  0.26,  1.39,  1.61,  0.83,  0.09,  0.95,  1.07,  0.77,  0.23,  0.26,  0.85,
          0.93,  0.91,  1.10,  0.47,  0.74,  1.42,  1.17,  0.32, -0.40,  0.76,  1.44,  1.69,  1.03,  0.01,  0.46,  0.61,  0.60, -0.09, -0.31, -0.96, -0.91,
          -0.06,  0.75,  1.32,  1.29,  0.55,  0.43, -1.25,  0.12, -0.05,  0.18, -0.77, -2.19, -1.85, -2.12, -1.51, -1.14, -0.79, -0.82, -1.13, -1.72, -2.14,
          -1.95, -0.63,  0.70,  0.64,  0.17, -1.04, -0.58, -0.57, -0.57, -1.05, -1.11, -0.59, -0.07,  1.22,  0.30, -0.15)

df <- data.frame(vec1, vec2)
colnames(df) <- c("ID", "SPI")

df = as.data.table(df)

你有整个 SPI 时间序列,1980 年到 2005 年之间的每个月都有一个值。

到目前为止,我得出了这个结果:

ggplot(data = df, aes(x = ID, y = SPI)) +
  geom_col(data = df[SPI <= 0], fill = "red") +
  geom_col(data = df[SPI >= 0], fill = "blue") +
  theme_bw()

当您运行代码时,您将看到以下图表:

这是朝着正确的方向发展,但前半部分数值之间的白色小差距令人不安,不应该存在。所以肯定有问题。

它应该看起来像这样,只是用蓝色和红色两种颜色表示正值和负值:

ggplot(data = df, aes(x = ID, y = SPI)) +
  geom_area() +
  theme_bw()

代码导致此图像:

您可以看到单个值之间没有空白,我完全不知道是什么导致了这些错误。

有人知道如何解决这个问题吗?

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    OP,您正在观察的是与图形驱动程序的分辨率和列之间的空间相关的工件。您显示的区域由 x 轴上彼此相邻的许多填充列组成。您没有为geom_col() 指定width= 参数,因此默认值在x 轴上的各个值之间留有空格。如果我们仅沿 x 轴获取您的数据的一部分,最好说明一下:

    ggplot(data = df, aes(x = ID, y = SPI)) +
      geom_col(data = df[SPI <= 0], fill = "red") +
      geom_col(data = df[SPI >= 0], fill = "blue") +
      theme_bw() +
      xlim(0,100)  # just the first part on the left
    

    这是你的白线 - 它是列之间的空间。当您有较大的图片时,白线的外观与图形设备的分辨率有关。如果您使用dpi= 的不同参数将图形保存为ggsave(),则可以对此进行测试。例如,在我的电脑上保存ggsave('filename.png', dpi=72) 不会显示任何线条,但ggsave('filename.png', dpi=600) 会在某些地方显示白线。

    对此有一个简单的解决方案,即指定 geom_col()width= 参数为 1。默认情况下,它设置为 0.75 或 0.8(不完全确定),这会在下一个值(填充〜75或80%的空间)。如果将此设置为 1,它将填充为该列分配的 100% 的空间,中间不留空白:

    ggplot(data = df, aes(x = ID, y = SPI)) +
      geom_col(data = df[SPI <= 0], fill = "red", width=1) +
      geom_col(data = df[SPI >= 0], fill = "blue", width=1) +
      theme_bw() +
      xlim(0,100)
    

    【讨论】:

    • 非常感谢您的快速回答。现在结果看起来非常好,几乎正是我想要的!我现在应用了这段代码:ggplot(data = df, aes(x = ID, y = SPI)) + geom_col(data = df[SPI = 0], fill = "blue", width=1) + theme_bw() 现在唯一剩下的就是相比第一张和第三张图我有点太像单列了如上所示。有没有办法改变它,让它更流畅?
    • 您必须使用geom_area 对其进行建模,然后根据y 轴的值应用不同的fill 美学。它不会像看起来那么简单,因为每当符号改变时并不总是有一个 y=0 点。您还可以通过在数据集中的每个点之间插入值来“伪造”它。您甚至可以这样做几次以使它们之间的路径更平滑,然后仍然使用 geom_col() 对数据进行建模。
    • 说实话,这听起来很复杂,目前我不知道该怎么做。
    【解决方案2】:

    如果更改列之间的距离会怎样? 刚刚在ggplot的“aes”中添加了“width=1”。

    ggplot(data = df, aes(x = ID, y = SPI, width=1)) +
      geom_col(data = df[SPI <= 0], fill = "red") +
      geom_col(data = df[SPI >= 0], fill = "blue") +
      theme_bw()
    

    我明白了:

    image.result

    【讨论】:

    • 感谢您的提示。它基本上导致与 chemdork123 的答案相同的结果。这样代码会短一些。
    猜你喜欢
    • 1970-01-01
    • 2019-08-14
    • 2016-12-28
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    • 2021-12-08
    相关资源
    最近更新 更多