r - ¿Cómo rellenar el área debajo/arriba de la curva con diferentes colores por encima y por debajo de 0?

CorePress2024-01-24  13

Me gustaría trazar una serie temporal del Índice de Precipitación Estandarizada (SPI). Normalmente esto se parece a esto:

Puedes ver que el área debajo/arriba de la curva está coloreada en azul/rojo. Esto es lo que me gustaría trazar también.

Sé que hubo preguntas similares, como ésta y aquella. Esto podría ir un poco más allá, pero lamentablemente aún no hasta el resultado final.

Para que sea más fácil de entender, aquí tienes un código para que todo el mundo pueda reproducirlo:

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)

Ahí tienes la serie temporal completa del SPI, un valor para cada mes entre 1980 y 2005.

Hasta ahora llegué a ese resultado:

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()

Cuando ejecutes el código verás el siguiente gráfico:

Esto va en la dirección correcta, pero el pequeñoLas brechas blancas entre los valores en la primera mitad son inquietantes y no se supone que estén ahí. Entonces debe haber algo mal.

Se supone que debe verse así, solo con los dos colores azul y rojo para los valores positivos y negativos:

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

El código conduce a esta imagen:

Puedes ver que no hay espacios en blanco entre los valores individuales y no tengo la menor idea de qué conduce a estos errores.

¿Alguien tiene una idea de cómo solucionarlo?



------------------------------------

OP, lo que estás observando son los artefactos relacionados con la resolución de tu controlador de gráficos y el espacio entre columnas. Las áreas que muestrasse componen de muchas columnas llenas una al lado de la otra en el eje x. No especifica el argumento width= para geom_col(), por lo que el valor predeterminado deja un espacio entre los valores individuales en el eje x. Es mejor ilustrarlo si tomamos solo una sección de sus datos a lo largo del eje 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

Están las líneas blancas: es el espacio entre las columnas. Cuando tienes la imagen más grande, la apariencia de las líneas blancas tiene que ver con la resolución de tu dispositivo gráfico. Puedes probar esto si guardas tu gráfico con ggsave() usando diferentes parámetros para dpi=. Por ejemplo, en mi computadora, al guardar ggsave('filename.png', dpi=72) no aparecen líneas, pero ggsave('filename.png', dpi=600) muestra líneas blancas en algunos lugares.

Sin embargo, hay una solución fácil para esto, queh es para especificar que el argumento width= de geom_col() sea 1. De forma predeterminada, está establecido en 0,75 o 0,8 (no estoy exactamente seguro), lo que deja un espacio entre el siguiente valor (llena ~75 u 80% del espacio) . Si lo establece en 1, llena el 100% del espacio asignado para esa columna, sin dejar espacios en blanco en el medio:

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)

3

Muchas gracias por la respuesta tan rápida. Ahora el resultado se ve muy bien, ¡casi exactamente lo que quería! Apliqué este código ahora: ggplot(data = df, aes(x = ID, y = SPI)) + geom_col(data = df[SPI <=0], fill = "red", ancho=1) + geom_col(data = df[SPI >= 0], fill = "blue", ancho=1) + theme_bw() Lo único que queda ahora es que se parece demasiado a columnas individuales en comparación con la primera y tercera imagen que mostré arriba. ¿Hay alguna manera de cambiar eso, de hacerlo un poco más fluido?

- Climsaver

26/03/2021 a las 16:57

Tendrías que modelarlo con geom_area y luego aplicar una estética de relleno diferente según el valor del eje y.No será tan sencillo como parece, ya que no siempre hay un punto y=0 cada vez que cambia el signo. También puedes "falsificar" un poco interpolando el valor entre cada uno de los puntos de su conjunto de datos. Incluso puedes hacerlo varias veces para suavizar el camino entre ellos y luego seguir modelando los datos usando geom_col().

- chemdork123

26/03/2021 a las 18:31

Para ser honesto, eso suena bastante complicado y en este momento no tendría idea de cómo hacerlo.eso.

- Climsaver

29 de marzo de 2021 a las 7:58



------------------------------------

¿Qué pasa si cambias la distancia entre columnas? Acabo de agregar "ancho=1" dentro de "aes" de ggplot.

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()

Entiendo esto:

imagen.resultado

Compartir mejorar esta respuesta Seguir respondió

26/03/2021 a las 17:03

Nikolas Schiozer

Nikolas Schiozer

19

1

1 insignia de bronce

1

Gracias por esa pista. Básicamente conduce al mismo resultado que la respuesta de chemdork123. El Código es un poco más corto de esta manera.

- Climsaver

29 de marzo de 2021 a las 7:57

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare