For comparing multiple trends over time; useful for directions of changes, as well as absolute values to some degree. Requires values to be on the same scale.

Sample Data

If your data is “wide” (each row might contain multiple observations taken at the same time),
we need it to be made “tall” (each row is exactly one data-point).
If you already have tall data, just skip the pivot_longer().

membership_raw <- data.frame(overall=c(65.26,55.21,56.29),
                              deu=c(11.66, 10.31, 9.26),
                              gbr=c(10.39, 8.28, 9.57),
                              esp=c(5.51, 4.32, 4.83))
membership_percent <- 
  membership_raw %>% 
  sapply(., function(col){col/col[1]}) %>%
  as.data.frame(.) %>% 
  mutate(., year=2019:2021) %>%
  pivot_longer(!year, names_to="market", values_to="membership") %>%
  mutate(market=factor(market,
                       levels=c("deu","gbr","esp","overall")))

labels <- as_labeller(c("deu"="Germany",
                        "gbr"="the UK",
                        "esp"="Spain",
                        "overall"="the Entire EU"))

head(membership_percent)
## # A tibble: 6 × 3
##    year market  membership
##   <int> <fct>        <dbl>
## 1  2019 overall      1    
## 2  2019 deu          1    
## 3  2019 gbr          1    
## 4  2019 esp          1    
## 5  2020 overall      0.846
## 6  2020 deu          0.884

Plot

Base Plot

The trick is to create a copy of the faceting variable(s) and group on that, so that the background data are grouped but not faceted into different panels.

ggplot(membership_percent, aes(x=year, y=membership)) +
  facet_grid(cols=vars(market), labeller = labels) +
  
  # the background lines present in every panel
  geom_line(data=membership_percent %>% 
              mutate(market2=market) %>%
              dplyr::select(-market),
            aes(group=market2),
            color="gray") +
  
  # the highlighted line corresponding to each panel
  geom_line() +
  
  # arranging the plot
  scale_x_continuous(breaks = seq(2019, 2021, by = 1)) +
  scale_y_continuous(expand = c(0.2,0.2)) +
  coord_cartesian(xlim=c(2019,2021)) +
  labs(title="Membership decreased from 2019",
       subtitle="in European Markets, in the years 2020 and 2021",
       y="Membership count relative to 2019") +
  theme_minimal()

With Extra Fluff

my_color <- "#233F7D"

ggplot(membership_percent, aes(x=year, y=membership)) +
  facet_grid(cols=vars(market), labeller = labels) +
  
  # the background lines present in every panel
  geom_line(data = membership_percent %>% 
              mutate(market2=market) %>%
              dplyr::select(-market),
            aes(group=market2),
            color = "gray") +
  
  # the highlighted line corresponding to each panel
  geom_line(color = my_color,
            linewidth = 1) +
  geom_point(data = dplyr::filter(membership_percent, year!=2020),
             size=2, color=my_color) +
  geom_text(data = dplyr::filter(membership_percent, year==2021),
          aes(label = scales::percent(membership)),
          nudge_y = 0.02 * c(1, -1, 1, 1), 
          # for some reason, this needs to be in the order the categories appear in the data set, not their order on the plot
          color = my_color,
          size = 5) +
  
  # arranging the plot
  scale_x_continuous(breaks = seq(2019, 2021, by = 1),
                     expand = c(0.3,0.3)) +
  coord_cartesian(xlim=c(2019,2021), ylim=c(0.7,1)) +
  labs(title=stringr::str_interp("<span style='color:${my_color}'>**Membership decreased**</span> from 2019"),
       subtitle="in European Markets, in the years 2020 and 2021",
       y="Membership count relative to 2019") +
  
  # theme
  theme_minimal() + 
  theme(plot.title=element_markdown(size=18, color='#535353'),
        plot.subtitle=element_text(size=14),
        strip.text = element_text(angle = 0, size = 14, 
                                  color='#818181'),
        text = element_text(color='#818181'),
        panel.grid = element_blank(),
        axis.ticks.y = element_blank(),
        axis.text.y = element_blank(),
        axis.title.x = element_blank())