Releases: Eden-Kramer-Lab/spectral_connectivity
Releases · Eden-Kramer-Lab/spectral_connectivity
v2.0.0
[2.0.0] - 2025-10-27
BREAKING CHANGES
3D Input Requirement for Multitaper Class
BREAKING CHANGE: Multitaper now requires 3D input arrays with explicit (n_time_samples, n_trials, n_signals) shape. Previously ambiguous 2D arrays now raise informative ValueError.
-
Migration Required: Use the new
prepare_time_series()helper function to convert 1D/2D arrays to 3D format -
Why: Eliminates dangerous ambiguity where
(n_time, n)could mean either:(n_time, 1 trial, n signals)OR(n_time, n trials, 1 signal)
Silent misinterpretation produces scientifically incorrect results.
Migration Example:
# Before (ambiguous)
mt = Multitaper(eeg_data, sampling_frequency=1000)
# After (explicit)
from spectral_connectivity.transforms import prepare_time_series
eeg_3d = prepare_time_series(eeg_data, axis='signals') # or axis='trials'
mt = Multitaper(eeg_3d, sampling_frequency=1000)Nyquist Frequency Now Included for Even-Length FFTs
BREAKING CHANGE: Corrected frequency bin indexing to include Nyquist frequency for even-length FFTs
- Impact on results:
- Even-length FFTs (N=1024): Now return 513 frequencies instead of 512 (adds Nyquist bin)
- Odd-length FFTs (N=1023): No change (still return 512 frequencies)
- Affected functions: All connectivity measures using
@_non_negative_frequenciesdecorator - Scientific justification: The Nyquist frequency (sampling_rate/2) represents valid spectral information that should not be discarded
- See CHANGELOG "Unreleased" section for complete details and migration guidance
Development Tooling Changes
- BREAKING: Migrated from
blacktoruff formatfor code formatting - BREAKING: Migrated from
flake8/pydocstyletorufffor linting - Development workflows now use
ruff formatandruff checkcommands - All formatting/linting configurations moved to
pyproject.tomlunder[tool.ruff] - Developers must update their tooling:
pip install ruff(100x faster than previous tools)
Added
prepare_time_series()helper function for safe dimension handling:- Converts 1D/2D arrays to required 3D format
- Explicit
axisparameter to clarify dimension meaning - Prevents ambiguous dimension interpretation
- Required for migration to v2.0.0
- Comprehensive notebook snapshot testing with Syrupy:
- 27 snapshot tests covering all tutorial notebook examples
- Tests validate output shapes, data types, and numerical properties
- Ensures tutorial examples remain accurate across releases
- Automatically catches breaking changes in example code
- Uses Syrupy's snapshot testing for efficient test maintenance
- Test infrastructure (
tests/conftest.py):- Added pytest fixture to reset numpy random state before each test
- Ensures consistent test reproducibility with fixed seed (42)
- Helps prevent test ordering issues from shared random state
- Auto-runs before every test without explicit fixture declaration
- Physical constants with scientific rationale (
spectral_connectivity/transforms.py):MIN_EIGENVALUE_THRESHOLD = 0.9: Minimum eigenvalue for low-bias tapers- Documents that 90% of taper energy must be in main lobe to reduce spectral leakage
- Reference: Thomson (1982), "Spectrum estimation and harmonic analysis"
TAPER_MULTIPLIER = 2.0: Multiplier for calculating number of tapers- Documents the theoretical basis: ~2*NW orthogonal Slepian sequences are well-concentrated
- Reference: Slepian (1978), "Prolate spheroidal wave functions"
- All magic numbers replaced with named constants throughout codebase
- Docstrings updated to reference constants while preserving readability
- Comprehensive test suite for advanced connectivity measures (
tests/test_advanced_connectivity.py):- 18 test methods covering
canonical_coherence(),global_coherence(), andgroup_delay() - Tests validate output shapes, value ranges, and mathematical properties (symmetry, antisymmetry)
- Integration tests for complete Multitaper → Connectivity → advanced measures workflow
- Tests handle edge cases: different group sizes, single signals, non-contiguous labels
- Graceful handling of group_delay edge case when no frequencies are significant
- 18 test methods covering
- Parameter helper functions for guided multitaper analysis:
estimate_frequency_resolution(): Calculate frequency resolution from parametersestimate_n_tapers(): Calculate number of tapers from time-halfbandwidth productsuggest_parameters(): Get parameter recommendations for your dataMultitaperParametersTypedDict for type-safe parameter handling
summarize_parameters()method toMultitaperclass:- Human-readable summary of all analysis parameters
- Shows computed values (n_tapers, frequency_resolution, n_windows)
- Displays overlap percentage for windowing
- Formatted for terminal/notebook output
- Enhanced
time_halfbandwidth_productdocstring with formulas and practical guidance:- Mathematical relationship to frequency resolution and n_tapers
- Typical values (NW=2,3,4,5+) with trade-off explanations
- Examples for achieving target resolutions (1 Hz, 5 Hz, 10 Hz)
- Cross-references to helper functions
- Comprehensive test suite for parameter helpers (
test_parameter_helpers.py):- 22 tests covering all helper functions
- Domain-specific tests (EEG, LFP typical parameters)
- Edge cases (conflicting parameters, impossible resolutions)
- Consistency checks with actual
Multitaperbehavior
Changed
- Complete type hint coverage (
spectral_connectivity/transforms.py,spectral_connectivity/connectivity.py):- Added type hints to ALL 28 previously untyped functions:
transforms._make_tapers(): Added parameter and return typesconnectivity.py: 27 functions including all connectivity measures and helper functions
- Used
TYPE_CHECKINGblock to avoid circular imports for Multitaper type - Added
Literaltypes formultiple_comparisons_methodparameter - Fixed
Optional/Nonehandling in_get_independent_frequency_step()and_bandpass() - Fixed phase_lag_index return type (extract real part from complex result)
- Enabled
disallow_untyped_defs = truefor transforms and connectivity modules - All 9 modules now have strict type checking enabled
- 100% of public API is now fully type-annotated
- Added type hints to ALL 28 previously untyped functions:
- Test coverage improvements:
- Overall coverage increased from 85% to 88%
connectivity.pycoverage improved from 71% to 93%- Fixed snapshot tests after Nyquist frequency bin correction
- Updated test assertions to use correct frequency bin calculation:
N//2 + 1instead of(N+1)//2
- Improved method discovery in
multitaper_connectivity()wrapper:- Replaced
dir()withinspect.getmembers(predicate=inspect.isfunction)for type-safe method filtering - Automatically excludes properties and classmethods (more robust)
- Renamed
bad_methodstoexcluded_methodswith clear categorization - Changed from list to set for O(1) membership testing
- Added test
test_method_discovery_with_inspect()to verify behavior
- Replaced
- Documented design decision for
adjust_for_multiple_comparisons():- Replaced TODO comment with clear explanation of current behavior
- Explained why axis parameter is not implemented (standard approach treats all p-values as single family)
- Left open for future enhancement if needed
Removed
- All TODO comments from codebase (2 resolved)
Changed
- Development tooling modernization:
- Migrated from
blacktoruff formatfor code formatting (100x faster) - Migrated from
flake8/pydocstyletoruff checkfor linting - Updated GitHub Actions CI to use
ruff format --checkandruff check - Updated CLAUDE.md with new ruff commands
- All formatting and linting now unified under single fast tool
- Migrated from
- Code quality improvements:
- Applied
ruff formatto all source files (10 files reformatted) - Fixed 19 auto-fixable ruff linting issues
- All source code and tests now pass
ruff checkwith zero warnings - Type hints improved with better union handling for
detrend()function
- Applied
- Updated tutorial notebooks to use
prepare_time_series()for 3D input - Improved random number generation in tests for better isolation
Fixed
- MyPy type annotation error in
detrend()function (transforms.py:1867-1876):- Fixed union type handling for
bpparameter (nowint | list[int] | NDArray[np.integer]) - Added support for list input in addition to int and ndarray
- Eliminated unreachable code warnings from MyPy
- All 9 source files now pass strict mypy type checking
- Fixed union type handling for
Nyquist Frequency Fix (from earlier release)
- Critical bug fix: Corrected frequency bin indexing to include Nyquist frequency for even-length FFTs
- Affected code: Changed frequency indexing from
(N+1)//2toN//2 + 1in three locations:_non_negative_frequenciesdecorator (line 107)canonical_coherencemethod (line 638)_estimate_spectral_granger_predictionfunction (line 2108)
- Impact on results:
- Even-length FFTs (N=1024): Now return 513 frequencies instead of 512 (adds Nyquist bin)
- Odd-length FFTs (N=1023): No change (still return 512 frequencies)
- Affected functions: All connectivity measures using
@_non_negative_frequenciesdecorator:coherency(),coherence_magnitude(),coherence_phase(),imaginary_coherence()phase_lag_index(),weighted_phase_lag_index(),debiased_squared_phase_lag_index()debiased_squared_weighted_phase_lag_index(),phase_locking_value(),pairwise_phase_consistency()power(), all Granger causality measures (DTF, PDC, etc.)
- Scientific justification: The Nyquist frequency (sampling_rate/2) represents the highest frequency
that can be unambiguously represented in sampled data....
- Affected code: Changed frequency indexing from
1.1.2
v1.1.0
v1.0.3
v1.0.2
v1.0.1
v1.0.0
v0.2.6.dev0
- Added global coherence
- Added ability to take expectation over time windows
v0.2.5.dev0
Add xarray wrapper from @mmyros.
v0.2.3.dev0
- Fix keys
- use lru_cache