How to Fix the Aspect Ratio in Ggplot

How to fix the aspect ratio in ggplot?

In ggplot the mechanism to preserve the aspect ratio of your plot is to add a coord_fixed() layer to the plot. This will preserve the aspect ratio of the plot itself, regardless of the shape of the actual bounding box.

(I also suggest you use ggsave to save your resulting plot to pdf/png/etc, rather than the pdf(); print(p); dev.off() sequence.)

library(ggplot2)
df <- data.frame(
x = runif(100, 0, 5),
y = runif(100, 0, 5))

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

Sample Image

ggplot2: aspect.ratio overpowers coord_equal or coord.fixed

You can force the plot to be square by manually setting the scale of the axes:

gg +
scale_x_continuous(limits=c(min(xy$x,xy$y), max(xy$x,xy$y))) +
scale_y_continuous(limits=c(min(xy$x,xy$y), max(xy$x,xy$y))) +
theme(aspect.ratio=1)

How do I fix an aspect ratio in ggplot2's geom_hex?

One option is to extract the size of the plotting area (in axis units) from the ggplot, then scale the hexagons (using binwidth rather than bins argument) based on the ratio.

plt1 = ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length)) +
geom_hex()

xrange = diff(ggplot_build(plt1)$layout$panel_params[[1]]$x.range)
yrange = diff(ggplot_build(plt1)$layout$panel_params[[1]]$y.range)
ratio = xrange/yrange
xbins = 10
xwidth = xrange/xbins
ywidth = xwidth/ratio
plt1 = ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length)) +
geom_hex(binwidth = c(xwidth,ywidth)) +
coord_fixed(ratio = ratio)
ggsave("plot1.pdf", plt1, width = 5, height = 4)

Sample Image

Or, if you prefer the plotting area to have an aspect ratio the same as the page, rather than square, then you can adjust the ratio accordingly:

width = 5 
height = 4
ratio = (xrange/yrange) * (height/width)

xwidth = xrange/xbins
ywidth = xwidth/ratio
plt1 = ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length)) +
geom_hex(binwidth = c(xwidth,ywidth)) +
coord_fixed(ratio = ratio)

ggsave("plot1.pdf", plt1, width = width, height = height)

Sample Image

Maintaining Aspect Ratio of Shapes and Images in ggplot/ ggimage

A different approach would be to not use ggimage - e.g., use cowplot for custom annotation, makes it super simple to add an image.

library(ggplot2)
library(cowplot)

p <- ggplot(mpg) +
see::geom_point2(aes(x = displ, y = hwy, size = cty), alpha = 0.2) +
scale_size_identity()

ggdraw(p) +
draw_image("https://upload.wikimedia.org/wikipedia/commons/d/de/Windows_live_square.JPG",
x = .5, y = .3, width = 0.5, height = 0.5)

Sample Image

Created on 2021-02-13 by the reprex package (v1.0.0)

Or, use the ggtextures package, with a little tweak of the coordinate system

this discussion seems relevant

library(ggtextures)
library(ggplot2)
library(tibble)
img_df <- tibble(
xmin = 1, ymin = 1, xmax = 4, ymax = 4,
image = "https://upload.wikimedia.org/wikipedia/commons/d/de/Windows_live_square.JPG"
)

ggplot(mpg) +
see::geom_point2(aes(x = displ, y = hwy, size = cty), alpha = 0.2) +
geom_textured_rect(data = img_df,
aes(xmin = xmin, xmax = xmax,
ymin = ymin, ymax = ymax, image = image),
nrow = 1,
ncol = 1,
img_width = unit(1, "null"),
img_height = unit(1, "null"),
position = "identity") +
coord_equal() # this is then necessary...

Sample Image

Created on 2021-02-13 by the reprex package (v1.0.0)

How can I adjust the size of two ggplots with a fixed aspect ratio in gridExtra?

EDIT after clarification:
We can use ylim(-150, 200) in plot1

library(gridExtra)
library(ggplot2)
data(mtcars)
lm1<-lm(disp~drat,data=mtcars)
lm2<-lm(hp~drat,data=mtcars)
lm3<-lm(disp~hp,data=mtcars)
residuals<-data.frame(lm1=residuals(lm1),lm2=residuals(lm2),lm3=residuals(lm3))
(resid2<-grid.arrange(
ggplot(residuals,aes(lm1,lm2))+
geom_point(size=3,shape=21,fill="gray")+
ylim(-150, 200) +
theme_classic()+
ggtitle("Plot1")+
coord_fixed(),
ggplot(residuals,aes(lm1,lm3))+
geom_point(size=3,shape=21,fill="gray")+
ggtitle("Plot2")+
theme_classic()+
coord_fixed(),
nrow=1))

Sample Image

ggplot: keep circle looking round when aspect ratio != 1

You can provide the limits argument of the position scales as a function that takes the natural limits of the data as the argument. This works with a fixed aspect ratio, but doesn't automatically adapt to fit the available size in the graphics device.

library(tidyverse)

n = 100
radius = 1
circle <- tibble(x = accumulate(1:(n-1), ~ radius*cos(.y*2*pi/n), .init = radius),
y = accumulate(1:(n-1), ~ radius*sin(.y*2*pi/n), .init = 0))

asp <- 3 / 4

ggplot(circle) +
geom_point(aes(x,y), color = "red") +
scale_x_continuous(
limits = function(x) {
mid <- mean(x)
mid + c(-1, 1) * (1/asp) * 0.5 * diff(x)
}
) +
coord_equal()

Sample Image

Created on 2021-07-29 by the reprex package (v1.0.0)

ggplot2: Flip axes and maintain aspect ratio of data

I agree that the theme solution isn't really a proper one. Here is a solution that does work programatically by calculating the aspect from the actual axes ranges stored in the plot object, but it takes a few lines of code:

ranges <- ggplot_build(p)$layout$panel_ranges[[1]][c('x.range', 'y.range')]
sizes <- sapply(ranges, diff)
aspect <- sizes[1] / sizes[2]

p + coord_flip() + theme(aspect.ratio = aspect)

Sample Image

The solution I would probably use in practice, is to use the horizontal geoms in the ggstance package (although this may not always be feasible).

Note: This will only give the exact correct answer for two continuous scales with an equal multiplicative extend argument (i.e. the default).

edit: In many cases I would recommend using coord_equal combined with the ggstance package instead of this solution.



Related Topics



Leave a reply



Submit