Draw a rectangle around bars and categories in (R, ggplot2)

Viewed 602

I would like to create a box/rectangle around a single level of a category and include the axis category text and the bar itself:

enter image description here

As you can see in the photo, the rectangle extends beyond the grid and into the plot area to encompass the axis text. I'm hoping for something customizable so I can draw rounded corners or not, change the color, and specify where it goes.

Here's some generic code I used to produce a plot:

ggplot(mtcars, aes(x=factor(cyl)))+
  geom_bar(stat="count", width=0.7, fill="steelblue")+
  theme_minimal()

Hopefully, this isn't answered somewhere already!

2 Answers
  1. For rectangle use annotate with "rect"
  2. to go over the x axis you can set the x axis to blank
  3. then add new quasi axis with geom_text setting y to 0 or -1. play around to fit:
p <- ggplot(mtcars, aes(x=factor(cyl)))+
    geom_bar(stat="count", width=0.7, fill="steelblue")+
    theme_minimal() 
    

p + annotate("rect", xmin = 0.5, xmax = 1.5, ymin = -1, ymax = 12,
             alpha = 0, color= "green") +
    theme(axis.text.x = element_blank(),
            axis.line.x = element_blank(),
            axis.ticks.x = element_blank()) +
    geom_text(aes(y = -0.5, x = factor(cyl), 
                  label = cyl)) +
    labs(title="Rectangle over x axis!",
          x ="cyl", y = "count")

enter image description here

That's what the ggforce package is great for. Here with a semi-programmatic approach to define x/y coordinates of your shape. If you intend to mark specific areas / data points, you might also want to look into ggforce::geom_mark_rect

I have also un-factorised the x.

library(tidyverse)
library(ggforce)

cyl <- 4
n_cyl4 <- table(mtcars$cyl)[1]
df_rect <- data.frame(x = c(cyl - .5, rep(cyl + .5, 2), cyl - .5), y = c(rep(-2, 2), rep(n_cyl4 + .5, 2)))

ggplot(mtcars, aes(x = cyl)) +
  geom_shape(data = df_rect, aes(x, y), fill = NA, color = "black", radius = .01) +
  geom_bar(stat = "count", width = 0.7, fill = "steelblue") +
  scale_x_continuous(breaks = seq(4, 8, 2)) +
  coord_cartesian(ylim = c(0, NA), clip = "off") +
  theme_minimal()

Created on 2021-08-03 by the reprex package (v2.0.0)

Related