Reputation: 371
I'd like to use geom_hex
to represent my counts, but I want the hexagons to be "square", with an aspect ratio 1:1.
I've seen coord_fixed
(and its alias coord_equal
), but these change the aspect ratio of the whole plotted area, while I'm interested in changing the aspect ratio of the hexagons themselves.
library(ggplot2)
# Here, in plot1.pdf, the hexagon aspect ratio is determined by
# the saved plot aspect ratio
plt1 <- ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length)) +
geom_hex(bins = 10)
ggsave("plot1.pdf", plt1, width = 5, height = 4)
# Here, in plot2.pdf, the hexagon aspect ratio is 1:1, but the
# plot doesn't fill the space well, particularly if the data change
ratio <- 2
plt2 <- ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length)) +
geom_hex(bins = 10 * c(1, ratio)) +
coord_fixed(ratio = ratio)
ggsave("plot2.pdf", plt2, width = 5, height = 4)
# In plot3.pdf, the only thing that's changed is the y-axis data,
# but the plot is unreadable because the x-axis is so compressed
ratio <- 2
plt3 <- ggplot(iris, aes(x = Sepal.Width, y = 5 * Sepal.Length)) +
geom_hex(bins = 10 * c(1, ratio)) +
coord_fixed(ratio = ratio)
ggsave("plot3.pdf", plt3, width = 5, height = 4)
In plot2.pdf
and plot3.pdf
above, the hexagons have a 1:1 aspect ratio, but the plots don't look good, because coord_fixed
has scaled the entire plotted area, not just the hexagons.
In each plot, I could tweak the bins
argument to get hexagons with an aspect ratio near 1:1, but I'd like to have the code pick automatically for me. Is there a way to say something like "pick 15 bins on the x-axis and however many bins are necessary on the y-axis to make the hexagons have a 1:1 aspect ratio"?
Upvotes: 1
Views: 536
Reputation: 31452
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)
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)
Upvotes: 2