Skip to content

Commit ff67c58

Browse files
committed
Release 0.6.0: changelog + version bump
Bump brainstat.__version__ to 0.6.0 and add a project CHANGELOG.md covering the work landed in #378 / #379 / #380 / #381. This release re-greens CI, fixes a cluster of correctness bugs in the statistics core, adds the FreeSurfer Destrieux atlas to fetch_parcellation, hardens the Neurosynth fetcher, and adopts the literature-aligned (high = darker) default for BigBrain histology profiles. Backwards-incompatible changes are called out at the top of CHANGELOG.md.
1 parent b588136 commit ff67c58

2 files changed

Lines changed: 134 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Changelog
2+
3+
All notable changes to BrainStat are recorded here. The project adopts
4+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
5+
6+
## [0.6.0] — 2026-05
7+
8+
This release re-greens CI after a long stretch of upstream-driven breakage,
9+
fixes a cluster of high-severity correctness bugs in the statistics core,
10+
adds the FreeSurfer Destrieux atlas to `fetch_parcellation`, hardens the
11+
Neurosynth fetcher, and adopts a literature-aligned default for BigBrain
12+
histology profiles. It also closes the longest-standing maintenance items
13+
in the issue tracker.
14+
15+
### Backwards-incompatible changes
16+
17+
- **`brainstat.context.histology.read_histology_profile` now inverts BigBrain
18+
intensities by default** (`invert=True`) so that higher = darker = more
19+
cell-dense, matching Paquola et al. 2021 (eLife) and most downstream
20+
BigBrain analyses. Pass `invert=False` to recover the previous behaviour.
21+
MPC and gradient computations are correlation-based and therefore
22+
invariant to this flip; only direct inspection of profile intensities is
23+
affected. (#274)
24+
- **`SLM.__init__` now coerces `contrast` to numeric and `mask` to
25+
boolean.** Pandas Series of object/categorical dtype now raise a clear
26+
`TypeError` instead of producing the cryptic `can't multiply sequence by
27+
non-int of type 'float'` deep inside `_t_test`. Integer 0/1 masks (the
28+
natural shape of `nib.load(...).get_fdata().astype(int)`) are now
29+
converted to bool rather than degenerating into fancy indexing inside
30+
`_fdr`. (#342)
31+
- **Pin numpy<2 and pandas<2.1.** `abagen 0.1.3` still imports
32+
`pkg_resources` and calls `DataFrame.groupby(axis=...)`; until upstream is
33+
patched, BrainStat must stay on the numpy 1.x ABI to avoid runtime
34+
binary-incompatibility errors. Will be lifted once abagen ships a
35+
compatible release.
36+
37+
### Bug fixes — statistics core
38+
39+
- `SLM._surfstat_to_brainstat_rft`: fix off-by-one in Yeo7 indexing.
40+
`peak_clus` returns 1-based vertex IDs (a SurfStat carry-over); these
41+
were being used to index a 0-based numpy array, raising `IndexError`
42+
when a peak landed on the final mesh vertex and silently mis-labelling
43+
Yeo networks for every other peak. (#347)
44+
- `SLM.py`: `from cmath import sqrt` was importing the **complex** square
45+
root; switched to `math.sqrt`. The expression was always real but the
46+
surrounding code would have silently propagated complex values had the
47+
branch ever been negative.
48+
- `SLM.py`: removed a duplicate `fetch_template_surface` import.
49+
- `_t_test.py`: `sys.exit("Contrast is not estimable :-(")` would kill the
50+
host Python process when invoked from a notebook or pipeline. Replaced
51+
with `raise ValueError(...)`.
52+
- `_t_test.py`: replace `float(...)` with `.item()` on the t-statistic
53+
computation. `numpy>=2.0` raises `TypeError: only 0-dimensional arrays
54+
can be converted to Python scalars` for `float()` on size-1 ndarrays.
55+
56+
### New features
57+
58+
- `brainstat.datasets.fetch_parcellation(template, "destrieux", ...)`
59+
now returns the FreeSurfer `aparc.a2009s` (Destrieux 2009)
60+
parcellation, sourced via
61+
`nilearn.datasets.fetch_atlas_surf_destrieux`. Native `fsaverage5`;
62+
other `fsaverage*` templates resampled with nearest-neighbour
63+
interpolation. `fslr32k` is rejected (FreeSurfer-specific). (#343)
64+
- The `surf=None + correction='rft'` error message now points users at
65+
`correction='fdr'` for volumetric data instead of just refusing.
66+
67+
### Maintenance
68+
69+
- **CI fully restored.** Both Python and MATLAB suites had been red on
70+
`master` for a long stretch. Root causes addressed:
71+
- `setuptools >= 81` no longer ships `pkg_resources`, breaking
72+
`abagen` import → pinned `setuptools<81` in CI and reinstalled it
73+
after the editable install.
74+
- `numpy.dtype size changed` from mixing pinned `pandas<2.1` (built
75+
against numpy 1.x ABI) with `numpy>=2` → pinned `numpy<2` to keep
76+
the stack consistent.
77+
- `pandas 2.0.x` has no Python 3.12 wheels → temporarily dropped 3.12
78+
from the matrix until abagen is patched and the pin can be lifted.
79+
- `MATLAB:Python:PythonUnavailable` from the precomputed-pickle tests
80+
→ bumped to `matlab-actions/setup-matlab@v2` +
81+
`matlab-actions/run-command@v2`, configure `pyenv()` before
82+
`runtests`, add explicit `addpath(genpath('brainstat_matlab'))`.
83+
- GitHub Actions versions: `actions/checkout@v4`,
84+
`actions/setup-python@v5`. (PR #379)
85+
- **Drop `# type: ignore` from `SLM.py` and `_multiple_comparisons.py`.**
86+
The class-body imports that were tripping
87+
[python/mypy#10521](https://github.com/python/mypy/issues/10521) have
88+
been lifted to module level and bound as class attributes (`_linear_model
89+
= _linear_model`, etc.). mypy now runs to completion on both files
90+
instead of crashing. The pre-existing untyped-code errors that the
91+
blanket ignore was hiding are surfaced but tracked separately; the
92+
`mypy` CI job remains commented out pending that triage. (#199)
93+
- **MATLAB R2019b/R2020a compatibility.** `peak_clus.column_vector`
94+
replaced the `mustBeVector` validator (introduced in R2020b) with an
95+
explicit `isvector` check. (#285)
96+
- **Resilient Neurosynth download.** `meta_analytic_decoder/fetch_neurosynth_data`
97+
validates the downloaded zip via `java.util.zip.ZipFile` before
98+
`unzip`, retries up to 3 times, cleans up partial zips between
99+
attempts, and verifies the post-extract file count. Truncated
100+
downloads no longer leave the toolbox in a permanently broken state.
101+
(#341)
102+
103+
### Issues closed
104+
105+
- #199 — Remove `# type: ignore` from `SLM` class
106+
- #274 — Flip the bits on the histological profiles
107+
- #285`column_vector` uses `mustBeVector` from MATLAB 2020b+
108+
- #341 — Neurosynth data failed to get fetched
109+
- #342 — Volumetric mixed effects (input contract bugs; cluster-level
110+
RFT/TFCE on volumes remains tracked separately as a feature request)
111+
- #343 — Atlas coverage for FreeSurfer GLM workflows (Destrieux added;
112+
hosted Desikan-Killiany remains tracked for a follow-up)
113+
- #347 — Retrieval of yeo7 information has off-by-1 error
114+
115+
### Known follow-ups
116+
117+
- **Lift the numpy/pandas/3.12 pins** once `abagen` drops `pkg_resources`
118+
and the `groupby(axis=)` call.
119+
- **Re-enable the commented-out `mypy` CI job** once the ~380 latent
120+
typing errors uncovered by removing `# type: ignore` are triaged.
121+
- **Volumetric cluster-level RFT/TFCE** for `SLM` — present in SurfStat,
122+
not yet ported.
123+
- **Hosted Desikan-Killiany (`aparc`) atlas** in `fetch_parcellation`
124+
— needs a stable mirror (OSF / Zenodo) for the `.annot` files.
125+
126+
## [0.5.2] — 2026-01
127+
128+
Hotfixes only; no formal changelog was kept for this release.
129+
130+
## [0.5.1] and earlier
131+
132+
See `git log` and the merged-PR history for releases prior to the
133+
introduction of this changelog.

brainstat/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""Neuroimaging statistics toolbox."""
2-
__version__ = "0.5.2"
2+
__version__ = "0.6.0"

0 commit comments

Comments
 (0)