Demand vs Low-Income Exposure (Manhattan Demo) — Powered by Etherdata’s Canonical US Census at H3 Resolution 8
Etherdata.ai makes spatial data trustworthy and usable for every team. We publish open, rigorous, deeply usable datasets that make decision-making fairer and faster.
This demo measures equitable bike access by comparing two surfaces on the same canonical H3 grid: (1) low-income exposure (ranked from census median income) and (2) bike access and demand (from dock supply and trip activity). The purpose is to identify where lower-income exposure coincides with relatively weaker access signals— priority candidates for deeper planning review.
SQL template
-- Equitable bike access
WITH
manhattan AS (
SELECT county_geom AS geom
FROM `bigquery-public-data.geo_us_boundaries.counties`
WHERE state_fips_code = '36'
AND RIGHT(county_fips_code, 3) = '061'
LIMIT 1
),
manhattan_h3 AS (
SELECT h3
FROM manhattan m,
UNNEST(bqcarto.h3.ST_ASH3_POLYFILL(m.geom, 8)) AS h3
),
-- Trips aggregated to H3 R8 (origin = start station)
trips_by_h3 AS (
SELECT
bqcarto.h3.LONGLAT_ASH3(t.start_station_longitude, t.start_station_latitude, 8) AS h3,
COUNT(1) AS trip_count
FROM `bigquery-public-data.new_york_citibike.citibike_trips` t
WHERE DATE(t.starttime) BETWEEN DATE '2018-04-10' AND DATE '2018-09-10'
AND t.start_station_latitude BETWEEN 40.68 AND 40.88
AND t.start_station_longitude BETWEEN -74.05 AND -73.90
AND t.start_station_latitude IS NOT NULL
AND t.start_station_longitude IS NOT NULL
GROUP BY 1
),
trips_manhattan AS (
SELECT t.*
FROM trips_by_h3 t
JOIN manhattan_h3 mh USING (h3)
),
-- Stations + docks aggregated to H3 R8 (supply proxy)
stations_by_h3 AS (
SELECT
bqcarto.h3.LONGLAT_ASH3(s.longitude, s.latitude, 8) AS h3,
COUNT(*) AS station_count,
SUM(COALESCE(s.capacity, 0)) AS total_docks
FROM `bigquery-public-data.new_york_citibike.citibike_stations` s
WHERE s.latitude BETWEEN 40.68 AND 40.88
AND s.longitude BETWEEN -74.05 AND -73.90
AND s.latitude IS NOT NULL
AND s.longitude IS NOT NULL
AND COALESCE(s.is_installed, TRUE) = TRUE
GROUP BY 1
),
stations_manhattan AS (
SELECT sb.*
FROM stations_by_h3 sb
JOIN manhattan_h3 mh USING (h3)
),
-- Etherdata canonical census (H3 R8) —
census_manhattan AS (
SELECT
c.h3,
c.total_pop,
c.households,
c.median_income
FROM `v3layer-pro.census_tract_h3r8.nydemo` c
JOIN manhattan_h3 mh USING (h3)
WHERE c.state_fips = '36'
AND c.h3 IS NOT NULL
),
-- Roll up to one row per H3 cell (weighted income)
census_rollup AS (
SELECT
h3,
SUM(total_pop) AS total_pop,
SUM(households) AS households,
SAFE_DIVIDE(SUM(median_income * total_pop), NULLIF(SUM(total_pop), 0)) AS median_income
FROM census_manhattan
GROUP BY 1
),
base AS (
SELECT
c.h3,
bqcarto.h3.ST_BOUNDARY(c.h3) AS geom,
ST_Y(ST_CENTROID(bqcarto.h3.ST_BOUNDARY(c.h3))) AS lat,
ST_X(ST_CENTROID(bqcarto.h3.ST_BOUNDARY(c.h3))) AS lon,
-- Census
c.total_pop,
c.households,
c.median_income,
-- Demand + supply
COALESCE(t.trip_count, 0) AS trip_count,
COALESCE(s.station_count, 0) AS station_count,
COALESCE(s.total_docks, 0) AS total_docks,
-- Normalized operational rates
SAFE_DIVIDE(COALESCE(t.trip_count, 0), NULLIF(c.households, 0)) AS trips_per_household,
SAFE_DIVIDE(COALESCE(t.trip_count, 0), NULLIF(COALESCE(s.total_docks, 0), 0)) AS trips_per_dock,
SAFE_DIVIDE(COALESCE(s.total_docks, 0), NULLIF(c.households, 0)) * 1000 AS docks_per_1k_households
FROM census_rollup c
LEFT JOIN trips_manhattan t USING (h3)
LEFT JOIN stations_manhattan s USING (h3)
WHERE c.total_pop > 0
),
scored AS (
SELECT
*,
-- Relative ranks within the Manhattan H3 domain
PERCENT_RANK() OVER (ORDER BY median_income) AS pct_income,
PERCENT_RANK() OVER (ORDER BY docks_per_1k_households) AS pct_access,
PERCENT_RANK() OVER (ORDER BY trips_per_household) AS pct_demand,
-- Low-income exposure: higher = lower income (relative)
(1 - PERCENT_RANK() OVER (ORDER BY median_income)) AS low_income_exposure_score,
-- Equity gap: higher = more low-income exposure with relatively lower access
((1 - PERCENT_RANK() OVER (ORDER BY median_income)) - PERCENT_RANK() OVER (ORDER BY docks_per_1k_households)) AS equity_gap_access,
-- Optional: low-income exposure vs realized demand (usage)
((1 - PERCENT_RANK() OVER (ORDER BY median_income)) - PERCENT_RANK() OVER (ORDER BY trips_per_household)) AS equity_gap_demand,
CASE
WHEN households < 50 THEN 'LOW_EXPOSURE_HH' -- guardrail: very low residential exposure
WHEN (1 - PERCENT_RANK() OVER (ORDER BY median_income)) >= 0.70
AND PERCENT_RANK() OVER (ORDER BY docks_per_1k_households) <= 0.30 THEN 'LOW_INCOME_LOW_ACCESS'
WHEN (1 - PERCENT_RANK() OVER (ORDER BY median_income)) >= 0.70
AND PERCENT_RANK() OVER (ORDER BY docks_per_1k_households) >= 0.70 THEN 'LOW_INCOME_HIGH_ACCESS'
WHEN (1 - PERCENT_RANK() OVER (ORDER BY median_income)) <= 0.30
AND PERCENT_RANK() OVER (ORDER BY docks_per_1k_households) <= 0.30 THEN 'HIGH_INCOME_LOW_ACCESS'
ELSE 'MIXED'
END AS equity_segment
FROM base
)
SELECT
*
FROM scored
WHERE h3 not in ("882a107295fffff","882a100f21fffff")
ORDER BY equity_gap_access DESC;
Results & Interpretation (What the charts show)
Low-Income Exposure vs Bike Access
The scatter shows no strong monotonic relationship between low-income exposure and access. Most cells cluster at relatively modest dock intensity across the full exposure range (0 to 1). There is at least one extreme outlier with very high dock intensity (~650 docks per 1K households) at high exposure (~0.85–0.9), which can happen when household denominators are small or where station density is unusually high.
Key finding: access does not automatically increase where low-income exposure is highest—alignment appears mixed.
Outlier note: extremely high docks-per-1K can be denominator-driven; always interpret alongside households and station_count.
How to operationalize: focus on “high exposure + low access” cells (upper-right exposure axis with low docks-per-1K) as candidates for equity review.
Low-Income Exposure vs Bike Demand
Demand (trips per household) also shows weak alignment with low-income exposure. Most cells sit in a moderate-to-low demand band regardless of exposure score. There is again a visible high-exposure outlier with unusually high trips-per-household (~60+), suggesting either a concentrated high-usage pocket or denominator effects (low household count).
Key finding: realized demand is not simply “higher where exposure is higher.”
Interpretation: demand is constrained by supply placement, network connectivity, safety, and destination dynamics—exactly why census context is needed.
Outlier note: very high trips-per-household should be validated with trip_count and households to avoid small-denominator artifacts.
Low-Income Exposure Score
The exposure surface is spatially structured and not random. The map shows a clear gradient where some corridors concentrate higher low-income exposure (higher score). This is exactly what you want from a census-derived context layer: it is stable, interpretable, and provides a consistent “equity baseline” independent of bike operations.
What it tells us: the city has distinct pockets where residents are structurally more likely to be constrained by income.
How to use it: treat this as the baseline surface that access and demand should be evaluated against.
Bike Access Map — Docks per 1K Households
Access (docks per 1K households) is broadly present across the core of Manhattan, but it is not uniform. The map indicates areas of higher dock intensity as well as visibly lower-intensity pockets. Importantly, this is a supply proxy: it reflects capacity placement rather than usage.
What it tells us: supply is relatively dense in many cells, but distribution is uneven when normalized by household exposure.
Planning implication: “green overall” can still hide equity gaps—use the gap and scatter charts to test alignment with exposure.
Key takeaways (grounded in the charts)
Exposure is structured and stable: the low-income exposure map provides a usable equity baseline.
Access is uneven and not clearly aligned to exposure: scatter indicates mixed alignment rather than a clean “more exposure → more access” pattern.
Demand is also weakly aligned: usage does not systematically rise with exposure; constraints and destination effects likely dominate.
Outliers exist and must be validated: extreme docks-per-1K and trips-per-household values are often denominator-sensitive; use the table to confirm.
Actionability comes from the gap + table: rank high-exposure, low-access cells with sufficient households to prioritize planning follow-up.
What we can conclude (and what we cannot)
Conclusions supported by the demo
Canonical census context enables a defensible equity baseline and makes access evaluation comparable across neighborhoods.
Access and demand do not appear automatically aligned with low-income exposure, suggesting equity gaps are plausible and worth targeting.
Equity hotspot identification should be based on a combined view (exposure + access + denominators), not trip counts alone.
What we cannot conclude from these data alone
No causality claims without controls for bike lanes, safety, land use, tourism, pricing, and time-of-day effects.
Docks/stations remain a proxy for “access”; true access includes connectivity and operational availability.
Per-household and per-1K rates can be distorted in low-household cells; thresholds are required for robust interpretation.