The user wants to enrich the attributes table with daily weather conditions
(max temperature, rain indicator) for the day of travel. This is only feasible
where exact calendar dates are preserved in the raw survey data.
| Source | Year | Month | Calendar day | Verdict |
|---|---|---|---|---|
| CMAP | ✓ | ✓ | ✓ (raw travdate is YYYY-MM-DD) |
Viable |
| NHTS | ✓ | ✓ | ✗ (YYYYMM only) | Not possible |
| LTDS | ✓ | ✗ | ✗ | Not possible |
| NTS | ✓ | ✓ | ✗ | Not possible |
| QHTS | ✓ | ✓ | ✗ | Not possible |
| VISTA | ✓ | ✓ | ✗ | Not possible |
CMAP is the only source where the raw household CSV (household.csv) has a full
travdate (YYYY-MM-DD) field. The current code parses it but immediately drops
it after extracting year/month/weekday. CMAP covers travel years 2017–2019
(Chicago metropolitan area).
Open-Meteo historical weather API
- Free, no API key required
- REST API returning JSON; callable with
urllib.request(no new deps) - Global coverage, 9 km grid resolution from 2017 onward (perfect for CMAP 2017–2019)
- Historical data back to 1940
- Relevant daily variables:
temperature_2m_max→max_temp_c(°C)precipitation_sum→ deriverainasprecipitation_sum > 0
For all CMAP respondents, use Chicago city-centre coordinates (lat = 41.85, lon = −87.65). The metro area spans ~50 miles but daily max temp and rain are sufficiently uniform at this scale.
One-time script to download Chicago daily weather and write a lookup CSV.
scripts/fetch_weather.py
--start DATE (default: 2017-01-01)
--end DATE (default: 2019-12-31)
--out PATH (default: configs/cmap/weather_chicago.csv)
Pre-generated by fetch_weather.py. Keyed on date (YYYY-MM-DD string).
Columns: date, max_temp_c, precipitation_mm.
load_households() — preserve the calendar date before dropping it:
hhs = hhs.with_columns(
survey_date=pl.col("date").dt.strftime("%Y-%m-%d"), # add
year=pl.col("date").dt.year().cast(pl.Int32),
month=pl.col("date").dt.month().cast(pl.Int8),
day=pl.col("date").dt.weekday().replace_strict(config["day"]),
).drop("date")New load_weather(configs_root) helper + join in load():
def load_weather(configs_root: Path) -> pl.DataFrame:
return pl.read_csv(Path(configs_root) / "cmap" / "weather_chicago.csv")
# in load():
weather = load_weather(configs_root)
attributes = attributes.join(weather, left_on="survey_date", right_on="date", how="left")
attributes = attributes.drop("survey_date")Add two nullable attributes fields:
max_temp_c:
dtype: float
default: True
description: "Daily maximum temperature (°C) for the travel day. Null if unavailable."
rain:
dtype: bool
default: True
description: "Whether precipitation > 0 mm was recorded on the travel day. Null if unavailable."| File | Change |
|---|---|
scripts/fetch_weather.py |
create — one-time download script |
configs/cmap/weather_chicago.csv |
create — generated by script, commit to repo |
foundata/cmap.py |
preserve survey_date, add load_weather(), join in load() |
configs/core/template.yaml |
add max_temp_c and rain fields |
# generate the weather CSV (run once)
uv run python scripts/fetch_weather.py
# lint
uv run ruff check foundata/ scripts/
# unit tests
uv run pytest tests/ -v
# dry run (requires CMAP data)
uv run python scripts/run.py --data-root ~/Data/foundata --output ~/Data
# check: all_attributes.csv should have non-null max_temp_c/rain for cmap rows