AI Updates
2026-02-18 — Fix reactable table not rendering
- Root cause:
Reactable(...)was called inside nestedifblocks inbirdweather/index.qmd. IPython only auto-displays the last top-level expression in a cell; expressions inside conditionals are silently discarded. - Fix: Wrapped the
Reactable(...)call withdisplay()so the widget is explicitly rendered.
2026-02-18 — Rare birds paginated table with reactable-py
- Replaced itables with reactable-py in
birdweather/pixi.toml(PyPI dependency, since it’s not on conda-forge). - Updated “Rarest Visitors” section in
birdweather/index.qmd: now shows all single-detection species (count == 1) in a searchable, paginated reactable table with thumbnail, species name, certainty indicator dots, and eBird link.
2026-02-18 — Fix broken eBird links in species gallery
- Root cause: The BirdWeather
topSpeciesAPI only returns the station’s top ~19 species — it caps at that regardless of thelimitparameter. The remaining 117 detected species had no metadata (includingebirdUrl), rendering brokenhref="#"links in the gallery. - New function (
birdweather/fetch_data.py): Addedget_species_by_ids()which uses the rootallSpecies(ids: [...])GraphQL query to batch-fetch full species metadata (ebirdUrl, imageUrl, etc.) for any set of species IDs. - Species meta sync (
birdweather/data_store.py):sync_species_metanow falls back toget_species_by_ids()for species not covered bytopSpecies. Also detects existing cache entries with nullebirdUrland backfills them. All 136 species now have valid eBird URLs. - Gallery fix (
birdweather/index.qmd): The “View on eBird →” link is now conditionally rendered only whenebirdUrlis non-empty, as a defensive measure. - Detections query (
birdweather/fetch_data.py): AddedebirdUrl,imageUrl,thumbnailUrl,color, andwikipediaSummaryto thespeciessubquery inget_detections()for richer data going forward. Schema alignment insync_detectionshandles old parquet files missing these columns. - Deleted and rebuilt
species_meta.parquet— now contains all 136 species with full metadata.
2026-02-18 — Add species richness tab to environmental correlations
- Refactored the Environmental Correlations section in
birdweather/index.qmdinto a Quarto.panel-tabsetwith two tabs: Detection Count (original charts) and Species Richness (new charts). - Species richness is computed as the number of unique species detected per day (
speciesId.n_unique()grouped by date). - Both tabs show temperature, humidity, and barometric pressure scatter plots with regression trend lines, mirroring each other’s structure.
- Data preparation is shared in a single hidden code cell; each tab has its own display cell.
- Added a
shown.bs.tabJS listener that dispatches aresizeevent so Vega-Lite charts inside initially-hidden tabs recalculate theirwidth:"container"dimensions on tab switch.
2026-02-18 — Automated daily birdweather render via launchd
- Created
scripts/render-birdweather.sh: rendersbirdweather/index.qmd(viapixi run), then renders the full site, commits_freeze/changes, and pushes to GitHub (triggering Netlify auto-deploy). Logs to~/Library/Logs/render-birdweather.logand sends a macOS notification on failure. - Created
~/Library/LaunchAgents/com.connorfrench.render-birdweather.plist: runs the script daily at 12 PM local time via macOS launchd. Handles wake-from-sleep catch-up. - Parquet data (
birdweather/data/) stays local and gitignored; only_freeze/and tracked file changes are committed. - To manage:
launchctl load|unload ~/Library/LaunchAgents/com.connorfrench.render-birdweather.plist
2026-02-18 — Move pixi environment to birdweather/
- Created
birdweather/pixi.tomlas a standalone pixi workspace with all previously root-level dependencies (polars, altair, seaborn, matplotlib, requests, python-dotenv, jupyter, vl-convert-python, Python 3.14). - Ran
pixi installinbirdweather/to generatebirdweather/pixi.lock. - Removed
[tool.pixi.*]sections from rootpyproject.toml(kept project/build-system metadata). - Deleted root
pixi.lock. - Updated
.gitattributesto trackbirdweather/pixi.lockinstead of rootpixi.lock. - Render birdweather from within its directory:
cd birdweather && pixi run quarto render index.qmd
2026-02-18 — Fix overview counts using local cached detections
- The “Species Detected” and “Total Detections” cards in the BirdWeather overview were using
overview["counts"]from the GraphQL API, which returned stale/incomplete numbers (19 species, 607 detections). Changedbirdweather/index.qmdto compute these counts from the locally synceddetectionsDataFrame instead, which has the full data (96K+ detections, 136 species).
2026-02-18 — Incremental Parquet Cache for BirdWeather
What changed
- New module: Added
birdweather/data_store.py— local Parquet caching layer with incremental sync and local aggregation functions - Incremental sync: Raw detections and environment sensor data are stored in
birdweather/data/as Parquet files. On each render, only new data since the last sync is fetched from the BirdWeather API. - Local aggregations: Top species, daily detection counts, and time-of-day counts are now computed locally from cached raw detections using Polars instead of calling the API for server-side aggregations.
- Species metadata: Cached in
species_meta.parquet, re-fetched only when new species appear in detections. - Species probabilities: Cached in
species_probabilities.parquet, re-fetched if older than 7 days (BirdWeather model data). - Station overview: Still fetched live from the API on each render (contains current weather).
.gitignore: Addedbirdweather/data/to exclude cached Parquet files from git.fetch_data.py: Increased defaultmax_pagesforget_detections()from 100 to 500 for initial seed load.index.qmd: Rewrote setup and fetch-data cells to usedata_storesync/compute functions instead of direct API calls. All downstream visualization cells unchanged (same DataFrame schemas).
2026-02-18
- Fixed
TypeError: 'DataFrame' object is not callableinbirdweather/index.qmd: removed spurious()afterenv_hist.with_columns(...)(line ~785) and changedpdf = combined()topdf = combined(line ~694). Log - Fixed “Not enough overlapping data” in env-correlations cell: changed inner join to full outer join with explicit
pl.Datecasting, useddaily_counts(365-day) instead of onlydaily_counts_30dfor more overlap with env sensor data, and filled missing detections with 0. - Root-caused env correlation issue: PUC sensor reports every ~40 seconds, so the old pagination defaults (100 rows × 50 pages = 5,000 rows) only covered ~2.3 days. Increased
page_sizefrom 100→1000 andmax_pagesfrom 50→100 inget_environment_history(), now fetching ~65K rows covering the full 30-day period. Updated both the default parameters infetch_data.pyand the call inindex.qmd. - Removed station name/number from the overview footer to avoid exposing the station ID on the public page (location is still shown).
- Fixed “Unavailable” weather: when the BirdWeather weather API returns null, the page now falls back to the PUC environment sensor’s temperature and humidity readings.
- Downsampled env-timeseries chart from ~65K raw sensor readings to hourly averages (~720 points) to stay within Altair’s 5,000-row limit.
- Extended env history fetch from 30 to 180 days (max_pages 100→400) to cover the full detection history for environmental correlations.
- Added
scale=alt.Scale(zero=False)to x-axes on all three env correlation scatter plots so the axis range fits the data rather than starting from zero.
2026-02-18 — BirdWeather Dashboard Page
What changed
- New page: Added
birdweather/index.qmd— a full bird detection dashboard page with interactive Altair visualizations - New module: Added
birdweather/fetch_data.py— Python module that wraps the BirdWeather GraphQL API, returning Polars DataFrames for station overview, top species, daily/hourly detection counts, environment sensor history, and species probability data - Navigation: Added “BirdWeather” tab to the navbar in
_quarto.yml(between Projects and Teaching) - Python environment: Initialized Pixi (
pyproject.toml) with dependencies: polars, altair, seaborn, matplotlib, requests, python-dotenv, jupyter, vl-convert-python - Config: Created
.env(forBIRDWEATHER_STATION_ID) and added.envand.pixi/to.gitignore
Dashboard sections
- Station Overview — metric cards showing total species, detections, date range, current weather & sensor readings
- Recent Activity — top 10 species in the last 7 days, new arrivals this week, 30-day detection trend, daily species richness
- All-Time Highlights — top 15 species with certainty breakdown (stacked bar), rarest visitors table
- When Do Birds Sing? — hourly detection bar chart + species × hour heatmap
- Seasonal Trends — monthly detection volume with species richness overlay, species probability heatmap (week of year × species)
- Environmental Correlations — scatter plots with trend lines for temperature, humidity, and barometric pressure vs. detection count; sensor time series
- Species Gallery — grid of top 20 species with images, names, detection counts, and Wikipedia summaries
Why
User requested a fun bird detection summary page for their BirdWeather PUC station, with short-term and long-term trends and environmental correlations.