Evenly Spaced Month Charts

I recently noticed that ggplot2 spaces date axes literally even when grouped by month. I’ve been using ggplot2 extensively for years and I don’t remember noticing before, so this is not really a big deal, but now that I know it bugs me a lot. Take a look below.

As always, let’s load the tidyverse.

library(tidyverse)

Next, we need some example data. Nothing fancy, just something to plot as an example.

month_data <- tibble(dates = seq(ymd("2023-11-01"), ymd("2024-04-30"), by = "day"),
                     data = sample(1:1e3, 182)) |>
  mutate(month = floor_date(dates, "month")) |>
  group_by(month) |>
  summarise(monthly_mean = mean(data))

month_data
## # A tibble: 6 × 2
##   month      monthly_mean
##   <date>            <dbl>
## 1 2023-11-01         572.
## 2 2023-12-01         601.
## 3 2024-01-01         471.
## 4 2024-02-01         562.
## 5 2024-03-01         487.
## 6 2024-04-01         438.

Now let me show you how the distance between the months is not equal.

month_data |>
  ggplot(aes(x = month, y = monthly_mean)) +
  geom_col(width = 29) +
  ggtitle("The Months Are Not Spaced Evenly!") +
  # add the year to the first month plotted in each year
  scale_x_date(labels = scales::label_date_short())

How frustrating! The fix is not that hard, though. We are going to change the date axis to factors with a neat little trick. We’re going to hack the label_date_short() function to change the dates to text and then change the dates to factors. Here we go.

# get the label_date_short() function
prettify_dates <- scales::label_date_short()

# we use the new function we made and make the dates factors so that they sort 
# correctly. 
new_month_data <- month_data |>
  mutate(pretty_month = prettify_dates(month),
         pretty_month = as_factor(pretty_month))

new_month_data
## # A tibble: 6 × 3
##   month      monthly_mean pretty_month
##   <date>            <dbl> <fct>       
## 1 2023-11-01         572. "Nov\n2023" 
## 2 2023-12-01         601. "Dec"       
## 3 2024-01-01         471. "Jan\n2024" 
## 4 2024-02-01         562. "Feb"       
## 5 2024-03-01         487. "Mar"       
## 6 2024-04-01         438. "Apr"

Now all we have to do is drop the date scale and let geom_col() chose its own width.

new_month_data |>
  ggplot(aes(x = pretty_month, y = monthly_mean)) +
  geom_col() +
  ggtitle("The Spacing Is Even Now!")

comments powered by Disqus