6. DGGRID and dggrid4py
DGGRID
DGGRID is a free software program for creating and manipulating Discrete Global Grids created and maintained by Kevin Sahr. DGGRID version 8.42 was released 21. September 2025.
DGGRID is packaged on conda-forge With the Micromamba approach the package should be included in the environment file. If you manage your won environment you could install like so:
micromamba install -c conda-forge dggridYou can also compile it yourself and use a locally installed version. As a last resort, we have pre-compiled binaries available. However, these are not regularly updated and might not be available for all architectures. In the next section, the dggrid4py library provides a function to download such a precompiled binary for Windows (amd64), Linux (amd64 and aarch64), and Mac(arm64).
DGGRID
You could use DGGRID “manually”. This involves crafting a so called metafile and placing required input files according as well (like for clipping or binning or address transformation).
The source code distribution of DGGRID contains mnany examples. For example, to create a global hexagonal grid of type ISEA7H at refinement level 3 (resolution) a minimal metafile would contain the following lines:
# the filename should be metafile
# specify the operation
dggrid_operation GENERATE_GRID
# specify the DGG
dggs_type ISEA7H
dggs_res_spec 3
# control the generation
clip_subset_type WHOLE_EARTH
geodetic_densify 0.0
# specify the output file name
cell_output_type SHAPEFILE
cell_output_file_name outputf_isea7h3
densification 3
precision 5Then you would call dggrid with the file as parameter, like so:
dggrid metafile
# And the output would be something like this:
>>> ** executing DGGRID version 8.42 with GDAL version 3110400 **
>>> type sizes: big int: 64 bits / big double: 64 bits
>>>
>>> ** using meta file metafile...
>>> * parameter values:
>>> dggrid_operation GENERATE_GRID (user set)
>>>
>>> ... lots output
>>>
>>> ** grid generation complete **
>>> * generated 3,432 cellsIn the same directory you would then find the generated files for outputf_isea7h3.shp including the shapefile sidecar files.
ls outputf_isea7h3*
>>> outputf_isea7h3.dbf outputf_isea7h3.prj outputf_isea7h3.shp outputf_isea7h3.shxBut for workflows this would be too cumbersome, so we want to automate this interaction with DGGRID via dggrid4py.
dggrid4py
dggrid4py is a Python library to run highlevel functions of DGGRID, it is a wrapper around the DGGRID commandline tool execution routines.
https://dggrid4py.readthedocs.io/en/latest/
To work with latest versions of DGGRID is also recommended to use the latest version of dggrid4py. dggrid4py is only available from PyPI. It can also be installed from the GitHub repository directly:
pip install "dggrid4py>=0.5.2"If you feel experimental, it is possible to install from the latest commits from GitHub:
pip install git+https://github.com/allixender/dggrid4py.gitYou can check the version, when importing dggrid4py in Python:
import dggrid4py
dggrid4py.__version__
# and it would print something like this
>>> 0.5.1-devFor the use of DGGRID in dggrid4py, you need to know the path to the exectible DGRID file. In most shells you can run:
which dggrid
# and it will show the path to an available installed version (in my case):
>>> /Users/akmoch/micromamba/envs/dggrid/bin/dggridWithin Python you can do that as well:
import shutil
shutil.which("dggrid")
>>> '/Users/akmoch/micromamba/envs/dggrid/bin/dggrid'You will need the path to the executable later on!
Usage
The main entry point are two class instances, DGGRIDv7 (simpler) and DGGRIDv8 (more detailed configuration possible).
DGGRIDv7 is the “classic” dggrid4py interface, easier to use, and also supports running DGGRID tool in version 8.
DGGRIDv8 is an effort to make the newer features in DGGRID accessible, and be more future-proof for the planned DGGRID v9.
You will need the path to the DGGRID executable now! Exemplary, in my case:
Ideally, set a variable: dggrid_exec = '/Users/akmoch/micromamba/envs/dggrid/bin/dggrid'
Usage examples:
import geopandas
import shapely
from dggrid4py import DGGRIDv7
# just checking if you remembered the DGGRID executable path :-)
print(dggrid_exec)
# create an inital instance that knows where the dggrid tool lives,
# configure temp workspace and log/stdout output
dggrid_instance = DGGRIDv7(executable=dggrid_exec,
working_dir='.',
capture_logs=False,
silent=False,
tmp_geo_out_legacy=False,
debug=False)
# global ISEA4T grid at resolution 5 into GeoDataFrame to Shapefile
gdf1 = dggrid_instance.grid_cell_polygons_for_extent('ISEA4T', 5)
print(gdf1.head())DGGRID does not always set the coordinate system on the produced output files.
We can manually set (force) the CRS to WGS84/EPSG:4326. This is in general not recommended at all when working spatial data. You should only do that if you know what you are doing.
This is a specific situation with DGGRID output, we assume the data to be lat/lon. (later more on that…)
print(gdf1.crs)
gdf1.crs = 4326
print(gdf1.crs)
Then we continue...
```python
print(gdf1.head())
gdf1.to_file('isea4t_5.shp')
gdf_centroids = dggrid_instance.grid_cell_centroids_for_extent(dggs_type='ISEA7H',
resolution=4,
mixed_aperture_level=None,
clip_geom=None)
print(gdf_centroids.head())
DGGRID has built-in functionality to show statistics for its different DGGS.
# generate cell and areal statistics for a ISEA7H grids from
# resolution 0 to 8 (return a pandas DataFrame)
df1 = dggrid_instance.grid_stats_table('ISEA7H', 8)
print(df1.head(8))
df1.to_csv('isea7h_8_stats.csv', index=False)You can also create the cells only within an area. For that you need to provide a shapely Polygon:
# clip extent
clip_bound = shapely.geometry.box(20.2,57.00, 28.4,60.0 )
# ISEA7H grid at resolution 9, for extent of provided WGS84 rectangle
# into GeoDataFrame to Shapefile
gdf3 = dggrid_instance.grid_cell_polygons_for_extent('ISEA7H', 9, clip_geom=clip_bound)
print(gdf3.head())
gdf3.to_file('grids/est_shape_isea7h_9.shp')
# generate the DGGS grid cells that would cover a GeoDataFrame of points,
# return Polygons with cell IDs as GeoDataFrame
# we could reuse the previous data
geodf_points_wgs84 = gdf3.centroid
gdf4 = dggrid_instance.cells_for_geo_points(geodf_points_wgs84, False, 'ISEA7H', 5)
print(gdf4.head())
gdf4.to_file('polycells_from_points_isea7h_5.shp')
# generate the DGGS grid cells that would cover a GeoDataFrame of points,
# return cell IDs added as column to the points GDF
gdf5 = dggrid_instance.cells_for_geo_points(geodf_points_wgs84=geodf_points_wgs84,
cell_ids_only=True,
dggs_type='ISEA4H',
resolution=8)
print(gdf5.head())
gdf5.to_file('geopoint_cellids_from_points_isea4h_8.shp')If you get an error regarding PROJ, along the lines of UserWarning: pyproj unable to set PROJ database path, consider setting the PROJ_DATA path manually. See: 5. Jupyter > Proj database location info
IGEO7 Usage examples
Hexagonal Discrete Global Grid Systems (DGGS) offer significant advantages for spatial analysis due to their uniform cell shapes and efficient indexing. Among the three central place apertures (3, 4, and 7), aperture 7 subdivisions exhibit very desirable properties, including the preservation of hexagonal symmetry and the formation of unambiguous indexing hierarchies.
Interest in hierarchically indexed aperture 7 hexagonal DGGS has recently increased due to the popularity of the H3 DGGS. But there are currently no open-source equal-area aperture 7 hexagonal DGGS available, that provide similar indexing capabilities like H3.
We present IGEO7, a novel pure aperture 7 hexagonal DGGS, and Z7, its associated hierarchical integer indexing system. In contrast to H3, where cell sizes vary by up to ±50% across the globe, IGEO7 uses cells of equal area, making it a true equal-area DGGS.
IGEO7 and Z7 are implemented in the open-source software DGGRID. We also present a use case for on-demand suitability modeling to demonstrate a practical application of this new DGGS.
We still use the DGGRIDv7 instance we created above.
gdf_z1 = dggrid_instance.grid_cell_polygons_for_extent('IGEO7',
5,
clip_geom=est_bound,
output_address_type='Z7_STRING')
print(gdf_z1.head(3))
df_z1 = dggrid_instance.guess_zstr_resolution(gdf_z1['name'].values,
'IGEO7',
input_address_type='Z7_STRING')
print(df_z1.head(3))
df_q2di = dggrid_instance.address_transform(gdf_z1['name'].values,
'IGEO7',
5,
input_address_type='Z7_STRING',
output_address_type='Q2DI')
print(df_q2di.head(3))
df_tri = dggrid_instance.address_transform(gdf_z1['name'].values,
'IGEO7',
5,
input_address_type='Z7_STRING',
output_address_type='PROJTRI')
print(df_tri.head(3))
children = dggrid_instance.grid_cell_polygons_from_cellids(
cell_id_list=['00012502340'], # the input/parent cell id
dggs_type='IGEO7', # dggs type
resolution=11, # target resolution of children
clip_subset_type='COARSE_CELLS', # new parameter
clip_cell_res=9, # resolution of parent cell
input_address_type='Z7_STRING', # address_type
output_address_type='Z7_STRING' # address_type
)
print(children.head(3))Sphere vs ellipsoid
The original IGEO7 implementation is available in the DGGRID software since version 8.41 and is a ISEA7H type DGGS with the new Z7 indexing system.
Recent developments in the OGC API DGGS standard draft make reference to refinement ratio 7 DGGRS with ISEA projection. In order to have DGGH and ZIRS compliant with the OGC DGGS standard, we aim to enable a few minor adjustments to IGEO7 through the use of dggrid4py:
- to apply authalic conversion to the WGS84 ellipsoid instead of the spherical approximation, using
pygeodesy(based off geographiclib), see :mod:dggrid4py.auxlat - a rotation of the base icosahedron by 0.05 degrees (from the default 11.25 to 11.20) to align the vertices better with water bodies through a specific parameter
dggs_vert0_lonin DGGRID.
In practice this means that IGEO7 as described in the original publication is not the same as the ellipsoid-adjusted IGEO7 version, though both can be generated through dggrid4py.
We hope to make the required changes available in DGGRID in the future, so that now further confusions can arise. Until then, there might be two slightly different IGEO7 implementations in use and implementers shall be explicit.
# single latittude use geographic to authalic conversion
# (optional, passing data from ellipsoid to the sphere)
# use for better accuracy on ellipsoid and with IGEO7
from dggrid4py.auxlat import geodetic_to_authalic, authalic_to_geodetic
clip_bound_auth = clip_bound = shapely.geometry.box(25.2,
auxlat.geodetic_to_authalic(58.1),
27.3,
auxlat.geodetic_to_authalic(59.2))
dggrid_instance_v8 = DGGRIDv8(executable=dggrid_exec, working_dir='.',
capture_logs=False, silent=False,
tmp_geo_out_legacy=False, debug=False)
output_address_kwargs= {
"output_cell_label_type": "OUTPUT_ADDRESS_TYPE",
"output_address_type": "HIERNDX",
"output_hier_ndx_system": "Z7",
# "output_address_type": "Z7_STRING", in DGGRIDv9 only the new form with HIERNDX is supported
"output_hier_ndx_form": "DIGIT_STRING",
"dggs_vert0_lon": 11.20
}
v8_cells = dggrid_instance_v8.grid_cell_polygons_for_extent("IGEO7",
resolution=9,
clip_geom=clip_bound_auth,
**output_address_kwargs)
print(v8_cells.head(3))
# geoseries bulk authalic conversion from authalic back to geodetic/geographic (wgs84)
# use for better accuracy on ellipsoid and with IGEO7
# and of course if you passed in coordinates above from geodetic to authalic form
from dggrid4py.auxlat import geoseries_to_authalic, geoseries_to_geodetic
geo_polys = geoseries_to_geodetic(v8_cells.geometry)
v8_cells["geometry"] = geo_polys
v8_cells.crs = 4326
print(v8_cells.head(3))