I have cyclic data that I am trying to plot a mean overlaid on a standard deviation band. Using geom_ribbon()
has the same issue as geom_line()
as it connects the nearest x values, not the order of the data. Is there a way to fill data between two paths, not lines?
Here is an example. As the resulting figure shows the standard deviation lines from geom_ribbon()
are connected by nearest x whereas geom_path()
correctly plots the lines. The desired graphic should fill the area between the red and blue standard deviation lines.
library(tidyverse)
DF <- tibble(
Order = seq(1,20),
x = c(seq(0,18,2), seq(19, 1, -2)),
y = sin(4.5*(Order-1)*pi/180),
sd1 = y + 1,
sd2 = y - 1
)
p <- ggplot(DF, aes(x=x, y=y)) +
geom_ribbon(aes(ymin = sd1, ymax = sd2), fill = 'lightblue', alpha = 0.2) +
geom_path() +
geom_path(aes(y=sd1), col = 'blue') +
geom_path(aes(y=sd2), col = 'red')
ggsave('plot.png', p)
library(tidyverse)
library(zoo)
DF <- tibble(
Order = seq(1,20),
x = c(seq(0,18,2), seq(19, 1, -2)),
y = sin(4.5*(Order-1)*pi/180),
sd1 = y + 1,
sd2 = y - 1
)
DF %>%
mutate(sl1 = (sd1 - lag(sd1, default = first(sd1))) / (x - lag(x, default = 1)),
sl2 = (sd2 - lag(sd2, default = first(sd2))) / (x - lag(x, default = 1))) %>%
{full_join(filter(., sl1 < 0) %>% select(-sd2, -sl1, -sl2),
filter(., sl2 >= 0) %>% select(-sd1, -sl1, -sl2))} %>%
arrange(x) %>%
mutate(sd1_app = zoo::na.spline(sd1, na.rm = F),
sd2_app = zoo::na.spline(sd2, na.rm = F)) -> DF1
ggplot(DF, aes(x=x, y=y)) +
geom_ribbon(data = DF1, aes(ymin = sd1_app, ymax = sd2_app),
fill = 'lightblue', alpha = 0.3) +
geom_path() +
geom_path(aes(y=sd1), col = 'blue') +
geom_path(aes(y=sd2), col = 'red')
Created on 2024-06-25 with reprex v2.0.2