Colored tick labels ggplot2

In the attached picture you will see that the tick labels of the Y axis are represented by three letters (e.g., ROG). Each of these letters represents the Google Maps typical traffic for mornings, noons and afternoons: R means "Red Traffic", "O means Orange Traffic" and "G indicates Green Traffic". Thus, "ROG" means that the typical traffic in the morning is "red", in the noon is "orange" and in the afternoon is green, showing a place where traffic conditions are better as time goes by.

Do you know how to replace these tick labels in ggplot2 with a set colored squares like the ones I show in the modified version of Fig1?

1 Like

I don't know of a way to use multiple colors within a single axis label. However, you can remove the native ggplot axis and hack your own new axis by plotting lines and symbols in the right places. Below is an example using the built-in iris data frame.

In the code below, we remove the y-axis and replace it with a y-axis at x=0 using geom_vline plus geom_segment for the tick marks. Then we add a call to geom_label to create the colored boxes. In the geom_label call, we do some data transformation to convert the data to long format and generate the x-values for the box locations.

library(tidyverse)
library(ggstance)

# Set up starting data
set.seed(2)
iris$code = replicate(nrow(iris), paste(sample(c("R","O","G"), 3, replace=TRUE), collapse=""))

# Split code column into three columns, one for each letter value
iris = cbind(iris, str_split_fixed(iris$code, "", 3))

ggplot(iris, aes(Petal.Width, code)) + 
  geom_boxploth() +
  geom_vline(xintercept=0, colour="grey80") +
  geom_segment(aes(x=-0.02, xend=0, yend=code), colour="grey80") + 
  geom_label(data=iris %>% gather(key, value, `1`:`3`) %>%
               mutate(key = -0.1 * (4 - as.numeric(key))),
             aes(x=key, fill=value, label=value), color="white", size=3,
             label.size=0, label.padding=unit(2,"pt"), label.r=unit(0,"pt")) +
  coord_cartesian(xlim=c(-0.35, max(iris$Petal.Width))) +
  scale_fill_manual(values=c("R"="red","O"="chocolate1", "G"="chartreuse4")) +
  theme_classic() +
  theme(axis.text.y=element_blank(),
        axis.ticks.y=element_blank(),
        axis.line.y=element_blank(),          
        axis.title.y=element_blank(),
        axis.line.x=element_line(colour="grey70")) +
  guides(fill=FALSE)

Rplot77

If you prefer unlabeled boxes, replace the geom_label code with the following and change to guides(colour=FALSE):

geom_point(data=iris %>% gather(key, value, `1`:`3`) %>% 
             mutate(key = -0.1 * (4 - as.numeric(key))), 
           aes(x=key, colour=value), shape=15, size=4)
9 Likes

This is great trick. Thank you for sharing!

How did you get all the squared symbols close to each others? Using your code I had something like this which is not as good as yours

This is just a guess, but it could have something to do with the width of your "Plots" pane, as it looks like his entire plot is narrower than yours. Does reducing the width of the pane make a difference?

1 Like

As @tbradley surmised, it has to do with the physical size of the rendered plot. If you reduce the width of the plot, the colored boxes will be closer together. In principle, it should be possible to programmatically scale the size of the boxes, their placement on the x-axis, and the size of the text relative to the physical dimensions of the desired rendered size of the plot, so that the boxes stay close together and the text size is reasonable, but I'm not sure how to do that. For this answer I just adjusted the size manually to get it to look right.

2 Likes