SB79 Transit Oriented Development Upzoning
- About the Dataset
- Background and Policy Context
- Resources
- Expected Fields
- Running the Pipeline
- Process Overview
- Development Notes
About the Dataset
Senate Bill 79 (SB79) requires Metropolitan Planning Organizations (MPOs) to identify and map Transit-Oriented Development (TOD) Zones based on proximity to qualifying transit stops.
This project develops a reproducible geospatial methodology to:
- Identify SB79-eligible transit stops (Tier 1 and Tier 2)
- Define pedestrian access points and stations associated with those stops
- Generate distinct TOD zones based on Euclidean distance bands around access points
- Apply jurisdictional population rules
- Produce a policy-compliant TOD zone layer for the Bay Area
The resulting datasets will serve as the authoritative SB79 TOD geography for Alameda, San Francisco, San Mateo, and Santa Clara counties.
Project Scope:
- Data Collection – Gather GTFS feeds, Caltrans HQTS data, jurisdiction boundaries, and transit station datasets.
- Data Preparation / Modeling – Identify TOD-eligible stops, classify tiers, construct pedestrian access points, and generate TOD bands.
- Data Ingestion – Prepare final geospatial layer for internal review and publication.
- Data Catalog / Publishing / MDM – Document methodology, inventory dataset in MDM Catalog, add to Enterprise Database, and publish to DAAS platforms (e.g. ArcGIS Online, Open Data, Socrata.)
Background and Policy Context
SB 79, the Abundant and Affordable Homes Near Transit Act, was signed into law on October 10, 2025 and is codified in Government Code §§ 65912.155–65912.162. The law makes qualified housing development an allowed use on residential, mixed-use, and commercial sites near high-quality transit stops in counties with more than 15 passenger rail stations. In the Bay Area, eligible counties are Alameda, San Francisco, San Mateo, and Santa Clara.
SB 79 establishes minimum standards for building height, density, and residential floor area ratio (FAR) that vary by distance from a transit stop and the classification of that stop. It also requires each metropolitan planning organization (MPO) to produce a tiered map of TOD stops and zones. That map carries a rebuttable presumption of validity for use by project applicants and local governments.
TOD stop tiers
Each qualifying transit stop is assigned one of two tiers based on service type:
- Tier 1 — served by heavy rail transit or very high-frequency commuter rail (at least 72 trains/day across both directions). In the Bay Area: BART stations in Alameda, San Francisco, San Mateo, and Santa Clara Counties, and qualifying Caltrain stations (Tamien Station through the future Salesforce Transit Center, excluding stations with no daily service).
- Tier 2 — served by light rail transit, high-frequency commuter rail (at least 48 trains/day), or bus rapid transit. In the Bay Area: VTA light rail, SF Muni Metro and Streetcar, AC Transit Tempo, and select additional stops.
Pedestrian access points
Buffer distances under SB 79 are measured as a straight line from the nearest edge of a parcel to a pedestrian access point for the TOD stop — not from a single station centroid. While “pedestrian access point” is not defined in the statute, guidance communicated by the bill author’s office to HCD establishes the following hierarchy:
- Where an entrance exists: the station entrance
- Where no entrance exists: the platform edges
- Where neither exists: a single point
Development standards
SB 79 sets the following minimum development standards by tier and distance from a TOD stop. Local agencies may not apply lower height, density, or residential FAR limits than those listed below.
| Distance from TOD stop | Tier 1 height | Tier 1 density | Tier 1 FAR | Tier 2 height | Tier 2 density | Tier 2 FAR |
|---|---|---|---|---|---|---|
| Adjacent (≤ 200 ft) | 95 ft | 160 du/ac | 4.5 | 85 ft | 140 du/ac | 4.0 |
| ≤ ¼ mile | 75 ft | 120 du/ac | 3.5 | 65 ft | 100 du/ac | 3.0 |
| ¼–½ mile (cities ≥ 35,000 residents) | 65 ft | 100 du/ac | 3.0 | 55 ft | 80 du/ac | 2.5 |
Source: MTC SB 79 MPO Mapping Requirements Summary (January 2026) — MTC internal only
Resources
Source Data
| Resource Type | Resource Name | Description | Source/Location | Format | Owner | Version | Date Acquired/Created | Dependencies | Usage Notes |
|---|---|---|---|---|---|---|---|---|---|
| Dataset | Pedestrian Access Points | Pre-defined pedestrian access points for transit agencies | Box Link | ZIP/Shapefile | MTC | Current | 2026-02-18 | None | Agency-specific access point locations |
| Dataset | Transit Stations | Transit station location data | Box Link | ZIP/Shapefile | MTC | Current | 2026-02-18 | None | Station geometries and attributes |
| API | 511 GTFS Data | Regional GTFS feeds for Bay Area transit agencies | Box Link | ZIP | MTC | Current | 2026-02-18 | None | Combined regional GTFS feed |
| Dataset | High Quality Transit Stops | Caltrans-defined major BRT stops and high-frequency transit | ArcGIS Online | Feature Service | MTC | Current | 2026-02-18 | None | Used to identify Tier 2 BRT stops |
| Dataset | Jurisdiction Boundaries | Bay Area city and county boundaries with population data | ArcGIS Online | Feature Service | MTC | Current | 2026-02-18 | None | Population rules and geographic scope |
Pipeline Outputs
The following authoritative layers are written to the shared GeoPackage (tod_database.gpkg). Intermediate development layers (tod_stations_dev, tod_stops_dev, tod_access_points_dev) are omitted.
| Layer | Description | Produced By |
|---|---|---|
tod_stations |
Finalized TOD parent station locations. | Step 3 |
tod_stops |
Finalized TOD stops with tier classification and station assignment. | Step 3 |
tod_access_points |
Finalized pedestrian access points used as the origin for TOD zone buffer generation. | Step 3 |
tod_zone_buffers |
Full-circle per-access-point buffers at all three distance bands (200 ft, ¼ mile, ½ mile), tagged with tod_tier and buffer_band. Retained as a diagnostic/QA layer and will be used in a public-facing web map to support transparency about how tod_zones were derived. |
Step 4 |
jurisdictions_with_pop_acs2019_2023 |
Bay Area jurisdiction boundaries joined to ACS 2019–2023 5-year total population estimates. Used to apply the jurisdictional population threshold rule. | Step 4 |
tod_zones |
Authoritative SB79 TOD zone polygons. Each polygon is assigned to exactly one of six non-overlapping zone_label classifications, representing the highest-priority applicable development standard under SB 79. |
Step 4 |
Expected Fields
This process will generate four interrelated datasets. Field types are logical/platform-agnostic; platform-specific type mappings (GeoPackage, ArcGIS, PostgreSQL) are documented separately at publication time.
Data Model

SB79 Transit-Oriented Development Zones
Final policy-compliant TOD zone polygons. One polygon per non-overlapping zone; each polygon is assigned the highest-priority applicable development standard under SB 79. See Geographic Prioritization Approach for how zones are derived.
| Field | Data Type | Allow NULL | Domain | Description |
|---|---|---|---|---|
zone_id |
UUID | No | — | Unique zone identifier; UUID4 assigned after priority resolution |
zone_label |
Text | No | Tier 1 - 200ft, Tier 2 - 200ft, Tier 1 - Quarter Mile, Tier 2 - Quarter Mile, Tier 1 - Half Mile, Tier 2 - Half Mile |
Priority tier and distance band classification |
geometry |
Geometry (Polygon) | No | — | Non-overlapping TOD zone polygon. All zones have unincorporated county lands erased. Half-mile zones additionally have sub-35,000 population incorporated city jurisdictions erased. Slivers < 100 m² are removed |
Stations
Parent transit station locations (GTFS location_type = 1).
| Field | Data Type | Allow NULL | Domain | Description |
|---|---|---|---|---|
station_id |
Text | No | — | Unique station identifier sourced from the curated stations_v1 GDB layer |
station_name |
Text | No | — | Human-readable station name |
location_type |
Integer | No | GTFS: 1 = Station |
GTFS location type |
manually_added |
Integer | No | 0 = sourced from GTFS; 1 = manually added |
Indicates whether the station was manually added during the Step 1 GIS review rather than sourced natively from GTFS |
geometry |
Geometry (Point) | No | — | Station location |
Stops
Individual transit stop/platform locations actively served by transit routes and classified as TOD-eligible under SB 79.
| Field | Data Type | Allow NULL | Domain | Description |
|---|---|---|---|---|
stop_id |
Text | No | — | Unique GTFS stop identifier |
station_id |
Text | No | — | Parent station ID — assigned by spatial buffer analysis in Step 2, with manual corrections applied in Step 3 |
location_type |
Integer | No | GTFS: 0 = Stop/Platform |
GTFS location type |
stop_name |
Text | Yes | — | Stop name from GTFS or curated GDB |
agency_id |
Text | No | BA, CT, AC, SC, SF |
Transit agency short code |
agency_name |
Text | No | — | Full transit agency name |
route_short_name |
Text | Yes | — | GTFS route short name or number |
route_type |
Integer | No | See GTFS routes.txt reference | GTFS route type (e.g. 0 = tram/streetcar/light rail, 1 = subway/metro, 2 = rail) |
tod_tier |
Text | No | Tier 1, Tier 2 |
SB79 tier designation |
geometry |
Geometry (Point) | No | — | Stop location |
Access Points
Pedestrian access locations for each transit station used as the origin for TOD zone buffer generation.
| Field | Data Type | Allow NULL | Domain | Description |
|---|---|---|---|---|
access_id |
Text | No | — | Unique access point identifier. Sourced from each agency’s stop ID field; falls back to a stable coordinate-based ID (geom:<lat>,<lon>) for records with missing or colliding IDs |
station_id |
Text | No | — | Parent station ID — joined from GTFS, then resolved spatially or manually via the Step 2–3 review workflow |
access_point_name |
Text | Yes | — | Descriptive name of the pedestrian access point, sourced from each agency’s stop name field |
location_type |
Integer | No | GTFS: 2 = Entrance/Exit, 3 = Generic Node |
GTFS location type; defaults to 2 if absent in the agency source file |
geometry |
Geometry (Point) | No | — | Access point location used as the origin for TOD zone buffer generation |
Running the Pipeline
The pipeline is implemented as a sequence of four Jupyter notebooks. Each notebook is self-contained and reads/writes to a shared GeoPackage (tod_database.gpkg) defined in config.py. There are two mandatory manual GIS review gates — one after Step 1 and one between Steps 2 and 3. Do not skip them.
Prerequisites
- Python environment with
geopandas,pandas,gtfs_kit,shapely,uuid, andopenpyxlinstalled - Access to the MTC Box folder containing source data (see Source Data)
- Paths in
config.pyupdated to match your local data directory - QGIS (or equivalent) for the manual GIS review gate after Step 1
- Excel (or equivalent spreadsheet application) for the manual review gate between Steps 2 and 3
Step 1 – GTFS TOD Stop Classification
Notebook: 1_gtfs_tod_stop_classification.ipynb
Loads the regional GTFS feed and Caltrans High Quality Transit Stops (HQTS) data, classifies each stop as TOD-eligible (Tier 1 or Tier 2), and writes the results to the shared GeoPackage.
Outputs written to GPKG:
stops— GTFS location_type=0 stop/platform records served by relevant routes, withtod_stopflag andtod_tierclassificationstations— GTFS location_type=1 parent station recordsaccess_points— GTFS location_type=2 (entrance/exit) and location_type=3 (generic node) records
Manual GIS review required before running Step 2.
The
stopsandstationslayers from the GPKG serve as the starting point for manual curation. Curated output is saved to a File Geodatabase (tod_database.gdb, layersstations_v1andstops_v1), which Step 2 reads directly. Pedestrian access points are not carried through the FGDB — they are loaded directly from per-agency source files in Step 2.Stations (
stations_v1):
- Load the
stationslayer from the GPKG into GIS.- Copy it into
tod_database.gdbasstations_v1.- Manually add station records for TOD-applicable stops that lack a parent station in GTFS — for example, SFMTA light rail stops not co-located with a BART station, VTA light rail stops, and BRT stops.
Stops (
stops_v1):
- Load the
stopslayer from the GPKG into GIS.- Copy it into
tod_database.gdbasstops_v1.- Review each stop flagged as
tod_stop = 1by the automated process to confirm correctness.- For any stops that should be TOD-applicable but were not caught by the automated logic, manually set
tod_stop = 1and populate theactioncolumn with the reason for inclusion (e.g."manual — VTA BRT stop","manual — SFMTA light rail").Once both curated layers are saved to
tod_database.gdb, proceed to Step 2.
Step 2 – TOD Stop and Access Point Assignment
Notebook: 2_tod_stop_and_access_assignment.ipynb
Loads per-agency pedestrian access point datasets, normalizes and merges them into a single GeoDataFrame, joins GTFS-authoritative station_id values, then spatially assigns each TOD stop and access point to a parent station by progressively expanding station buffers at 150 ft, 300 ft, 500 ft, and 1000 ft (EPSG:26910). Points falling within exactly one station buffer are assigned; points intersecting multiple station buffers at the same distance are flagged as conflicts. Non-TOD stations are excluded before spatial assignment using the station overrides list (2026_03_04_tod_stations_overrides.xlsx). Outputs development layers to the shared GeoPackage and a review Excel workbook for manual resolution.
Access point sources (loaded and normalized in order):
Defined in ACCESS_PTS_SOURCES in config.py. Update file paths there when new agency source files are available.
Outputs written to GPKG (development layers — not yet authoritative):
tod_stations_dev— station layer used for spatial assignment (filtered to TOD stations)tod_stops_dev— TOD stops with spatially assignedstation_idandassignment_statustod_access_points_dev— merged access points with spatially assignedstation_idandassignment_status
Review workbook written to Box data folder:
SB79_tod_review.xlsx— contains all stops and access points withassignment_statusandstation_id; reviewers use this file to resolve conflicts and no-match records before running Step 3
Manual Excel review required before running Step 3.
- Before editing — rename the file. Rename
SB79_tod_review.xlsxtoSB79_tod_review_reviewed_YYYY_MM_DD.xlsx(replacingYYYY_MM_DDwith today’s date). This prevents a future re-run of Step 2 from overwriting your work. Then updateREVIEW_XLSXinconfig.pyto point to the renamed file path.- Priority — resolve
conflictandno_matchrecords first.
- Filter each sheet to rows where
assignment_statusisconflictorno_match.- Open the corresponding
_devlayer (tod_stops_devortod_access_points_dev) in QGIS/ArcGIS Pro alongsidetod_stations_devto visually identify the correct parent station.- Copy the correct
station_idfromtod_stations_devinto thestation_idcell for that row.- Set
assignment_status=manual_station_assignmentusing the dropdown.- Secondary — correct any mis-assigned records.
- If a row has
assignment_status = assignedbut the spatial assignment produced the wrong station (e.g., a stop was snapped to the nearest station rather than its true parent), updatestation_idto the correct value and setassignment_status=manual_station_assignment.- Leave correctly-assigned rows untouched — only rows with
assignment_status = manual_station_assignmentare applied as updates in Step 3.- Save the workbook, then run Step 3.
Step 2b – Review Reconciliation
Notebook: 2b_tod_review_reconciliation.ipynb
Run only when Step 2 has been re-run after new stops or access points were added, making the existing reviewed workbook stale. Reconciles the fresh SB79_tod_review.xlsx with the previously-reviewed workbook (REVIEW_XLSX in config.py) to carry forward valid manual_station_assignment decisions, then writes a new dated workbook as the starting point for the next manual review cycle.
Carry-over rules:
- Only rows with
assignment_status = manual_station_assignmentare carried from the stale workbook —conflictandno_matchrows are discarded in favour of the fresh spatial assignment. - Carried-over
station_idvalues that no longer exist in the current TOD station universe are downgraded toconflictand flagged for re-review. - Records dropped from the new ID universe (present in the stale workbook but absent from the fresh Step 2 output) are reported in the notebook output but not written to the reconciled workbook.
Inputs (set in config.py):
REVIEW_XLSX_OUTPUT(SB79_tod_review.xlsx) — fresh Step 2 output; authoritative ID universeREVIEW_XLSX(SB79_tod_review_reviewed_YYYY_MM_DD.xlsx) — stale reviewed workbook with prior manual overridesGPKG_TOD_STATIONS_DEV_LAYER— used to validate carried-overstation_idvalues
Output written to Box data folder:
SB79_tod_review_YYYY_MM_DD.xlsx— reconciled workbook with today’s date; ready for manual review
After running this notebook:
- Update
REVIEW_XLSXinconfig.pyto point to the new dated output file.- Open the file and resolve any remaining
conflictorno_matchrows (same process as after Step 2).- Save the workbook, then run Step 3.
Step 3 – Station Assignment Reintegration
Notebook: 3_tod_station_assignment_reintegration.ipynb
Reads the manually-reviewed Excel workbook (path set via REVIEW_XLSX in config.py), validates any manually-assigned station_id values against the TOD station universe, applies corrections to the development datasets, and exports the final authoritative layers to the shared GeoPackage.
Inputs:
- Reviewed workbook (path set via
REVIEW_XLSXinconfig.py) — the renamedSB79_tod_review_reviewed_YYYY_MM_DD.xlsxfile withmanual_station_assignmentrows filled in tod_stations_dev,tod_stops_dev,tod_access_points_dev— development layers from Step 2 (read from GPKG)
Outputs written to GPKG (final authoritative layers):
tod_stations— final station layer (see Pipeline Outputs)tod_stops— final stops with all manual corrections applied (see Pipeline Outputs)tod_access_points— final access points with all manual corrections applied (see Pipeline Outputs)
No manual review required between Steps 3 and 4.
Step 4 – TOD Zone Buffer Generation
Notebook: 4_tod_zone_buffer_generation.ipynb
Loads the finalized tod_access_points layer from the shared GeoPackage and generates the SB79 TOD zone geography through four main stages:
- Buffer generation — creates full-circle Euclidean buffers at 200 ft, ¼ mile, and ½ mile around each access point, tagged with
tod_tierandbuffer_band. - Jurisdictional population rule — erases all buffers (200 ft, ¼ mile, ½ mile) within unincorporated county lands; additionally erases half-mile buffers within incorporated cities with total population < 35,000.
- Geographic priority resolution — applies a sequential erase to produce six non-overlapping zone layers labeled by
zone_label. See Geographic Prioritization Approach in Development Notes. - Finalization (planned) — dissolves by
zone_labeland explodes to single-part polygons, producing a dataset with uniform geometry types throughout.
Inputs:
tod_access_points— finalized pedestrian access points (from Step 3)tod_stations— finalized TOD stations (from Step 3)tod_stops— finalized TOD stops (from Step 3)- Bay Area jurisdiction boundaries with ACS 2019–2023 5-year population estimates (loaded from ArcGIS REST service)
Outputs written to GPKG:
tod_zone_buffers— full-circle per-access-point buffers at all three distance bands; diagnostic/QA layer (see Pipeline Outputs)jurisdictions_with_pop_acs2019_2023— jurisdiction boundaries with ACS 2019–2023 population attributestod_zones— authoritative SB79 TOD zone polygons, post-priority resolution (see Pipeline Outputs)
Process Overview
This section describes the conceptual methodology behind the pipeline. For step-by-step execution instructions, see Running the Pipeline.
Manual Data Preparation
- Manually create stations for stops that will be flagged as TOD applicable, such as SFMTA light rail stops not co-located with a BART Station (e.g. Van Ness, Church, Forest Hill, Yerba Buena/Moscone, etc.), VTA light rail stops, and BRT stops.
- Manually create pedestrian access points for stops that will be flagged as TOD applicable following the same process as above (add guidance from HCD on what constitutes a pedestrian access point, e.g. crosswalks, sidewalks, etc.).
Load Data and Libraries
- Set up environment and load necessary libraries (e.g., pandas, geopandas, gtfs_kit)
- Load GTFS data using gtfs_kit and convert to GeoDataFrame for spatial analysis
- Load pedestrian access point data and transit station data as GeoDataFrames
- Load Caltrans High Quality Transit Stops (HQTS) data as GeoDataFrame
Prepare Data for Analysis
- Enrich GTFS stops with route and agency information by merging with routes and agency tables; aggregate to get lists of routes and agencies serving each stop
- Filter GTFS stops to include only those served by relevant transit agencies (e.g., BART, Caltrain, AC Transit, SFMTA, VTA)
- Separate stations and stops based on GTFS hierarchy based on location_type and parent_station fields (see GTFS documentation for details)
- Filter Caltrans High Quality Station Stops to include only those with
HQTA Type == major_stop_brt
Flag Transit-Oriented Development (TOD) Stops
- Flag GTFS stops as TOD applicable if they are either:
- A stop that meets the Caltrans definition of a major BRT stop (i.e., in the filtered Caltrans dataset) using a list of
stop_ids from the filtered HQTS dataset, OR - A stop with
route_type in [0 (Tram, Streetcar, Light rail), 1 (Subway, Metro)](see GTFS documentation for details) oragency_id == 'CT' (Caltrain)- Exceptions: Exclude stops South of Tamien Station on the Caltrain System, and BART stops within Contra Costa County.
- A stop that meets the Caltrans definition of a major BRT stop (i.e., in the filtered Caltrans dataset) using a list of
- Create Transit Tier classification:
- Tier 1:
route_type == 1 (Subway, Metro)oragency_id == 'CT' (Caltrain) - Tier 2:
route_type == 0 (Tram, Streetcar, Light rail)or a stop that meets the Caltrans definition of a major BRT stop (i.e., in the filtered Caltrans dataset) using a list ofstop_ids from the filtered HQTS dataset.
- Tier 1:
- Create a final filtered GeoDataFrame of TOD applicable stops, including relevant attributes such as stop_id, stop_name, parent_station, agency_name, route_short_name, and geometry.
Associate Parent Stations with TOD Stops & Access Points
- Associate stops and access points with parent stations. This may be performed by spatially joining stops and access points to stations using a near spatial join with a specified distance threshold (e.g. 200 feet) though manual review and adjustments will likely be necessary to ensure accurate associations, especially in dense urban areas where multiple stations and stops may be in close proximity.
Create Transit-Oriented Development (TOD) Zones
- Generate full-circle Euclidean buffers at 200 ft, ¼ mile, and ½ mile around each finalized pedestrian access point; tag each buffer with
tod_tierandbuffer_band. - Apply the jurisdictional population rule: erase all buffers (200 ft, ¼ mile, ½ mile) within unincorporated county lands; additionally erase half-mile buffers within incorporated cities with total population < 35,000.
- Resolve geographic priority via sequential erase: split buffers into six groups by
(tod_tier, buffer_band), then for each group in priority order, erase the accumulated geometry of all higher-priority zones before assigning azone_label. This produces six clean, non-overlapping zone layers. See Geographic Prioritization Approach for implementation details. - Finalize: dissolve by
zone_label - Export the buffer layer, jurisdiction boundaries with population, and resolved TOD zones to the shared GeoPackage.
Development Notes
SB79 TOD Zones – Policy Applicability Matrix
This table summarizes where Transit-Oriented Development (TOD) Zones apply by Transit Tier and Jurisdiction Type. Distances are measured from pedestrian access points and represent distinct distance bands.
Where TOD Zones Apply
| Tier | City with Population > 35,000 | City with Population ≤ 35,000 | Unincorporated Area |
|---|---|---|---|
| Tier 1 | 0–200’ 201’–1320’ 1321’–2640’ |
0–200’ 201’–1320’ |
Not Applicable |
| Tier 2 | 0–200’ 201’–1320’ 1321’–2640’ |
0–200’ 201’–1320’ |
Not Applicable |
Policy Constraints
- Tier Precedence Rule:
- Where Tier 1 and Tier 2 zones intersect, Tier 1 supersedes Tier 2. Tier 2 geometry must be erased in overlapping areas. The one exception is where a Tier 2 200 ft zone overlaps with a Tier 1 quarter-mile or half-mile zone — in that case Tier 2 200 ft prevails, as it carries higher development standards than either Tier 1 distance band.
- Geographic Scope:
- Applies only to cities located within:
- Alameda County
- San Francisco County
- San Mateo County
- Santa Clara County
- Applies only to cities located within:
- Distance Bands:
- Bands are distinct (non-cumulative):
- 0–200 feet
- 201–1320 feet (¼ mile ring excluding first 200 feet)
- 1321–2640 feet (½ mile ring excluding first ¼ mile)
- Bands are distinct (non-cumulative):
TOD Zone Geographic Prioritization
Where buffers from different tiers and distance bands overlap after union, each geometry is assigned a single TOD zone classification representing the most permissive applicable development standard under SB 79. The prioritization cascades as follows:
| Priority | Zone | Height limit | Density (du/ac) | Residential FAR |
|---|---|---|---|---|
| 1 | Tier 1 — 200 ft | 95 ft | 160 | 4.5 |
| 2 | Tier 2 — 200 ft | 85 ft | 140 | 4.0 |
| 3 | Tier 1 — Quarter mile | 75 ft | 120 | 3.5 |
| 4 | Tier 1 — Half mile* | 65 ft | 100 | 3.0 |
| 5 | Tier 2 — Quarter mile | 65 ft | 100 | 3.0 |
| 6 | Tier 2 — Half mile* | 55 ft | 80 | 2.5 |
*Half-mile band only applies within incorporated cities with population ≥ 35,000. All bands (200 ft, quarter-mile, and half-mile) are erased from unincorporated county lands.
This ordering reflects two rules. First, Tier 1 takes full precedence over Tier 2 at all distance bands — all Tier 1 zones are resolved before any Tier 2 zone beyond 200 ft. Second, both 200 ft zones are resolved first as a pair because Tier 2 200 ft development standards (85 ft, 140 du/ac) are more permissive than either Tier 1 quarter-mile (75 ft, 120 du/ac) or Tier 1 half-mile (65 ft, 100 du/ac), so Tier 2 200 ft takes priority 2 ahead of those bands. The result is that Priority 1 always yields the highest entitlements and Priority 6 the lowest — a geometry retains the classification of the highest-priority zone it falls within.
See Geographic Prioritization Approach for implementation details.
Geographic Prioritization Approach
The priority order above is implemented via a sequential erase rather than a union-then-classify approach. A union-based approach would fragment geometry at every intersection boundary — producing thousands of small polygons across the entire study area, each requiring individual classification. The sequential erase avoids this entirely and produces clean, non-overlapping polygons directly.
The approach works as follows: the six (tod_tier, buffer_band) groups are processed in priority order. The highest-priority group (Tier 1 – 200 ft) is kept unchanged and becomes the initial accumulated mask. For each subsequent group, a dissolved union of all previously processed groups is erased from the current group’s geometry before it is assigned its zone_label. The accumulated mask grows with each iteration, so by the time the lowest-priority group (Tier 2 – Half Mile) is processed, the geometry of all five higher-priority zones has already been removed from it.
After each erase step, zero-area floating-point artifacts are dropped and geometry validity is repaired before the result is appended to the accumulated mask. The six resulting layers are concatenated to form tod_zones.
Technical Considerations
- GTFS data provides the authoritative source for transit stop locations and service patterns. Agency filtering focuses on relevant Bay Area operators: BART (BA), Caltrain (CT), AC Transit (AC), VTA (SC), and SFMTA (SF). Parent-child relationships in the GTFS hierarchy distinguish between stations (
location_type=1) and individual stops/platforms (location_type=0). - Some stops and access points are not fully represented in GTFS and require manual mapping. This includes SFMTA light rail stops not co-located with a BART station, VTA light rail stops, and BRT stops. Manually mapped features are tracked via the
actioncolumn in the curated stop and station layers. - Caltrans High Quality Transit Areas (HQTA) Stops data is used to identify TOD-eligible bus stops. Specifically, stops with
hqta_type = major_stop_brtare used to flag Tier 2 BRT stops based on frequency standards derived from GTFS schedule data. The HQTA dataset is updated monthly by Caltrans — the version acquired for this analysis is recorded in the Source Data table. For methodology details see the Caltrans HQTA documentation. - All spatial operations in Step 4 use EPSG:26910 (UTM Zone 10N) as the analysis CRS for accurate planar distance and area measurements. Reprojection to EPSG:4326 occurs only at final GeoPackage export.
- After each erase operation in Step 4, polygon fragments smaller than 100 m² are discarded as floating-point artifacts. This threshold was validated against the actual area distribution of post-overlay fragments, which showed a hard gap between near-zero artifacts (all < 1 m²) and the smallest legitimate fragment (> 1,279,000 m²).
tod_zone_buffersis a diagnostic layer retained for QA and public transparency. The authoritative output for policy and regulatory use istod_zones.