Releases: darksim33/Pyneapple
Pyneapple v2.0.0
Pyneapple v2.0.0
This is a major release with breaking changes. The entire fitting architecture has been redesigned. Code written against v1.x will require updates — see the migration notes below.
Breaking Changes
- Entire module structure replaced.
pyneapple/parameters/,pyneapple/fitting/,pyneapple/utils/, andradimgarrayhave been removed. The new structure isModels,Solvers, andFittersfollowing scikit-learn estimator conventions. - Old fitting functions removed:
fit_pixel_wise(),fit_segmentation_wise(),fit_ivim_segmented(),fit_ideal()are gone. - CLI redesigned:
pyneapple-fitdatais replaced bypyneapple pixelwise,pyneapple segmentationwise,pyneapple ideal,pyneapple segmented. - TOML config format changed:
[General]with aClassfield is replaced by a[Fitting]section. All example configs have been updated. IDEALFitter.interpolation_methodremoved: replaced bydownsampling_method(default"block_average") andupsampling_method(default"cubic").IDEALFitter.step_toltype changed fromlist/np.ndarraytodict[str, float]keyed by parameter name. TOML configs must update from a flat list to a[Fitting.ideal.step_tol]sub-table.pygpufitmoved to a separate package.- Minimum Python version lowered to 3.9 (was 3.12); dependency version ranges now split per Python version.
What's New
- scikit-learn-style architecture —
MonoExpModel,BiExpModel,TriExpModel,NNLSModelas stateless forward models;CurveFitSolver,NNLSSolver,ConstrainedCurveFitSolveras backends;PixelWiseFitter,SegmentationWiseFitter,IDEALFitter,SegmentedFitteras high-level orchestrators. FitResultpublic container — all fitters now populateresults_with aFitResultafter fitting; exported from the top-levelpyneapplepackage.- Registry-based plugin discovery via entry points for models, solvers, and fitters.
pyneapple.iomodule — unified I/O for NIfTI, b-values, TOML configs, Excel, and HDF5.pyneapple.utilitymodule — spectrum processing, plotting, and validation utilities.- Optional dependency groups:
pip install pyneapple[excel,plotting,export] SegmentedFitterfor two-step model fitting workflows, now including TOML config support viafitter = "segmented".- IDEAL block-average downsampling —
_block_average_array()porting MATLAB IDEAL referenceaccumarray(@nanmean)behavior, dispatched via newdownsampling_method/upsampling_methodsplit. - New
clamp_interpolated_p0parameter onIDEALFitter(defaultTrue) — controls clamping of upsampled parameter maps to solver bounds before step-wise tolerances are derived. - New user guides:
docs/guide/fitting-config.md(FittingConfig /load_config) anddocs/guide/logging.md(configure_logging(), log levels, file sinks,PYNEAPPLE_QUIET).
Improvements & Changes
configure_logging()no longer attaches a console sink by default — a sink is only added when explicitly requested.numpy,scipy, andnibabeldependencies split into Python-version-specific ranges for correct resolution across Python 3.9–3.12+.tomli>=2.0added as a conditional dependency for Python < 3.11 to backporttomllib.- Ruff
target-versionupdated topy39.
Bug Fixes
ConstrainedCurveFitSolver:fraction_constraint=Truenow correctly raisesValueErrorwhenfit_reduced=False.ConstrainedCurveFitSolver: gradient callable no longer returnsNoneto SLSQP when model Jacobian is unavailable; falls back to finite-difference approximation.CurveFitSolver:use_jacobianflag now respected in both fixed-params and unfixed branches.CurveFitSolver:n_pools=Nonein multi-threading configuration no longer raises an error.IDEALFitter: cubic-interpolated parameter maps are clamped to solver bounds before step-wise bounds are derived, preventing out-of-range initial guesses from interpolation overshoot.IDEALFitter: a warning is logged and all voxels are fitted when no voxels survive the segmentation threshold at a coarse step — previously collapsed silently.IDEALFitter._validate_step_tol(): error message now contains"step_tol"when dict keys don't matchmodel.param_names.get_model("nnls"): factory now accepts**kwargsand raises a descriptiveValueErrorfor missing required arguments.save_parameter_map: NNLS 4-D coefficient arrays saved correctly as 4-D NIfTI volumes.hdf5._encode_key(): unhandled key types fall back tostrinstead of returningNoneand crashing the caller.isinstance(value, h5py.Group | h5py.Dataset)replaced with tuple form — runtime|union inisinstance()requires Python 3.10+.SegmentedFitteris now properly exported frompyneapple.fitters.- Stale
pyneapple-<cmd>CLI references corrected topyneapple <cmd>in all example configs and guides. - Various TOML example config corrections (wrong
fit_s0values, transposeddim_stepsshape,fit_reduce→fit_reducedtypo).
Migration from v1.x
The architecture change is significant. Key points:
- Replace
FitData+ parameter classes with the new Fitter/Model/Solver pattern - Update TOML configs from
[General] Class = ...to[Fitting] fitter = ... - Replace
pyneapple-fitdataCLI calls withpyneapple <subcommand> - Replace
from pyneapple.utils import loggerwithfrom pyneapple import configure_logging
v2.0.0-beta.2
Fixed - \SegmentedFitter\ was missing from \pyneapple.fitters\ public API — now properly exported.
v2.0.0-beta.1
v2.0.0-beta.1 (Pre-release)
⚠️ This is a pre-release. This major version introduces significant breaking changes to align with scikit-learn conventions.
What's New
Architecture — scikit-learn Style Restructure
The entire codebase has been refactored to follow scikit-learn conventions with a clear separation of concerns:
- Models: Stateless, pure math forward model functions (
forward,jacobian,residual) - Solvers: Curve fitting backends (
CurveFitSolver,NNLSSolver,ConstrainedCurveFitSolver) - Fitters: High-level fitting orchestrators (
PixelWiseFitter,SegmentationWiseFitter,IDEALFitter,SegmentedFitter) - Registry-based plugin discovery via entry points for models, solvers, and fitters
New I/O Module (pyneapple.io)
load_dwi_nifti,save_parameter_map,reconstruct_maps,save_spectrum_to_niftiload_bvalues,save_bvaluesload_config/FittingConfigfor TOML configs- Excel export:
save_params_to_excel,save_spectrum_to_excel - HDF5 export with gzip compression:
save_to_hdf5,load_from_hdf5,save_params_to_hdf5
New Utilities (pyneapple.utility)
spectrum— Spectrum processing utilitiesplotting— Visualization helpersvalidation— Validation helpers
New CLI Tools
pyneapple pixelwise # Per-pixel fitting
pyneapple segmented # Segmented fitting (two-step)
pyneapple ideal # IDEAL iterative fitting
pyneapple segmentationwise # ROI mean signal fittingOptional Dependencies
pip install pyneapple[excel,plotting,export]Breaking Changes
1. Removed Entire Module Hierarchy
| Old Path | Status |
|---|---|
pyneapple/parameters/ |
Removed entirely |
pyneapple/results/ |
Removed entirely |
pyneapple/fitting/ |
Removed entirely |
pyneapple/utils/ |
Removed entirely |
2. Removed Parameter Classes
# REMOVED - No direct replacement
from pyneapple.parameters import Parameters
from pyneapple.parameters.ivim import IVIMParams
from pyneapple.parameters.ivim import IVIMSegmentedParams
from pyneapple.parameters.nnls import NNLSParams
from pyneapple.parameters.nnls import NNLSCVParams
from pyneapple.parameters.ideal import IDEALParams
from pyneapple.parameters.boundaries import BaseBoundaryDict3. Removed Result Classes
# REMOVED - No direct replacement
from pyneapple.results import Results
from pyneapple.results.ivim import IVIMResults
from pyneapple.results.ivim import IVIMSegmentedResults
from pyneapple.results.nnls import NNLSResults
from pyneapple.results.nnls import NNLSCVResults
from pyneapple.results.types import Results
from pyneapple.results.result_dict import ResultDict4. Removed Fitting Interface
# REMOVED - Replaced by new Fitters
from pyneapple.fitting.fitdata import FitData
# OLD API (removed)
fit_data = FitData(img, seg, "params.toml")
fit_data.fit_pixel_wise()
fit_data.fit_segmentation_wise()
fit_data.fit_ivim_segmented()
fit_data.fit_ideal()5. Removed Utility Modules
# REMOVED
from pyneapple.utils.logger import logger
from pyneapple.utils.plotting import plot_results
from pyneapple.utils.processing import *6. Removed External Dependency
# REMOVED - Was using radimgarray submodule
from radimgarray import RadImgArray, SegImgArray7. TOML/JSON Parameter File Format — Complete Redesign
Old format (params_biexp.toml):
[General]
Class = "IVIMParams" # ← Required class name
b_values = [0, 10, 50, ...]
[Model]
model = "biexp"
fit_s0 = false
[boundaries.D]
1 = [0.001, 0.0007, 0.05] # ← Complex boundary format
2 = [0.02, 0.003, 0.3]New format (segmentationwise_biexp.toml):
[Fitting]
fitter = "segmentationwise"
[Fitting.model]
type = "biexp"
[Fitting.solver]
type = "curvefit"
max_iter = 250
[Fitting.solver.p0] # ← Simple initial guess
S0 = 1000.0
f1 = 0.2
D2 = 0.02
[Fitting.solver.bounds] # ← Simple bounds
S0 = [1.0, 5000.0]
f1 = [0.01, 0.99]8. CLI Interface Changes
# OLD
pyneapple-fitdata --params params_biexp.toml
pyneapple-fitdata --img data.nii --seg mask.nii
# NEW
pyneapple pixelwise --image data.nii --bval data.bval --config config.toml
pyneapple segmented --image data.nii --bval data.bval --config config.toml --seg mask.nii
pyneapple ideal --image data.nii --bval data.bval --config config.toml --seg mask.nii9. Model API Changes
# OLD - Multiple model classes for different fitting modes
from pyneapple.models import NNLSModel, NNLSCVModel
from pyneapple.models.ivim import BiExpFitModel, TriExpFitModel, MonoExpFitModel
# NEW - Unified model naming
from pyneapple.models import MonoExpModel, BiExpModel, TriExpModel, NNLSModel10. Removed Example Scripts
examples/ivim_fitdata_script.pyexamples/nnls_fitdata_script.py
11. Removed Example Parameter Files
All JSON and TOML parameter files in examples/parameters/ have been replaced:
params_biexp.json,params_biexp.tomlparams_biexp_ideal.jsonparams_biexp_segmented.jsonparams_biexp_s0.toml,params_biexp_t1.toml,params_biexp_t1_steam.tomlparams_monoexp.jsonparams_nnls.json,params_nnls.toml,params_nnls_cv.jsonparams_triexp.json,params_triexp_ideal.json,params_triexp_reduced.toml
12. Removed pygpufit Module
The pygpufit integration has been moved to a separate package.
Import Changes Summary
| OLD | NEW |
|---|---|
Parameters classes |
Models |
IVIMParams, NNLSParams |
BiExpModel, NNLSModel, etc. |
Results classes |
No direct replacement |
FitData |
Fitters (PixelWiseFitter, etc.) |
logger from utils |
configure_logging() from pyneapple |
RadImgArray |
NIfTI via numpy arrays |
params.toml (with Class field) |
config.toml ([Fitting] section) |
fit_ivim(), fit_nnls() |
fitter.fit(data, model) |
Migration Guide
1. Replace parameters with models
# OLD
params = IVIMParams(bvalues=bvals, ...)
results = fit_ivim(data, params)
# NEW
from pyneapple.models import BiExpModel
from pyneapple.fitters import PixelWiseFitter
from pyneapple.solvers import NNLSSolver
model = BiExpModel(bvalues=bvals, ...)
fitter = PixelWiseFitter(solver=NNLSSolver())
results = fitter.fit(data, model)2. Replace TOML configs
- Remove
Classfield - Restructure under
[Fitting]section - Rename
[boundaries]to[Fitting.solver.bounds] - Add explicit
p0section for initial guesses
3. Update imports
Parameters→ModelsResults→ Fitter return values (numpy arrays)FitData→Fitters
4. Update logging
# OLD
from pyneapple.utils import logger
logger.info("message")
# NEW
from pyneapple import configure_logging
configure_logging(level="DEBUG")Installation
pip install pyneapple==2.0.0b1
# With optional dependencies
pip install pyneapple==2.0.0b1[excel,plotting,export]What's Changed
- Test Enhancements by @darksim33 in #200
- Test Enhancements (finalizing) by @darksim33 in #201
- v2.0.0-beta.1 Release by @darksim33 in #207
Full Changelog: v1.7.0...v2.0.0-beta.1
v1.7.0
Release Summary: v1.5.6 → v1.7.0
Overview
This summary covers four major releases with significant enhancements to Pyneapple's capabilities, including logger implementation, TOML support, IVIM results improvements, and comprehensive IO functionality.
📦 Version 1.7.0 (Latest) - IO Update
Major Features
-
- Complete HDF5 data storage and export functionality
- Transform ResultDicts to Arrays before HDF5 export
- Support for 3D and 4D data structures
- Switched from scipy.sparse to
sparselibrary for N-D support - Dict import capabilities
- Comprehensive test suite
-
NIfTI Support
- NIfTI helper functions for medical imaging
- Refactored results saving for NIfTI format
- Comprehensive test suite with preparation helpers
-
NNLS Enhancements
- Cutoff handling and peak merging
- Improved peak handling with IVIM T1 flag
- Comprehensive results test suite
- Fixed variable array length issues
Improvements
- GPU fitter model retrieval and constraint handling (#197)
- Expanded DataExport documentation
- Added
fit_optparameter to track fitting type (pixel/segmentation/segmented/ideal) - Moved JSON and TOML operations to dedicated IO module
- Enhanced type support and hints throughout codebase
Bug Fixes
- Default
fit_optto empty string - GPU fitter constraints and imports
- NNLS model params not passed properly
- Shape calculation issues
- Missing logger output
📦 Version 1.6.2 - IVIM Results Patch
Key Changes
-
IVIM Results Refactoring
- Switched from separate S0 and f extraction to unified method
- Fixed segmented test issues
- Improved extraction logic
-
Core Fixes
- Additional small fraction issue resolved
- dimstep now always returns np.ndarray
- Parameter class invoke error fixed
- JSON to params_file conversion issues
-
Testing & Quality
- seg_args tests for mean calculations
- Updated radimgarray commit
- Removed unused methods and imports
- Pylance compatibility improvements
Documentation
- Updated class descriptions
- Fixed type hints
📦 Version 1.6.1 - TOML Parameter Support
Major Feature: TOML Support (#168)
- TOML File Format
- Added TOML parameter file import/export
- Renamed
params.jsontoparams.filefor format flexibility - TOML packages added to dependencies (
tomli,tomli-w,tomlkit)
Implementation Details
- TOML test suite
- TOML import examples
- TOML documentation
- Backward compatible with JSON files
Dependencies
tomli ^2.0.1for Python <3.11tomli-w ^1.0.0for Python <3.11tomlkit ^0.12.0for Python >=3.11
📦 Version 1.6.0 - Logger Implementation
Major Feature: Custom Logger (#167)
- Loguru Integration
- Custom logger implementation using loguru
- Replaced print statements throughout codebase
- File output support for logs
- Configurable log levels
Logger Features
- Top-level logger access
- Option to get/set log level dynamically
- File output redirection
- pytest integration (log level set to ERROR for tests)
- Logger tests added
Supporting Changes
- Added
tox.inito pyproject.toml - Linux GPUFit library (Ubuntu 22.04 LTS)
- Moved tox.ini to test directory
- kwargs passing for GPU fitter tuning
- More realistic kidney fitting values in JSON files
Bug Fixes
- LOG_LEVEL variable naming
- Removed global variables
- Stopped unwanted file output
- Model-related issues
- Missing segmented S0
🔄 Cross-Version Major Changes
Models Rework (#163, #171)
Implemented across v1.6.0-v1.6.2
-
Model Class Restructuring
- Created base fit model classes
- Moved from wrapper pattern to direct model classes
- Added model properties to dedicated model class
- IVIM model loader implementation
- Mono, Bi, and Tri exponential models
- GPU model constructor
-
Model Improvements
fit_reduced,fit_S0,fit_t1properly pass values- Renamed
reducedtofit_reducedfor clarity - Updated NNLSCV model
- Refactored
*_comment*to*description* - Added S0 model options and tests
-
Segmented Fitting
- Reworked to use two sub-parameter classes
- Fixed component handling improved
- Better S0 and fraction extraction
- Unit and integration tests added
Boundary System Rework (#178, #197)
Implemented across v1.6.1-v1.7.0
-
Individual Boundaries
- Pixel-by-pixel boundary support (
btype) - Individual bounds for fit functions
- GPU fit individual boundaries
- Boundary validity checks
- Pixel-by-pixel boundary support (
-
Structure Changes
- Reworked to altered dict structure
- Boundary order handling
- Default btype and individual bound returns
- Comprehensive test suite
-
Constraint Handling
- Fixed
constrain_typesfor individual bounds - Improved constraint returns
- Better handling of missing f and D values
- Fixed
Parameters Import Update (#109, #184)
Implemented in v1.6.0
-
Dynamic Parameter Handling
- Switched from static file-based to dynamic dict-based
- Better file structure with tables/dicts
- Model parameters from model class directly
- Capitalized boundary keys allowed
-
File Organization
- Moved file fixtures to
_files - Parameter fixtures to
_parameters - Moved parameter files from fitting to parameters directory
- Created dynamic parameter file creator
- Moved file fixtures to
Documentation Improvements (#191)
Implemented in v1.6.2
-
Comprehensive Documentation
- Detailed model descriptions
- IVIM models documentation
- NNLS description
- Example TOML files for different cases
- Fit example scripts
- Extended example descriptions
- Fixed equation expressions
-
Examples
- IVIM parameters file example
- BiExp IVIM TOML
- NNLS fitting script
- FitData IVIM example script
T1 Fitting Fix (#190, #193)
Implemented in v1.6.2
- Added
fit_t1_steamfor models - Tests for new T1 fitting with fixes
- Updated documentation with T1 STEAM option
- Removed model from Args (no longer needed)
- T1 fit check for export
Testing Infrastructure
Continuous improvements across all versions
-
Test Coverage Expansion
- pytest-mock and pytest-cov added
- Fitting tests initialized
- Boundary tests
- GPU fitter tests
- NNLS results tests
- NIfTI tests
- HDF5 tests
- Segmented fitting tests
-
Test Organization
- Moved fixtures to conftest
- Refactored mocks
- Added pytest marks (slow, gpu, ideal)
- Improved test structure
Python Version Support
- Added Python 3.13 support
- Maintained support for 3.9, 3.10, 3.11, 3.12
Code Quality Improvements
Across all versions
- Extensive type hint additions
- Black code formatting
- Ruff import organization
- Removed unused imports and methods
- Improved docstring formats
- Better error handling
- Pyright configuration
🐛 Notable Bug Fixes Summary
Data Handling
- b_values handling (array vs list)
- Shape calculations
- Array dimension handling
- Segmentation key handling with int keys
Fitting
- NNLS model params passing
- kwargs overwriting bools
- MonoExp equation order (exp(D1)*S0)
- fit_s0 addition to params2
- D1 position in first fit
Results
- NNLS results boolean parsing
- Variable array length for NNLS
- Fixed component handling
- S0 and fraction extraction
Configuration
- JSON to params_file conversion
- TOML import issues
- Parameter file path resolution
- Model selection logic
📊 Statistics
- Total Commits: 344
- Major Versions: 4 (v1.6.0, v1.6.1, v1.6.2, v1.7.0)
- Pull Requests: 10+ merged
- Major Features: 4 (Logger, TOML, IVIM Patch, IO Module)
- Major Refactorings: 3 (Models, Boundaries, Parameters)
🎯 Breaking Changes
v1.6.0
- Changed default parameter file handling from static to dynamic
- Model wrapper pattern replaced with direct model classes
Notes
- Most changes maintain backward compatibility
- Configuration file structure enhanced but old formats supported where possible
What's Changed
- update logger by @darksim33 in #166
- v1.6.0: Logger by @darksim33 in #167
- v1.6.1: add toml support by @darksim33 in #168
- v1.7.0: model rework by @darksim33 in #171
- 109-parameters-import-update by @darksim33 in #184
- Update IDEAL with some fixes by @darksim33 in #187
- Update Documentation by @darksim33 in #191
- 190-fix-t1-fitting by @darksim33 in #193
- Update Boundary Rework by @darksim33 in #196
- 178 Rework Boundaries by @darksim33 in #197
- add hdf5 support by @darksim33 in #198
- 195 add IO module by @darksim33 in #199
Full Changelog: v1.5.6...v1.7.0
v1.5.6
Added GPUfit capabilities and reworked models to look the same across CPU and GPU fitting approaches.
The fitting procedure and json parameter files were update to support new functionality. Therefore, parameter files from v1.3.1 or older are no longer supported.
The whole package structure is streamlined to better match the used fitting approaches by introducing new classes for result handling. The multi exponential wrapper was depreciated and is no longer available in favor of explizit models to match GPU fitting. (Might be reintroduced in the future.)
What's Changed
- v1.3.3: direct fitting by @darksim33 in #148
- v1.4.0: Added GPU fitting with pygpufit for CUDA GPUs by @darksim33 in #150
- v1.5.0: Full GPU integration and Model rework c092bb7
- 152-rework-fitting-models by @darksim33 in #158
- v1.5.1: moved IDEAL to branch #156 and remove files from main branch until ideal is working properly 186a7fd
- v1.5.2: updated doc with new fitting and parameter instructions and detail
- 153-update-readme @darksim33 in #159
- v1.5.3: fix typos, conditionals and fit_model issues 94979ca
- v1.5.4: fix s0 and fraction related issues for ivim 10d14b1
- v1.5.5: fix: remove reorder array since all models use the same set of parameters for ivim 2748c4d
- v1.5.6: fix: change fit_type: default is now set in the parameters file but can be overwritten during function calls 09572ea
Full Changelog: v1.3.1...v1.5.6
v1.3.1
What's Changed
- 140-reconstruction-split-ui-and-fitting by @darksim33 in #141
- v1.3.0 RadImgArray implementation and UI removal by @darksim33 in #145
- v1.3.1: results rework patch by @darksim33 in #146
Full Changelog: v1.1.1...v1.3.1
Release v1.1.1
What's Changed
- Changed Fit Results to use Custum dicts by @darksim33 in #121
- Fixed Save results bug by @darksim33 in #127
- Restructured fit_data; fixed AboutDlg Size by @darksim33 in #133
- Added load b-values option for context menu by @darksim33 in #131
- 135-ivim-fixed-parameters by @darksim33 in #136
- 137-python39-support by @darksim33 in #138
Full Changelog: v1.0.0...v1.1.1
Release v1.0
First Pyneapple Release for public repo.
Added main testing and ui properties.
Fitting for IVIM and NNLS is up and Running.
IDEAL is still work in progress.
v0.7.3
Version with new package structure, icons and clean directory
What's Changed
- Update Exp by @darksim33 in #54
- Merge pull request #54 from darksim33/main by @darksim33 in #55
- Update to previous Pull by @darksim33 in #56
- Fitting Dlg Update by @darksim33 in #58
- reg = 0 fitting fix (issue #57) by @JoJas102 in #59
- Fixed Issue #51 by @darksim33 in #63
- Fixed Fit Area Issue #62 by @darksim33 in #64
- Fixed Issue #53 by @darksim33 in #60
- Tidied up imports by @JoJas102 in #67
- Update branch by @darksim33 in #77
- 61 todo management by @JoJas102 in #79
- Scrollbar Update by @darksim33 in #86
- IDEAL Fixes by @darksim33 in #85
- 80 merge nnlsparams and nnlsregparams for consistency reasonable by @JoJas102 in #88
- Fixed Zeropadding by @darksim33 in #89
- 90 revert nnlsreg and nnls merge by @JoJas102 in #91
- 94 spring cleaning for project directory by @JoJas102 in #97
- Reworked the QFileDialogs to use the last_dir property; by @darksim33 in #96
- Pip and Poetry Update by @darksim33 in #103
New Contributors
Full Changelog: v0.7.0...v0.7.3