# Hexagon binning using Google Maps

I have a bunch of geolocated points that I am looking to cluster on a google map using hexagons. These clusters will be stored in a db for quick retrieval and will be reduced to a single point and radius. I am using the http://www.geocodezip.com/v3_MW_example_eshapes.html library to draw the hexagons but because of the mercator projection the hexs overlap at higher latitudes.

Here is a jsfiddle attempt with the overlap http://jsfiddle.net/kworthin/Lkuqykog/2 • So it seems the solution is hidden within the following library github.com/d3/d3-plugins/blob/master/hexbin/hexbin.js. Ultimately being able to determine which hex a map point should be placed by returning the lat/lng position of the hex based on a specific hex size would satisfy the objective. Oct 24 '14 at 15:00
• Here is a simpler example using squares jsfiddle.net/kworthin/388a1fb0 Surely someone knows how to prevent this overlap while keeping the shapes uniform. Apologies for calling you Surely :) Oct 28 '14 at 3:06

If you're pregenerating the hex information, as your question suggests, you could use my R package dggridR to generate the hexagons' boundaries.

dggridR uses some rather complicated maths to tile the entire Earth with non-overlapping, equally-sized hexagons.

Here's an example of how you might use dggridR to create the grid you need:

``````#Include libraries
library(dggridR)
library(dplyr)
library(OpenStreetMap)
library(rgdal)

#Construct a global grid with cells approximately 10 miles across
dggs          <- dgconstruct(spacing=10, metric=FALSE, resround='down')

nylat = 40.7127
nylon = -74.0059

#Generate a bunch of random points
lats <- runif(100,nylat-1,nylat+1)
lons <- runif(100,nylon-1,nylon+1)
df   <- data.frame(lat=lats, lon=lons)

#Get the corresponding hexagonal grid cells for each point
df\$cell <- dgtransform(dggs,df\$lat,df\$lon)

#Get the number of points in each cell
pcounts <- df %>% group_by(cell) %>% summarise(count=n())

#Get the grid cell boundaries for the the points in a form suitable for plotting
grid    <- dgcellstogrid(dggs,df\$cell,frame=TRUE)

#Update the grid cells' properties to include the number of points
grid    <- merge(grid,pcounts,by.x="Name",by.y="cell")

#Get a street map of the area
map   <- openmap(c(nylat+1,nylon-1),c(nylat-1,nylon+1),type='osm')
mapLL <- openproj(map)
plot(mapLL)

#Plot everything on a flat map
p<-autoplot(mapLL)

p<- p+    geom_polygon(data=grid,      aes(x=long, y=lat, group=group, fill=count), alpha=0.4)    +
geom_path   (data=grid,      aes(x=long, y=lat, group=group), alpha=0.4, color="white") +
p
`````` Okay, it works! Now let's save the grid, with the data, to somewhere it can be read by other programs:

``````#Get the grid cell boundaries in a form suitable for printing to a KML file
grid <- dgcellstogrid(dggs,df\$cell,frame=FALSE)

#Update the grid cells' properties to include the number of earthquakes
#in each cell
grid@data\$count <- merge(grid@data, pcounts, by.x="Name", by.y="cell", all.x=TRUE)\$count

#Write out the grid
writeOGR(grid, "ny_grid.kml", "cells", "KML")
``````
• Thanks so much for sharing Richard. This is a super cool library you have written. Sep 5 '18 at 17:42
• Does this library require that the grid be pre-generated for the entire world? Or can an arbitrary set of bounds by chosen, and the bounds of a grid will be generated for that area? If so, say I chose a different set of bounds, will the second grid line up with the first if I was to later generate a grid in between them? Ie. I can select any arbitrary area and have a grid that is scaled, aligned, and positioned to match any other grid in any other area (I could make a "line" of hexagons between the areas and they would all align). Jan 9 '20 at 5:04
• Can select regions to generate cells for but the cells are pinned to the globe and so generate the same regardless of order or union of generation regions. Jan 9 '20 at 5:22