I've created a map whereby each quarter has its own histogram. The histograms share a legend, thus I'd like a legend to be placed horizontally underneath the map, which I've tried to do with get_legend but I keep getting the warning, and no legend is plotted.
In get_plot_component(plot, "guide-box") :
Multiple components found; returning the first one. To return all, use `return_all = TRUE`.'
So I'm providing the original code hoping someone can tell me how to create the desired plot. Furthermore, if anyone has tips on how to ggsave the final object without the positions of each subplot moving from how it looks if I open the plot in a new window from R using 'zoom', that would be helpful too. I always have to play around with the width and the height to reproduce that.
Here is what the map looks like now, in plot zoom:
Here is the code to create it. I can't provide the original object because the dput() would be extremely long:
# Reshape the data from wide to long format
quarts_long <- tidyr::pivot_longer(quarts, cols = c("Mammals", "Birds", "Amphibians", "Reptiles"), names_to = "Class", values_to = "Count")
# Calculate centroids of each quarter
quarts_centroids <- st_centroid(quarts)
# Create histograms for each quarter
hist_plots <- list()
for (i in 1:nrow(quarts)) {
hist_plots[[i]] <- ggplot(quarts_long[quarts_long$Quarter == quarts$Quarter[i],]) +
geom_col(aes(x = Class, y = Count, fill = Class)) +
scale_y_continuous(limits = c(0, 300), breaks = c(0, 150, 300)) +
labs(y = "", x = "") + # Remove axis labels
theme_void() + # Use minimal theme
theme(axis.title.y = element_text(margin = margin(t = 0, r = 10, b = 0, l = 0)), # Adjust y-axis label position
axis.text.x = element_blank(), # Remove x-axis text
axis.text.y = element_text(size = 10),
legend.position = "none") # Adjust y-axis text size
}
# Create the quarters map
map_plot <- ggplot() +
geom_sf(data = quarts, fill = alpha("white", 0)) +
labs(x = NULL, y = NULL) +
theme_void() +
theme(legend.position = "none") # Move legend to bottom
# Define shared legend
shared_legend <- get_legend(hist_plots[[1]])
# Draw the final plot with legend
p <- ggdraw() +
draw_plot(hist_plots[[1]], 0.48, 0.63, 0.17, 0.15) + # Draw the northeast
draw_plot(hist_plots[[2]], 0.28, 0.63, 0.17, 0.15) + # Draw the northwest
draw_plot(hist_plots[[3]], 0.48, 0.38, 0.17, 0.15) + # Draw the southeast
draw_plot(hist_plots[[4]], 0.28, 0.38, 0.17, 0.15) + # Draw the southwest
draw_plot(map_plot, 0.05, 0.05, 0.95, 0.95) + # Draw the quarters map
draw_plot(shared_legend, 0.2, 0.05, 0.6, 0.1)
You have at least one and possibly two issues. To start, here's a simpler reprex that produces the same problem:
library(ggplot2)
library(cowplot)
p <- ggplot(mpg, aes(cty, hwy)) +
geom_point(aes(color = drv)) +
theme(legend.position = "none")
shared_legend <- get_legend(p)
#> Warning in get_plot_component(plot, "guide-box"): Multiple components found;
#> returning the first one. To return all, use `return_all = TRUE`.
ggdraw() +
draw_plot(p, x = 0, width = .45) +
draw_plot(p, x = .45, width = .45) +
draw_plot(shared_legend, x = .85, width = .2)
Your first problem is that you're specifying legend.position = "none"
in theme()
. This removes the legend, so there's no legend for get_legend()
to "get." Instead, remove legend.position = "none"
from your original plot spec, then add it after getting the legend:
library(ggplot2)
library(cowplot)
p <- ggplot(mpg, aes(cty, hwy)) +
geom_point(aes(color = drv))
shared_legend <- get_legend(p)
#> Warning in get_plot_component(plot, "guide-box"): Multiple components found;
#> returning the first one. To return all, use `return_all = TRUE`.
p <- p + theme(legend.position = "none")
ggdraw() +
draw_plot(p, x = 0, width = .45) +
draw_plot(p, x = .45, width = .45) +
draw_plot(shared_legend, x = .85, width = .2)
get_legend()
bugThis will solve the issue as long as legend.position = "right"
, which is the default. But otherwise, get_legend()
won't return the legend, which is a known issue.
As a workaround, you can use get_plot_component(plot, "guide-box", return_all = TRUE)
. You'll need to inspect this to see what position the legend is in, and index into the result accordingly. e.g., for legend.position = "bottom"
:
p <- ggplot(mpg, aes(cty, hwy)) +
geom_point(aes(color = drv)) +
theme(legend.position = "bottom")
# when position = "bottom," legend is the third grob in the list
shared_legend <- cowplot::get_plot_component(p, "guide-box", return_all = TRUE)[[3]]
p <- p + theme(legend.position = "none")
ggdraw() +
draw_plot(p, x = 0, y = .1, width = .5, height = .9) +
draw_plot(p, x = .5, y = .1, width = .5, height = .9) +
draw_plot(shared_legend, x = 0, y = 0, height = .2)
Created on 2024-04-11 with reprex v2.1.0