Question

I'd like to a find a way to keep regular hexagons (all sides have equal length) when resizing hexbin plots in ggplot2 without manually adjusting the binwidth parameter.

To illustrate:

d <- ggplot(diamonds, aes(carat, price))+ 
  stat_binhex(colour="white")
try(ggsave(plot=d,filename=<some file>,height=6,width=8))

yields hexagons that at least look regular to the eye:ggplot2 stat_binhex plot1

And

try(ggsave(plot=d,filename=<some other file>,height=6,width=12))

yields irregular hexagons:ggplot2 stat_binhex plot2

The documentation describes the binwidth parameter (e.g. binwidth = c(1, 1000)) which specifies bin width. I'd like a function which, when given any plot size, returns the right binwidth settings to create regular hexagons.

Was it helpful?

Solution 2

Here's the solution to adjust binwidth dynamically. I've included handling for portrait aspect ratios and explicitly stated axis limits.

bins <- function(xMin,xMax,yMin,yMax,height,width,minBins) {
  if(width > height) {
    hbins = ((width/height)*minBins)
    vbins = minBins
  } else if (width < height) { 
    vbins = ((height/width)*minBins)
    hbins = minBins
  } else { 
    vbins = hbins = minBins
    }
  binwidths <- c(((xMax-xMin)/hbins),((yMax-yMin)/vbins))
  return(binwidths)
}

For example this code:

h = 5
w = 5
yMin = min(diamonds$price)
yMax = max(diamonds$price)
xMin = min(diamonds$carat)
xMax = max(diamonds$carat)
minBins = 30

d <- ggplot(diamonds, aes(x = carat, y = price))+ 
  stat_binhex(colour="white", binwidth = bins(xMin,xMax,yMin,yMax,h,w,minBins))+
  ylim(yMin,yMax)+
  xlim(xMin,xMax)
try(ggsave(plot=d,filename=<some file>,height=h,width=w))

Yields: graham jeffries - hexbin plot 1 And when we change the width:

w = 8
d <- ggplot(diamonds, aes(x = carat, y = price))+ 
  stat_binhex(colour="white", binwidth = bins(xMin,xMax,yMin,yMax,h,w,minBins))+
  ylim(yMin,yMax)+
  xlim(xMin,xMax)
try(ggsave(plot=d,filename=<some file>,height=h,width=w))

graham jeffries - hexbin plot 2

Or change the height:

h = 8
w = 5
d <- ggplot(diamonds, aes(x = carat, y = price))+ 
  stat_binhex(colour="white", binwidth = bins(xMin,xMax,yMin,yMax,h,w,minBins))+
  ylim(yMin,yMax)+
  xlim(xMin,xMax)
try(ggsave(plot=d,filename=<some file>,height=h,width=w))

graham jeffries - hexbin plot 3

We can also change the x and y limits:

h = 5
w = 5
xMin = -2

d <- ggplot(diamonds, aes(x = carat, y = price))+ 
  stat_binhex(colour="white", binwidth = bins(xMin,xMax,yMin,yMax,h,w,minBins))+
  ylim(yMin,yMax)+
  xlim(xMin,xMax)
try(ggsave(plot=d,filename=<some file>,height=h,width=w))

graham jeffries - hexbin plot 4

OTHER TIPS

Your choices are to set coord_fixed with an appropriate ratio so that the plot will not stretch over the size of the graphics device

In this case 5/17000 would appear reasonable

d <- ggplot(diamonds, aes(carat, price))+ 
  stat_binhex(colour="white") + coord_fixed(ratio = 5/17000)

The other option is to create the binwidths and ratio of the coordinate dimensions with the ratio of device dimensions in mind.

Unless the coordinate ratio is fixed (as per my first example), you can't expect to stretch the same plot into a window that is 1.5 times wider, without the plot looking stretched.

so if you are stretching the width by a factor of 1.5, then decrease the binwidth in the x dimension by a factor 1.5

d <- ggplot(diamonds, aes(carat, price))+ 
   stat_binhex(colour="white",bin.widths = c((5/45),17000/30 ))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top