pgx
PGX — Lightweight Postgres for AI agents. Written in Rust. Thousands of isolated databases in one runtime. 🐘
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
An interactive map of every recorded pedestrian fatality in the United States from 2001 to 2023 — over 123,000 incidents — drawn from the NHTSA Fatality Analysis Reporting System (FARS).
Each dot on the map is a person who died. The map makes two arguments visually:
1. Darkness kills. Fatalities cluster at dusk, night, and dawn — the solar overlay makes this causally visible, not just decorative.
2. The same roads keep killing. The road heat layer traces the arterial pathology of every city. The same stretches appear year after year.查看完整 README ↗An interactive map of every recorded pedestrian fatality in the United States from 2001 to 2023 — over 123,000 incidents — drawn from the NHTSA Fatality Analysis Reporting System (FARS).
Each dot on the map is a person who died. The map makes two arguments visually:
Static mode (default)
Animate mode
Incident popup
Road heat layer
Year range selector
| Layer | Technology | Notes |
|---|---|---|
| Frontend | MapLibre GL JS | Open-source Mapbox fork — no API key |
| Map tiles | OpenFreeMap | Free, no rate limits |
| Solar math | SunCalc.js | Per-slot centroid solar altitude curves |
| Backend | Python / Flask | REST API serving GeoJSON |
| Database | PostgreSQL + PostGIS | Spatial indexing for fast bbox queries |
| ETL | Python (stdlib only) | Processes raw FARS zips → PostGIS |
| Dev environment | Docker Compose | One command to start |
| Deployment target | Render + Neon | Zero ongoing cost |
data/raw/# 1. Clone (sparse — skips the large data zips)
git clone --filter=blob:none https://github.com/eddielathamjones/pedestrian-safety-mapper.git
cd pedestrian-safety-mapper
# 2. Configure environment
cp .env.example .env
# 3. Start PostGIS + Flask
docker compose up -d
# 4. Load data
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# Single year
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/pedestrian_safety \
python -m src.data_processing.etl --years 2023 --data-dir data/raw
# All years (requires full data/raw/ checkout)
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/pedestrian_safety \
python -m src.data_processing.etl --years 2001-2023 --data-dir data/raw
# 5. Open http://localhost:5001
python scripts/data_download.py
Downloads all years to data/raw/ as FARS{year}NationalCSV.zip. Decimal lat/lon coordinates are available from 2001 onwards; the ETL filters out records with missing or sentinel coordinates.
NHTSA publishes a new FARS year annually, typically August–October for the prior year. The app checks for this automatically — no manual monitoring needed to know when new data lands:
GET /api/data-status compares the live DB's max year against what's published on NHTSA and is polled once per page load (15-minute cache); if a newer year is available, the frontend shows a "Data available through YYYY" badge.scripts/check_fars_update.py does the same check standalone (python scripts/check_fars_update.py), useful for a cron/CI check outside the running app. It exits non-zero when an update is available.When a new year is available, ingest it:
# 1. Download just the new year (not the full 1975-2024 range)
python scripts/data_download.py --years 2025
# 2. Run the ETL for that year only
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/pedestrian_safety \
python -m src.data_processing.etl --years 2025 --data-dir data/raw
# 3. Update DB_MAX_YEAR in scripts/check_fars_update.py to the new max
The ETL does not deduplicate — it's a plain INSERT, not INSERT ... ON CONFLICT. Only run it for years not already in the DB; re-running it for an already-loaded year will duplicate every row for that year. If a year needs to be reloaded, delete it first: DELETE FROM incidents WHERE year = 2025;.
pedestrian-safety-mapper/
├── src/
│ ├── backend/
│ │ ├── app.py # Flask API
│ │ └── schema.sql # incidents table + GiST spatial index
│ ├── frontend/
│ │ ├── index.html
│ │ ├── css/app.css
│ │ └── js/app.js # map, animation, filter, solar overlay, popup
│ └── data_processing/
│ └── etl.py # FARS zips → PostGIS
├── data/
│ └── raw/ # FARS zip files (not tracked in git)
├── docs/
│ ├── roadmap.md # Design direction and priorities
│ ├── solar-correction.md # Solar position methodology — full technical writeup
│ ├── future-ml-direction.md
│ └── shaping/ # Product design decisions (R, shapes, slices)
├── scripts/
│ └── data_download.py
├── docker-compose.yml
├── requirements.txt
└── .env.example
GET /api/incidentsReturns a GeoJSON FeatureCollection of pedestrian fatalities.
| Parameter | Type | Required | Description |
|---|---|---|---|
year | integer | yes | Year to query (2001–2023) |
bbox | string | no | minLon,minLat,maxLon,maxLat |
Example response:
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": { "type": "Point", "coordinates": [-86.69, 33.54] },
"properties": {
"year": 2022, "month": 1, "day": 2,
"hour": 18, "minute": 48,
"lgt_cond": 2, "weather": 1, "route": 5, "rur_urb": 2,
"state": 1, "county": 73,
"age": 27, "sex": 1, "inj_sev": 4
}
}]
}
GET /api/summaryReturns total incident counts by year.
{ "2001": 4389, "2022": 7522 }
| Field | Source | Description |
|---|---|---|
geom | ACCIDENT | Point geometry (EPSG:4326) |
year, month, day | ACCIDENT | Crash date |
hour, minute | ACCIDENT | Local wall-clock time (99 = unknown) |
lgt_cond | ACCIDENT | 1=Daylight, 2=Dark–not lit, 3=Dark–lit, 4=Dawn, 5=Dusk |
weather | ACCIDENT | 1=Clear, 2=Rain, 3=Sleet, 4=Snow, 5=Fog |
route | ACCIDENT | 1=Interstate, 2=US Hwy, 3=State, 4=County, 5=Local |
rur_urb | ACCIDENT | 1=Rural, 2=Urban (available 2013+) |
state, county | ACCIDENT | FIPS codes |
age, sex | PERSON | Victim demographics (FARS sentinel values suppressed in display) |
inj_sev | PERSON | Injury severity (all records = 4, fatal) |
The map applies a solar position overlay rather than using the FARS lgt_cond field directly. Clock time is a social construct that varies by time zone and daylight saving. Solar altitude is a physical measurement.
For each hour slot, the app computes a centroid from all incidents at that hour, then uses SunCalc.js to calculate the sun's altitude at the equinox for that location. This produces a 24-element solar curve that drives the night overlay opacity and Sun HUD display.
Full technical writeup — altitude formula, UTC offset approximation, smoothstep opacity mapping, per-slot centroid method, and known limitations — is in docs/solar-correction.md.
| Slice | Status | Description |
|---|---|---|
| V1 — Data on the map | ✅ Done | Fatalities as interactive points |
| V2 — Year selector | ✅ Done | Multi-year filter (2001–2023) |
| V3 — Incident popup | ✅ Done | Date, time, lighting, weather, demographics, Street View |
| V4 — Viewport loading | ✅ Done | Fetch only visible incidents on pan/zoom |
| V5 — Extended history | ✅ Done | Full 2001–2023 dataset (123k+ incidents) |
| V6 — Solar overlay + animation | ✅ Done | 24h and week animation, solar-corrected night overlay, Sun HUD |
| V7 — Static filter mode | ✅ Done | Time window, day-of-week chips, presets, solar condition label |
| V8 — Road heat layer | ✅ Done | Kernel-density heat lines on roads |
| Phase 2 — Solar terminator | 💡 Planned | Real terminator line as a GeoJSON layer |
| Phase 2 — Sound layer | 💡 Planned | Ambient tone per dot on first appearance |
| Phase 2 — Streetlight overlay | 💡 Planned | OSM streetlight data correlated with fatality clusters |
| Phase 3 — Predictive risk model | 💡 Planned | ML risk scoring from FARS feature data |
| Phase 3 — Street View forensics | 💡 Planned | Embedded panel, thumbnails, vehicle direction |
See docs/roadmap.md for design direction and priorities.
MIT — see LICENSE for details.
Research and educational use. Consult official sources for safety-critical decisions.