I am using facetted plots via ggplot
that contain a colorbar. I want to scale the colorbar to the size of the facetted plot. Following the ideas of @AllanCameron in this post regarding a single plot and tweaking the function to account for both the strip size and the space between plots, I am able to correctly work out the size of the legend. Thereby, the size of the legend is correctly specified irrespective of the ncol
, panel.spacing.y
, or strip.text.x
specification.
However, by default, the legend is centered between the two plots without strips. Adjusting the legend via legend.position
or legend.justification
did so far not help to correctly specify it. How can I properly align the legend with the top of the chart i.e., the top of the strip (see the plot on the right side for the exptected output)?
I only aligned in the right chart the legend to the top without adjusting the size using an external graphics programme. Thus, while the legend height looks too small in the picture on the left chart, the size is actually fine.
library(ggplot2)
df <- expand.grid(
x = c(1, 2, 3),
y = c(1, 2, 3),
g = c("one", "two", "three", "four")
)
set.seed(1)
df$v <- runif(nrow(df), min = 0, max = 1)
make_fullsize <- function() structure("", class = "fullsizebar")
ggplot_add.fullsizebar <- function(obj, g, name = "fullsizebar") {
h <- ggplotGrob(g)$heights
panel <- which(grid::unitType(h) == "null")
panel_height <- unit(1, "npc") - sum(h[-c(panel, (panel-1), grep("lines", h))])
g +
guides(fill = guide_colorbar(barheight = panel_height,
title.position = "right")) +
theme(legend.title = element_text(angle = -90, hjust = 0.5))
}
ggplot(df, aes(x = x, y = y, fill = v)) +
facet_wrap(. ~ g, ncol = 2) +
geom_tile(color = "black") +
scale_y_discrete(expand = c(0,0)) +
scale_x_discrete(expand = c(0,0)) +
theme(panel.spacing.y = unit(1, "lines"),
strip.text.x = element_text(size = 15, margin = margin(2,0,2,0, "cm")),
strip.background.x = element_rect(
colour = "black", linewidth = 1)) +
make_fullsize()
Building on the original code by @AllanCameron and my adapted approach we can easily compute the correct bar height. However, to achieve your desired result requires some additional tweaks via theme
. Set the legend.justification
to bottom
and remove the top and bottom legend.margin
:
library(ggplot2)
make_fullsize <- function() structure("", class = "fullsizebar")
ggplot_add.fullsizebar <- function(obj, g, name = "fullsizebar") {
p <- ggplotGrob(g)
h <- p$heights
ix_panel <- grep("^panel", p$layout$name)
ix_strip <- grep("^strip", p$layout$name)
panel_t <- min(p$layout[ix_strip, "t"])
panel_b <- max(p$layout[ix_panel, "b"])
barheight <- unit(1, "npc") - sum(h[-seq(panel_t, panel_b)])
g +
guides(fill = guide_colorbar(
barheight = barheight,
title.position = "right"
)) +
theme(
legend.justification = "bottom",
legend.margin = margin(0, 5.5, 0, 5.5),
legend.title = element_text(angle = -90, hjust = 0.5)
)
}
ggplot(df, aes(x = x, y = y, fill = v)) +
facet_wrap(. ~ g, ncol = 2) +
geom_tile(color = "black") +
scale_y_discrete(expand = c(0, 0)) +
scale_x_discrete(expand = c(0, 0)) +
theme(
panel.spacing.y = unit(1, "lines"),
strip.text.x = element_text(size = 15, margin = margin(2, 0, 2, 0, "cm")),
strip.background.x = element_rect(
colour = "black", linewidth = 1
)
) +
make_fullsize()
ggsave("foo.png", width = 5, height = 5)