R gglot2 want to reflect different colors in a line

Viewed 88

I used R language to perform regression analysis/smoothing on the known data. The red line is the fitted regression curve, and the green background is the 95% confidence interval. Now I want to set different colors for the red line and green confidence interval in this picture by time period (red solid line and gray confidence interval before 2020, green dotted line and blue confidence interval from 2020 to 2030), but I don't know how to set the code.

Here is my code.

data <- data.frame(
  year = c(2003:2030),
  number = c(40.84,49.2354,51.5988,53.9622,56.3256,64.79,61.0524,63.4158,65.7792,68.1426,76.4,72.8694,75.2328,77.5962,79.9596,76.36,71.99236,71.10268,70.39136,69.80928,69.31588,68.89523,68.53132,68.21586,67.93846,67.69439,67.47674,67.28291),
  stringsAsFactors = FALSE
)

p3 <- ggplot(data, aes(x=year, y=number)) +
  geom_point() +
  geom_smooth(method = lm, formula = y ~ splines::bs(x, 3), color="red", fill="#69b3a2", se=TRUE) +
  theme_ipsum()

p3

This figure is what I have drawn so far.

enter image description here

This figure is what I want in the end.

enter image description here

Thanks!!

2 Answers

This is another try:

library(tidyverse)
library(hrbrthemes)

data %>% 
  mutate(year_dich = ifelse(year<2015, "<2020", ">=2020")) %>% 
  ggplot(aes(x=year, y=number, group=year_dich)) +
  geom_point() +
  geom_smooth(method = lm, formula = y ~ splines::bs(x, 3), se=TRUE,
              aes(color = ifelse(data$year<2015, "red", "green"),
                  fill = ifelse(data$year<2015, "blue", "black"),
                  linetype = ifelse(data$year<2015, "dashed", "solid"))
              )+
  theme_ipsum()+
  theme(legend.position = "none")

enter image description here

Often people try to do too much inside ggplot - when you have very specific requirements it is best to just work out what you want to plot, then draw it:

library(ggplot2)
library(hrbrthemes)

mod <- lm(formula = number ~ splines::bs(year, 3), data = data)
pred <- as.data.frame(predict(mod, se = TRUE)[1:2])
pred$year <- 2003:2030
pred$number <- pred$fit
pred$pre <- pred$year < 2020

ggplot(pred, aes(x=year, y=number)) +
  geom_point(data = data) +
  geom_line(aes(color = pre, linetype = pre), size = 1.2) +
  geom_ribbon(aes(ymin = fit - 1.96 * se.fit, ymax = fit + 1.96 * se.fit,
                  fill = pre), alpha = 0.2) +
  scale_fill_manual(values = c("dodgerblue", "gray")) +
  scale_color_manual(values = c("forestgreen", "red")) +
  scale_linetype_manual(values = c(2, 1)) +
  theme_ipsum() +
  theme(legend.position = "none")

If you want an interpretable formula for the line (since the actual formula for a spline regression is complicated and not easy to recover), you could try a simple polynomial regression, which seems to fit your data about the same as a spline regression:

mod <- lm(number ~ poly(year, 3), data = data)
pred <- as.data.frame(predict(mod, se.fit = TRUE)[1:2])
pred$year <- 2003:2030
pred$number <- pred$fit
pred$pre <- pred$year < 2020

ggplot(pred, aes(x=year, y=number)) +
  geom_point(data = data) +
  geom_line(aes(color = pre, linetype = pre), size = 1.2) +
  geom_ribbon(aes(ymin = fit - 1.96 * se.fit, ymax = fit + 1.96 * se.fit,
                  fill = pre), alpha = 0.2) +
  scale_fill_manual(values = c("dodgerblue", "gray")) +
  scale_color_manual(values = c("forestgreen", "red")) +
  scale_linetype_manual(values = c(2, 1)) +
  theme_ipsum() +
  theme(legend.position = "none") +
  annotate("text", x = 2020, y = 45, 
           label = paste("number =", 
                         paste0(format(coef(mod), digits = 3), 
                          c("", " * year", " * year\u00b2", " * year\u00b3"), 
                          collapse = " + ")), fontface = "bold")

enter image description here

Where we can see the equation added as an annotation, retrieved from the regression equation with:

 paste("number =", 
       paste0(format(coef(mod), digits = 3), 
              c("", " * year", " * year\u00b2", " * year\u00b3"), 
              collapse = " + "))
#> [1] "number =  66.5 +  27.4 * year + -34.3 * year² +  10.0 * year³"
Related