r - Fixed aspect ratio prevents patchwork to collect axis titles - Stack Overflow

When merging axis labels with the patchwork package, problems occurred (see this question). From the an

When merging axis labels with the patchwork package, problems occurred (see this question). From the answer of the question, I applied the idea of the example code to my concrete example, in which I also used a fixed aspect ratio for each plot.

Here is the example code

library(ggplot2)
library(patchwork)

# Create different datasets for each plot
df1 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df1$z <- with(df1, dnorm(x, mean = 500, sd = 50) * dnorm(y, mean = 400, sd = 50))

df2 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df2$z <- with(df2, dnorm(x, mean = 600, sd = 50) * dnorm(y, mean = 450, sd = 50))

df3 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df3$z <- with(df3, dnorm(x, mean = 550, sd = 50) * dnorm(y, mean = 500, sd = 50))

df4 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df4$z <- with(df4, dnorm(x, mean = 650, sd = 50) * dnorm(y, mean = 350, sd = 50))

# Compute global min and max for z-values across all datasets
min_z <- min(c(df1$z, df2$z, df3$z, df4$z), na.rm = TRUE)
max_z <- max(c(df1$z, df2$z, df3$z, df4$z), na.rm = TRUE)

# Generate basic ggplot() objects with fixed aspect ratio
p_tmp <- lapply(list(df1, df2, df3, df4), function(df) {
  ggplot(df, aes(x, y, fill = z)) +
    geom_raster(interpolate = TRUE) +
    theme_minimal() +
    theme(
      aspect.ratio = 1,
      legend.position = "bottom",
      legend.box = "horizontal"
    )
})

plot_aspr <- wrap_plots(
    p_tmp,
    nrow = 2,
    ncol = 2,
    axis_titles = "collect",
    guides = "collect"
  ) +
  plot_annotation(
    title = "Emission-Excitation-Matrix",
    subtitle = "Rayleigh Filtered Data") &
  labs(
    x = "Emission Wavelength / nm",
    y = "Excitation Wavelength / nm"
  ) &
  scale_fill_viridis_c(limits = c(min_z, max_z)) &
  coord_cartesian(expand = FALSE)

print(plot_aspr)

and the corresponding plot. In this plot, the axis labels are not merged, but the legends are. In addition, the individual efficiencies are distributed here and have the desired square shape by definition.

Without the fixed aspect ratio

# Generate basic ggplot() objects without fixed aspect ratio

p_tmp <- lapply(list(df1, df2, df3, df4), function(df) {
  ggplot(df, aes(x, y, fill = z)) +
    geom_raster(interpolate = TRUE) +
    theme_minimal() +
    theme(
      legend.position = "bottom",
      legend.box = "horizontal"
    )
})

plot_noaspr <- wrap_plots(
    p_tmp,
    nrow = 2,
    ncol = 2,
    heights = rep(1, 2),
    widths = rep(1, 2),
    axis_titles = "collect",
    guides = "collect"
  ) +
  plot_annotation(
    title = "Emission-Excitation-Matrix",
    subtitle = "Rayleigh Filtered Data") &
  labs(
    x = "Emission Wavelength / nm",
    y = "Excitation Wavelength / nm"
  ) &
  scale_fill_viridis_c(limits = c(min_z, max_z)) &
  coord_cartesian(expand = FALSE)

print(plot_noaspr)

results in the following plot for the same data set:

In this case, both the axis labels and the legends are combined. One shortcoming here is that the shape of the individual graphs in the overall graph is not automatically perfectly square. Based on the results, I conclude that axis_title = "collect" from patchwork is not compatible with aspect.ratio, but is compatible with guide = "collect". Hence the question of whether this is desired or a bug.

Edit:

After posting this question, I found an interesting question and article regarding this topic. However, the problem was mainly the alignment of the graphs and not the combination of their axis titles.

When merging axis labels with the patchwork package, problems occurred (see this question). From the answer of the question, I applied the idea of the example code to my concrete example, in which I also used a fixed aspect ratio for each plot.

Here is the example code

library(ggplot2)
library(patchwork)

# Create different datasets for each plot
df1 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df1$z <- with(df1, dnorm(x, mean = 500, sd = 50) * dnorm(y, mean = 400, sd = 50))

df2 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df2$z <- with(df2, dnorm(x, mean = 600, sd = 50) * dnorm(y, mean = 450, sd = 50))

df3 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df3$z <- with(df3, dnorm(x, mean = 550, sd = 50) * dnorm(y, mean = 500, sd = 50))

df4 <- expand.grid(x = seq(300, 800, length.out = 50), y = seq(300, 600, length.out = 50))
df4$z <- with(df4, dnorm(x, mean = 650, sd = 50) * dnorm(y, mean = 350, sd = 50))

# Compute global min and max for z-values across all datasets
min_z <- min(c(df1$z, df2$z, df3$z, df4$z), na.rm = TRUE)
max_z <- max(c(df1$z, df2$z, df3$z, df4$z), na.rm = TRUE)

# Generate basic ggplot() objects with fixed aspect ratio
p_tmp <- lapply(list(df1, df2, df3, df4), function(df) {
  ggplot(df, aes(x, y, fill = z)) +
    geom_raster(interpolate = TRUE) +
    theme_minimal() +
    theme(
      aspect.ratio = 1,
      legend.position = "bottom",
      legend.box = "horizontal"
    )
})

plot_aspr <- wrap_plots(
    p_tmp,
    nrow = 2,
    ncol = 2,
    axis_titles = "collect",
    guides = "collect"
  ) +
  plot_annotation(
    title = "Emission-Excitation-Matrix",
    subtitle = "Rayleigh Filtered Data") &
  labs(
    x = "Emission Wavelength / nm",
    y = "Excitation Wavelength / nm"
  ) &
  scale_fill_viridis_c(limits = c(min_z, max_z)) &
  coord_cartesian(expand = FALSE)

print(plot_aspr)

and the corresponding plot. In this plot, the axis labels are not merged, but the legends are. In addition, the individual efficiencies are distributed here and have the desired square shape by definition.

Without the fixed aspect ratio

# Generate basic ggplot() objects without fixed aspect ratio

p_tmp <- lapply(list(df1, df2, df3, df4), function(df) {
  ggplot(df, aes(x, y, fill = z)) +
    geom_raster(interpolate = TRUE) +
    theme_minimal() +
    theme(
      legend.position = "bottom",
      legend.box = "horizontal"
    )
})

plot_noaspr <- wrap_plots(
    p_tmp,
    nrow = 2,
    ncol = 2,
    heights = rep(1, 2),
    widths = rep(1, 2),
    axis_titles = "collect",
    guides = "collect"
  ) +
  plot_annotation(
    title = "Emission-Excitation-Matrix",
    subtitle = "Rayleigh Filtered Data") &
  labs(
    x = "Emission Wavelength / nm",
    y = "Excitation Wavelength / nm"
  ) &
  scale_fill_viridis_c(limits = c(min_z, max_z)) &
  coord_cartesian(expand = FALSE)

print(plot_noaspr)

results in the following plot for the same data set:

In this case, both the axis labels and the legends are combined. One shortcoming here is that the shape of the individual graphs in the overall graph is not automatically perfectly square. Based on the results, I conclude that axis_title = "collect" from patchwork is not compatible with aspect.ratio, but is compatible with guide = "collect". Hence the question of whether this is desired or a bug.

Edit:

After posting this question, I found an interesting question and article regarding this topic. However, the problem was mainly the alignment of the graphs and not the combination of their axis titles.

Share Improve this question edited Mar 25 at 18:38 M-- 29.5k10 gold badges69 silver badges106 bronze badges Recognized by R Language Collective asked Mar 25 at 13:37 ExcelsiorExcelsior 2671 silver badge5 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 4

I didn't give it much thought to be able to explain the reason for this, but using unit(rep(1,2), rep("in",2)) instead of rep(1,2) for widths/heights seems to work. I have also used design instead of nrow/ncol to have more control over overall plotting area. Moreover, I had to move theme(...) to the end of patchwork code.

p_tmp <- lapply(list(df1, df2, df3, df4), function(df) {
  ggplot(df, aes(x, y, fill = z)) +
    geom_raster(interpolate = TRUE) +
    theme_minimal()
})

wrap_plots(p_tmp,
           design = "AAAAABBBBB
                     AAAAABBBBB
                     AAAAABBBBB
                     AAAAABBBBB
                     AAAAABBBBB
                     CCCCCDDDDD
                     CCCCCDDDDD
                     CCCCCDDDDD
                     CCCCCDDDDD
                     CCCCCDDDDD",
  widths = unit(rep(1,2), rep("cm",2)),
  heights = unit(rep(1,2), rep("cm",2)),
  axis_titles = "collect",
  guides = "collect") +
  plot_annotation(title = "Emission-Excitation-Matrix",
                  subtitle = "Rayleigh Filtered Data") &
  labs(x = "Emission Wavelength / nm",
       y = "Excitation Wavelength / nm") &
  scale_fill_viridis_c(limits = c(min_z, max_z)) &
  coord_cartesian(expand = FALSE) &
  theme(legend.position = "bottom",
        legend.box = "horizontal")

This gives us the aspect ratio of 1:

 

As per the dev's comment on this patchwork GitHub ticket:

there is no way to ensure that plots with fixed aspects are actually occupying the same vertical or horizontal space when resizing the plot so collecting the axes doesn't make sense in general.

This is perhaps why aspect.ratio overrides axis_titles = "collect", alluded to in the Fixed aspect plots section of the Patchwork: Controlling Layouts doc:

It is not possible to simultaneously assign even dimensions and align fixed aspect plots

which, if I'm interpreting this correctly, means patchwork is forced to 'choose' and aspect.ratio subsequently overrides any previously defined parameters. However, your desired outcome can be achieved using the patchwork::plot_layout() function.

As per my answer on your linked question, it's better to keep plot elements in your list of ggplot() objects to the bare minimum, and instead assign things like titles inside wrap_plots().

library(ggplot2)
library(patchwork)

# Generate basic ggplot() objects as a list
p_tmp <- lapply(list(df1, df2, df3, df4), function(df) {
  ggplot(df, aes(x, y, fill = z)) +
    geom_raster(interpolate = TRUE) +
    theme_minimal()
})

wrap_plots(p_tmp,
           nrow = 2,
           ncol = 2,
           axis_titles = "collect",
           guides = "collect") +
  plot_layout(widths = unit(rep(4,2), rep("cm", 2)),
              heights = unit(rep(4,2), rep("cm", 2))) +
  plot_annotation(title = "Emission-Excitation-Matrix",
                  subtitle = "Rayleigh Filtered Data") &
  labs(x = "Emission Wavelength / nm",
       y = "Excitation Wavelength / nm") &
  scale_fill_viridis_c(limits = c(min_z, max_z)) &
  coord_cartesian(expand = FALSE) &
  theme(legend.position = "bottom",
        legend.box = "horizontal")

I checked the x/y plot panel dimensions in an external editor and they are the same for each panel.

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

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

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

关注微信