rggplot2ggtext

R ggplot2 Customizing date axis labels with different colors


I would like to color the date axis labels considering some conditions. Here is an example:

# Libraries
library("ggplot2")
library("lubridate")

# Create data
data0 <- data.frame(dt = seq(as.Date('2022-01-01'),as.Date('2022-01-20'),1))
data0$y <- runif(length(data0$dt))
head(data0)
###           dt          y
### 1 2022-01-01 0.99842049
### 2 2022-01-02 0.10663102
### 3 2022-01-03 0.04824916
### 4 2022-01-04 0.49312740
### 5 2022-01-05 0.01445124
### 6 2022-01-06 0.96767266

# Define color red for Saturday and Sunday
lab_col <- with(data0, ifelse(wday(dt) %in% c(1,7),"red","black"))

ggplot(data0,aes(dt,y)) +
    geom_line() +
    scale_x_date(date_breaks = "1 day"
               , date_labels = "%Y-%m-%d (%a)"
                 ) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.3, hjust=1, colour=lab_col))

This gives what I expected:

enter image description here

But it also gives this message:

Warning message:
Vectorized input to `element_text()` is not officially supported.
Results may be unexpected or may change in future versions of ggplot2.

Indeed, using my original data the wrong weekdays are colored red.

I found a possible solution here using ggtext:

data0$dt2 <- with(data0, paste0("<i style = 'color: "
                                 , lab_col
                                 , ";'>"
                                 , dt
                                 , " (",wday(dt, label=TRUE),")"
                                 , "</i>"
                                  )
                  )
head(data0)
###           dt          y                                            dt2
### 1 2022-01-01 0.99842049   <i style = 'color: red;'>2022-01-01 (Sa)</i>
### 2 2022-01-02 0.10663102   <i style = 'color: red;'>2022-01-02 (So)</i>
### 3 2022-01-03 0.04824916 <i style = 'color: black;'>2022-01-03 (Mo)</i>
### 4 2022-01-04 0.49312740 <i style = 'color: black;'>2022-01-04 (Di)</i>
### 5 2022-01-05 0.01445124 <i style = 'color: black;'>2022-01-05 (Mi)</i>
### 6 2022-01-06 0.96767266 <i style = 'color: black;'>2022-01-06 (Do)</i>    

library("ggtext")
ggplot(data0,aes(dt2,y)) +
    geom_line() +
    scale_x_date(date_breaks = "1 day") +
    theme(axis.text.x = element_markdown(angle = 90, vjust = 0.3, hjust=1))

But this gives me this error:

Error: Invalid input: date_trans works with objects of class Date only

This makes sense since dt2 is not a date. The SO-example from above link consider factor variables. How can I use the power of ggtext with date as x-variable?


Solution

  • You're right about why ggtext doesn't work, but we can work around this.

    You can use a function for the labels argument of the scale. This can be a function that does the label formatting for you.

    # Libraries
    library("ggplot2")
    library("lubridate")
    library("ggtext")
    
    # Create data
    data0 <- data.frame(dt = seq(as.Date('2022-01-01'),as.Date('2022-01-20'),1))
    data0$y <- runif(length(data0$dt))
    
    ggplot(data0,aes(dt,y)) +
      geom_line() +
      scale_x_date(
        date_breaks = "1 day",
        labels = function(x) {
          col <- ifelse(wday(x) %in% c(1, 7), "red", "black")
          lab <- strftime(x, format = "%Y-%m-%d (%a)")
          glue::glue("<span style = 'color:{col}'>{lab}</span>")
        }
      ) +
      theme(axis.text.x = element_markdown(angle = 90, vjust = 0.3, hjust=1))
    

    Created on 2022-08-26 by the reprex package (v2.0.0)