How to Control the Canvas Size in Ggplot

How can I control the canvas size in ggplot?

Using the ggplot2 plot.margin and/or panel.margin theme options you should be able to control the internal margins, once you've adequately set the output dimensions of the canvas. This certainly will work for normal graphics devices and should also work within the shiny application:

library(ggplot2)
library(grid)

hex=c("#CC0000", "#90BD31", "#178CCB")

q <- ggplot(data=NULL)
q <- q + geom_rect(data=NULL, aes(xmin=0, xmax=1, ymin=0.5, ymax=1.5), fill=hex[1])
q <- q + geom_rect(data=NULL, aes(xmin=1.5, xmax=2.5, ymin=0.5, ymax=1.5), fill=hex[2])
q <- q + geom_rect(data=NULL, aes(xmin=3, xmax=4, ymin=0.5, ymax=1.5), fill=hex[3])
q <- q + annotate("text", x=.5, y=0.1, label='Impaired', size=4)
q <- q + annotate("text", x=2, y=0.1, label='Normal', size=4)
q <- q + annotate("text", x=3.5, y=0.1, label='Optimal', size=4)
q <- q + coord_fixed()
q <- q + theme_classic()
q <- q + theme(axis.line=element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks=element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
panel.background=element_blank(),
panel.border=element_blank(),
panel.grid.major=element_blank(),
panel.grid.minor=element_blank(),
plot.background=element_blank(),
plot.margin=unit(c(0,0,0,0), "cm"),
panel.margin=unit(c(0,0,0,0), "cm"))
q

No margin output

Can you change the proportions of the ggplot2 graph from square to rectangle?

To fix the ratio on the x and y-axis to some value (e.g. 1, or 0.2), you can use coord_fixed():

g + coord_fixed(ratio = 0.2)

where g is your original plot. You have to play around a bit to get what you need. In addition, like @Andrie said, you can also fix the canvas size, e.g. using ggsave:

print(g)
ggsave("/tmp/plt.png", width = 16, height = 9, dpi = 120)

I'd try out both, or maybe combine them. See also this earlier post.

How to keep consistent axes scaling in a grid of ggplot2 plots with different canvas size

Alright, I think I have gotten my best guess at what you are asking, though I agree with @MrFlick that explictly sharing data would be a huge help to that.

If you had simple data with all of your animals on the same basic grid, I am guessing you wouldn't be asking (at least not the way you are). That is, given these data:

set.seed(8675309)
df <-
data.frame(
x = runif(40, 1, 20)
, y = runif(40, 100, 140)
, ind = sample(LETTERS[1:4], 40, TRUE)
)

This straightforward facet_grid works:

ggplot(df , aes(x = x, y = y)) +
geom_point() +
facet_wrap(~ind) +
coord_fixed()

to give this:

Sample Image

But, you said that facet_wrap solutions wouldn't work. So, I am guessing that you have data where each animal is in a different grid, like this (note, using dplyr here and much more below):

modDF <-
df %>%
mutate(x = x + as.numeric(ind)*10
, y = y + as.numeric(ind)*20)

And that means that the above code (using modDF instead of df)

ggplot(modDF, aes(x = x, y = y)) +
geom_point() +
facet_wrap(~ind) +
coord_fixed()

gives this:

Sample Image

which has a ton of wasted space and doesn't look great. So, I think you are asking how to handle data like these. For that, I think what you need to do is calculate the largest range (in each axis) and then generate that range centered on the data for each individual. For that, I am relying heavily on dplyr to group_by individual and calculate the minimum and maximum x/y locations. Then, I calculate a number of additional columns to calculate the midpoint of the data for each individual, the size of the range, and then where the range should extend to be set to the largest width/height needed and be centered on that individual's data. Note that I am also padding these a little bit so that I can set expand = FALSE when I implement the ranges.

getRanges <-
modDF %>%
group_by(ind) %>%
summarise(
minx = min(x)
, maxx = max(x)
, miny = min(y)
, maxy = max(y)
) %>%
mutate(
# Find mid points for range setting
midx = (maxx + minx)/2
, midy = (maxy + miny)/2
# Find size of all ranges
, xrange = maxx - minx
, yrange = maxy - miny
# Set X lims the size of the biggest range, centered at the middle
, xstart = midx - max(xrange)/2 - 0.5
, xend = midx + max(xrange)/2 + 0.5
# Set Y lims the size of the biggest range, centered at the middle
, ystart = midy - max(yrange)/2 - 0.5
, yend = midy + max(yrange)/2 + 0.5
)

gives

     ind     minx     maxx     miny     maxy     midx     midy   xrange   yrange   xstart     xend   ystart     yend
<fctr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 A 14.91873 29.53871 120.0743 157.6944 22.22872 138.8844 14.61997 37.62010 14.17717 30.28027 119.5743 158.1944
2 B 22.50432 37.27647 153.5654 179.0589 29.89039 166.3122 14.77215 25.49352 21.83884 37.94195 147.0021 185.6222
3 C 32.15187 47.08845 165.9829 195.0261 39.62016 180.5045 14.93658 29.04320 31.56861 47.67171 161.1945 199.8146
4 D 44.49392 59.59702 192.7243 214.5523 52.04547 203.6383 15.10310 21.82806 43.99392 60.09702 184.3283 222.9484

Then, I loop through each individual, generating the plot needed and setting the range to what was calculated for that individual. (You could use ggtitle instead of facet_wrap but I like the strip effect from facet_wrap.)

sepPlots <- lapply(levels(modDF$ind), function(thisInd){
thisRange <-
filter(getRanges, ind == thisInd)

modDF %>%
filter(ind == thisInd) %>%
ggplot(aes(x = x, y = y)) +
geom_point() +
coord_fixed(
xlim = c(thisRange$xstart, thisRange$xend)
, ylim = c(thisRange$ystart, thisRange$yend)
, expand = FALSE
) +
# ggtitle(thisInd)
facet_wrap(~ind)
})

Then, I use plot_grid from cowplot to arrange the plots together. Note that loading cowplot sets a theme. So, I am resetting the theme because I am not a huge fan of the one from cowplot

library(cowplot)
theme_set(theme_gray())

plot_grid(plotlist = sepPlots)

gives:

Sample Image

From there, you can play around with scales and axis labels as you see fit.

Adjust the size of panels plotted through ggplot() and facet_grid

I'm sorry for unintended self promotion, but I wrote a function a while back to more precisely control the sizes of panels. I've put it in a package on github CRAN. I'm not sure how it'd work with a shiny app, but here is how you'd work with it in ggplot2.

You can control the relative sizes of the width/height by setting plain numbers for the rows/colums.

library(ggplot2)
library(ggh4x)

df <- expand.grid(1:12, 3:5)
df$x <- 1

ggplot(df, aes(x, x)) +
geom_point() +
facet_grid(Var1 ~ Var2) +
force_panelsizes(rows = 1, cols = 2, TRUE)

Sample Image

You can also control the absolute sizes of the panel by setting an unit object. Note that you can set them for individual rows and columns too if you know the number of panels in advance.

ggplot(df, aes(x, x)) +
geom_point() +
facet_grid(Var1 ~ Var2) +
force_panelsizes(rows = unit(runif(12) + 0.1, "cm"),
cols = unit(c(1, 5, 2), "cm"),
TRUE)

Sample Image

Created on 2020-05-05 by the reprex package (v0.3.0)

Hope that helped.

Set the size of ggsave exactly

To understand why the DPI is important, consider these two plots:

ggsave(filename = "foo300.png", ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point(size=2, shape=23) + theme_bw(base_size = 10),
width = 5, height = 4, dpi = 300, units = "in", device='png')
ggsave(filename = "foo150.png", ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point(size=2, shape=23) + theme_bw(base_size = 10),
width = 10, height = 8, dpi = 150, units = "in", device='png')

The resulting files have the same pixel dimensions, but the font size in each is different. If you place them on a page with the same physical size as their ggsave() calls, the font size will be correct (i.e. 10 as in the ggsave() call). But if you put them on a page at the wrong physical size, the font size won't be 10. To maintain the same physical size and font size while increasing DPI, you have to increase the number of pixels in the image.

Explicitly set panel size (not just plot size) in ggplot2

You can use set_panel_size() function from the egg package

library(tibble)
library(dplyr)
library(ggplot2)

ds_mt <- mtcars %>% rownames_to_column("model")
mt_short <- ds_mt %>% arrange(nchar(model)) %>% slice(1:4)
mt_long <- ds_mt %>% arrange(-nchar(model)) %>% slice(1:4)

p_short <-
mt_short %>%
ggplot(aes(x = model, y = mpg)) +
geom_col() +
coord_flip()

library(egg)
library(grid)
p_fixed <- set_panel_size(p_short,
width = unit(10, "cm"),
height = unit(4, "in"))
grid.newpage()
grid.draw(p_fixed)

Sample Image

Created on 2018-11-13 by the reprex package (v0.2.1.9000)



Related Topics



Leave a reply



Submit