Compliance Mapping Frameworks for Spatial Epidemiology Pipelines
This guide is part of the Spatial Epidemiology Fundamentals & Data Standards foundation, and it covers how to encode legal, privacy, and statistical constraints as deterministic gates that every geospatial output must clear before reaching a dashboard or an agency report. A compliance mapping framework is the governance layer that sits between raw spatial ingestion and analytical routines: it enforces field-level metadata, validates coordinate references, applies statistical disclosure control, and writes an audit trail that survives a statutory review without watering down the underlying epidemiology.
Concept & Epidemiological Alignment
A compliance mapping framework is not a document — it is executable policy. In disease surveillance, environmental exposure assessment, and health-resource allocation, the same geometry can be lawful at one aggregation level and a reportable privacy breach at another. The framework’s job is to make the difference deterministic: given a dataset and a target use, it either approves the data or rejects it with a logged reason, never silently degrades it.
Use a framework like this when datasets carry protected health information, when outputs feed inter-agency handoffs, or when longitudinal analyses must reconcile shifting administrative boundaries. The controlling assumptions that must hold in public health surveillance data are concrete:
- Minimum population thresholds apply to every geographic identifier. The HIPAA Privacy Rule restricts geographic units smaller than a state, permitting the first three ZIP digits only when the aggregated population exceeds 20,000 (HHS Safe Harbor guidance).
- k-anonymity holds at the geometry level, not just the attribute level — a polygon that isolates a single household re-identifies it regardless of how the attributes are masked.
- Coordinate references are explicit and authorized, because an undeclared or unexpected projection silently biases distance decay, buffer radii, and spatial autocorrelation statistics.
- Transformations are reproducible, so that an auditor can replay ingestion and obtain a byte-identical result.
Where a generic GIS validation script stops at “is the geometry valid?”, a compliance framework adds the regulatory and statistical predicates above and refuses to pass anything it cannot defend. It complements rather than replaces method-level rigor: downstream code in the Disease Clustering & Spatial Statistical Modeling topic area assumes the data it receives has already cleared these gates.
Decision Flow: From Raw Dataset to Approved Layer
Every dataset passes through layered compliance gates before it can reach analytical routines. A record only becomes “approved” when it satisfies the disclosure threshold and carries an authorized coordinate reference with valid topology; failing either branch routes the record to suppression/aggregation or to a logged rejection rather than into the analytical set.
The same logic expressed as a gate-by-gate contract clarifies what each stage owns and what a failure does:
| Gate | Validates | On failure |
|---|---|---|
| Metadata registry | Schema version, controlled vocabularies, lineage fields present | Reject, log missing fields |
| Disclosure threshold | k-anonymity ≥ k, population ≥ statutory minimum | Suppress or aggregate, re-check |
| CRS authorization | EPSG code is recognized and on the allow-list | Reject, log unauthorized datum |
| Topology validation | is_valid, no slivers below area floor |
Repair if safe, else reject |
| Lineage export | Deterministic ordering, hashed config written | Block release until written |
Spatial Data Prerequisites
Before the framework can issue an approval, inputs must satisfy structural prerequisites:
- Geometry type — vector polygons for aggregated rates, points for case locations; mixed-type layers are split, never silently coerced.
- Coordinate reference — a defined CRS on the allow-list. Enforce canonical Coordinate Reference Systems for Public Health so distance, buffer, and weights operations run in a metric projection rather than raw degrees.
- Topology — geometries pass
is_valid; self-intersections, sliver polygons, and duplicate vertices are repaired or rejected before any spatial join. - Format — an interoperable, schema-preserving container. Standardize ingestion on the options described in Spatial Data Types & Formats — GeoPackage or GeoParquet — which retain attribute typing and spatial indexing without proprietary lock-in.
- Precision — a fixed coordinate-rounding tolerance (commonly 6 decimal places for decimal degrees) applied consistently, so that precision itself never becomes an unlogged re-identification vector. Aggressive precision reduction is governed by the Precision Standards in Epi Mapping rules.
- Minimum sample size — small-area denominators must clear the disclosure floor; cells below it are merged upward before rate calculation.
Coordinate validation should verify EPSG codes against the allow-list, restrict datum transformations to explicitly authorized pipelines, and reject layers lacking a defined spatial reference. Using pyproj and shapely, the framework programmatically confirms CRS consistency and flags topology violations before any join executes. Mixed vector formats are read through GDAL/OGR drivers so translation preserves the spatial reference rather than dropping it.
Production Implementation
The framework below integrates validation gates, parameterized thresholds, deterministic ordering, and centralized audit logging. It enforces CRS authorization, repairs or rejects invalid geometry, applies a statistical-disclosure area floor, and writes a hashed lineage record for replay.
# Pinned: geopandas==0.14.4, pyproj==3.6.1, shapely==2.0.4 (Python 3.11)
import json
import hashlib
import logging
from datetime import datetime, timezone
import geopandas as gpd
import pyproj
from shapely.validation import make_valid
# Audit logger — one structured line per compliance event
logging.basicConfig(
filename="compliance_audit.log",
level=logging.INFO,
format="%(asctime)s | %(levelname)s | %(message)s",
)
TARGET_CRS = "EPSG:4326" # storage/output reference
METRIC_CRS = "EPSG:5070" # CONUS Albers — equal-area, for areal filtering
AUTHORIZED_CRS = {4326, 5070, 4269, 3857} # allow-list of EPSG codes
MIN_AREA_KM2 = 0.001 # statistical-disclosure floor on tiny polygons
def _config_hash() -> str:
"""Hash the compliance configuration so a run is reproducible and auditable."""
cfg = {
"target_crs": TARGET_CRS,
"metric_crs": METRIC_CRS,
"authorized_crs": sorted(AUTHORIZED_CRS),
"min_area_km2": MIN_AREA_KM2,
}
return hashlib.sha256(json.dumps(cfg, sort_keys=True).encode()).hexdigest()
def validate_and_transform(input_path: str, output_path: str, stable_id: str = "geoid") -> dict:
gdf = gpd.read_file(input_path)
# 1. CRS authorization — reject undeclared or off-allow-list references
if not gdf.crs:
logging.error("Rejected: input layer lacks a defined CRS")
raise ValueError("Input layer lacks defined CRS. Rejecting for compliance.")
src_epsg = gdf.crs.to_epsg()
if src_epsg not in AUTHORIZED_CRS:
logging.error("Rejected: unauthorized CRS EPSG:%s", src_epsg)
raise ValueError(f"Unauthorized CRS EPSG:{src_epsg}. Not on allow-list.")
if src_epsg != pyproj.CRS(TARGET_CRS).to_epsg():
logging.info("Transforming EPSG:%s -> %s", src_epsg, TARGET_CRS)
gdf = gdf.to_crs(TARGET_CRS)
# 2. Geometry validation & topology repair (logged, never silent)
invalid = ~gdf.geometry.is_valid
if invalid.any():
logging.warning("Repairing %d invalid geometries", int(invalid.sum()))
gdf.loc[invalid, "geometry"] = gdf.loc[invalid, "geometry"].apply(make_valid)
# 3. Statistical disclosure control — drop sub-floor polygons (area in equal-area CRS)
gdf["area_km2"] = gdf.to_crs(METRIC_CRS).geometry.area / 1e6
before = len(gdf)
gdf = gdf[gdf["area_km2"] >= MIN_AREA_KM2].copy()
# 4. Deterministic ordering — stable sort so output is byte-reproducible
if stable_id in gdf.columns:
gdf = gdf.sort_values(stable_id, kind="mergesort").reset_index(drop=True)
# 5. Lineage metadata + export
metadata = {
"ingestion_timestamp": datetime.now(timezone.utc).isoformat(),
"source_crs": f"EPSG:{src_epsg}",
"target_crs": TARGET_CRS,
"config_sha256": _config_hash(),
"records_before": before,
"records_after": len(gdf),
"validation_status": "PASS",
}
gdf.to_file(output_path, driver="GPKG")
with open(f"{output_path}.metadata.json", "w") as fh:
json.dump(metadata, fh, indent=2)
logging.info("Pipeline complete: %d records -> %s", len(gdf), output_path)
return metadata
The metadata registry that backs the stable_id and controlled vocabularies above is built out in Building a HIPAA-Compliant Spatial Metadata Schema, which extends ISO 19115-2 and FGDC CSDGM fields so lineage is machine-readable rather than free text. For deployment, wrap each gate in a pytest fixture, parameterize the constants via environment variables, and run the suite in CI so a merge is blocked whenever a compliance check fails.
Parameter Selection & Tuning
The framework’s behavior is governed by a small set of parameters that must be chosen deliberately and version-controlled:
AUTHORIZED_CRSallow-list — keep it minimal: a storage CRS (EPSG:4326), the jurisdiction’s analytical projection (UTM zone or State Plane), and an equal-area CRS for areal computations. Every code not on the list is a rejection, not a silent reprojection.METRIC_CRSfor area — never compute area inEPSG:4326. Use an equal-area projection (EPSG:5070for CONUS) so the disclosure floor means a real square-kilometre value.MIN_AREA_KM2disclosure floor — set from the smallest defensible reporting unit, not an arbitrary epsilon. Document the population that the floor corresponds to.- k for k-anonymity — choose per data-use agreement (commonly k ≥ 11 for cell-suppression regimes); record the chosen k alongside the output.
- Precision tolerance — coordinate rounding is a tuning knob, not a default; tighter precision raises re-identification risk and must be logged.
When the approved data later feeds spatial autocorrelation, the same discipline applies to analytical parameters — minimum neighbor thresholds and false-discovery-rate correction are tuned in Global & Local Moran’s I Implementation, and every sensitivity sweep is logged beside the model output.
Edge Cases & Failure Modes
- Transboundary CRS drift — datasets spanning two UTM zones or State Plane zones cannot share a single analytical projection without distortion; detect the span and route each partition through its zone-appropriate CRS before merging.
- Island and sliver polygons —
make_validcan emitGeometryCollectionfragments; filter to the intended geometry type after repair so a repaired multipolygon does not smuggle in zero-area lines. - Zero and sub-floor denominators — small-area rates with near-zero populations explode under division; merge cells upward to the disclosure floor before computing rates, and log every merge.
- Boundary version drift — administrative zones change between census vintages, breaking longitudinal denominators. Pin the boundary vintage in lineage metadata and reconcile updates with an explicit crosswalk rather than a spatial overlay.
- Memory at scale (N > 50k) — read in chunks or use a spatially partitioned GeoParquet layout, and build a spatial index before joins so predicate evaluation stays on indexed bounding boxes.
- Silent attribute-key duplication — verify that attribute merges preserve primary keys without fan-out; a duplicated key inflates case counts and corrupts every downstream rate.
Compliance & Audit Controls
Defensibility depends on the run being reproducible and the decisions being recorded:
- Deterministic execution — sort by a stable identifier before export (the
kind="mergesort"stable sort above) so two runs on identical input produce byte-identical output. - Configuration logging with SHA-256 — hash the compliance configuration (CRS allow-list, thresholds, precision) into the lineage record so an auditor can prove which policy produced a given release.
- Append-only audit log — every transform, repair, suppression, and rejection writes a timestamped line; the log is the evidence trail for a statutory review.
- Output schema — export a documented column set (
geoid,area_km2, rate fields) with ISO 19115 metadata, including source and target CRS, record counts before and after suppression, and the validation status. - Provenance for handoff — the
.metadata.jsonsidecar travels with the layer so a receiving agency inherits the full lineage rather than reconstructing it.
Treating compliance as a parameterized, testable component of the data lifecycle removes manual audit overhead while preserving the statistical rigor that high-stakes public health decisions demand.
Related Topics
- Building a HIPAA-Compliant Spatial Metadata Schema — the registry and controlled vocabularies that back these gates.
- Coordinate Reference Systems for Public Health — CRS governance and authorized datum transformations.
- Spatial Data Types & Formats — interoperable, schema-preserving ingestion containers.
- Precision Standards in Epi Mapping — coordinate precision as a re-identification control.
- Spatial Epidemiology Fundamentals & Data Standards — the parent topic for this framework.