Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions examples/osm-equity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,17 @@ The end-to-end test drives every handler in the workflow's data order and
asserts the built-in digital-divide signal is recovered (Spearman ρ > 0.3,
p < 0.05; Moran's I > 0) and that data deserts are the low-income tracts.
Set `FW_EQUITY_GRID` to change the grid resolution (default 6 → 36 tracts).

## Atlas workflow — fan out over cities, one map

`MappingEquityAtlas` (in `ffl/osm_equity.ffl`) turns the whole study into a
single parameterised workflow: it resolves a **sequence of regions** + a
**city-size** floor (min population) into cities, runs each city in parallel
(`andThen foreach` — the fan-out is by subregion/city), tiles each at a chosen
**tile size**, and merges every tile into **one** combined map.

Parameters: `regions` (e.g. `["north-america"]`), `min_population`, `tile_sqmi`,
`acs_year`, `osm_kinds` (`poi` for large sweeps, `building,road,poi` for detail),
`with_footprints`, `metric` (which per-tile metric colours the map), `half_deg`,
`update`, `title`. Handlers: `ResolveCities` / `CityTiles` (fan-out unit) /
`BuildAtlasMap`, in `handlers/atlas/`.
73 changes: 73 additions & 0 deletions examples/osm-equity/ffl/osm_equity.ffl
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,77 @@ namespace osm.equity {
)
}

// ===================================================================
// ATLAS - fan out over cities (subregions), tile each, combine to ONE map.
//
// Parameters let the caller choose the region sequence, the "city size"
// (min population), the tile size, and how the OSM/quality layers are
// built; the workflow resolves the region(s) into cities, runs each city
// in parallel (andThen foreach), and merges every tile into a single map.
// ===================================================================
schema CityRef {
name: String,
lon: Double,
lat: Double,
half_deg: Double,
population: Long
}

// Expand a sequence of regions + a population floor into cities to map.
event facet ResolveCities(regions: [String], min_population: Long, half_deg: Double) => (cities: [CityRef])

// Per-city tiled analysis (the fan-out unit): TIGER tracts + ACS equity
// areal-interpolated onto a `tile_sqmi` grid, OSM (kinds) clipped per tile,
// optional Microsoft-footprint extrinsic check. Returns the city's tiles.
event facet CityTiles(city: CityRef, tile_sqmi: Double, acs_year: Long, osm_kinds: String, with_footprints: Boolean, update: Boolean) => (records: [TractQuality])

// Render ONE combined MapLibre map of every tile, coloured by `metric`.
event facet BuildAtlasMap(records: [TractQuality], stats: StatResults, metric: String, title: String) => (map_html: String, tile_count: Long, city_count: Long)

// Fan-out: one parallel branch per city; every city's tiles aggregate into
// the shared `records` collection.
facet CollectCityTiles(cities: [CityRef], tile_sqmi: Double, acs_year: Long, osm_kinds: String, with_footprints: Boolean, update: Boolean) => (records: [TractQuality]) andThen foreach c in $.cities {
ct = CityTiles(city = $.c, tile_sqmi = $.tile_sqmi, acs_year = $.acs_year, osm_kinds = $.osm_kinds, with_footprints = $.with_footprints, update = $.update)
yield CollectCityTiles(records = ct.records)
}

workflow MappingEquityAtlas(
regions: [String] = ["north-america"],
min_population: Long = 500000,
tile_sqmi: Double = 2.0,
acs_year: Long = 2022,
osm_kinds: String = "poi",
with_footprints: Boolean = false,
metric: String = "attr_completeness",
half_deg: Double = 0.12,
update: Boolean = false,
title: String = "OSM Mapping Equity Atlas - North America"
) => (map_html: String, tile_count: Long, city_count: Long) andThen {

// resolve the region sequence + city-size floor into cities
cities = ResolveCities(regions = $.regions, min_population = $.min_population, half_deg = $.half_deg)

// fan out: tile every city in parallel, aggregate all tiles
tiles = CollectCityTiles(
cities = cities.cities,
tile_sqmi = $.tile_sqmi,
acs_year = $.acs_year,
osm_kinds = $.osm_kinds,
with_footprints = $.with_footprints,
update = $.update
)

// national analysis over the combined tiles
stats = AnalyzeEquity(records = tiles.records, snapshot = "atlas")

// ONE combined map
atlas = BuildAtlasMap(records = tiles.records, stats = stats.results, metric = $.metric, title = $.title)

yield MappingEquityAtlas(
map_html = atlas.map_html,
tile_count = atlas.tile_count,
city_count = atlas.city_count
)
}

}
4 changes: 4 additions & 0 deletions examples/osm-equity/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from .acquisition.acquisition_handlers import register_acquisition_handlers
from .analysis.analysis_handlers import register_analysis_handlers
from .atlas.atlas_handlers import register_atlas_handlers
from .design.design_handlers import register_design_handlers
from .metrics.metrics_handlers import register_metrics_handlers
from .reporting.reporting_handlers import register_reporting_handlers
Expand All @@ -16,12 +17,14 @@ def register_all_handlers(poller) -> None:
register_metrics_handlers(poller)
register_analysis_handlers(poller)
register_reporting_handlers(poller)
register_atlas_handlers(poller)


def register_all_registry_handlers(runner) -> None:
"""Register every handler with a RegistryRunner."""
from .acquisition.acquisition_handlers import register_handlers as reg_acq
from .analysis.analysis_handlers import register_handlers as reg_ana
from .atlas.atlas_handlers import register_handlers as reg_atlas
from .design.design_handlers import register_handlers as reg_des
from .metrics.metrics_handlers import register_handlers as reg_met
from .reporting.reporting_handlers import register_handlers as reg_rep
Expand All @@ -31,3 +34,4 @@ def register_all_registry_handlers(runner) -> None:
reg_met(runner)
reg_ana(runner)
reg_rep(runner)
reg_atlas(runner)
Empty file.
Loading
Loading