I have a ggplot2 object using facet_wrap to make 26 separate histograms in one image, but I would like to assign separate x-labels to each graph (the numbers on each axis are fine as-is, I just want to put some custom text underneath each plot). I've searched up and down google and stackoverflow to try to find an answer to no avail.
There are a few ways to do this... but none that are very direct like you are probably expecting. I'll assume that you want to replace the default x axis title with new titles, so we'll go from there. Here's an example from the iris
dataset:
library(ggplot2)
p <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() +
facet_wrap(~Species)
One way to create an axis title specific for each is to use the strip text (also called the facet label). The idea is to position the strip text at the bottom of the facet (usually it's at the top by default) and mess with formatting.
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() +
labs(x=NULL) + # remove axis title
facet_wrap(
~Species,
strip.position = "bottom") + # move strip position
theme(
strip.placement = "outside", # format to look like title
strip.background = element_blank()
)
Here we do a few things:
What about doing what we did above... but making your own labels? You can adjust the strip text labels (facet labels) by setting a named vector as.labeller()
. Otherwise, it's the same changes as above. Here's an example:
my_strip_labels <- as_labeller(c(
"setosa" = "My Setosa",
"versicolor" = "Your versicolor",
"virginica" = "Some other stuff"
))
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_point() +
labs(x=NULL) +
facet_wrap(
~Species, labeller = my_strip_labels, # add labels
strip.position = "bottom") +
theme(
strip.placement = "outside",
strip.background = element_blank()
)
What about if you want to keep your facet labels, and just add an axis title below each facet? Well, perhaps you can do that via annotation_custom()
and make some grobs, but I think it might be easier to place those as a text geom. For this to work, the idea is that you add a text geom outside of your plot area and map the label text itself to the facets. You'll need to do this with a separate data frame (to avoid overlabeling), and the data frame needs to contain two columns: one that is labeled the same as the label of your facetting column, and one that is to be used to store our preferred text for the axis title.
Here's something that works:
axis_titles <- data.frame(
Species = c("setosa", "versicolor", "virginica"),
axis_title = c("Setosa's Axis", "Versi's Axis", "Virgin's Axis")
)
p + labs(x=NULL) +
geom_text(
data=axis_titles,
aes(label=axis_title), hjust=0.5,
x=min(iris$Sepal.Length) + diff(range(iris$Sepal.Length))/2,
y=1.7, color='red', fontface='bold'
) +
coord_cartesian(clip="off") +
theme(
plot.margin= margin(b=30)
)
Here we have to do a few things:
geom_text()
linked to the new data frame and modify placement. Note I'm mathematically fixing the position to be "in the middle" of the x axis. I manually placed the y value, but you could use an equation there too if you want.clip="off"
. This is important, because with clip="on"
it will prevent any geoms from being shown if they are outside the panel area.