RAINBOWSTATS™ · OUR FIRST ECOLOGICAL STUDY

Remembering the River

From two weeks in Wisconsin’s Northwoods to Chinook passage at Bonneville: a book, a new data source, and a first attempt to listen to the record.

By Bill Igoe · October 20, 2026

Run the complete study in RainbowStats →
Open the models, threshold comparisons, and residual diagnostics. The full script is also included below.

A book in the Northwoods

During my two weeks in the Northwoods of Wisconsin, I read Jason Dove Mark’s The Earth Said Remember Me: How to Revive Our Memories and Restore the Planet. It gave me the impetus to add ecological data to RainbowStats. Could the statistical tools I have spent so much time developing help us document changes in the Earth system?

On his website, Mark puts the invitation simply:

“Go outside. Bear witness.
Make a record. Pass it on.”

A record gives memory something to return to. It lets us compare observations across years, examine relationships, and question an impression that might otherwise become accepted as normal. My response to the book was to begin with data close to home: the Columbia Basin’s salmon and rivers.

I approach this as an amateur ecologist, bringing the habits of a time-series analyst: examine the observations, state the assumptions, and look carefully at what a model leaves unexplained.

Our first step: DART and Bonneville

Columbia River DART—Data Access in Real Time—is provided by Columbia Basin Research at the University of Washington. It brings together fish passage and environmental records from monitoring programs across the basin. Our new DART command makes selected records available directly in RainbowStats:

salmon=DART("BON","CHINOOK")
temp=DART("BON","TEMPERATURE")
flow=DART("BON","OUTFLOW")
spill=DART("BON","SPILL")

This first study examines Chinook passage at Bonneville Dam, with a data request beginning in 2000 and extending into 2026. Temperature is measured in degrees Celsius; outflow and spill are in thousands of cubic feet per second. The regression uses 7,484 complete observations.

These are passage counts at a dam. They do not directly measure survival, unique fish, or the total abundance of salmon across the basin. That distinction matters when interpreting every chart that follows.

2026-10-20T16:22:34.905982 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/ 0 10000 20000 30000 40000 50000 60000 70000 Reported passage (fish/day) Bonneville: a record of passage and river temperature 2000 2005 2010 2015 2020 2025 0 5 10 15 20 Water temperature (°C) 20°C: illustrative model split
Figure 1. Bonneville passage and temperature series retrieved through RainbowStats. The dashed line marks the illustrative 20°C split used below. Plots use the chart display series; the regression uses its complete-case estimation sample. Missing intervals are not filled with zeros. These charts provide context, not an estimated long-term trend.

Start with the seasons

The first question is modest: how much of the daily variation in passage can we account for with water temperature, outflow, spill, and monthly seasonal controls?

The monthly controls matter because migration is seasonal. A temperature coefficient without a seasonal comparison can mix the timing of a run with the conditions fish encounter. Month indicators help make that comparison more specific, although they cannot capture every feature of run timing.

ResultPooled model
Complete observations7,484
R²0.411
Durbin–Watson statistic0.264
Temperature coefficient+107.18 fish/day per °C

The model accounts for about 41% of the observed passage variation. The positive temperature coefficient is a conditional association in this specification. It does not establish that warmer water benefits salmon. Seasonal composition, omitted influences, and dependence over time all affect how much we can infer.

Does a temperature split help?

We next fit separate regressions at or below 20°C and above 20°C. This is a fixed, illustrative split; we have not estimated or validated a biological threshold.

There are 5,884 observations at or below the split and 1,600 above it. Allowing the two regimes to have separate coefficients reduces the in-sample residual sum of squares by 5.29%.

That is a useful clue, but the extra flexibility belongs to the entire model: temperature, river-operation coefficients, and the available monthly effects can all change. The improvement cannot be attributed solely to temperature. Nor does a better in-sample fit establish better forecasting performance.

The conventional temperature t-statistics within the two regimes are only about 1.16 and 1.03. Coupled with the dependence discussed next, these results call for restraint about a distinct temperature-slope effect. Blank or undefined coefficients for some warm-regime month indicators reflect absent or redundant information within that restricted sample.

The residuals have a story

The pooled model’s Durbin–Watson statistic, 0.264, is a strong warning of positive residual persistence. A large unexplained passage count tends to be followed by another unexplained count in the same direction. Monthly indicators and contemporaneous river conditions have left temporal structure behind.

2026-10-20T16:22:35.354754 image/svg+xml Matplotlib v3.10.8, https://matplotlib.org/ Mar 2024 Sep 2024 Mar 2025 Sep 2025 Mar 2026 Sep 2026 −10000 −5000 0 5000 10000 15000 20000 25000 Actual − fitted (fish/day) What the pooled regression leaves unexplained
Figure 2. A recent window of pooled-regression residuals, in fish/day. Positive values indicate passage above the fitted value; negative values indicate passage below it. These are residuals from the pooled regression, not from the two-regime fit.

We fit ARMA(1,2), ARMA(3,2), and a SARIMA model with a five-observation seasonal period to those pooled residuals. The five-observation period is an exploratory modeling choice, not a demonstrated biological cycle.

The revised diagnostic examines autocorrelation through 24 observation lags, with a fitted-parameter adjustment to the reference degrees of freedom:

Model for pooled residualsQ(24)Test dfReference p-value
ARMA(1,2)168.40215.25 × 10⁻²⁵
ARMA(3,2)162.74197.42 × 10⁻²⁵
SARIMA(1,0,2)(0,0,1)₅157.99201.83 × 10⁻²³

All three report substantial remaining dependence over this horizon. A reassuring result at lag 1 alone would have missed it. The residual models capture some persistence, but they have not exhausted the temporal structure in the record.

These are approximate diagnostic reference probabilities, not probabilities that a model is true. The observations are a complete-case sample, and gaps in the calendar or between migration seasons require explicit treatment. The preceding regression and subsequent residual modeling also make this a two-stage exploration. We should not treat the tiny numbers as a measure of ecological importance.

What this changes: conventional regression standard errors are not a reliable stopping point. HAC inference is a next comparison, and a model with serially correlated errors may be appropriate. Fitting ARMA to residuals alone does not revise the original temperature, flow, or spill coefficients.

A beginning worth recording

Our first ecological study has produced a useful result: a simple model explains part of the passage record, while its residuals expose questions that the model has not answered.

We have not established a long-term warming trend, a change in salmon survival, or a causal effect of dam operations. Documenting change over time will require explicit comparisons of temperature, passage timing, run composition, and coverage across years. The present study establishes a reproducible starting point for that work.

A second post will extend the analysis to Bonneville, McNary, and Lower Granite, using seemingly unrelated regression and HAC inference to examine dependence across locations as well as through time. Migration delays will need attention too.

Mark’s book prompted me to make a record. DART gives us access to records that others have carefully collected. Our task is to use them with enough care that the questions, as well as the findings, can be passed on.

Explore and reproduce the Bonneville study →
The saved analysis provides the script; values may change as source observations are revised or extended.

Reproduce the study

Show the complete RainbowStats script
salmon=DART("BON","CHINOOK")
temp=DART("BON","TEMPERATURE")
flow=DART("BON","OUTFLOW")
spill=DART("BON","SPILL")
hydro=ADD_MONTHLY_DUMMY_SERIES(LIST(salmon,temp,flow,spill))
hydro_model=REGRESSION(hydro)
hydro_threshold=FIXED_THRESHOLD_REGRESSION(hydro,1,20)
hydro_summary=EXTRACT(hydro_threshold,model)
hydro_below=EXTRACT(hydro_threshold,below_model)
hydro_above=EXTRACT(hydro_threshold,above_model)
hydro_pooled=EXTRACT(hydro_threshold,pooled_model)
res=EXTRACT(hydro_threshold,pooled_residuals)
a=ARMA(res,1,2)
b=ARMA(res,3,2)
c=SARIMA(res,1,0,2,0,0,1,5)
intro=TEXT_SLIDE("Chinook Passage at Bonneville","Temperature, outflow, spill, monthly seasonal controls, a fixed 20-degree threshold, and residual persistence.")
SLIDESHOW(intro,hydro_model,hydro_summary,hydro_below,hydro_above,hydro_pooled,a,b,c,EXTRACT(a,autocorrelation),EXTRACT(b,autocorrelation),EXTRACT(c,autocorrelation))