0

I would like to have two x axes. One of them (primary preferably) having year quarter and the second one having the months. I'm trying to do this, since my date observations are not uniform/sequential. i.e I can have only Jan in Q1, but the whole 3 months in Q2.

My attempt was to use scale_x_date having the date in the standard date format (as.Date()) and using date_labels and breaks. For the secondary axis, I've used dup_axis and passed zoo::as.yearqtr.

library("zoo")
library("ggplot2")
set.seed(44)

## Creating a reproducible data-frame ##

df <- data.frame("id" = sample(1:100, 3, replace=TRUE),
                 "date" = c("2020-01-01","2020-02-01","2020-03-01",
                            "2020-04-01",
                            "2020-07-01","2020-09-01",
                            "2020-10-01","2020-11-01","2020-12-01")
                 )
## Plotting ##
df %>% 
{
ggplot(data = ., aes(x = as.Date(date), y = id, group = 1)) +
  geom_line() +
  geom_point() +
  scale_x_date(date_labels = "%b", breaks = "1 month",
               sec.axis = dup_axis(name = "month", breaks = scales::date_breaks("3 month"),  labels = as.yearqtr)
               )
}

Here is a plot image of my attempt: enter image description here

The downsides I'm facing here:

  1. The quarter is being plotted for the last 3rd month (i.e it will match March), I'd like for it to match January instead.

Extras - Other low severity issues are:

  1. All dates are plotted, I guess it's because I'm using scale_x_date and we should use scale_x_discrete .. It would be helpful if we wrote labels for only points that exist, otherwise I'm okay for the viewer to match/interpret the points with his eyes.

  2. This is the lowest severity, but I would like to pass arguments to function as.yearqtr so I can format quarter. i.e This will yield as.yearqtr(Sys.Date()) %>% format("%y Q%q") "20 Q2" instead of "2020 Q2"

  • Regarding you first low severity issue, no you should not use `scale_x_discrete` because then the spacing between months will no longer be the same. You can adjust the `breaks` to only be the months that you want to label if necessary. – Axeman May 28 '20 at 21:26
  • Regarding your second issue, you can write e.g. `labels = function(x) as.yearqtr(x, your, other, args)` or `labels = . %>% as.yearqrt(your, other, args)`. – Axeman May 28 '20 at 21:27
  • Thanks for the suggestions, for the second low priority issue, I believe they pass the arguments yes .. but they don't work with `as.yearqrt` as it doesn't accept it. So I've formatted it from the outside: e.g `labels = function(x) format(as.yearqtr(x),"%y Q%q")` – Mohamed Mostafa El-Sayyad May 28 '20 at 21:37

1 Answers1

0

I've changed my attempt to another perspective, the solution is the following:

1- For the main issue, the solution is to use sec_axis instead of dup_axis.

Extras - Other low severity solutions are:

1- For plotting only existing observations, I've used unique(). This is listed in that SO thread link

2- From function as.yearqtr documentation, I can see format as a function parameter, but passing parameters didn't work, so I've used this workaround labels = function(x) format(as.yearqtr(x),"%y Q%q"). Thanks @Axeman for providing the syntax/way.

df %>% 
{
ggplot(data = ., aes(x = as.Date(date), y = id, group = 1)) +
  geom_line() +
  geom_point() +
  scale_x_date(breaks = unique(as.Date(.$date)), date_labels = "%b",
               sec.axis = sec_axis(name = "quarter", trans = ~ ., labels = function(x) format(as.yearqtr(x),"%y Q%q"))
  ) +
  xlab("month")
}

Solution plot result: enter image description here