Find climates you like.
Pogodapp is a small FastAPI app that scores long-term climate normals against a few preferences, then shows matching cities and a world heatmap.
- Single-page app: controls, map, and ranked results stay on one screen.
- Scores land cells from WorldClim climate normals.
- Ranks cities near good-scoring cells.
- Lets you hover the map to inspect one cell with
/probe.
- FastAPI
- DuckDB
- NumPy
- Jinja2 for first render
- HTMX for form submission
- MapLibre GL for the map
- Pillow for PNG heatmaps
GET /renders the app shell.POST /scoreaccepts standard form fields and returns JSON with ranked cities plus aheatmap_url.GET /heatmapreturns the rendered PNG for the current preferences, or204when nothing matches.GET /probereturns a score breakdown for one map point.GET /healthis a basic health check.
Input fields for scoring:
preferred_day_temperaturesummer_heat_limitwinter_cold_limitdryness_preferencesunshine_preference
Temperature rules:
preferred_day_temperature:-5..35summer_heat_limit:-5..42winter_cold_limit:-15..35preferred_day_temperature <= summer_heat_limitpreferred_day_temperature >= winter_cold_limit
Rate limits:
/score:30/minute/heatmap:30/minute/probe:120/minute
- Temperature is the main signal.
- Dryness and sunshine matter more when the user moves those sliders away from neutral.
- Scores are normalized per request, so the best available match is
1.0. - City results are spread out so one region does not flood the list.
- Source: WorldClim 2.1 monthly normals.
- Default runtime dataset: native
5mresolution. - Main database:
data/climate.duckdb. climate.duckdbis generated, not committed to the repo.- If the database is missing, the app falls back to a small in-repo stub dataset by default.
- Set
POGODAPP_BUILD_CLIMATE_DB_IF_MISSING=trueto generate and validateclimate.duckdbduring app launch. - Production deployments should use persistent
data/storage so startup generation is a one-time bootstrap. - Older databases from before the
tmin_*andtmax_*schema change are not compatible. Rebuild them.
uv sync
uv run pogodappDefault local URL: http://127.0.0.1:8000
Useful variants:
POGODAPP_CLIMATE_DB=data/climate-5m.duckdb uv run pogodapp
uv run pogodapp --port 9000
uv run pogodapp --host 0.0.0.0
uv run pogodapp --no-reloaduv run python scripts/build_climate_db.pyOptional resolution override:
uv run python scripts/build_climate_db.py --resolution 10mSupported resolutions: 10m, 5m, 2.5m, 30s.
docker build -t pogodapp .
docker run -p 8000:8000 pogodappThe image excludes generated DuckDB data. Mount persistent data when running with a real climate database:
docker run -p 8000:8000 -v pogodapp-data:/app/data pogodappSet POGODAPP_BUILD_CLIMATE_DB_IF_MISSING=true to bootstrap /app/data/climate.duckdb on startup.
POGODAPP_DATA_DIR: base directory for runtime data. Default:dataPOGODAPP_CLIMATE_DB: DuckDB path. Default:{POGODAPP_DATA_DIR}/climate.duckdbPOGODAPP_CLIMATE_CACHE_DIR: download cache directory. Default:{POGODAPP_DATA_DIR}/worldclimPOGODAPP_BUILD_CLIMATE_DB_IF_MISSING: build the database on startup when missing. Default: disabled, using stub data insteadPOGODAPP_CLIMATE_RESOLUTION: bootstrap resolution. Default:5mPOGODAPP_HOST: bind host overridePORT: bind port. Default:8000POGODAPP_RELOAD: toggles reload modeLOG_LEVEL: log level override. Default:INFOLOG_FORMAT:jsonorplain. Default:json
uv run ruff check .
uv run ruff format --check .
uv run ty check
uv run pytest