admin管理员组

文章数量:1122832

I have tried using various different methods to be able to create one combined legend for my 4 ggplots, however, either it causes one of the graphs to be squished as compared to the other because the legend is within that plot area or it errors.

Here is a reproducible data set to work with and code for my graphs:

var=c("White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian")
gender=c("Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women")
p=c(25, 35, 45, 26, 57, 43,35, 45, 43, 36, 27, 53,23, 55, 25, 25, 37, 23)
n=c(50, 100, 96, 57, 56, 54,50, 90, 96, 57, 56, 54,60, 110, 66, 37, 56, 54)
year=c(2019,2019,2019,2019,2019,2019, 2020,2020,2020,2020,2020,2020,2021,2021,2021,2021,2021,2021)

df=data.frame(year,var,gender,n,p)
df$var=factor(df$var, levels=c("Black","Asian","White"))
df$year=factor(df$year, levels=c(2019, 2020, 2021))

# Create graphs for men
men1=ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 150)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed")

men2=ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 100)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed")

# Combine graphs
men_combined=ggarrange(men1, men2,
                 nrow=1, ncol=2
)

# Add title to figure
men_combined=annotate_figure(men_combined, 
                       top = text_grob("\nMen",
                                       color = "black", face = "bold", size = 25))

# Create graphs for women
women1=ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 150)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed")

women2=ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 100)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed")

# Combine graphs
women_combined=ggarrange(women1, women2,
                       nrow=1, ncol=2
)

# Add title to figure
women_combined=annotate_figure(women_combined, 
                             top = text_grob("\nWomen",
                                             color = "black", face = "bold", size = 25))

# Combine all together
    all_plots=ggarrange(men_combined, women_combined,
                       nrow=2, ncol=1)`

I have tried using the following to help and I was able to get a common legend but it then did not work when I tried using annotate_figure as I need to have a title above each to show the gender. Add a common Legend for combined ggplots

This is code I used which then did not work when I added the 'Men' and 'Women' titles:

grid_arrange_shared_legend <- function(..., nrow = 1, ncol = length(list(...)), position = c("bottom", "right")) {
    
    plots <- list(...)
    position <- match.arg(position)
    g <- ggplotGrob(plots[[1]] + theme(legend.position = position))$grobs
    legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
    lheight <- sum(legend$height)
    lwidth <- sum(legend$width)
    gl <- lapply(plots, function(x) x + theme(legend.position = "none"))
    gl <- c(gl, nrow = nrow, ncol = ncol)
    
    combined <- switch(position,
                       "bottom" = arrangeGrob(do.call(arrangeGrob, gl),
                                              legend,
                                              ncol = 1,
                                              heights = unit.c(unit(1, "npc") - lheight, lheight)),
                       "right" = arrangeGrob(do.call(arrangeGrob, gl),
                                             legend,
                                             ncol = 2,
                                             widths = unit.c(unit(1, "npc") - lwidth, lwidth)))
    grid.newpage()
    grid.draw(combined)
    
}

grid_arrange_shared_legend(men1, men2, women1, women2, nrow = 2, ncol = 2)

This is what the code came out with which is exactly what I want but it needs to have a 'Men' and 'Women' title:

Please help!! :)

I have tried using various different methods to be able to create one combined legend for my 4 ggplots, however, either it causes one of the graphs to be squished as compared to the other because the legend is within that plot area or it errors.

Here is a reproducible data set to work with and code for my graphs:

var=c("White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian","White", "Black", "Asian")
gender=c("Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women","Men","Women")
p=c(25, 35, 45, 26, 57, 43,35, 45, 43, 36, 27, 53,23, 55, 25, 25, 37, 23)
n=c(50, 100, 96, 57, 56, 54,50, 90, 96, 57, 56, 54,60, 110, 66, 37, 56, 54)
year=c(2019,2019,2019,2019,2019,2019, 2020,2020,2020,2020,2020,2020,2021,2021,2021,2021,2021,2021)

df=data.frame(year,var,gender,n,p)
df$var=factor(df$var, levels=c("Black","Asian","White"))
df$year=factor(df$year, levels=c(2019, 2020, 2021))

# Create graphs for men
men1=ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 150)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed")

men2=ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 100)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed")

# Combine graphs
men_combined=ggarrange(men1, men2,
                 nrow=1, ncol=2
)

# Add title to figure
men_combined=annotate_figure(men_combined, 
                       top = text_grob("\nMen",
                                       color = "black", face = "bold", size = 25))

# Create graphs for women
women1=ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 150)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed")

women2=ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 100)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        legend.position="none",
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed")

# Combine graphs
women_combined=ggarrange(women1, women2,
                       nrow=1, ncol=2
)

# Add title to figure
women_combined=annotate_figure(women_combined, 
                             top = text_grob("\nWomen",
                                             color = "black", face = "bold", size = 25))

# Combine all together
    all_plots=ggarrange(men_combined, women_combined,
                       nrow=2, ncol=1)`

I have tried using the following to help and I was able to get a common legend but it then did not work when I tried using annotate_figure as I need to have a title above each to show the gender. Add a common Legend for combined ggplots

This is code I used which then did not work when I added the 'Men' and 'Women' titles:

grid_arrange_shared_legend <- function(..., nrow = 1, ncol = length(list(...)), position = c("bottom", "right")) {
    
    plots <- list(...)
    position <- match.arg(position)
    g <- ggplotGrob(plots[[1]] + theme(legend.position = position))$grobs
    legend <- g[[which(sapply(g, function(x) x$name) == "guide-box")]]
    lheight <- sum(legend$height)
    lwidth <- sum(legend$width)
    gl <- lapply(plots, function(x) x + theme(legend.position = "none"))
    gl <- c(gl, nrow = nrow, ncol = ncol)
    
    combined <- switch(position,
                       "bottom" = arrangeGrob(do.call(arrangeGrob, gl),
                                              legend,
                                              ncol = 1,
                                              heights = unit.c(unit(1, "npc") - lheight, lheight)),
                       "right" = arrangeGrob(do.call(arrangeGrob, gl),
                                             legend,
                                             ncol = 2,
                                             widths = unit.c(unit(1, "npc") - lwidth, lwidth)))
    grid.newpage()
    grid.draw(combined)
    
}

grid_arrange_shared_legend(men1, men2, women1, women2, nrow = 2, ncol = 2)

This is what the code came out with which is exactly what I want but it needs to have a 'Men' and 'Women' title:

Please help!! :)

Share Improve this question asked Nov 21, 2024 at 20:04 Vicki LathamVicki Latham 674 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 2

Instead of creating and combining 4 individual plots, you could use a facet_ function to create small multiples. I'm using ggh4x::facet_grid2 specifically to get independent y-axis scales. To more directly answer the question, I also include an approach for collecting legends with patchwork below.

library(dplyr)
library(tidyr)
library(ggh4x)
#> Loading required package: ggplot2


df |>
  pivot_longer(cols = c(n, p)) |>
  ggplot(aes(x = year, y = value, group = var, colour = var)) +
  geom_line() +
  facet_grid2(gender ~ name,
             independent = "y",
             scales = "free_y",
             labeller = labeller(name = c(n = "Number diagnosed",
                                          p = "Proportion diagnosed"))) +
  labs(colour = "") +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)),
        legend.position = "bottom",
        strip.background = element_blank())

library(ggplot2)
library(patchwork)

# Create graphs for men
men1 <- ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 150)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed", title = "Men")

men2 <- ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 100)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed", title = "Men")


# Create graphs for women
women1 <- ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 150)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed", title = "Women")

women2 <- ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  scale_y_continuous(expand = expansion(mult = c(0, .06)), limits = c(0, 100)) +
  theme(text=element_text(size=12),
        axis.text = element_text(size=12),
        axis.title = element_text(size=12, face="bold"),
        axis.line.y=element_blank(),
        plot.title.position="plot",
        plot.subtitle=element_text(size=12, face="bold", margin = margin(b = 2)))+
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed", title = "Women")


men1 + men2 + women1 + women2 + plot_layout(guides = 'collect')

Created on 2024-11-21 with reprex v2.1.1

You can use patchwork::wrap_elements like this

library(patchwork)
library(dplyr)
library(ggplot2)



men1=ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed") +
  theme(legend.position = 'none')

men2=ggplot(data=df %>% filter(gender=="Men"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed") +
  theme(legend.position = 'none')

women1=ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=n,group=var, colour=var))+
  geom_line() +
  labs(x = NULL, y = NULL, subtitle = "Number diagnosed") +
  theme(legend.position = 'none')

women2=ggplot(data=df %>% filter(gender=="Women"), aes(x=year,y=p,group=var, colour=var))+
  geom_line() +
  labs(x = NULL, y = NULL, subtitle = "Proportion diagnosed")


men_plot = men1 + men2 + plot_annotation(subtitle = 'Men') 

women_plot = women1 + women2 + plot_annotation(subtitle = 'Women') + plot_layout(guides = 'collect') & theme(legend.position = 'bottom')


wrap_elements(men_plot)/ wrap_elements(women_plot)

Created on 2024-11-21 with reprex v2.1.1

本文标签: rCombining ggplots and creating one combined legendStack Overflow