Creates a HexGridInfo object that stores all parameters needed for hexagonal grid operations. Use this to define the grid once and pass it to all downstream functions.
Arguments
- area_km2
Target cell area in square kilometers. Mutually exclusive with
resolution.- resolution
Grid resolution level: for ISEA 0-30 for aperture 3, 0-29 for aperture 4, 0-21 for aperture 7 on the icosahedron, where the cell count stays within the 2^63 - 1 cell IDs a 64-bit integer numbers; 0-15 for H3. Mutually exclusive with
area_km2. For H3, typical use cases by resolution:0-3: continental/country scale
4-7: regional/city scale
8-10: neighborhood/block scale (FCC uses 8-9)
11-15: building/sub-meter scale
- aperture
Grid aperture: 3 (default), 4, 7, a mixed family such as "4/3", "4/7" or "7/4", or one aperture per resolution level as a vector, e.g.
c(4, 4, 7, 3). A family name refines by the first aperture for the firstfloor(resolution / 2)levels and by the second for the rest, which is how DGGRID arranges ISEA43H. A per-level vector needsresolutionrather thanarea_km2; one shorter thanresolutionrecurs, as OGC Topic 21 reads a list of refinement ratios, soc(4, 3)at resolution 5 refines by 4, 3, 4, 3, 4. It is stored as a comma-separated string with one aperture per level ("4,3,4,3,4"), whichaperturealso accepts. It names no level finer thanresolution, soget_children()needs a family name. Ignored for H3 grids (fixed at 7).- type
Grid type: "isea" (default) or "h3".
- resround
Resolution rounding when using
area_km2: "nearest" (default), "up", or "down".- crs
Coordinate reference system: an EPSG code, or a 'PROJ' or 'WKT' string. Defaults to 'WGS84' on Earth, and to a longlat CRS on the sphere of
radius_kmon any other body, which has no EPSG code to name it.- radius_km
Radius of the body the grid covers, in kilometers, or the name of a body: "mercury", "venus", "earth" (default), "moon", "mars", "ceres", "jupiter", "io", "europa", "ganymede", "callisto", "saturn", "enceladus", "titan", "uranus", "neptune", "pluto".
- orientation
Where the icosahedron of an ISEA grid sits on the sphere: "standard" (default), "dymaxion", "gosper", "random", "region", "face", or
c(vert0_lon, vert0_lat, azimuth)in degrees. See the Orientation section. H3 fixes its own orientation, so H3 grids take only "standard".- projection
How an ISEA-family grid projects each icosahedron face onto its plane triangle: "isea" (default), Snyder's equal-area projection, or "fuller", Fuller's projection. See the Projection section. H3 fixes its own projection, so H3 grids take only "isea".
- region
For
orientation = "region"or"face", the area to centre the grid on:c(lon, lat)in degrees, or an sf, sfc or bbox object, whose spherical centroid is used.- polyhedron
The solid an ISEA-family grid is built on: "icosahedron" (default) or "octahedron". See the Polyhedron section. H3 grids are built on the icosahedron and take only the default.
Details
Exactly one of area_km2 or resolution must be provided.
When area_km2 is provided, the resolution is calculated automatically
using the cell count formula: N = 10 * aperture^res + 2 (ISEA on the
icosahedron, 4 * aperture^res + 2 on the octahedron) or by matching the
closest H3 resolution.
H3 grids use the Uber H3 hierarchical hexagonal system. Unlike ISEA grids, H3 cells are NOT exactly equal-area: hexagon area varies by about a factor of 2 within a resolution, and by about 2.4 once the twelve pentagons are counted. The variation follows position on the icosahedron rather than latitude, with the smallest cells near face centres.
Other Bodies
A grid is a partition of the sphere, and radius_km sets the sphere it
is measured on. Cell geometry – which cell a coordinate lands in, where cell
centres and corners sit, the hierarchy, the neighbours – is angular and
identical on every body; the radius sets the kilometer figures: cell area,
diagonal, spacing, and the resolution that area_km2 picks. Earth's
area comes from the 'WGS84' ellipsoid, every other radius gives the sphere
area 4pir^2.
mars <- hex_grid(area_km2 = 1000, radius_km = "mars")
hex_grid(resolution = 8, radius_km = 3389.5) # the same gridBoth backends take a radius. 'H3' reports a cell's area as its solid angle times Earth's radius squared, so another radius scales those areas by the square of the radius ratio, exactly. One caveat carries: an 'H3' cell ID names a position in 'H3”s topology, which 'Uber”s 'H3' reads on Earth, so the IDs of a grid on another body are that topology on that body and are not interchangeable with Earth 'H3' data.
Orientation
An ISEA grid is built on a solid, an icosahedron unless polyhedron
names another, and its orientation places that solid on the sphere: vertex
0 at longitude vert0_lon and latitude vert0_lat, and vertex 1
at azimuth azimuth seen from vertex 0, all in degrees, as DGGRID's
dggs_vert0_lon, dggs_vert0_lat and dggs_vert0_azimuth
do.
"standard" is the ISEA orientation on the icosahedron: vertex 0 at 11.25E, 58.28N, azimuth 0, symmetric about the equator, with eleven of the twelve pentagons over the oceans and one in Sichuan (Sahr et al. 2003). On the octahedron it puts vertices at both poles and at longitudes 0, 90E, 180 and 90W on the equator.
"dymaxion" is Fuller's orientation of the icosahedron for his Dymaxion map: vertex 0 at 5.2454W, 2.3009N, azimuth 7.46658 (Sahr et al. 2003), with all twelve pentagons in the ocean. With
projection = "fuller"the grid lies on Fuller's Dymaxion map."gosper" places the octahedron as Van de Sande's Gosper World places its poles, at midpoints of octahedron edges: vertex 0 at 21.25W, 45N, vertex 1 across the north pole from it, all six vertices at least 619 km offshore.
net_layoutlays it out as four hexagons. The standard octahedron puts the poles at vertices instead, as Rus's four-hexagon map does."random" draws vertex 0 uniformly on the sphere and the azimuth uniformly in [0, 360), from R's random number generator, so
set.seed()repeats it. Grids in several random orientations show how much a result depends on where the cell boundaries fall."region" places the grid as DGGRID's
REGION_CENTERdoes: the centre ofregionlands on the midpoint of an edge of the solid, the middle of the two faces sharing it, far from the vertices where the vertex cells and the largest distortion sit."face" places the centre of
regionon the centre of a face. On the icosahedron that is about 20.9 degrees from the nearest face edge and 37.4 degrees from the nearest vertex, so a region up to about 40 degrees across lies on one face, away from the face edges where the projection bends.
Rotating the icosahedron rotates the grid with it, so cell IDs, the cell hierarchy and neighbours are the same under every orientation; only where each cell sits on the sphere changes. Every function taking the grid reads its orientation.
Projection
An ISEA-family grid lays its cells out on the plane triangles of the
icosahedron's faces, and the projection carries each spherical face onto its
triangle. With "isea", Snyder's icosahedral equal-area projection,
every cell of a resolution has the same area. With "fuller", Fuller's
projection keeps lengths along the face edges and is not equal-area, so
area_km2 is the mean cell area and cell_area() reports each
cell's own; the Equal-Area Earth Reference System of OGC Topic 21 asks for
cells of equal area, so a Fuller grid falls outside it. These are DGGRID's
dggs_proj ISEA and FULLER,
giving FULLER3H, FULLER4H, FULLER7H and FULLER43H. Cell IDs, the hierarchy
and neighbours are the same under both projections; where each cell's centre
and corners sit on the sphere differs.
hex_grid(resolution = 5, aperture = 4, projection = "fuller") # FULLER4HPolyhedron
Snyder's equal-area projection is defined on every regular solid with
triangular faces, and a hexagonal grid lies on the icosahedron and on the
octahedron alike: each pair of faces sharing an edge forms a diamond of
cells, and the cell at each vertex has one side per face meeting there.
The icosahedron has twelve pentagons and the octahedron six squares; every
other cell is a hexagon, and every cell of a resolution has the same area
(the vertex cells two thirds or five sixths of it, by their sides). The
octahedron's cells are more distorted than the icosahedron's, so it suits
layouts that need its four-fold symmetry rather than analysis. Fuller's
projection is defined on the icosahedron only. The tetrahedron carries the
face projection (see hexify_forward) but no grid: its faces
do not pair into diamonds.
hex_grid(resolution = 5, aperture = 4, polyhedron = "octahedron")One Grid, Many Datasets
A HexGridInfo acts as a shared spatial reference system - like a CRS, but discrete and equal-area. Define the grid once, then attach multiple datasets without repeating parameters:
# Step 1: Define the grid once
grid <- hex_grid(area_km2 = 1000)
# Step 2: Attach multiple datasets to the same grid
birds <- hexify(bird_obs, lon = "longitude", lat = "latitude", grid = grid)
mammals <- hexify(mammal_obs, lon = "lon", lat = "lat", grid = grid)
climate <- hexify(weather_stations, lon = "x", lat = "y", grid = grid)
# No aperture, resolution, or area needed after step 1 - the grid
# travels with the data.
# Step 3: Work at the cell level
# Once hexified, lon/lat no longer matter - cell_id is the shared key
bird_counts <- aggregate(species ~ cell_id, data = as.data.frame(birds), length)
mammal_richness <- aggregate(species ~ cell_id, data = as.data.frame(mammals),
function(x) length(unique(x)))
# Join datasets by cell_id - guaranteed to align because same grid
combined <- merge(bird_counts, mammal_richness, by = "cell_id")
# Step 4: Visual confirmation
# All datasets produce identical grid overlays
plot(birds) # See the grid
plot(mammals) # Same grid, different dataSee also
hexify for assigning points to cells,
HexGridInfo-class for class documentation
Examples
# Create grid by target area
grid <- hex_grid(area_km2 = 1000)
print(grid)
# Create grid by resolution
grid <- hex_grid(resolution = 8, aperture = 3)
# Create grid with different aperture
grid4 <- hex_grid(area_km2 = 500, aperture = 4)
# Create mixed aperture grid
grid43 <- hex_grid(area_km2 = 1000, aperture = "4/3")
# Mix in aperture 7, either as a family or level by level
grid47 <- hex_grid(area_km2 = 1000, aperture = "4/7")
grid_seq <- hex_grid(resolution = 4, aperture = c(4, 4, 7, 3))
# Grid on another body, by name or by radius
mars <- hex_grid(area_km2 = 1000, radius_km = "mars")
titan <- hex_grid(resolution = 6, radius_km = 2574.76)
# Use grid in hexify
df <- data.frame(lon = c(0, 10, 20), lat = c(45, 50, 55))
result <- hexify(df, lon = "lon", lat = "lat", grid = grid)