Closed jbengler closed 3 weeks ago
I found something that works. Might not be pretty, though.
library(patchwork)
library(ggplot2)
p1 <- ggplot(mtcars) +
geom_point(aes(mpg, disp)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_boxplot(aes(gear, disp, group = gear)) +
ggtitle('Plot 2')
p3 <- ggplot(mtcars) +
geom_point(aes(hp, wt, colour = mpg)) +
ggtitle('Plot 3')
p4 <- ggplot(mtcars) +
geom_bar(aes(gear)) +
ggtitle('Plot 4')
patchwork <-
p1 + p2 + p3 + p4 +
plot_layout(
ncol = 4,
widths = unit(c(50, 25, 50, 25), "mm"),
heights = unit(50, "mm"),
guides = "collect"
)
gtab <- patchwork:::plot_table(patchwork, 'auto')
overall_width <- grid::convertWidth(sum(gtab$widths) + unit(1, "mm"), unitTo = "mm", valueOnly = TRUE)
overall_height <- grid::convertHeight(sum(gtab$heights) + unit(1, "mm"), unitTo = "mm", valueOnly = TRUE)
ggsave("test_patchwork.pdf", width = overall_width, height = overall_height, unit = "mm", useDingbats = FALSE)
Here, the solution from above wrapped in a function called bro_ggsave()
.
Ideas to solve this more elegantly are welcome.
devtools::install_github("thomasp85/patchwork")
library(patchwork)
library(tidyverse)
p1 <- ggplot(mtcars) +
geom_point(aes(mpg, disp)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_boxplot(aes(gear, disp, group = gear)) +
ggtitle('Plot 2')
p3 <- ggplot(mtcars) +
geom_point(aes(hp, wt, colour = mpg)) +
ggtitle('Plot 3')
p4 <- ggplot(mtcars) +
geom_bar(aes(gear)) +
ggtitle('Plot 4')
patchwork <-
p1 + p2 + p3 + p4 +
plot_layout(
ncol = 4,
widths = unit(c(50, 25, 50, 25), "mm"),
heights = unit(50, "mm"),
guides = "collect"
)
bro_get_ggsize <- function(plot) {
gtab <- patchwork:::plot_table(plot, 'auto')
has_fixed_dimensions <-
!gtab$widths %>% map(~is.null(attr(.x, "unit"))) %>% unlist() %>% any() |
!gtab$heights %>% map(~is.null(attr(.x, "unit"))) %>% unlist() %>% any()
if (has_fixed_dimensions) {
width <- grid::convertWidth(sum(gtab$widths) + unit(1, "mm"), unitTo = "mm", valueOnly = TRUE)
height <- grid::convertHeight(sum(gtab$heights) + unit(1, "mm"), unitTo = "mm", valueOnly = TRUE)
c(width = width, height = height)
} else {
c(width = NA, height = NA)
}
}
bro_get_ggsize(p1)
bro_get_ggsize(patchwork)
bro_ggsave <- function(plot = last_plot(), filename, width = NA, height = NA, units = c("in", "cm", "mm"), ...) {
width <- bro_get_ggsize(plot)[["width"]]
height <- bro_get_ggsize(plot)[["height"]]
if(!is.na(width)) message("Saving plot with fixed dimensions: ", round(width, 1), " x ", round(height, 1), " mm")
ggsave(filename = filename, plot = plot, width = width, height = height, units = "mm", ...)
}
bro_ggsave(p1, "bro_test_p1.pdf")
ggsave(plot = p1, filename = "test_p1.pdf")
bro_ggsave(patchwork, "bro_test_patchwork.pdf")
ggsave(plot = patchwork, filename = "test_patchwork.pdf")
It would be great to have an inbuilt function in the patchwork to calculate the resulting image size for these scenarios. I run in the same problem when I was trying to position correctly in an RMd a couple of “patchworked” plots where the heights was set to an equal amount.
Unfortunately the solution kindly provided by the @jbengler is not working for me. Do you have any idea how to solve it?
library(tidyverse)
library(patchwork)
p <- mtcars %>%
ggplot(aes(mpg, hp)) +
geom_smooth()
mtcars_10 <- p + p + p + p + p + p + p + p + p + p +
plot_layout(widths = unit(3, "in"), heights = unit(2, "in"))
bro_get_ggsize <- function(plot) {
gtab <- patchwork:::plot_table(plot, 'auto')
has_fixed_dimensions <-
!gtab$widths %>% map(~is.null(attr(.x, "unit"))) %>% unlist() %>% any() |
!gtab$heights %>% map(~is.null(attr(.x, "unit"))) %>% unlist() %>% any()
if (has_fixed_dimensions) {
width <- grid::convertWidth(sum(gtab$widths) + unit(1, "mm"), unitTo = "mm", valueOnly = TRUE)
height <- grid::convertHeight(sum(gtab$heights) + unit(1, "mm"), unitTo = "mm", valueOnly = TRUE)
c(width = width, height = height)
} else {
c(width = NA, height = NA)
}
}
bro_get_ggsize(mtcars_10)
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> width height
#> NA NA
gtab <- patchwork:::plot_table(mtcars_10, 'auto')
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
#> `geom_smooth()` using method = 'loess' and formula 'y ~ x'
gtab$widths
#> [1] 1.93302891933029mm 0mm 0mm 0mm
#> [5] 4.93526445966514mm 7.29597602739726mm 0mm 3inches
#> [9] 0mm 0mm 0mm 0mm
#> [13] 0mm 0mm 1.93302891933029mm 1.93302891933029mm
#> [17] 0mm 0mm 0mm 4.93526445966514mm
#> [21] 7.29597602739726mm 0mm 3inches 0mm
#> [25] 0mm 0mm 0mm 0mm
#> [29] 0mm 1.93302891933029mm 1.93302891933029mm 0mm
#> [33] 0mm 0mm 4.93526445966514mm 7.29597602739726mm
#> [37] 0mm 3inches 0mm 0mm
#> [41] 0mm 0mm 0mm 0mm
#> [45] 1.93302891933029mm 1.93302891933029mm 0mm 0mm
#> [49] 0mm 4.93526445966514mm 7.29597602739726mm 0mm
#> [53] 3inches 0mm 0mm 0mm
#> [57] 0mm 0mm 0mm 1.93302891933029mm
gtab$heights
#> [1] 1.93302891933029mm 0mm 0mm 0mm
#> [5] 0mm 0mm 0mm 0mm
#> [9] 0mm 2inches 0mm 4.91472602739726mm
#> [13] 4.93526445966514mm 0mm 0mm 0mm
#> [17] 0mm 1.93302891933029mm 1.93302891933029mm 0mm
#> [21] 0mm 0mm 0mm 0mm
#> [25] 0mm 0mm 0mm 2inches
#> [29] 0mm 4.91472602739726mm 4.93526445966514mm 0mm
#> [33] 0mm 0mm 0mm 1.93302891933029mm
#> [37] 1.93302891933029mm 0mm 0mm 0mm
#> [41] 0mm 0mm 0mm 0mm
#> [45] 0mm 2inches 0mm 4.91472602739726mm
#> [49] 4.93526445966514mm 0mm 0mm 0mm
#> [53] 0mm
It's working when removing the check for the has_fixed_dimensions
, just I have to add a bit more extra space to the width (10 mm instead 1 mm, but this can be case by case).
For anyone roaming here in the future, can replace gtab <- patchwork:::plot_table(plot, 'auto')
with gtab <- patchwork::patchworkGrob(plot)
which also seems to account for overhangs related to plot tags and so it's not necessary to add an extra mm of padding around the patchwork.
I'm going to close this. While nifty, and the above function works for your use case, it is generally not possible to know how much space a plot will take up before the graphics device is opened and I can't thus provide a general solution
Dear Thomas,
I really like the
plot_layout()
function you came up with!I often write something like this:
p1 + p2 + p3 + plot_layout(widths = unit(50, 'mm'), heights = unit(50, 'mm'))
Now, my question is, how to efficiently save this as a pdf with the correct dimensions. Is there a way to extract thewidth
andheight
of thepatchwork
to feed it intoggsave
for export? This would be really great!Thanks a lot and keep up the great work! Broder