You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #352 ships stop statistical radius apportionment for individual results tables (Stops/Routes/Agencies) and for the aggregation table at the State, County, and Tract layers. The aggregation rollup works via a FIPS prefix match — Pass F returns tract-level intersections with the union of stop buffers, and geographiesForAggregationRow filters those tracts by GEOID prefix to populate each county/state row.
The prefix trick only works when the aggregation layer is a strict GEOID prefix of tract — i.e. State, County, Tract. For Place, CBSA, CSA, UAC20, and FTA-UAC20-Nonurban the GEOIDs are not prefixes (a place can span counties, a CBSA is composed of counties not tracts), so the rollup can't be done client-side without polygon math, which is banned by CLAUDE.md.
As a stopgap, PR #352 disables those non-hierarchical layer choices in the aggregation pickers whenever stopBufferRadius > 0 and surfaces a warning banner. Users have to either switch to a hierarchical layer or set the radius to 0.
Goal
Restore Place / CBSA / CSA / UAC aggregation when buffer apportionment is on, with the same per-tract resolution we get today for County rows. The math we want per aggregation row is:
row demographics = Σ over tracts t: tract_value × (place ∩ buffer ∩ tract area / tract area)
so that density is assumed uniform within each tract (matching the Frequent Transit Service Study calculation referenced in #315) rather than uniform within the whole place/CBSA.
Proposed approaches
Two backend options, both in transitland-server. We don't have a strong preference yet — would like input.
A. Filter by another geography's ID
Extend census_geographies(where: CensusGeographyFilter) to accept a containing-geography filter, e.g.:
The resolver would intersect (buffer ∩ tract ∩ place) server-side via PostGIS and return per-tract rows. The client would call this once per visible place row, or batch by passing an array of containing IDs.
Cons: one query per aggregation row (could be dozens), or backend has to support an array variant.
B. Re-upload the selected layer as a multi-polygon clip
Allow the caller to POST a GeoJSON multi-polygon as the spatial filter and run the existing stop_buffer ∩ tract ∩ intersection against it. Same shape as today's admin-boundary path.
Pros: doesn't require the server to host the layer being clipped against — caller supplies it.
Cons: payload size for fine-grained layers, duplication of polygon data the server already has.
Acceptance criteria
With stopBufferRadius > 0 and aggregation layer set to Place / CBSA / CSA / UAC / FTA-UAC20-Nonurban, the aggregation table shows the same buffer-apportioned demographic columns + % Area within Stop Radius that today's State/County/Tract rows show.
Follow-up to #315 / PR #352.
Background
PR #352 ships stop statistical radius apportionment for individual results tables (Stops/Routes/Agencies) and for the aggregation table at the State, County, and Tract layers. The aggregation rollup works via a FIPS prefix match — Pass F returns tract-level intersections with the union of stop buffers, and
geographiesForAggregationRowfilters those tracts by GEOID prefix to populate each county/state row.The prefix trick only works when the aggregation layer is a strict GEOID prefix of tract — i.e. State, County, Tract. For Place, CBSA, CSA, UAC20, and FTA-UAC20-Nonurban the GEOIDs are not prefixes (a place can span counties, a CBSA is composed of counties not tracts), so the rollup can't be done client-side without polygon math, which is banned by CLAUDE.md.
As a stopgap, PR #352 disables those non-hierarchical layer choices in the aggregation pickers whenever
stopBufferRadius > 0and surfaces a warning banner. Users have to either switch to a hierarchical layer or set the radius to 0.Goal
Restore Place / CBSA / CSA / UAC aggregation when buffer apportionment is on, with the same per-tract resolution we get today for County rows. The math we want per aggregation row is:
so that density is assumed uniform within each tract (matching the Frequent Transit Service Study calculation referenced in #315) rather than uniform within the whole place/CBSA.
Proposed approaches
Two backend options, both in transitland-server. We don't have a strong preference yet — would like input.
A. Filter by another geography's ID
Extend
census_geographies(where: CensusGeographyFilter)to accept a containing-geography filter, e.g.:The resolver would intersect (buffer ∩ tract ∩ place) server-side via PostGIS and return per-tract rows. The client would call this once per visible place row, or batch by passing an array of containing IDs.
Pros: minimal schema surface, reuses existing types, aggregation precision matches today's per-row math.
Cons: one query per aggregation row (could be dozens), or backend has to support an array variant.
B. Re-upload the selected layer as a multi-polygon clip
Allow the caller to POST a GeoJSON multi-polygon as the spatial filter and run the existing stop_buffer ∩ tract ∩ intersection against it. Same shape as today's admin-boundary path.
Pros: doesn't require the server to host the layer being clipped against — caller supplies it.
Cons: payload size for fine-grained layers, duplication of polygon data the server already has.
Acceptance criteria
stopBufferRadius > 0and aggregation layer set to Place / CBSA / CSA / UAC / FTA-UAC20-Nonurban, the aggregation table shows the same buffer-apportioned demographic columns +% Area within Stop Radiusthat today's State/County/Tract rows show.Related