laurel.pipelines.describe_locations package
Submodules
laurel.pipelines.describe_locations.nodes module
Kedro pipeline nodes for the describe_locations pipeline (Model Module 3 — Augment TAZs).
Constructs the spatial foundation of the model: H3 resolution-8 hexagonal Traffic Analysis Zones (TAZs) covering the continental U.S., each labelled with a freight-activity class that determines which charger types are deployed there and how many. This pipeline implements Model Module 3 (Augment TAZs) from the paper.
Pipeline overview
Substation territory construction:
format_substation_boundaries_pg_and_e — Sums transformer bank ratings to substation level and adds provenance metadata for PG&E ICA data.
format_substation_profiles — Collapses hour-month baseload profiles to a characteristic 24-hour day per substation.
describe_substation_usage — Joins profiles and capacities to compute available headroom at each substation hour.
format_substations_contin — Formats HIFLD point-based substation data (continental U.S.) for merging with polygon data.
fill_out_substations — Fills in substation territories not covered by ICA polygon data using Voronoi tessellation of HIFLD point locations.
build_remainder_polys — Constructs Voronoi-based territory polygons for point substations outside the ICA coverage area (called by
fill_out_substations).
Spatial layer formatting:
format_states — Renames columns in the U.S. state polygons layer.
format_urban — Renames columns in the urban-area polygons layer.
format_highways — Dissolves and buffers highway polylines to create highway-corridor polygons.
build_land_use_areas — Constructs three mutually exclusive land-use area polygons: urban, rural-highway, and rural-non-highway.
clip_to_extent — Clips any spatial layer to the extent of a reference layer.
hexify_polygons — Converts polygon layers to H3 hex grids by assigning each hex that overlaps the polygon the polygon’s attributes.
Establishment data preparation:
concat_columns — Joins per-hexagon feature tables by shared hex index.
fill_missingness — Drops rows with missing required values and fills optional columns with configured defaults.
prepare_shared_locations — Formats shared truck-stop locations (e.g., Jason’s Law) with a standardised location-type label.
format_estabs — Merges raw Data Axle establishment core, geo, and relationship tables; assigns H3 hex IDs.
reassign_hqs — Reassigns NAICS codes for corporate-headquarters establishments to a HQ-specific code to prevent them from being misidentified as large freight facilities.
prepare_stop_locations_public — Formats publicly available truck-stop locations from Jason’s Law for use as establishment records.
get_osm_estabs_truck_stops — Extracts fuel stations matching a truck- stop name pattern from an OSM PBF file.
get_osm_estabs_warehouses — Extracts warehouse/distribution-centre candidates from an OSM PBF file by name pattern.
concat_extra_estabs — Concatenates supplementary establishment sources.
format_extra_estabs — Reprojects extra establishments, assigns H3 hex IDs, and deduplicates.
collapse_naics_classes — Maps 8-digit NAICS codes to the smaller set of leaf classes used for clustering.
pivot_hex_estabs — Pivots the establishment table to a per-hexagon employment matrix (one column per NAICS leaf class).
NLCD land use raster extraction (read_land_use tag):
partition_hex_corresp — Converts the pandas
hex_base_correspfeather to a partitioned Dask parquet file for parallel raster extraction.read_land_use — Extracts NLCD 2023 land cover fractions for every H3 hexagon using
exactextract; writeshex_land_usein long format.
Freight-activity-class assignment:
pivot_hex_land_use — Pivots the land-use coverage table to a per-hexagon land-use-group fraction matrix.
group_hexes — Assigns each hexagon a freight-activity class using a combination of development threshold, freight-intensity rules, special- establishment flags, and K-Means clustering.
apply_groups — Merges freight-activity-class labels onto the hexagon feature table.
Key design decisions
Voronoi gap-filling: HIFLD substation data provides points for most of the U.S., but ICA data provides polygons for PG&E territory only. Voronoi tessellation fills the remaining territory while avoiding overlap with known ICA polygons. Disconnected Voronoi shards (islands separated from their substation point) are merged into the nearest connected territory to prevent orphaned hexagons.
Headquarters NAICS reassignment: Data Axle assigns some large corporate headquarters the NAICS of the parent company’s primary activity. Without reassignment, a trucking-company HQ would be indistinguishable from a freight terminal. The heuristic (employment ratio × business-status code × establishment count) is conservative to avoid over-correction.
K-Means on sparse employment matrices: The clustering uses log1p- transformed sparse COO matrices as input so that large employment counts in a single NAICS class do not dominate the distance metric. Only hexagons with non-zero freight-intensive NAICS employment (excluding special categories like truck stops) are clustered; others receive rule-based labels.
Neighbor embedding: Each hexagon’s feature vector is augmented with the summed employment of its six H3 ring-1 neighbors to capture the local land-use context, which improves cluster coherence at the cluster-boundary hexagons.
Land use raster extraction runtime: Extracting NLCD fractions for all H3 resolution 8 hexagons in the Continental U.S. via
exactextractis I/O-intensive and may take several hours on a single machine. The step is isolated under theread_land_usetag so it can be run once and its output (hex_land_use) reused for subsequent runs. The raster path is stored as a parameter rather than a catalog dataset becauseexactextractreads the GeoTIFF directly from disk and there is no standard Kedro dataset type that loads it in the required format.
References
Passow, F., & Rajagopal, R. (2026). Identifying indicators to inform proactive substation upgrades for charging electric heavy-duty trucks. Applied Energy.
Uber Technologies. H3: Hierarchical Hexagonal Geospatial Indexing System. https://h3geo.org/
Data Axle USA. Business listings database. U.S. DOT FHWA. Jason’s Law Truck Parking Survey. Homeland Infrastructure Foundation-Level Data (HIFLD). Electric substations. USGS National Land Cover Database (NLCD).
- laurel.pipelines.describe_locations.nodes.apply_groups(hexes, groups, params)[source]
Merge freight-activity-class labels onto a hexagon feature table.
- Parameters:
hexes (
DataFrame) – Per-hexagon feature DataFrame indexed by hex ID.groups (
DataFrame) – Freight-activity-class labels indexed by hex ID (output ofgroup_hexes).params (
dict) –Pipeline parameters dict with keys:
hex_col(str): name of the shared hexagon index.
- Return type:
DataFrame- Returns:
The
hexesDataFrame with the freight-activity-class column fromgroupsmerged in on the shared hex index.- Raises:
AssertionError – If either
hexesorgroupsdoes not haveparams["hex_col"]as its index name.
- laurel.pipelines.describe_locations.nodes.build_land_use_areas(govt, highways, urban, params)[source]
Construct three mutually exclusive land-use area polygons: urban, highway, and rural.
The three areas are:
urban: the union of all Census urban-area polygons.
highway: the highway-corridor polygon union, minus the urban areas.
rural: the full state extent minus both urban and highway areas.
- Parameters:
govt (
GeoDataFrame) – State boundary GeoDataFrame used to define the full analysis extent.highways (
GeoDataFrame) – Highway-corridor polygons (output offormat_highways).urban (
GeoDataFrame) – Urban-area polygons (output offormat_urban).params (
dict) –Pipeline parameters dict with keys:
crs(str | CRS): common CRS for all overlay operations.highway_buffer_miles(float): additional buffer applied to the already-buffered highway polygons (set to 0 if not needed).land_use_col(str): name of the land-use category column in the output.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFramewith three rows (urban, highway, rural) and aland_use_colcolumn, inparams["crs"].
- laurel.pipelines.describe_locations.nodes.build_remainder_polys(points, poly_mask, buff_dist, id_col)[source]
Construct Voronoi-based territory polygons for point substations outside the ICA coverage area.
This function fills in the substation territory map for all point substations that are not already covered by a polygon from
poly_mask. The algorithm proceeds in seven stages:Filter: Retain only point substations whose location does not intersect the union of
poly_maskpolygons.Voronoi: Compute Voronoi polygons for the remaining point locations.
Difference: Subtract the
poly_maskunion from each Voronoi polygon so that known ICA territories take precedence.Explode: Split multi-part polygons into individual shards and flag shards that do not contain their originating substation point as “disconnected” (these are Voronoi islands).
Compact donors: Buffer disconnected shards by
buff_distand dissolve nearby ones together to reduce the number of donor groups.Find acceptors: For each compacted donor group, find the nearest connected (“acceptor”) territory by spatial join and centroid proximity.
Dissolve: Merge each donor shard into its chosen acceptor territory.
- Parameters:
points (
GeoDataFrame) – GeoDataFrame of point-substation locations; must be in the same CRS aspoly_mask.poly_mask (
GeoSeries) – GeoSeries of existing territory polygons to subtract from the Voronoi result.buff_dist (
float) – Buffer distance (in the projected CRS units, typically metres) used to compact nearby disconnected shards.id_col (
str) – Column name inpointscontaining the unique substation ID.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFramewith one row per substation territory, matching the column schema ofpoints.- Raises:
ValueError – If
points.crsdoes not matchpoly_mask.crs.
- laurel.pipelines.describe_locations.nodes.clip_to_extent(gdf, extent, params)[source]
Clip a geometry layer to the extent of a reference layer via polygon intersection.
Reprojects both layers to
params["crs"], performs an overlay intersection, drops empty or null geometries, and dissolves on all non-geometry attribute columns to merge adjacent fragments that share the same attributes.- Parameters:
gdf (
GeoDataFrame) – Input GeoDataFrame to clip.extent (
GeoDataFrame) – Reference GeoDataFrame whose union defines the clip boundary.params (
dict) –Pipeline parameters dict with keys:
crs(str | CRS): CRS for the overlay operation.
- Return type:
DataFrame- Returns:
A
pd.DataFrame(GeoDataFrame) clipped to the extent and dissolved on all attribute columns.
- laurel.pipelines.describe_locations.nodes.collapse_naics_classes(estabs, naics_leaves, params)[source]
Map 8-digit NAICS codes to the smaller set of leaf classes used for clustering.
Each raw NAICS code is mapped to the most specific leaf in
naics_leavesthat is a prefix of the raw code. Codes with no matching leaf are assignedparams["fill_leaf"]. This reduces the dimensionality of the employment embedding while preserving the distinctions most relevant to freight activity.- Parameters:
estabs (
GeoDataFrame) – Establishment GeoDataFrame with an 8-digit NAICS column.naics_leaves (
DataFrame) – DataFrame of allowed leaf NAICS codes.params (
dict) –Pipeline parameters dict with keys:
naics_cols(dict): sub-keysraw(input column) andout(output column) andleaf(column innaics_leavescontaining the allowed codes).fill_leaf(int): leaf code to use when no match is found.
- Return type:
GeoDataFrame- Returns:
The establishment GeoDataFrame with
params["naics_cols"]["out"]added as an integer column.
- laurel.pipelines.describe_locations.nodes.concat_columns(*args)[source]
Outer-join multiple per-hexagon DataFrames on their shared hex index.
- Parameters:
*args (
list[DataFrame]) – Two or morepd.DataFrameobjects sharing the same hex-ID index.- Return type:
DataFrame- Returns:
A single
pd.DataFramewith all columns from all inputs, joined on the shared index withjoin="outer"(hexagons present in any input are retained).
- laurel.pipelines.describe_locations.nodes.concat_extra_estabs(*args)[source]
Concatenate supplementary establishment GeoDataFrames from multiple sources.
- Parameters:
*args (
list[GeoDataFrame]) – Two or moregpd.GeoDataFrameobjects sharing the same column schema.- Return type:
GeoDataFrame- Returns:
A single
gpd.GeoDataFramewith all rows concatenated and a fresh integer index.
- laurel.pipelines.describe_locations.nodes.describe_substation_usage(profs, subs, params)[source]
Join baseload profiles and rated capacities to compute hourly available headroom.
Merges the characteristic-day profile onto the substation capacity table and computes
cap_avail_mw = rating_mw - baseload_mwfor each hour.- Parameters:
profs (
DataFrame) – Characteristic-day baseload profiles (output offormat_substation_profiles).subs (
GeoDataFrame) – Substation GeoDataFrame with rated capacity.params (
dict) –Pipeline parameters dict with keys:
drop_substation_cols(list[str]): columns to drop fromsubsbefore merging.columns(dict): sub-keyssubstation_id,hour,rating_mw,baseload_mw,cap_avail_mw.
- Return type:
DataFrame- Returns:
A
pd.DataFrameindexed bysubstation_id, sorted by hour, with columns for baseload, capacity, and available headroom (all MW).
- laurel.pipelines.describe_locations.nodes.fill_missingness(df, params)[source]
Drop rows with required missing values and fill optional missing values.
Applies two sequential operations: first drops all rows with NaN in
drop_na_cols(required columns); then fills NaN infill_na_valscolumns with configured constants. HandlesCategoricalDtypecolumns correctly by adding the fill value to the category list before filling.- Parameters:
df (
DataFrame) – Input DataFrame, typically the concatenated hexagon feature table.params (
dict) –Pipeline parameters dict with keys:
drop_na_cols(list[str] | None): columns whose NaN rows should be dropped entirely.fill_na_vals(dict[str, any] | None): mapping from column name to fill value for optional NaN imputation.
- Return type:
DataFrame- Returns:
A
pd.DataFramewith required NaN rows removed and optional NaN values filled.
- laurel.pipelines.describe_locations.nodes.fill_out_substations(poly_subs, point_subs, params)[source]
Build complete substation territory coverage by supplementing ICA polygons with Voronoi polygons.
Calls
build_remainder_polysto create Voronoi-based territory polygons for HIFLD point substations that fall outside the PG&E ICA polygon coverage area, then concatenates both polygon sets into a single unified GeoDataFrame.- Parameters:
poly_subs (
GeoDataFrame) – ICA polygon substations (output offormat_substation_boundaries_pg_and_e).point_subs (
GeoDataFrame) – HIFLD point substations (output offormat_substations_contin).params (
dict) –Pipeline parameters dict with keys:
columns(dict): sub-keyssubstation_idandsource.proj_crs(str | CRS): projected CRS for distance operations.buff_dist_meters(float): buffer distance used to compact disconnected Voronoi shards.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFramecovering all substation territories, with a composite{substation_id}_{source}column indexing each territory.
- laurel.pipelines.describe_locations.nodes.format_estabs(estabs_core, estabs_geo, estabs_rels, params)[source]
Merge Data Axle establishment core, geo, and relationship tables into a single GeoDataFrame.
The three raw Data Axle tables are joined on the establishment ID:
estabs_corecontains NAICS codes and employment;estabs_geocontains latitude/longitude;estabs_relscontains parent-company relationships. Establishments missing geographic coordinates are dropped. H3 resolution-8 hex IDs are computed from the coordinates.- Parameters:
estabs_core (
DataFrame) – Dask DataFrame of establishment business attributes.estabs_geo (
DataFrame) – Dask DataFrame of establishment geographic coordinates.estabs_rels (
DataFrame) – Dask DataFrame of parent-company relationship records.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names, applied to all three tables.default_naics(int): fallback NAICS code for establishments with a missing code.calculated_keep_cols(list[str]): computed columns to retain (e.g.,"hex_id","geometry").
- Return type:
GeoDataFrame- Returns:
A Dask GeoDataFrame with one row per establishment, point geometry, H3 hex-ID column, and the columns specified by
col_renamerpluscalculated_keep_cols.
- laurel.pipelines.describe_locations.nodes.format_extra_estabs(estabs, params)[source]
Reproject, compute H3 hex IDs, and deduplicate supplementary establishment records.
Converts polygon geometries to centroids in a projected CRS, reprojects to the H3 geographic CRS, computes H3 resolution-8 hex IDs, and drops duplicate (hex, NAICS, name) combinations.
- Parameters:
estabs (
GeoDataFrame) – Concatenated supplementary establishment GeoDataFrame (output ofconcat_extra_estabs).params (
dict) –Pipeline parameters dict with keys:
proj_crs(str | CRS): projected CRS for centroid computation.hex_col(str): output H3 hex-ID column name.naics_col(str): NAICS column name (used for deduplication).name_col(str): name column name (used for deduplication).
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFrameof establishments withuint64H3 hex IDs and duplicates removed.
- laurel.pipelines.describe_locations.nodes.format_highways(highways, params)[source]
Dissolve and buffer highway polylines into corridor polygons.
Dissolves all highway segments sharing the same
dissolve_colsvalues into a single geometry, reprojects to a projected CRS for accurate buffering, applies a mile-radius buffer, then reprojects back to the original CRS.- Parameters:
highways (
GeoDataFrame) – Raw highway polyline GeoDataFrame.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names.dissolve_cols(list[str]): columns to dissolve on.highway_buffer_miles(float): buffer radius in miles.buff_crs(str | CRS): projected CRS for buffering.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFrameof highway-corridor polygons in the original CRS.
- laurel.pipelines.describe_locations.nodes.format_states(states, params)[source]
Rename columns in the U.S. state polygons layer to internal names.
- Parameters:
states (
GeoDataFrame) – Raw state-boundary GeoDataFrame.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names.
- Return type:
GeoDataFrame- Returns:
The GeoDataFrame with columns renamed.
- laurel.pipelines.describe_locations.nodes.format_substation_boundaries_pg_and_e(infra, params)[source]
Aggregate transformer bank ratings to substation level for PG&E ICA data.
The PG&E ICA dataset provides one polygon per transformer bank; this function dissolves them to one polygon per substation, summing the MW ratings, and adds source and state metadata columns.
- Parameters:
infra (
GeoDataFrame) – Raw PG&E ICA GeoDataFrame with one row per transformer bank.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names (e.g., renaming the capacity and ID columns).add_state_col(dict):nameandvaluefor a static state-name column to add.add_source_col(dict):nameandvaluefor a static data-source column to add.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFrameindexed bysubstation_idwith dissolved territory polygons, summed ratings, and metadata columns.
- laurel.pipelines.describe_locations.nodes.format_substation_profiles(profs, params)[source]
Collapse hourly-by-month PG&E baseload profiles to a characteristic 24-hour day.
The raw PG&E ICA data encodes load as a
month_hourstring (e.g.,"1_14"for January hour 14). This function splits the combined column, aggregates to the maximum baseload for each (substation, hour) combination across all months, and derives the substation’s peak baseload across all hours.- Parameters:
profs (
DataFrame) – Raw PG&E ICA baseload profile DataFrame with a combinedmonth_hourstring column.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names.columns(dict): sub-keysmonth_hour,month,hour,substation_id,baseload(kW column name).
- Return type:
DataFrame- Returns:
A
pd.DataFrameindexed bysubstation_idwith columnshour,max_base_by_hour_mw(max baseload for that hour, in MW), andmax_base_mw(peak baseload across all hours, in MW).
- laurel.pipelines.describe_locations.nodes.format_substations_contin(subs, params)[source]
Standardise the HIFLD continental substation GeoDataFrame for territory construction.
- Parameters:
subs (
GeoDataFrame) – Raw HIFLD substation point GeoDataFrame.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names.add_source_col(dict):nameandvaluefor a static data-source column.keep_cols(list[str]): columns to retain.
- Return type:
GeoDataFrame- Returns:
A standardised
gpd.GeoDataFramewith integersubstation_id, a source label, and only the required columns retained.
- laurel.pipelines.describe_locations.nodes.format_urban(urban, params)[source]
Rename columns in the urban-areas polygons layer to internal names.
- Parameters:
urban (
GeoDataFrame) – Raw Census urban-area GeoDataFrame.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names.
- Return type:
GeoDataFrame- Returns:
The GeoDataFrame with columns renamed.
- laurel.pipelines.describe_locations.nodes.get_osm_estabs_truck_stops(osm_path, params)[source]
Extract truck-stop fuel stations from an OSM PBF file by name pattern.
Filters OSM nodes/ways that have a
nametag, are tagged asamenity=fuel, and whose name matchesparams["tag_regex"](e.g.,"(?i)truck stop|travel center").- Parameters:
osm_path (
str) – Path to the OSM PBF input file, supplied by theosm_north_americacatalog entry. Read directly byosmiumrather than loaded through the catalog, because the file is far too large to hold in memory and osmium streams it.params (
dict) –Pipeline parameters dict with keys:
naics_code(int): NAICS code to assign to all extracted records.tag_regex(str): regular-expression pattern matched against the OSMnametag.naics_col(str): output column name for the NAICS code.temp_path(str): path for the filtered intermediate PBF written during OSM parsing. Distinct per node so two OSM nodes cannot overwrite each other’s intermediate.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFrameof matching OSM establishments with anaics_colcolumn added.
- laurel.pipelines.describe_locations.nodes.get_osm_estabs_warehouses(osm_path, params)[source]
Extract warehouse and distribution-centre candidates from an OSM PBF file by name pattern.
Filters OSM nodes/ways that have a
nametag and whose name matchesparams["tag_regex"](e.g.,"(?i)warehouse|distribution"). Records tagged asamenity=social_facilityare excluded as false positives.- Parameters:
osm_path (
str) – Path to the OSM PBF input file, supplied by theosm_north_americacatalog entry. Read directly byosmiumrather than loaded through the catalog, because the file is far too large to hold in memory and osmium streams it.params (
dict) –Pipeline parameters dict with keys:
naics_code(int): NAICS code to assign to all extracted records.tag_regex(str): regular-expression pattern matched against the OSMnametag.naics_col(str): output column name for the NAICS code.temp_path(str): path for the filtered intermediate PBF written during OSM parsing. Distinct per node so two OSM nodes cannot overwrite each other’s intermediate.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFrameof matching OSM establishments (excluding social facilities) with anaics_colcolumn added.
- laurel.pipelines.describe_locations.nodes.group_hexes(land_use, estabs, params)[source]
Assign each hexagon a freight-activity class using development thresholds, rules, and K-Means.
The assignment algorithm proceeds in five stages:
Development threshold: Only hexagons with at least
params["development"]["frac_thresh"]developed land cover are considered “developed” and are eligible for freight-class assignment. All others receive the label"undeveloped".Neighbor embedding: Each developed hexagon’s employment vector is augmented with the summed employment of its ring-1 H3 neighbors (
include_center=False, distance=1), capturing the surrounding land-use context.Special establishment detection: Hexagons containing (or adjacent to) any establishment with a NAICS code listed in
params["special_naics"]are labelled with that special class (e.g.,"truck_stop"). Special labels take precedence over cluster-assigned labels.K-Means clustering: The remaining developed hexagons with at least one freight-intensive NAICS establishment are clustered using K-Means on the log1p-transformed sparse employment matrix. Hexagons with no freight-intensive establishments receive the label
"some_estabs"or"no_estabs".Output: All labels (including
"undeveloped") are consolidated into a single categorical column.
- Parameters:
land_use (
DataFrame) – Per-hexagon land-use-group fraction matrix (output ofpivot_hex_land_use).estabs (
DataFrame) – Per-hexagon employment embedding matrix (output ofpivot_hex_estabs).params (
dict) –Pipeline parameters dict with keys:
development(dict):col(developed land-cover column) andfrac_thresh(minimum fraction threshold).naics_prefix(str): prefix identifying NAICS columns.default_naics(int): NAICS code used as the “no freight industry” category (excluded from freight-intensity tests).special_naics(dict[str, int]): mapping from label to NAICS code for special establishment categories.loc_group_col(str): output freight-activity-class column name.clusterer_kwargs(dict): keyword arguments forwarded tosklearn.cluster.KMeans.
- Return type:
DataFrame- Returns:
A
pd.DataFrameindexed by hexagon ID with a single categorical columnparams["loc_group_col"]containing the freight-activity class for each hexagon.
- laurel.pipelines.describe_locations.nodes.hexify_polygons(gdf, params)[source]
Convert polygon geometries to an H3 hexagon index by assigning hex IDs to overlapping hexes.
For each polygon in
gdf, all H3 resolution-8 hexagons that overlap the polygon are identified and assigned the polygon’s attribute values. Whenn_partitions > 1, the operation is parallelised via Dask GeoDataFrame; otherwise it runs in-process.- Parameters:
gdf (
GeoDataFrame) – GeoDataFrame of polygons, each with attribute columns to carry forward to the hex index.params (
dict) –Pipeline parameters dict with keys:
hex_col(str): name of the H3 hex-ID output column.n_partitions(int): number of Dask partitions (1 = no Dask).
- Return type:
DataFrame- Returns:
A
pd.DataFrameindexed by H3 hex ID (uint64), with one row per unique hexagon and the polygon attribute columns attached. Duplicate hexagons (where a hexagon intersects multiple polygons) are dropped, keeping the first occurrence.
- laurel.pipelines.describe_locations.nodes.partition_hex_corresp(hex_base, params)[source]
Split the hexagon base correspondence table into Dask parquet partitions.
Converts the pandas feather
hex_base_correspto a Dask DataFrame so that the downstreamread_land_use()node can extract raster values in parallel, one partition per worker. The index is sorted before partitioning so that each partition covers a contiguous range of uint64 hex IDs.- Parameters:
hex_base (
DataFrame) – Pandas DataFrame of hexagon base correspondence data, indexed by uint64 hex ID.params (
dict) –Pipeline parameters dict with key:
n_partitions(int): number of Dask partitions to create. Controls parallelism during raster extraction.
- Return type:
DataFrame- Returns:
Dask DataFrame with the same schema as
hex_base, split inton_partitionspartitions and saved ashex_base_corresp_dask.
- laurel.pipelines.describe_locations.nodes.pivot_hex_estabs(estabs, params)[source]
Build a per-hexagon employment embedding matrix from the establishment dataset.
For each hexagon, computes the total employment in each NAICS leaf class across all establishments in that hexagon. Establishments reporting zero employees are filled with the median employment for that NAICS class, then offset by
params["zero_emp_buff"]to avoid log-zero issues downstream.Column names for NAICS codes are prefixed with
params["naics_prefix"]and sorted lexically to ensure stable column ordering across pipeline runs.- Parameters:
estabs (
GeoDataFrame) – Establishment GeoDataFrame with leaf NAICS codes and employment (output ofcollapse_naics_classes).params (
dict) –Pipeline parameters dict with keys:
columns(dict): sub-keyshex_id,naics,n_employees,geom.naics_prefix(str): string prefix for NAICS column names (e.g.,"naics_").zero_emp_buff(float): small constant added to all employee counts after median-fill to prevent exact zeros.keep_metadata_cols(list[str]): non-NAICS attribute columns to retain in the output (e.g., substation territory ID).
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFrameindexed by hexagon ID with one column per NAICS leaf class (integer employment totals) plus metadata columns.
- laurel.pipelines.describe_locations.nodes.pivot_hex_land_use(land_use, params)[source]
Pivot the per-hexagon NLCD land-use coverage table from long to wide format.
Maps fine-grained NLCD category codes to broader land-use groups using
params["code_group_corresp"], then aggregates fractional coverage by (hexagon, group) and unstacks to produce one column per land-use group.The hexagon index is cast to
uint64to match the dtype used elsewhere in the pipeline.- Parameters:
land_use (
DataFrame) – Dask DataFrame of NLCD coverage fractions in long format, indexed by hexagon ID string.params (
dict) –Pipeline parameters dict with keys:
input_cols(dict): sub-keyscategories(NLCD code column),fractions(coverage fraction column),hex(hexagon index name after renaming).code_group_corresp(dict[str, str]): mapping from NLCD code to land-use group label.
- Return type:
DataFrame- Returns:
A
pd.DataFrameindexed by hexagon ID (uint64) with one column per land-use group, filled with 0.0 for groups with no coverage.
Format shared truck-stop charger locations with a standardised location-type label.
- Parameters:
shared (
GeoDataFrame) – Raw truck-stop GeoDataFrame (e.g., Jason’s Law locations already assigned H3 hex IDs).params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names.loc_col(str): output column name for the location type.shared_location_type(str): categorical value assigned to all rows (e.g.,"truck_stop").
- Return type:
DataFrame- Returns:
A
pd.DataFramewith a categoricalloc_colcolumn.
- laurel.pipelines.describe_locations.nodes.prepare_stop_locations_public(parks, params)[source]
Format Jason’s Law truck-stop locations as establishment records.
Assigns the truck-stop NAICS code and renames columns so that these public data records can be concatenated with the Data Axle establishment dataset.
- Parameters:
parks (
GeoDataFrame) – Jason’s Law truck-stop GeoDataFrame.params (
dict) –Pipeline parameters dict with keys:
col_renamer(dict[str, str]): mapping from raw to internal column names.columns(dict): sub-keynaicsfor the NAICS column name.naics_code(int): NAICS code to assign to all records.keep_cols(list[str]): columns to retain.
- Return type:
GeoDataFrame- Returns:
A
gpd.GeoDataFrameready to be concatenated withformat_estabsoutput.
- laurel.pipelines.describe_locations.nodes.read_land_use(hex_base_corresp, params)[source]
Extract NLCD 2023 land cover fractions for every H3 hexagon using exactextract.
Reads the NLCD land cover raster directly via
exactextract, computing for each hexagon polygon the fraction of its area covered by each NLCD category code. The result is in long format: one row per (hexagon × category) pair.The algorithm proceeds in three steps:
Attach polygon geometries to each partition of
hex_base_correspusingadd_geometries(), producing a Dask GeoDataFrame.Reproject each partition to the raster’s native CRS (read once from the file header) so that fractional areas are computed in the correct coordinate space.
Call
_extract_land_use_part()viamap_partitions, passing the raster path directly soexactextracthandles file I/O per partition.
Note
This node is I/O-intensive and may take several hours to complete on a single machine. Run it once with
kedro run --pipeline=describe_locations --tags=read_land_useand rely on the cachedhex_land_useparquet output for subsequent runs.The index of the output is a string representation of the uint64 hex ID (
{hex_col}_str). The downstreampivot_hex_land_use()node casts it back touint64and renames it to{hex_col}.- Parameters:
hex_base_corresp (
DataFrame) – Dask DataFrame of hexagon correspondence data, indexed by uint64 hex ID. Loaded fromhex_base_corresp_daskin the catalog.params (
dict) –Pipeline parameters dict with keys:
raster_path(str): path to the NLCD 2023 GeoTIFF, relative to the Kedro project root. Passed directly toexactextractrather than loaded through the Kedro catalog because there is no standard dataset type that reads a GeoTIFF into the formatexactextractrequires.hex_col(str): name of the hex ID column / index; used to derive the string column{hex_col}_strthat becomes the output index.
- Returns:
unique(int32): NLCD land cover category code.frac(float64): fraction of hexagon area covered by that category.
- Return type:
Dask DataFrame indexed by
{hex_col}_str(object dtype) with columns
- laurel.pipelines.describe_locations.nodes.reassign_hqs(estabs, params)[source]
Reassign corporate-HQ establishments to a HQ-specific NAICS code to prevent misclassification.
A corporate headquarters may be coded with its parent company’s primary NAICS (e.g., a trucking-company HQ coded as a freight terminal), which would cause the clustering step to treat the HQ building as a large freight facility. This function identifies likely HQ records using a combination of employment ratio, business-status code, number of sibling establishments, and NAICS window, then overrides their NAICS code with
params["hq_naics"].The heuristic is intentionally conservative (large employee ratio, specific HQ business codes, many sibling establishments) to avoid reassigning genuine large freight terminals.
- Parameters:
estabs (
GeoDataFrame) – Establishment GeoDataFrame with NAICS, employment, business- status, and parent-ID columns.params (
dict) –Pipeline parameters dict with keys:
columns(dict): sub-keysparent_id,naics,n_employees,buss_status,estab_id.emp_ratio_min(float): minimum(establishment_employees / median_sibling_employees)ratio for HQ classification.hq_bus_codes(list): business-status code values indicating an HQ.n_estabs_big(int): minimum number of sibling establishments required.naics_window(dict):lowerandupperNAICS code bounds for the window within which HQ reassignment is applied.hq_naics(int): the NAICS code to assign to identified HQ establishments.
- Return type:
GeoDataFrame- Returns:
The establishment GeoDataFrame with HQ NAICS codes overridden.
laurel.pipelines.describe_locations.pipeline module
Kedro pipeline definition for the describe_locations pipeline.
Wires the nodes from laurel.pipelines.describe_locations.nodes into a single Pipeline object.
For full documentation of each node’s inputs, outputs, and algorithm,
see laurel.pipelines.describe_locations.nodes.
Module contents
This is a boilerplate pipeline ‘describe_locations’ generated using Kedro 0.19.3