tassones
tassones

Reputation: 1692

In ggplot2, how can I display the month abbreviation on the x-axis vertically with the year below the months horizontally?

I would like the following time series to display the month abbreviation (e.g., Jan, Feb, etc.) in chronological order with a vertical orientation while also displaying the year horizontally below the months. Please see the ideal figure example below.

Example Data:

library(dplyr)
library(ggplot2)

df1 <- data.frame(matrix(ncol = 3, nrow = 12))
colnames(df1)[1:3] <- c("Date", "Group", "Value")
df1$Date <- rep(seq.Date(as.Date("2020-03-14"),as.Date("2020-08-20"),"1 month"),2)
df1$Group <- sort(rep(c("A","B"),6))
df1$Value <- rnorm(12,50,10)
df1 <- df1 %>%
  mutate(Month = month(Date),
         Year = year(Date),
         date = zoo::as.yearmon(paste(Year, Month), "%Y %m"))

df2 <- data.frame(matrix(ncol = 3, nrow = 12))
colnames(df2)[1:3] <- c("Date", "Group", "Value")
df2$Date <- rep(seq.Date(as.Date("2021-03-14"),as.Date("2021-08-20"),"1 month"),2)
df2$Group <- sort(rep(c("A","B"),6))
df2$Value <- rnorm(12,50,10)
df2 <- df2 %>%
  mutate(Month = month(Date),
         Year = year(Date),
         date = zoo::as.yearmon(paste(Year, Month), "%Y %m"))

df3 <- rbind(df1,df2)

Example Figure: This code produces the figure below with the year associated with each month, both vertically oriented.

cols <- c("A" = "#ca0020", "B" = "#0571b0")

ggplot(data = df3, aes(x = factor(date), y = Value, color = Group, group = paste(Year,Group))) +
  geom_line() +
  geom_point(size = 3, aes(fill = Group), color = "black", shape = 21) +
  scale_fill_manual(values = cols) +
  scale_color_manual(values = cols) +
  labs(x = "") +
  theme_bw() +
  theme(panel.grid = element_blank(),
        text = element_text(size = 16),
        axis.text.x = element_text(size = 14, color = "black", angle = 90, vjust = 0.5, hjust = 1),
        axis.text.y = element_text(size = 14, color = "black"),
        legend.title = element_blank(),
        legend.direction = "horizontal",
        legend.margin = margin(),
        legend.background = element_blank(),
        legend.position = c(0.1,0.93),
        panel.border = element_blank()) +
  guides(fill = guide_legend(nrow = 2)) +
  coord_cartesian(clip = 'off', ylim = c(0, 100)) +
  annotation_custom(grid::rectGrob(gp = grid::gpar(fill = NA))) +
  annotate('rect',
           xmin = 6.35,
           xmax = 6.65,
           ymin = -10, ymax = 0, fill = 'white') +
  annotate('segment',
           x = c(6.35, 6.65),
           xend = c(6.35, 6.65), y = -10, yend = 0)

enter image description here

Ideal Figure: The ideal figure would display the month vertically and the year horizontally (please see below). I'm pretty sure I can add the year horizontally based off this SO question, I am just having an issue with displaying the month without the year in chronological order.

I have tried using zoo::scale_x_yearmon(format = "%b") in the example figure code above but have not had success with this approach.

enter image description here

Upvotes: 1

Views: 624

Answers (2)

TarJae
TarJae

Reputation: 78927

Alternative: Using strip.position = "bottom" in facet_wrap

library(tidyverse)
library(lubridate)
df3 %>%
  mutate(Month = month(date, label=TRUE, abbr=TRUE),
         Year = year(date)) %>% 
  arrange(Year) %>% 
  ggplot(aes(x = Month, y = Value, color = Group, group = paste(Year,Group))) +
  geom_line() +
  geom_point(size = 3, aes(fill = Group), color = "black", shape = 21) +
  scale_fill_manual(values = cols) +
  scale_color_manual(values = cols) +
  labs(x = "") +
  coord_cartesian(clip = 'off', ylim = c(0, 100)) +
  facet_wrap(~Year, scales = "free_x", strip.position = "bottom") +
  theme(strip.background = element_blank(),
        strip.placement = "outside") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1))

enter image description here

Upvotes: 1

Ric
Ric

Reputation: 5722

Here a solution partially based in Multi-row x-axis labels in ggplot line chart

ggplot(data = df3, aes(x = factor(date), y = Value, color = Group, group = paste(Year,Group))) +
  geom_line() +
  geom_point(size = 3, aes(fill = Group), color = "black", shape = 21) +
  scale_fill_manual(values = cols) +
  scale_color_manual(values = cols) +
  scale_x_discrete(labels=substr(df3$date,1,3))+
  labs(x = "") +
  theme_bw() +
  theme(plot.margin = unit(c(1, 1, 2, 1), "lines"),
        panel.grid = element_blank(),
        text = element_text(size = 16),
        axis.text.x = element_text(size = 14, color = "black", angle = 90, vjust = 0.5, hjust = 1),
        axis.text.y = element_text(size = 14, color = "black"),
        legend.title = element_blank(),
        legend.direction = "horizontal",
        legend.margin = margin(),
        legend.background = element_blank(),
        legend.position = c(0.1,0.93),
        panel.border = element_blank()) +
  guides(fill = guide_legend(nrow = 2)) +
  coord_cartesian(clip = 'off', ylim = c(0, 100)) +
  annotation_custom(grid::rectGrob(gp = grid::gpar(fill = NA))) +
    annotate(geom = "text", x = 3.5 + 6 * (0:1), y = -30, label = unique(df3$Year), size = 6) +
  annotate('rect',
           xmin = 6.35,
           xmax = 6.65,
           ymin = -10, ymax = 0, fill = 'white') +
  annotate('segment',
           x = c(6.35, 6.65),
           xend = c(6.35, 6.65), y = -10, yend = 0)

Upvotes: 1

Related Questions