ggplot: Add geom_rect using categorical value for min and max values

Viewed 952

I have a very basic ggplot:

library(ggplot)

ggplot(mpg, aes(x=displ, y=manufacturer)) +
  geom_point() +
  geom_rect(aes(xmin=1.8, xmax=3.0, ymin='audi', ymax='audi', fill='red')) 

I'd like to add a bar from x axis values 1.8 to 3.0 only for the audi row on the y axis. Is there a way to achieve this in ggplot? Any help others can offer on this question would be greatly appreciated!

2 Answers

It can be done. Categorical values are converted to integers for plotting, so you can either specify them as integers (audi is the first category, so integer is 1), or, as I've done below, make a list of the category names and specify by name.

library(ggplot)
data("mpg")
man_list <- unique(mpg$manufacturer)

ggplot(mpg, aes(x=displ, y=manufacturer)) +
  geom_point() +
  # geom_rect(aes(xmin=1.8, xmax=3.0, ymin= "audi", ymax=lead("audi"), fill='red')) 
  geom_rect(aes(ymin = which(man_list=="audi")-0.5,
                ymax = which(man_list=="audi")+0.5,
                xmin=1.8,
                xmax=3,
                fill="red"))

enter image description here

Building on @Greg's answer, I believe it is is safer to recreate the factor levels in the aes call in geom_rect. This is because it is the factor levels rather than the character strings that are coerced to integer.

ggplot(mpg, aes(x=displ, y=manufacturer)) +
  geom_point() +
  geom_rect(aes(ymin = which(levels(as.factor(manufacturer))=="audi") -0.5,
                ymax = which(levels(as.factor(manufacturer))=="audi") +0.5,
                xmin=1.8,
                xmax=3,
                fill="red"))

enter image description here

This works even if the factor levels have been altered from default:

my.mpg <- mpg
my.mpg$manufacturer <-as.factor(my.mpg$manufacturer)
my.mpg$manufacturer <-factor(my.mpg$manufacturer,
                             levels = rev(levels(my.mpg$manufacturer)))
ggplot(my.mpg, aes(x=displ, y=manufacturer)) +
  geom_point() +
  geom_rect(aes(ymin = which(levels(as.factor(manufacturer))=="audi") -0.5,
                ymax = which(levels(as.factor(manufacturer))=="audi") +0.5,
                xmin=1.8,
                xmax=3,
                fill="red"))

enter image description here

In contrast, the which(unique(...)) method fails:

man_list <- unique(my.mpg$manufacturer)

ggplot(my.mpg, aes(x=displ, y=manufacturer)) +
  geom_point() +
  # geom_rect(aes(xmin=1.8, xmax=3.0, ymin= "audi", ymax=lead("audi"), fill='red')) 
  geom_rect(aes(ymin = which(man_list=="audi")-0.5,
                ymax = which(man_list=="audi")+0.5,
                xmin=1.8,
                xmax=3,
                fill="red"))

enter image description here

Related