r - Keeping two plots vertically aligned with ggplot2gridExtra - Stack Overflow

I am trying to merge multiple ggplot2 plots into a single picture, while retaining control over the res

I am trying to merge multiple ggplot2 plots into a single picture, while retaining control over the respective height of each element. The following code works well and it generates a barplot and a curve plot that are perfectly aligned to each other (see here):



library(ggplot2)
library(grid)
library(gridExtra)

# Save plot as PDF (set to NULL initially)
pdf(file = NULL)

# Data frame for the first plot
df_1 <- data.frame(
    data = c(0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.2, 0.2, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.4, 0.2,
             0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.5, 0.1, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.2, 0.2,
             0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.4, 0.2, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.5, 0.1,
             0.5, 0.1, 0.15, 0.5, 0.5, 0.4),
    base = 1:54,
    value = c(0.9557, 0.4407, 0.141, 3.4229, 3.5197, 4.7386, 6.9897, 0.3958, 4.7268, 1.8085,
              10.5312, 5.9011, 7.9393, 5.7363, 13.8539, 11.2096, 14.8407, 11.4008, 0.5412, 10.3042,
              11.3208, 15.6669, 8.2177, 12.6917, 20.7124, 10.9896, 24.7246, 7.0544, 21.0489, 16.4536,
              7.4753, 28.2106, 32.7284, 29.7557, 23.3567, 29.9186, 30.3813, 15.1307, 20.2323, 34.4262,
              20.8036, 18.7994, 41.7036, 26.828, 10.7628, 28.2335, 4.4982, 3.6528, 33.8571, 11.6208,
              43.54, 26.7859, 22.2176, 11.0588)
)

# First plot with ggplot
plot_1 <- ggplot(df_1, aes(x = base, y = data, fill = value)) +
    geom_bar(stat = 'identity', position = position_dodge(width = 0.9)) +
    scale_fill_distiller(palette = 'YlGnBu') +
    theme(
        axis.text.x = element_text(size = 9, angle = 0, vjust = 0.5),
        axis.text.y = element_text(size = 9),
        legend.position = 'right',
        legend.spacing.x = unit(5, 'pt'),
        legend.text = element_text(margin = margin(0, 0, 0, 0, 'pt'), size = 10),
        legend.key = element_rect(fill = NA),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),plot.margin = margin(0,0,0,0)
    ) +
    guides(
        colour = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        shape = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        fill = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5)
    )+
    xlim(0, 55)


# Data frame for the second plot
df_2 <- data.frame(
    x1 = c(4, 12, 1, 2),
    x2 = c(9, 15, 24, 54),
    y1 = c(0, 0, 0, 0),
    y2 = c(0, 0, 0, 0),
    priority = c('high', 'low', 'mid', 'high')
)

# Second plot with ggplot
plot_2 <- ggplot(df_2) +
    geom_curve(aes(x = x1, xend = x2, y = y1, yend = y2, color = priority),
               curvature = 1, linewidth = 0.5, ncp = 1000) +
    expand_limits(y = -1) +
    coord_fixed(ratio = 22, ylim = c(-1, 0)) +
    scale_colour_brewer(palette = 'YlGnBu') +
    theme(

        legend.position = 'right',
        legend.spacing.x = unit(5, 'pt'),
        legend.text = element_text(margin = margin(0, 0, 0, 0, 'pt'), size = 10),
        legend.key = element_rect(fill = NA),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),plot.margin = margin(0,0,0,0)
    ) +
    guides(
        colour = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        shape = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        fill = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5)
    ) +
    xlim(0, 55)


# List of ggplot objects
plots <- list(plot_1, plot_2)  # Add as many plots as you need

# Apply a small margin to each plot to reduce extra white space
plots_adjusted <- lapply(plots, "+", theme(plot.margin = margin(0, 0, 0, 0)))

# Convert adjusted plots to gtables
grob_plots <- lapply(plots_adjusted, ggplotGrob)

# Calculate the maximum widths across all plots
max_widths <- do.call(unit.pmax, lapply(grob_plots, function(g) g$widths))

# Set each plot's widths to the calculated maximum widths
grob_plots <- lapply(grob_plots, function(g) { g$widths <- max_widths; g })

# Arrange the grobs with specific heights
combined_plot <- arrangeGrob(grobs = grob_plots, heights = unit(c(1,1), "null"), padding = unit(0, "pt"))


dev.off()

# Save the combined plot to a file
ggsave("~/Downloads/mytest.pdf", combined_plot,dpi = 300)

However, when I try to modify the width on the output PDF file in ggsave() (for example by setting width=20), the relative proportions of the plots are lost, and only the first one is extended to fill the print area (see here).

Can you advise me on how to fix this?

I am trying to merge multiple ggplot2 plots into a single picture, while retaining control over the respective height of each element. The following code works well and it generates a barplot and a curve plot that are perfectly aligned to each other (see here):



library(ggplot2)
library(grid)
library(gridExtra)

# Save plot as PDF (set to NULL initially)
pdf(file = NULL)

# Data frame for the first plot
df_1 <- data.frame(
    data = c(0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.2, 0.2, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.4, 0.2,
             0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.5, 0.1, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.2, 0.2,
             0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.4, 0.2, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.5, 0.1,
             0.5, 0.1, 0.15, 0.5, 0.5, 0.4),
    base = 1:54,
    value = c(0.9557, 0.4407, 0.141, 3.4229, 3.5197, 4.7386, 6.9897, 0.3958, 4.7268, 1.8085,
              10.5312, 5.9011, 7.9393, 5.7363, 13.8539, 11.2096, 14.8407, 11.4008, 0.5412, 10.3042,
              11.3208, 15.6669, 8.2177, 12.6917, 20.7124, 10.9896, 24.7246, 7.0544, 21.0489, 16.4536,
              7.4753, 28.2106, 32.7284, 29.7557, 23.3567, 29.9186, 30.3813, 15.1307, 20.2323, 34.4262,
              20.8036, 18.7994, 41.7036, 26.828, 10.7628, 28.2335, 4.4982, 3.6528, 33.8571, 11.6208,
              43.54, 26.7859, 22.2176, 11.0588)
)

# First plot with ggplot
plot_1 <- ggplot(df_1, aes(x = base, y = data, fill = value)) +
    geom_bar(stat = 'identity', position = position_dodge(width = 0.9)) +
    scale_fill_distiller(palette = 'YlGnBu') +
    theme(
        axis.text.x = element_text(size = 9, angle = 0, vjust = 0.5),
        axis.text.y = element_text(size = 9),
        legend.position = 'right',
        legend.spacing.x = unit(5, 'pt'),
        legend.text = element_text(margin = margin(0, 0, 0, 0, 'pt'), size = 10),
        legend.key = element_rect(fill = NA),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),plot.margin = margin(0,0,0,0)
    ) +
    guides(
        colour = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        shape = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        fill = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5)
    )+
    xlim(0, 55)


# Data frame for the second plot
df_2 <- data.frame(
    x1 = c(4, 12, 1, 2),
    x2 = c(9, 15, 24, 54),
    y1 = c(0, 0, 0, 0),
    y2 = c(0, 0, 0, 0),
    priority = c('high', 'low', 'mid', 'high')
)

# Second plot with ggplot
plot_2 <- ggplot(df_2) +
    geom_curve(aes(x = x1, xend = x2, y = y1, yend = y2, color = priority),
               curvature = 1, linewidth = 0.5, ncp = 1000) +
    expand_limits(y = -1) +
    coord_fixed(ratio = 22, ylim = c(-1, 0)) +
    scale_colour_brewer(palette = 'YlGnBu') +
    theme(

        legend.position = 'right',
        legend.spacing.x = unit(5, 'pt'),
        legend.text = element_text(margin = margin(0, 0, 0, 0, 'pt'), size = 10),
        legend.key = element_rect(fill = NA),
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),plot.margin = margin(0,0,0,0)
    ) +
    guides(
        colour = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        shape = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
        fill = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5)
    ) +
    xlim(0, 55)


# List of ggplot objects
plots <- list(plot_1, plot_2)  # Add as many plots as you need

# Apply a small margin to each plot to reduce extra white space
plots_adjusted <- lapply(plots, "+", theme(plot.margin = margin(0, 0, 0, 0)))

# Convert adjusted plots to gtables
grob_plots <- lapply(plots_adjusted, ggplotGrob)

# Calculate the maximum widths across all plots
max_widths <- do.call(unit.pmax, lapply(grob_plots, function(g) g$widths))

# Set each plot's widths to the calculated maximum widths
grob_plots <- lapply(grob_plots, function(g) { g$widths <- max_widths; g })

# Arrange the grobs with specific heights
combined_plot <- arrangeGrob(grobs = grob_plots, heights = unit(c(1,1), "null"), padding = unit(0, "pt"))


dev.off()

# Save the combined plot to a file
ggsave("~/Downloads/mytest.pdf", combined_plot,dpi = 300)

However, when I try to modify the width on the output PDF file in ggsave() (for example by setting width=20), the relative proportions of the plots are lost, and only the first one is extended to fill the print area (see here).

Can you advise me on how to fix this?

Share Improve this question asked Nov 17, 2024 at 14:41 steven_oppsteven_opp 453 bronze badges 2
  • Have you looked at the patchwork package? library(patchwork); plot_1 / plot_2 might do the whole thing for you and should align perfectly – Allan Cameron Commented Nov 17, 2024 at 21:08
  • Unfortunately it doesn't... it aligns things, but the size stays the same, no matter how the whole print area is resized. – steven_opp Commented Nov 17, 2024 at 22:03
Add a comment  | 

1 Answer 1

Reset to default 1

As pointed out in the comments, combining the plots using patchwork will keep them aligned. To control the height of each plot, you can use the height argument in the patchwork::plot_layout function. However, this only works if you remove the coord_fixed argument from plot_2.

library(ggplot2)
library(patchwork)

# Data frame for the first plot
df_1 <- data.frame(
  data = c(0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.2, 0.2, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.4, 0.2,
           0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.5, 0.1, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.2, 0.2,
           0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.4, 0.2, 0.25, 0.5, 0.1, 0.15, 0.5, 0.5, 0.5, 0.1,
           0.5, 0.1, 0.15, 0.5, 0.5, 0.4),
  base = 1:54,
  value = c(0.9557, 0.4407, 0.141, 3.4229, 3.5197, 4.7386, 6.9897, 0.3958, 4.7268, 1.8085,
            10.5312, 5.9011, 7.9393, 5.7363, 13.8539, 11.2096, 14.8407, 11.4008, 0.5412, 10.3042,
            11.3208, 15.6669, 8.2177, 12.6917, 20.7124, 10.9896, 24.7246, 7.0544, 21.0489, 16.4536,
            7.4753, 28.2106, 32.7284, 29.7557, 23.3567, 29.9186, 30.3813, 15.1307, 20.2323, 34.4262,
            20.8036, 18.7994, 41.7036, 26.828, 10.7628, 28.2335, 4.4982, 3.6528, 33.8571, 11.6208,
            43.54, 26.7859, 22.2176, 11.0588)
)

# First plot with ggplot
plot_1 <- ggplot(df_1, aes(x = base, y = data, fill = value)) +
  geom_bar(stat = 'identity', position = position_dodge(width = 0.9)) +
  scale_fill_distiller(palette = 'YlGnBu') +
  theme(
    axis.text.x = element_text(size = 9, angle = 0, vjust = 0.5),
    axis.text.y = element_text(size = 9),
    legend.position = 'right',
    legend.spacing.x = unit(5, 'pt'),
    legend.text = element_text(margin = margin(0, 0, 0, 0, 'pt'), size = 10),
    legend.key = element_rect(fill = NA),
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),plot.margin = margin(0,0,0,0)
  ) +
  guides(
    colour = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
    shape = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
    fill = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5)
  )+
  xlim(0, 55)


# Data frame for the second plot
df_2 <- data.frame(
  x1 = c(4, 12, 1, 2),
  x2 = c(9, 15, 24, 54),
  y1 = c(0, 0, 0, 0),
  y2 = c(0, 0, 0, 0),
  priority = c('high', 'low', 'mid', 'high')
)

# Second plot with ggplot
plot_2 <- ggplot(df_2) +
  geom_curve(aes(x = x1, xend = x2, y = y1, yend = y2, color = priority),
             curvature = 1, linewidth = 0.5, ncp = 1000) +
  expand_limits(y = -1) +
  coord_fixed(ratio = 22, ylim = c(-1, 0)) +
  scale_colour_brewer(palette = 'YlGnBu') +
  theme(
    
    legend.position = 'right',
    legend.spacing.x = unit(5, 'pt'),
    legend.text = element_text(margin = margin(0, 0, 0, 0, 'pt'), size = 10),
    legend.key = element_rect(fill = NA),
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),plot.margin = margin(0,0,0,0)
  ) +
  guides(
    colour = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
    shape = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5),
    fill = guide_legend(label.position = 'right', title.position = 'top', title.hjust = 0.5)
  ) +
  xlim(0, 55)


p <- plot_1 / plot_2 


# Save the combined plot to a file
ggsave("~/Downloads/mytest.pdf", 
       p,
       width = 20, height = 10)

If you want to adjust the heights, you can do:

p <- plot_1 / plot_2 + plot_layout(heights = c(2,1))
p

To use a large width in ggsave, one option is to change the aspect ratio of the plot:

p <- plot_1 / plot_2 & 
  theme(aspect.ratio = 1/10)

ggsave("~/Downloads/mytest.pdf", 
       p,
       width = 40, height = 10)

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745635580a4637372.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信