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.