This is an extension beyond a previous question, where the goal was to set different limits for each facet. The code from that question is stored in a gist, and has been in production since.
A quick demo with sample data:
set.seed(42)
dat <- data.frame(x = seq(0,1,len=101), y = cumsum(runif(101,-1,1)), z=sample(1:3, size=101, replace=TRUE))
dat$y <- dat$y * dat$z
dat$y[50] <- 99
dat$z[50] <- 2L
lims <- data.frame(z=1:3, ymin=0, ymax=c(10,25,30))
ggplot(dat, aes(x, y)) +
facet_grid(z ~ ., switch="both", scales="free_y") +
scale_x_continuous(expand = c(0, 0)) +
geom_line() +
coord_cartesian_panels(panel_limits = lims, clip = "on")
I now have a need to add geom_labels to the right side of the plot, outside of plot region. Edit: multiple labels per facet, with colors (whose order is inconsistent between facets). Doing this is relatively straight-forward: place the label at the edge of the screen, extend the theme's plot.margin, and turn off clipping. Unfortunately, as you might imagine with the two excursions in facets 2 and 3, disabling clipping is a concern.
summ <- aggregate(y ~ z, dat, FUN = function(z) c(lo=mean(z)-3, hi=mean(z)+3)) |>
do.call(data.frame, args = _) |>
reshape2::melt("z", variable.name = "ign", value.name = "y") |>
transform(lbl = sprintf("%0.03f", y)) |>
transform(fill = factor(ave(z, z, FUN = function(ign) sample(seq_along(ign)))))
ggplot(dat, aes(x, y)) +
facet_grid(z ~ ., switch="both", scales="free_y") +
scale_x_continuous(expand = c(0, 0)) +
geom_line() +
geom_label(x = 1, aes(y = y, label = lbl, fill = fill), data = summ, hjust = -0.1) +
coord_cartesian_panels(panel_limits = lims, clip = "off") +
theme(plot.margin = unit(c(0.5, 0.65 * max(nchar(summ$lbl)), 0.5, 0.5), "char")) +
scale_fill_discrete(guide = "none")
I supposed there are three possible ways to resolve this:
Find another way to add the labels on the right side that does not require disabling clipping. To be clear, theming (background, axis lines/ticks/labels, etc) should not be affected by this. There are many other components to these plots here, I need the plot region to "stop" cleanly before the labels begin.
Find a way to clip on the
yaxis and not thex. In this case I have "strict" control over the x-values so am not as concerned about running amuck on either the left or right side.Incorporate
oobuse (e.g.,scales::oob_squish) into theggprotouse withincoord_cartesian_panels.Something else?




(I suppose there are reasons not to consider plotting the labels separately & combining the results together using one of the usual suspects such as cowplot, patchwork, etc.)
I wrote a modified version of
FacetGridthat could accept separate clipping instructions for each layer. Combine that with specifyingclip = c("on", "off")incoord_cartesian_panelsseems to work.Note: having a legend positioned to the right of the plot (i.e. default legend position) will mess up the appearance, but I'd consider that an intrinsic part of the way ggplot grobs are laid out. Since the use case here doesn't place a legend on the right, I assume it's not a key requirement for now.
Demonstration with same use case in the question:
Further demonstration for layer-specific clipping by adding another geom layer, but this one clipped at the edge:
Code for
facet_grid2/FacetGrid2(change from original is mainly a chunk in the middle of the latter'sdraw_panelsfunction, to allow separate clipping options for different geom layers; everything else is inherited directly from my current version of ggplot2, which is 3.4.2):Disclaimer: I haven't tested this for other use cases because I haven't had a need for it, so... caveat emptor. :)