%matplotlib inline
from h3 import h3
import geopandas
from shapely.geometry import Polygon
import contextily as ctx
import cenpy21 H3 Grid
21.1 Build a H3 grid for the San Diego region
21.2 Infrastructure
To create a container that includes h3 save the following on a file called Dockerfile:
FROM darribas/gds_dev:4.1
USER root
RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add - \
&& apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' \
&& apt-get update \
&& apt-get install --yes cmake
USER $NB_UID
RUN pip install h3And build the container by running the following from the same folder where the file is stored:
docker build -t gds_h3 .
When if finishes, you should be able to launch the gds_h3 container and run this notebook from there.
21.3 Region to cover
sd = geopandas.read_file("sd_city_centre.geojson")
ax = sd.plot(alpha=0.25, color="orange", figsize=(9, 9))
ctx.add_basemap(ax, crs=sd.crs.to_string())21.4 Build H3 geography
%time hexs = h3.polyfill(sd.geometry[0].__geo_interface__, 8, geo_json_conformant = True)polygonise = lambda hex_id: Polygon(
h3.h3_to_geo_boundary(
hex_id, geo_json=True)
)
%time all_polys = geopandas.GeoSeries(list(map(polygonise, hexs)), \
index=hexs, \
crs="EPSG:4326" \
)ax = all_polys.plot(alpha=0.5, color="xkcd:pale yellow", figsize=(9, 9))
ctx.add_basemap(ax, crs=all_polys.crs.to_string())
ax.set_title(f"{all_polys.shape[0]} Hexagons");21.5 Clip ocean out
There are quite a few hexagons that fall within the ocean. Let’s get rid of them. For that, we will pull down the polygon for San Diego county using cenpy:
census = cenpy.Decennial2010()
tracts = census.from_msa("San Diego, CA", level="tract")Now these geometries include also some ocean:
ax = tracts.plot(alpha=0.5, color="xkcd:pale green")
ctx.add_basemap(ax, crs=tracts.crs.to_string())It turns out that part is a separate polygon that may be removed easily:
tracts.head()tracts_land_one = geopandas.GeoDataFrame(
{"geometry": [tracts.query("GEOID != '06073990100'").unary_union],
"id": ["one"]
}, crs=tracts.crs)ax = tracts_land_one.to_crs(epsg=4269).plot()
all_polys.to_crs(epsg=4269).plot(color="xkcd:pale yellow", ax=ax)Let’s convert all_polys into a GeoDataFrame:
h3_all = geopandas.GeoDataFrame({"geometry": all_polys,
"hex_id": all_polys.index},
crs=all_polys.crs
)We’re an overlay away from our target:
%%time
h3_land = geopandas.overlay(h3_all,
tracts_land_one.to_crs(h3_all.crs),
how="intersection"
)ax = h3_land.plot(alpha=0.5, color="xkcd:pale yellow")
ctx.add_basemap(ax, crs=h3_land.crs.to_string())21.6 Write out to GPKG
! rm sd_h3_grid.gpkg
h3_land.drop("id", axis=1).to_file("sd_h3_grid.gpkg", driver="GPKG")21.7 Tract Vs H3 geographies
Get tracts only within the grid:
shp = geopandas.GeoDataFrame(
{"geometry": [h3_land.unary_union],
"id": ["one"]
}, crs = h3_land.crs).to_crs(tracts.crs)
sub = geopandas.overlay(tracts, shp, how="intersection")Compare:
ax = sub.plot(facecolor="k", edgecolor="xkcd:lilac", figsize=(9, 9))
h3_land.to_crs(sub.crs).plot(facecolor="none", linewidth=0.5, edgecolor="xkcd:light aqua", ax=ax)
ctx.add_basemap(ax, crs=sub.crs.to_string())21.8 Download link
{download}[Download the *sd_h3_grid.gpkg* file] <sd_h3_grid.gpkg>