Dias et al. (2025): the autumn AHY main model (Table 3), filtering reading (a)¶
Dataset DRYAD:bvq83bkk9, version id 333377 (the only
version; files and SHA-256 in the header of reproduce_dias_2025.ipynb). Paper
doi:10.1098/rspb.2024.2556.
The hierarchical model of lm_mod.stan (Zenodo doi:10.5281/zenodo.14226724) for autumn AHY birds,
as Script01 fits it: scaled wing on scaled tarsus per species-year, with sex effects per species;
the species-year intercepts and slopes depend on PrevPrevPrecipWinMo, PrevTempBreedBase,
PrevPrecipBreedBase, PrevMinTempFallMig, MinTempFallMig and year (per decade); NUTS, adapt_delta
0.85, 4 chains of 4000 iterations with 2000 warm-up, seed 9. Filtering reading (a):
{"a": "the data as deposited", "c": "specimens more than 5 MAD from the median of their species and sex removed",
"d": "specimens more than 5 unscaled MAD from the median of their species removed"}["a"].
Claims tested here, under this reading: table3-autumn-ahy-prior-breeding-temperature, table3-autumn-ahy-prior-autumn-temperature, table3-autumn-ahy-recent-autumn-temperature and the main-model part of table3-autumn-ahy-prior-wintering-precipitation. The autumn AHY numbers of claims that also need the HY and spring AHY models are printed for the record.
import tempfile
import time
import warnings
from pathlib import Path
import numpy as np
import pandas as pd
import wingallom as w
warnings.filterwarnings("ignore", module="rdata")
pd.set_option("display.width", 220)
pd.set_option("display.max_columns", 40)
import logging
started = time.time()
for name, digest in w.check_staged().items():
print(f"{name}: SHA-256 {digest} (matches Dryad's file list, version {w.DRYAD_VERSION} of {w.DRYAD_ID})")
t0 = time.time()
print("CmdStan", w.CMDSTAN_VERSION, "at", w.install_cmdstan(Path(tempfile.gettempdir()) / "cmdstan"),
f"({time.time() - t0:.0f} s to install or find)")
logging.getLogger("cmdstanpy").setLevel(logging.ERROR) # sampler messages; divergences are counted below
code_zip = w.code_zip()
original = code_zip.read("Code/lm_mod.stan").decode()
model_code = w.port_stan(original)
workdir = Path(tempfile.mkdtemp())
t0 = time.time()
model = w.compile_stan(model_code, workdir)
cpu = next((line.split(":", 1)[1].strip() for line in open("/proc/cpuinfo") if line.startswith("model name")), "unknown")
print("CPU:", cpu, "(the model is compiled with -march=native, as Script01 does, so the draws depend on the CPU)")
print(f"lm_mod.stan compiled in {time.time() - t0:.0f} s")
READING = "a"
Data.zip: SHA-256 2185ac50e9a59c3a1dff59473216de2ab001d0d0044b1fa15442ae18a520d554 (matches Dryad's file list, version 333377 of bvq83bkk9) README.md: SHA-256 6c19de67b1c6c52802be42a6593c175a02bee0dab0ca2f6f958f08a0a3fa0482 (matches Dryad's file list, version 333377 of bvq83bkk9) CmdStan 2.40.0 at /tmp/cmdstan/cmdstan-2.40.0 (0 s to install or find)
/home/runner/work/_temp/executed/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html from .autonotebook import tqdm as notebook_tqdm
03:25:16 - cmdstanpy - INFO - compiling stan file /tmp/tmpfc_2qb70/lm_mod.stan to exe file /tmp/tmpfc_2qb70/lm_mod
03:25:37 - cmdstanpy - INFO - compiled model executable: /tmp/tmpfc_2qb70/lm_mod
CPU: AMD EPYC 7763 64-Core Processor (the model is compiled with -march=native, as Script01 does, so the draws depend on the CPU) lm_mod.stan compiled in 21 s
Data check¶
morph = w.morph_prepared(READING)
removed = w.outlier_mask(w.read_csv("morphdata.csv"), READING)
p = w.prepare(morph, "autumn AHY", "main")
data = w.stan_data(p, w.MAIN_PREDICTORS["autumn AHY"])
md_ = p["md"]
print(f"reading ({READING}): {int(removed.sum())} specimens removed by the filter; {len(morph)} kept")
print(f"autumn AHY: {data['N']} birds in {data['J']} species-years of {data['K']} species (paper: 3250 and 171)")
print(f"species-years dropped for a missing climate value: rows {p['missing_rows']} of {p['n_merged']}")
print("\nBirds per species and sex:")
print(pd.crosstab(md_.Taxon, md_.Sex).to_string())
print(f"\nYears {p['G'].year.min()} to {p['G'].year.max()}; year column {data['G'][:, -1].min():.2f} to {data['G'][:, -1].max():.2f} decades")
print(f"scaled wing {data['WL'].min():.2f} to {data['WL'].max():.2f}, scaled tarsus {data['X'][:, 1].min():.2f} to {data['X'][:, 1].max():.2f}")
print("climate columns of G (scaled within species), min and max:")
print(pd.DataFrame(data["G"][:, 1:-1], columns=w.MAIN_PREDICTORS["autumn AHY"][:-1]).agg(["min", "max"]).round(2).to_string())
reading (a): 0 specimens removed by the filter; 27486 kept
autumn AHY: 3250 birds in 171 species-years of 5 species (paper: 3250 and 171)
species-years dropped for a missing climate value: rows [np.int64(1), np.int64(36), np.int64(106), np.int64(111), np.int64(112), np.int64(142)] of 177
Birds per species and sex:
Sex f m
Taxon
Junco_hyemalis 250 279
Melospiza_georgiana 353 440
Melospiza_melodia 78 112
Seiurus_aurocapilla 260 315
Zonotrichia_albicollis 627 536
Years 1982 to 2016; year column -1.60 to 1.80 decades
scaled wing -4.01 to 3.04, scaled tarsus -4.28 to 3.79
climate columns of G (scaled within species), min and max:
PrevPrevPrecipWinMo PrevTempBreedBase PrevPrecipBreedBase PrevMinTempFallMig MinTempFallMig
min -2.74 -1.92 -2.24 -2.95 -2.95
max 2.65 2.00 1.77 2.23 2.47
Fit¶
t0 = time.time()
fit = w.fit_stan(model, data, w.STAN_SEEDS["autumn AHY"], workdir)
fit_minutes = (time.time() - t0) / 60
print(f"fitted in {fit_minutes:.1f} minutes")
print(f"divergent transitions after warm-up: {fit['divergent']} of 8000 draws (chains 1 to 4: {fit['divergent_per_chain']}); "
f"largest R-hat over mu_i, mu_s, mu_stl and the standard deviations: {fit['max_rhat']:.3f}; smallest bulk ESS: {fit['min_ess_bulk']:.0f}")
names = ["Intercept", *w.MAIN_PREDICTORS["autumn AHY"]]
diag = fit["mu_summary"].copy()
diag.index = [f"{'mu_i' if i.startswith('mu_i') else 'mu_s'} {names[int(i.split('[')[1][:-1]) - 1]}" for i in diag.index]
print("\nCmdStan's diagnostics of mu_i (intercept) and mu_s (slope):")
print(diag.round(4).to_string())
table3 = w.effect_table(fit, w.MAIN_PREDICTORS["autumn AHY"])
print("\nTable 3 as fitted here (mean, s.d. and pd of mu_i, effects on the allometric intercept, and mu_s, on the slope):")
print(table3[["int_mean", "int_sd", "int_pd", "slope_mean", "slope_sd", "slope_pd"]].round(3).to_string())
print("\nMonte Carlo error of each pd (from the effective sample size of the sign indicator) and the pd of each chain:")
mc = pd.DataFrame({"int_pd": table3.int_pd, "int_pd_mcse": table3.int_pd_mcse, "int_pd_ess": table3.int_pd_ess,
"int_pd_chains": [[round(x, 3) for x in v] for v in table3.int_pd_chains],
"slope_pd": table3.slope_pd, "slope_pd_mcse": table3.slope_pd_mcse, "slope_pd_ess": table3.slope_pd_ess,
"slope_pd_chains": [[round(x, 3) for x in v] for v in table3.slope_pd_chains]})
print(mc.round(4).to_string())
stuck = w.stuck_chains(fit)
if stuck:
moving = w.effect_table(w.drop_chains(fit, stuck), w.MAIN_PREDICTORS["autumn AHY"])
print(f"\nChain(s) {', '.join(str(c + 1) for c in stuck)} stuck (every kept draw divergent). The pd over the "
f"{4 - len(stuck)} chains that move, pooled, with its Monte Carlo error:")
print(moving[["int_mean", "int_pd", "int_pd_mcse", "slope_mean", "slope_pd", "slope_pd_mcse"]].round(4).to_string())
else:
moving = None
print("\nNo chain is stuck (none has every kept draw divergent).")
def show(term, paper):
"""The claim's numbers for one term: mean, s.d. and pd with its Monte Carlo error and chains,
against the paper's mean, tolerance and pd."""
row = table3.loc[term]
print(f"{term}, reading ({READING}):")
for part in ("int", "slope"):
m, sd, pd_, se = row[part + "_mean"], row[part + "_sd"], row[part + "_pd"], row[part + "_pd_mcse"]
pm, ptol, ppd = paper[part]
print(f" {'intercept' if part == 'int' else 'slope':9s} mean {m:+.3f} (s.d. {sd:.3f}), pd {pd_:.2%};"
f" paper {pm:+.2f} (tolerance {ptol}), pd {ppd}%; within tolerance: {abs(m - pm) <= ptol + 1e-9};"
f" sign as paper: {np.sign(m) == np.sign(pm) or pm == 0}; pd >= 90%: {pd_ >= 0.9}")
print(f" Monte Carlo error of pd {se:.2%} (ESS {row[part + '_pd_ess']:.0f}), so pd - 90% is "
f"{(pd_ - 0.9) / se:+.1f} errors; pd of chains 1 to 4: {', '.join(f'{x:.2%}' for x in row[part + '_pd_chains'])}")
if moving is not None:
mrow = moving.loc[term]
mpd, mse = mrow[part + "_pd"], mrow[part + "_pd_mcse"]
print(f" chains that move, pooled: mean {mrow[part + '_mean']:+.3f}, pd {mpd:.2%}, Monte Carlo error {mse:.2%},"
f" so pd - 90% is {(mpd - 0.9) / mse:+.1f} errors; pd >= 90%: {mpd >= 0.9}")
03:25:38 - cmdstanpy - INFO - CmdStan start processing
03:25:38 - cmdstanpy - INFO - Chain [1] start processing
03:25:38 - cmdstanpy - INFO - Chain [2] start processing
03:25:38 - cmdstanpy - INFO - Chain [3] start processing
03:25:38 - cmdstanpy - INFO - Chain [4] start processing
03:34:21 - cmdstanpy - INFO - Chain [4] done processing
03:37:52 - cmdstanpy - INFO - Chain [2] done processing
03:37:56 - cmdstanpy - INFO - Chain [1] done processing
03:39:38 - cmdstanpy - INFO - Chain [3] done processing
03:39:38 - cmdstanpy - WARNING - Non-fatal error during sampling: Exception: normal_lpdf: Scale parameter[1] is 0, but must be positive! (in 'lm_mod.stan', line 43, column 6 to column 35) Exception: normal_lpdf: Scale parameter is 0, but must be positive! (in 'lm_mod.stan', line 38, column 4 to column 29) Exception: normal_lpdf: Scale parameter is 0, but must be positive! (in 'lm_mod.stan', line 38, column 4 to column 29) Exception: normal_lpdf: Scale parameter is 0, but must be positive! (in 'lm_mod.stan', line 38, column 4 to column 29) Exception: normal_lpdf: Scale parameter is 0, but must be positive! (in 'lm_mod.stan', line 38, column 4 to column 29) Exception: normal_lpdf: Scale parameter[2] is 0, but must be positive! (in 'lm_mod.stan', line 43, column 6 to column 35) Consider re-running with show_console=True if the above output is unclear!
03:39:38 - cmdstanpy - WARNING - Some chains may have failed to converge. Chain 1 had 435 divergent transitions (21.8%) Chain 1 had 15 iterations at max treedepth (0.8%) Chain 2 had 142 divergent transitions (7.1%) Chain 2 had 5 iterations at max treedepth (0.2%) Chain 3 had 196 divergent transitions (9.8%) Chain 3 had 20 iterations at max treedepth (1.0%) Chain 4 had 334 divergent transitions (16.7%) Use the "diagnose()" method on the CmdStanMCMC object to see further information.
fitted in 14.1 minutes
divergent transitions after warm-up: 1107 of 8000 draws (chains 1 to 4: [435, 142, 196, 334]); largest R-hat over mu_i, mu_s, mu_stl and the standard deviations: 1.083; smallest bulk ESS: 45
CmdStan's diagnostics of mu_i (intercept) and mu_s (slope):
Mean MCSE R_hat ESS_bulk ESS_tail
mu_i Intercept 0.9986 0.0020 1.0032 1873.68 1774.260
mu_i PrevPrevPrecipWinMo 0.0311 0.0006 1.0007 2208.94 2102.900
mu_i PrevTempBreedBase -0.0940 0.0006 1.0029 2223.63 2001.480
mu_i PrevPrecipBreedBase -0.0460 0.0011 1.0047 1786.51 1702.890
mu_i PrevMinTempFallMig -0.0201 0.0008 1.0019 2626.26 1942.860
mu_i MinTempFallMig 0.0282 0.0005 1.0037 2735.90 2385.350
mu_i y_id 0.1916 0.0011 1.0012 2199.45 3006.720
mu_s Intercept 0.1094 0.0007 1.0030 1376.99 1939.890
mu_s PrevPrevPrecipWinMo 0.0268 0.0009 1.0032 1158.98 323.135
mu_s PrevTempBreedBase -0.0122 0.0010 1.0095 1049.61 831.074
mu_s PrevPrecipBreedBase -0.0135 0.0012 1.0023 1893.23 1046.010
mu_s PrevMinTempFallMig 0.0129 0.0006 1.0018 2425.92 2775.700
mu_s MinTempFallMig -0.0321 0.0006 1.0019 2697.86 2845.020
mu_s y_id 0.0135 0.0006 1.0036 1855.59 2325.150
Table 3 as fitted here (mean, s.d. and pd of mu_i, effects on the allometric intercept, and mu_s, on the slope):
int_mean int_sd int_pd slope_mean slope_sd slope_pd
term
Intercept 0.999 0.081 1.000 0.109 0.026 0.999
PrevPrevPrecipWinMo 0.031 0.027 0.904 0.027 0.026 0.886
PrevTempBreedBase -0.094 0.028 0.996 -0.012 0.029 0.713
PrevPrecipBreedBase -0.046 0.038 0.930 -0.013 0.047 0.654
PrevMinTempFallMig -0.020 0.040 0.762 0.013 0.031 0.698
MinTempFallMig 0.028 0.030 0.876 -0.032 0.032 0.905
y_id 0.192 0.049 0.995 0.014 0.027 0.732
Monte Carlo error of each pd (from the effective sample size of the sign indicator) and the pd of each chain:
int_pd int_pd_mcse int_pd_ess int_pd_chains slope_pd slope_pd_mcse slope_pd_ess slope_pd_chains
term
Intercept 0.9995 0.0005 2003.0195 [1.0, 0.998, 1.0, 1.0] 0.9992 0.0004 6013.6915 [0.999, 1.0, 1.0, 0.999]
PrevPrevPrecipWinMo 0.9038 0.0060 2395.7268 [0.897, 0.899, 0.907, 0.911] 0.8860 0.0073 1911.7295 [0.883, 0.885, 0.895, 0.88]
PrevTempBreedBase 0.9959 0.0012 2857.8814 [0.993, 0.996, 0.996, 0.999] 0.7130 0.0125 1302.9124 [0.705, 0.739, 0.737, 0.672]
PrevPrecipBreedBase 0.9295 0.0057 2021.2715 [0.941, 0.909, 0.935, 0.932] 0.6544 0.0091 2723.4329 [0.649, 0.657, 0.637, 0.674]
PrevMinTempFallMig 0.7619 0.0117 1314.1981 [0.737, 0.8, 0.771, 0.74] 0.6985 0.0099 2144.3774 [0.684, 0.702, 0.683, 0.724]
MinTempFallMig 0.8764 0.0062 2832.7413 [0.867, 0.867, 0.871, 0.902] 0.9048 0.0046 4032.1087 [0.905, 0.916, 0.901, 0.896]
y_id 0.9948 0.0019 1500.3642 [0.988, 0.998, 1.0, 0.994] 0.7318 0.0100 1965.2939 [0.715, 0.751, 0.733, 0.729]
No chain is stuck (none has every kept draw divergent).
The sampler does not converge well: 1107 of 8000 draws are divergent (435, 142, 196 and 334 in chains 1 to 4) and the largest R-hat is 1.083 (smallest bulk ESS 45, among the standard deviations). The effects of the table mix well enough to read: their R-hat is at most 1.010 and their bulk ESS about 1050 or more, and the Monte Carlo error of each pd that a claim uses is 0.12% to 1.25%. The Methods say convergence was confirmed with R-hat and trace plots; no diagnostic values are reported. The model is compiled with -march=native, as Script01 does, so the draws depend on the CPU printed above, and a run on another machine gives other draws with the same seed. The Monte Carlo error and the pd of each chain, printed above, show how far each pd that decides an outcome could move with other draws.
table3-autumn-ahy-prior-breeding-temperature¶
In autumn AHY birds, warmer temperature in the breeding season of their development (the year before the most recent) is again associated with a more negative allometric intercept (beta -0.09, pd 99.5%) and not with the slope (beta -0.01, pd 75.1%).
paper = {"int": (-0.09, 0.03, 99.5), "slope": (-0.01, 0.03, 75.1)}
show("PrevTempBreedBase", paper)
PrevTempBreedBase, reading (a):
intercept mean -0.094 (s.d. 0.028), pd 99.59%; paper -0.09 (tolerance 0.03), pd 99.5%; within tolerance: True; sign as paper: True; pd >= 90%: True
Monte Carlo error of pd 0.12% (ESS 2858), so pd - 90% is +80.0 errors; pd of chains 1 to 4: 99.30%, 99.60%, 99.55%, 99.90%
slope mean -0.012 (s.d. 0.029), pd 71.30%; paper -0.01 (tolerance 0.03), pd 75.1%; within tolerance: True; sign as paper: True; pd >= 90%: False
Monte Carlo error of pd 1.25% (ESS 1303), so pd - 90% is -14.9 errors; pd of chains 1 to 4: 70.50%, 73.85%, 73.65%, 67.20%
Result: under reading (a), the claim holds. PrevTempBreedBase has an intercept effect of -0.094 (pd 99.59%) and a slope effect of -0.012 (pd 71.30%), both within tolerance, each pd many Monte Carlo errors from 90%. Over readings (a), (c) and (d) the claim holds in all three: reproduced.
table3-autumn-ahy-prior-autumn-temperature¶
In autumn AHY birds, the temperature of the autumn migration before the most recent one has no significant association with the allometric intercept (beta -0.02, pd 78.0%) or slope (beta 0.01, pd 70.9%).
paper = {"int": (-0.02, 0.07, 78.0), "slope": (0.01, 0.05, 70.9)}
show("PrevMinTempFallMig", paper)
PrevMinTempFallMig, reading (a):
intercept mean -0.020 (s.d. 0.040), pd 76.19%; paper -0.02 (tolerance 0.07), pd 78.0%; within tolerance: True; sign as paper: True; pd >= 90%: False
Monte Carlo error of pd 1.17% (ESS 1314), so pd - 90% is -11.8 errors; pd of chains 1 to 4: 73.70%, 80.00%, 77.10%, 73.95%
slope mean +0.013 (s.d. 0.031), pd 69.85%; paper +0.01 (tolerance 0.05), pd 70.9%; within tolerance: True; sign as paper: True; pd >= 90%: False
Monte Carlo error of pd 0.99% (ESS 2144), so pd - 90% is -20.3 errors; pd of chains 1 to 4: 68.45%, 70.20%, 68.35%, 72.40%
Result: under reading (a), the claim holds. PrevMinTempFallMig: intercept -0.020 (pd 76.19%), slope 0.013 (pd 69.85%), both below 90% and within tolerance. It holds under (c) and (d) as well: reproduced.
table3-autumn-ahy-recent-autumn-temperature¶
In autumn AHY birds, temperature during the autumn migration in which they were collected has no significant association with the allometric intercept (beta 0.03, pd 88.6%) but a negative association with the allometric slope (beta -0.03, pd 90.3%).
paper = {"int": (0.03, 0.04, 88.6), "slope": (-0.03, 0.05, 90.3)}
show("MinTempFallMig", paper)
MinTempFallMig, reading (a):
intercept mean +0.028 (s.d. 0.030), pd 87.64%; paper +0.03 (tolerance 0.04), pd 88.6%; within tolerance: True; sign as paper: True; pd >= 90%: False
Monte Carlo error of pd 0.62% (ESS 2833), so pd - 90% is -3.8 errors; pd of chains 1 to 4: 86.65%, 86.65%, 87.05%, 90.20%
slope mean -0.032 (s.d. 0.032), pd 90.48%; paper -0.03 (tolerance 0.05), pd 90.3%; within tolerance: True; sign as paper: True; pd >= 90%: True
Monte Carlo error of pd 0.46% (ESS 4032), so pd - 90% is +1.0 errors; pd of chains 1 to 4: 90.55%, 91.65%, 90.10%, 89.60%
Result: under reading (a), the claim holds. MinTempFallMig: intercept 0.028 (pd 87.64%), slope -0.032 (pd 90.48%), within tolerance. The slope pd is 1.0 Monte Carlo error above 90% (error 0.46%; chains 89.60% to 91.65%), so another draw could put it below, and the run reviewed in round 1 gave 89.98% under (a): the (a) call changes between runs. It holds under (c) too (slope pd 91.24%, 2.3 errors above). Under (d) chain 4 is stuck and the fit fails the R-hat check, so the (d) call rests on chains 1 to 3: their pooled slope pd is 83.32%, 5.4 Monte Carlo errors below 90% (each chain 82.20% to 84.65%), and the round-1 (d) fit, which had no stuck chain, gave 85.1%. Over the three readings the outcome is partially reproduced.
table3-autumn-ahy-prior-wintering-precipitation¶
In autumn AHY birds the HY association does not hold. Wintering precipitation before development has a positive association with the allometric intercept (beta 0.03, pd 90.0%), none with the slope (beta 0.02, pd 88.7%), and pre-breeding precipitation before development is not associated with wing length in the preliminary model (Table S6). (The preliminary part is in
reproduce_dias_2025.ipynb.)
paper = {"int": (0.03, 0.03, 90.0), "slope": (0.02, 0.03, 88.7)}
show("PrevPrevPrecipWinMo", paper)
PrevPrevPrecipWinMo, reading (a):
intercept mean +0.031 (s.d. 0.027), pd 90.38%; paper +0.03 (tolerance 0.03), pd 90.0%; within tolerance: True; sign as paper: True; pd >= 90%: True
Monte Carlo error of pd 0.60% (ESS 2396), so pd - 90% is +0.6 errors; pd of chains 1 to 4: 89.75%, 89.90%, 90.70%, 91.15%
slope mean +0.027 (s.d. 0.026), pd 88.60%; paper +0.02 (tolerance 0.03), pd 88.7%; within tolerance: True; sign as paper: True; pd >= 90%: False
Monte Carlo error of pd 0.73% (ESS 1912), so pd - 90% is -1.9 errors; pd of chains 1 to 4: 88.35%, 88.55%, 89.50%, 88.00%
Result: under reading (a), the claim holds. PrevPrevPrecipWinMo: intercept 0.031 (pd 90.38%, 0.6 Monte Carlo errors above 90%), slope 0.027 (pd 88.60%), within tolerance; the preliminary part holds (reproduce_dias_2025.ipynb). Under (c) the intercept pd is 89.15%, 1.3 errors below 90%. Under (d) chain 4 is stuck and the fit fails the R-hat check, so the (d) call rests on chains 1 to 3: their pooled intercept pd is 91.35% and slope pd 91.72%, 2.5 Monte Carlo errors above 90% (each chain 90.80% to 93.15%, chain 1 under one point from the line), so the slope effect falls on the other side of its line under (d); the round-1 (d) fit gave a slope pd of 93.6%. Signs and means hold under all three readings, and over the three readings the outcome is partially reproduced.
Autumn AHY parts of claims that also need the HY and spring AHY models¶
These claims are blocked for time (the HY and spring AHY fits are not run); the autumn AHY numbers are printed for the record: year (tables1-3-year-intercept, tables2-3-ahy-year-slope-none) and breeding precipitation before development (tables1-3-breeding-precipitation), and reading (a) of climate-explains-little (every climate effect on the intercept smaller than the year effect).
print(table3.loc[["y_id", "PrevPrecipBreedBase"], ["int_mean", "int_sd", "int_pd", "int_pd_mcse", "slope_mean", "slope_sd", "slope_pd", "slope_pd_mcse"]].round(3).to_string())
print("paper, Table 3: year intercept 0.19 (pd 99.8%), slope 0.02 (pd 75.9%); PrevPrecipBreedBase intercept -0.05 (pd 93.4%), slope -0.01 (pd 65.3%)")
climate = [t for t in w.MAIN_PREDICTORS["autumn AHY"] if t != "y_id"]
year = abs(table3.loc["y_id", "int_mean"])
print(f"\nclimate-explains-little, reading (a) of its criterion, autumn AHY part: |year effect on the intercept| {year:.3f}; "
f"|climate effects on the intercept|: " + ", ".join(f"{t} {abs(table3.loc[t, 'int_mean']):.3f}" for t in climate))
print(f"every climate effect smaller than the year effect: {all(abs(table3.loc[t, 'int_mean']) < year for t in climate)}")
print(f"\nNotebook time: {(time.time() - started) / 60:.1f} minutes")
int_mean int_sd int_pd int_pd_mcse slope_mean slope_sd slope_pd slope_pd_mcse term y_id 0.192 0.049 0.995 0.002 0.014 0.027 0.732 0.010 PrevPrecipBreedBase -0.046 0.038 0.930 0.006 -0.013 0.047 0.654 0.009 paper, Table 3: year intercept 0.19 (pd 99.8%), slope 0.02 (pd 75.9%); PrevPrecipBreedBase intercept -0.05 (pd 93.4%), slope -0.01 (pd 65.3%) climate-explains-little, reading (a) of its criterion, autumn AHY part: |year effect on the intercept| 0.192; |climate effects on the intercept|: PrevPrevPrecipWinMo 0.031, PrevTempBreedBase 0.094, PrevPrecipBreedBase 0.046, PrevMinTempFallMig 0.020, MinTempFallMig 0.028 every climate effect smaller than the year effect: True Notebook time: 14.4 minutes