mrax 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mrax-0.1.0/CITATION.cff +13 -0
- mrax-0.1.0/LICENSE +21 -0
- mrax-0.1.0/MANIFEST.in +13 -0
- mrax-0.1.0/MRax_logo.png +0 -0
- mrax-0.1.0/PKG-INFO +177 -0
- mrax-0.1.0/README.md +115 -0
- mrax-0.1.0/docs/_static/MRax_logo.png +0 -0
- mrax-0.1.0/docs/_static/MRax_logo_nav.png +0 -0
- mrax-0.1.0/docs/_static/MRax_logo_square.png +0 -0
- mrax-0.1.0/docs/_static/custom.css +227 -0
- mrax-0.1.0/docs/_templates/license-contact.html +4 -0
- mrax-0.1.0/docs/analysis.rst +93 -0
- mrax-0.1.0/docs/api.rst +422 -0
- mrax-0.1.0/docs/batch.rst +85 -0
- mrax-0.1.0/docs/bruker_import.rst +201 -0
- mrax-0.1.0/docs/conf.py +158 -0
- mrax-0.1.0/docs/gui.rst +185 -0
- mrax-0.1.0/docs/guides.rst +53 -0
- mrax-0.1.0/docs/importer_development.rst +259 -0
- mrax-0.1.0/docs/index.rst +98 -0
- mrax-0.1.0/docs/model_template.py +70 -0
- mrax-0.1.0/docs/models.rst +246 -0
- mrax-0.1.0/docs/notebooks.rst +39 -0
- mrax-0.1.0/docs/overview.rst +166 -0
- mrax-0.1.0/docs/preprocessing.rst +113 -0
- mrax-0.1.0/docs/pulseq_import.rst +106 -0
- mrax-0.1.0/docs/quantitative_fits.rst +139 -0
- mrax-0.1.0/docs/reconstruction.rst +209 -0
- mrax-0.1.0/docs/references.rst +130 -0
- mrax-0.1.0/docs/release_notes.rst +32 -0
- mrax-0.1.0/docs/roadmap.rst +16 -0
- mrax-0.1.0/docs/setup.rst +191 -0
- mrax-0.1.0/docs/storage.rst +83 -0
- mrax-0.1.0/docs/studies.rst +186 -0
- mrax-0.1.0/mrax/__init__.py +3 -0
- mrax-0.1.0/mrax/analysis/__init__.py +107 -0
- mrax-0.1.0/mrax/analysis/dce.py +273 -0
- mrax-0.1.0/mrax/analysis/dti.py +401 -0
- mrax-0.1.0/mrax/analysis/group.py +288 -0
- mrax-0.1.0/mrax/analysis/roi.py +279 -0
- mrax-0.1.0/mrax/analysis/saturation_transfer.py +218 -0
- mrax-0.1.0/mrax/analysis/stats.py +155 -0
- mrax-0.1.0/mrax/analysis/timecourse.py +134 -0
- mrax-0.1.0/mrax/analysis/timecourse_processing.py +391 -0
- mrax-0.1.0/mrax/core/__init__.py +22 -0
- mrax-0.1.0/mrax/core/batch.py +109 -0
- mrax-0.1.0/mrax/core/fit_sanity.py +480 -0
- mrax-0.1.0/mrax/core/loss_builder.py +921 -0
- mrax-0.1.0/mrax/core/runtime.py +24 -0
- mrax-0.1.0/mrax/core/study_runner.py +165 -0
- mrax-0.1.0/mrax/core/synthetic.py +139 -0
- mrax-0.1.0/mrax/data_struct/__init__.py +46 -0
- mrax-0.1.0/mrax/data_struct/dataset.py +36 -0
- mrax-0.1.0/mrax/data_struct/dimensions.py +485 -0
- mrax-0.1.0/mrax/data_struct/experiment.py +237 -0
- mrax-0.1.0/mrax/data_struct/joint.py +426 -0
- mrax-0.1.0/mrax/data_struct/model.py +333 -0
- mrax-0.1.0/mrax/data_struct/quantity.py +59 -0
- mrax-0.1.0/mrax/data_struct/storage.py +1032 -0
- mrax-0.1.0/mrax/data_struct/study.py +209 -0
- mrax-0.1.0/mrax/gui/__init__.py +39 -0
- mrax-0.1.0/mrax/gui/_deps.py +73 -0
- mrax-0.1.0/mrax/gui/app.py +13591 -0
- mrax-0.1.0/mrax/gui/masks.py +602 -0
- mrax-0.1.0/mrax/gui/models.py +288 -0
- mrax-0.1.0/mrax/gui/registration.py +631 -0
- mrax-0.1.0/mrax/gui/session.py +2680 -0
- mrax-0.1.0/mrax/io/__init__.py +42 -0
- mrax-0.1.0/mrax/io/bruker_import.py +6713 -0
- mrax-0.1.0/mrax/io/dipy.py +61 -0
- mrax-0.1.0/mrax/io/import_definitions.py +1005 -0
- mrax-0.1.0/mrax/io/nifti.py +281 -0
- mrax-0.1.0/mrax/io/pulseq_import.py +918 -0
- mrax-0.1.0/mrax/io/study_selection.py +164 -0
- mrax-0.1.0/mrax/library/__init__.py +45 -0
- mrax-0.1.0/mrax/library/default_experiments.py +158 -0
- mrax-0.1.0/mrax/library/default_models.py +1678 -0
- mrax-0.1.0/mrax/library/parameter_library.py +191 -0
- mrax-0.1.0/mrax/library/parameter_library.toml +159 -0
- mrax-0.1.0/mrax/opt/__init__.py +38 -0
- mrax-0.1.0/mrax/opt/ops.py +88 -0
- mrax-0.1.0/mrax/opt/optimizers.py +208 -0
- mrax-0.1.0/mrax/opt/regularizers.py +329 -0
- mrax-0.1.0/mrax/opt/wavelets.py +53 -0
- mrax-0.1.0/mrax/preprocessing/__init__.py +62 -0
- mrax-0.1.0/mrax/preprocessing/denoise.py +436 -0
- mrax-0.1.0/mrax/preprocessing/drift.py +898 -0
- mrax-0.1.0/mrax/preprocessing/motion.py +637 -0
- mrax-0.1.0/mrax/reco/__init__.py +87 -0
- mrax-0.1.0/mrax/reco/jax_fft.py +40 -0
- mrax-0.1.0/mrax/reco/observables.py +251 -0
- mrax-0.1.0/mrax/reco/pipeline.py +380 -0
- mrax-0.1.0/mrax/reco/processing.py +280 -0
- mrax-0.1.0/mrax/reco/utils.py +75 -0
- mrax-0.1.0/mrax/reco/variational.py +1736 -0
- mrax-0.1.0/mrax.egg-info/PKG-INFO +177 -0
- mrax-0.1.0/mrax.egg-info/SOURCES.txt +117 -0
- mrax-0.1.0/mrax.egg-info/dependency_links.txt +1 -0
- mrax-0.1.0/mrax.egg-info/entry_points.txt +2 -0
- mrax-0.1.0/mrax.egg-info/requires.txt +45 -0
- mrax-0.1.0/mrax.egg-info/top_level.txt +1 -0
- mrax-0.1.0/notebooks/analysis_toolbox.ipynb +1203 -0
- mrax-0.1.0/notebooks/getting_started.ipynb +581 -0
- mrax-0.1.0/notebooks/preprocessing_denoiser_benchmarks.ipynb +426 -0
- mrax-0.1.0/notebooks/pulseq_import_demo.ipynb +560 -0
- mrax-0.1.0/notebooks/reconstruction_pipeline.ipynb +187 -0
- mrax-0.1.0/notebooks/variational_reconstruction.ipynb +370 -0
- mrax-0.1.0/pyproject.toml +115 -0
- mrax-0.1.0/pyrightconfig.json +10 -0
- mrax-0.1.0/requirements-dev.txt +18 -0
- mrax-0.1.0/requirements.txt +14 -0
- mrax-0.1.0/setup.cfg +4 -0
- mrax-0.1.0/tests/test_core_workflows.py +186 -0
- mrax-0.1.0/tests/test_extended_release_workflows.py +174 -0
- mrax-0.1.0/tests/test_gui_workflows.py +282 -0
- mrax-0.1.0/tests/test_import_workflows.py +98 -0
- mrax-0.1.0/tests/test_preprocessing_workflows.py +69 -0
- mrax-0.1.0/tests/test_release_regressions.py +74 -0
- mrax-0.1.0/tests/test_timecourse_baseline.py +56 -0
mrax-0.1.0/CITATION.cff
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use MRax in your research, please cite it using the metadata in this file."
|
|
3
|
+
title: "MRax: JAX-based tools for quantitative MRI research"
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
date-released: 2026-07-10
|
|
6
|
+
type: software
|
|
7
|
+
license: MIT
|
|
8
|
+
authors:
|
|
9
|
+
- given-names: Chris
|
|
10
|
+
family-names: Lippe
|
|
11
|
+
repository-code: "https://github.com/chris-lippe/MRax"
|
|
12
|
+
url: "https://github.com/chris-lippe/MRax"
|
|
13
|
+
abstract: "MRax is a JAX-based Python library for quantitative MRI model fitting, reconstruction, and analysis."
|
mrax-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Chris Lippe
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
mrax-0.1.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
include LICENSE
|
|
2
|
+
include README.md
|
|
3
|
+
include CITATION.cff
|
|
4
|
+
include MRax_logo.png
|
|
5
|
+
include pyrightconfig.json
|
|
6
|
+
include requirements.txt
|
|
7
|
+
include requirements-dev.txt
|
|
8
|
+
recursive-include mrax *.py *.toml
|
|
9
|
+
recursive-include docs *.rst *.py *.css *.html *.png
|
|
10
|
+
recursive-include notebooks *.ipynb
|
|
11
|
+
recursive-include tests *.py
|
|
12
|
+
prune docs/_build
|
|
13
|
+
global-exclude __pycache__ *.py[cod] .DS_Store
|
mrax-0.1.0/MRax_logo.png
ADDED
|
Binary file
|
mrax-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mrax
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: JAX-based tools for quantitative MRI model fitting, reconstruction, and analysis.
|
|
5
|
+
Author: Chris Lippe
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/chris-lippe/MRax
|
|
8
|
+
Project-URL: Documentation, https://chris-lippe.github.io/MRax
|
|
9
|
+
Project-URL: Repository, https://github.com/chris-lippe/MRax
|
|
10
|
+
Project-URL: Issues, https://github.com/chris-lippe/MRax/issues
|
|
11
|
+
Keywords: MRI,JAX,quantitative imaging,reconstruction
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: jax<0.11,>=0.4.35
|
|
23
|
+
Requires-Dist: optax<0.3,>=0.2.4
|
|
24
|
+
Requires-Dist: numpy<3,>=2
|
|
25
|
+
Requires-Dist: scipy<2,>=1.14
|
|
26
|
+
Requires-Dist: ismrmrd<2,>=1.14
|
|
27
|
+
Requires-Dist: nibabel<6,>=5.3
|
|
28
|
+
Requires-Dist: dipy<2,>=1.10
|
|
29
|
+
Requires-Dist: pypulseq<2,>=1.4
|
|
30
|
+
Requires-Dist: SimpleITK<3,>=2.4
|
|
31
|
+
Requires-Dist: PySide6<7,>=6.8
|
|
32
|
+
Requires-Dist: pyqtgraph<0.15,>=0.13
|
|
33
|
+
Requires-Dist: qtpy<3,>=2.4
|
|
34
|
+
Requires-Dist: superqt<1,>=0.7
|
|
35
|
+
Requires-Dist: matplotlib<4,>=3.9
|
|
36
|
+
Provides-Extra: nufft
|
|
37
|
+
Requires-Dist: jax-finufft<2,>=1; extra == "nufft"
|
|
38
|
+
Provides-Extra: denoise-external
|
|
39
|
+
Requires-Dist: bm3d<5,>=4; extra == "denoise-external"
|
|
40
|
+
Requires-Dist: bm4d<5,>=4; extra == "denoise-external"
|
|
41
|
+
Provides-Extra: all
|
|
42
|
+
Requires-Dist: jax-finufft<2,>=1; extra == "all"
|
|
43
|
+
Requires-Dist: bm3d<5,>=4; extra == "all"
|
|
44
|
+
Requires-Dist: bm4d<5,>=4; extra == "all"
|
|
45
|
+
Provides-Extra: docs
|
|
46
|
+
Requires-Dist: sphinx<11,>=8; extra == "docs"
|
|
47
|
+
Requires-Dist: myst-parser<6,>=4; extra == "docs"
|
|
48
|
+
Requires-Dist: pydata-sphinx-theme<1,>=0.16; extra == "docs"
|
|
49
|
+
Requires-Dist: nbsphinx<1,>=0.9; extra == "docs"
|
|
50
|
+
Provides-Extra: notebooks
|
|
51
|
+
Requires-Dist: jupyterlab<5,>=4; extra == "notebooks"
|
|
52
|
+
Requires-Dist: scikit-image<1,>=0.25; extra == "notebooks"
|
|
53
|
+
Provides-Extra: dev
|
|
54
|
+
Requires-Dist: build<2,>=1.2; extra == "dev"
|
|
55
|
+
Requires-Dist: coverage<8,>=7.6; extra == "dev"
|
|
56
|
+
Requires-Dist: isort<7,>=5.13; extra == "dev"
|
|
57
|
+
Requires-Dist: pytest<10,>=8.3; extra == "dev"
|
|
58
|
+
Requires-Dist: pyright<2,>=1.1.400; extra == "dev"
|
|
59
|
+
Requires-Dist: ruff<1,>=0.9; extra == "dev"
|
|
60
|
+
Requires-Dist: twine<7,>=6; extra == "dev"
|
|
61
|
+
Dynamic: license-file
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
# MRax
|
|
66
|
+
|
|
67
|
+
MRax is a JAX-based Python library for quantitative MRI research. It provides
|
|
68
|
+
data structures for experiments and studies, differentiable signal models,
|
|
69
|
+
optimization utilities, reconstruction helpers, analysis tools, and ISMRMRD-backed
|
|
70
|
+
storage for images, k-space, and fitted maps.
|
|
71
|
+
|
|
72
|
+
Disclaimer: MRax is intended for research use only. This is an early release, and bugs may occur.
|
|
73
|
+
Coding agents were used to assist in development. Code was manually reviewed and validated on Bruker ParaVision 360 3.6 data.
|
|
74
|
+
|
|
75
|
+
## Installation
|
|
76
|
+
|
|
77
|
+
Install the release package from PyPI:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
pip install mrax
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The default install includes fitting, Cartesian reconstruction, import, built-in
|
|
84
|
+
denoising, registration, analysis, storage, and desktop GUI support. Optional
|
|
85
|
+
non-Cartesian and external denoising backends are installed explicitly:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
pip install "mrax[nufft]"
|
|
89
|
+
pip install "mrax[denoise-external]"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`jax-finufft` does not publish Windows wheels. The upstream `bm3d` and `bm4d`
|
|
93
|
+
packages are licensed for non-commercial use; review their licenses before installing
|
|
94
|
+
the `denoise-external` extra. Development, documentation, and notebook authoring tools
|
|
95
|
+
remain outside the base runtime package.
|
|
96
|
+
|
|
97
|
+
MRax uses the `mrax.*` import namespace:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from mrax.core.loss_builder import run_fit
|
|
101
|
+
from mrax.library import make_t2_se_model
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Contributor extras are available for notebook and documentation workflows:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pip install "mrax[notebooks]"
|
|
108
|
+
pip install "mrax[docs]"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
For local development from a clone:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
python -m pip install --upgrade pip
|
|
115
|
+
python -m pip install -e ".[all,dev,docs,notebooks]"
|
|
116
|
+
pytest
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Dev Container
|
|
120
|
+
|
|
121
|
+
The repository includes one VS Code compatible dev container. Open the public clone in
|
|
122
|
+
VS Code and choose **Dev Containers: Reopen in Container**. The container installs
|
|
123
|
+
all runtime features plus development, documentation, and notebook tooling, then
|
|
124
|
+
installs MRax in editable mode:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
python -m pip install -e ".[all,dev,docs,notebooks]"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Inside the container, common checks are:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
pytest
|
|
134
|
+
sphinx-build -E -b html docs docs/_build/html
|
|
135
|
+
jupyter lab notebooks
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Documentation Website
|
|
139
|
+
|
|
140
|
+
Documentation is built with Sphinx:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
python -m pip install -e ".[docs]"
|
|
144
|
+
sphinx-build -E -b html docs docs/_build/html
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## PyPI Release
|
|
148
|
+
|
|
149
|
+
Build and inspect a local distribution with:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
python -m pip install -e ".[all,dev,docs,notebooks]"
|
|
153
|
+
python -m build
|
|
154
|
+
twine check dist/*
|
|
155
|
+
```
|
|
156
|
+
## Quick Example
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
import jax.numpy as jnp
|
|
160
|
+
|
|
161
|
+
from mrax.core.loss_builder import run_fit
|
|
162
|
+
from mrax.data_struct import DataSet, Quantity
|
|
163
|
+
from mrax.library import build_default_experiment, make_t2_se_model
|
|
164
|
+
|
|
165
|
+
te = jnp.asarray([8.0, 24.0, 48.0, 96.0])
|
|
166
|
+
experiment = build_default_experiment(
|
|
167
|
+
"mse",
|
|
168
|
+
frame_count=te.size,
|
|
169
|
+
spatial_shape=(2, 2),
|
|
170
|
+
observables={"TE": Quantity(te, "ms")},
|
|
171
|
+
)
|
|
172
|
+
model = make_t2_se_model(scale=1.0)
|
|
173
|
+
dataset = DataSet(data=jnp.ones((te.size, 2, 2)), name="demo")
|
|
174
|
+
|
|
175
|
+
fields, losses = run_fit(experiment, model, dataset, num_steps=20, step_size=0.03)
|
|
176
|
+
print(fields["t2"].si_unit, losses[-1])
|
|
177
|
+
```
|
mrax-0.1.0/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# MRax
|
|
4
|
+
|
|
5
|
+
MRax is a JAX-based Python library for quantitative MRI research. It provides
|
|
6
|
+
data structures for experiments and studies, differentiable signal models,
|
|
7
|
+
optimization utilities, reconstruction helpers, analysis tools, and ISMRMRD-backed
|
|
8
|
+
storage for images, k-space, and fitted maps.
|
|
9
|
+
|
|
10
|
+
Disclaimer: MRax is intended for research use only. This is an early release, and bugs may occur.
|
|
11
|
+
Coding agents were used to assist in development. Code was manually reviewed and validated on Bruker ParaVision 360 3.6 data.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Install the release package from PyPI:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install mrax
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The default install includes fitting, Cartesian reconstruction, import, built-in
|
|
22
|
+
denoising, registration, analysis, storage, and desktop GUI support. Optional
|
|
23
|
+
non-Cartesian and external denoising backends are installed explicitly:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install "mrax[nufft]"
|
|
27
|
+
pip install "mrax[denoise-external]"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`jax-finufft` does not publish Windows wheels. The upstream `bm3d` and `bm4d`
|
|
31
|
+
packages are licensed for non-commercial use; review their licenses before installing
|
|
32
|
+
the `denoise-external` extra. Development, documentation, and notebook authoring tools
|
|
33
|
+
remain outside the base runtime package.
|
|
34
|
+
|
|
35
|
+
MRax uses the `mrax.*` import namespace:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from mrax.core.loss_builder import run_fit
|
|
39
|
+
from mrax.library import make_t2_se_model
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Contributor extras are available for notebook and documentation workflows:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install "mrax[notebooks]"
|
|
46
|
+
pip install "mrax[docs]"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
For local development from a clone:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
python -m pip install --upgrade pip
|
|
53
|
+
python -m pip install -e ".[all,dev,docs,notebooks]"
|
|
54
|
+
pytest
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Dev Container
|
|
58
|
+
|
|
59
|
+
The repository includes one VS Code compatible dev container. Open the public clone in
|
|
60
|
+
VS Code and choose **Dev Containers: Reopen in Container**. The container installs
|
|
61
|
+
all runtime features plus development, documentation, and notebook tooling, then
|
|
62
|
+
installs MRax in editable mode:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
python -m pip install -e ".[all,dev,docs,notebooks]"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Inside the container, common checks are:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pytest
|
|
72
|
+
sphinx-build -E -b html docs docs/_build/html
|
|
73
|
+
jupyter lab notebooks
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Documentation Website
|
|
77
|
+
|
|
78
|
+
Documentation is built with Sphinx:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
python -m pip install -e ".[docs]"
|
|
82
|
+
sphinx-build -E -b html docs docs/_build/html
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## PyPI Release
|
|
86
|
+
|
|
87
|
+
Build and inspect a local distribution with:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
python -m pip install -e ".[all,dev,docs,notebooks]"
|
|
91
|
+
python -m build
|
|
92
|
+
twine check dist/*
|
|
93
|
+
```
|
|
94
|
+
## Quick Example
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import jax.numpy as jnp
|
|
98
|
+
|
|
99
|
+
from mrax.core.loss_builder import run_fit
|
|
100
|
+
from mrax.data_struct import DataSet, Quantity
|
|
101
|
+
from mrax.library import build_default_experiment, make_t2_se_model
|
|
102
|
+
|
|
103
|
+
te = jnp.asarray([8.0, 24.0, 48.0, 96.0])
|
|
104
|
+
experiment = build_default_experiment(
|
|
105
|
+
"mse",
|
|
106
|
+
frame_count=te.size,
|
|
107
|
+
spatial_shape=(2, 2),
|
|
108
|
+
observables={"TE": Quantity(te, "ms")},
|
|
109
|
+
)
|
|
110
|
+
model = make_t2_se_model(scale=1.0)
|
|
111
|
+
dataset = DataSet(data=jnp.ones((te.size, 2, 2)), name="demo")
|
|
112
|
+
|
|
113
|
+
fields, losses = run_fit(experiment, model, dataset, num_steps=20, step_size=0.03)
|
|
114
|
+
print(fields["t2"].si_unit, losses[-1])
|
|
115
|
+
```
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--pst-color-primary: #1f77b4;
|
|
3
|
+
--pst-color-secondary: #ff7f0e;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.mrax-hero {
|
|
7
|
+
border: 1px solid var(--pst-color-border);
|
|
8
|
+
border-radius: 12px;
|
|
9
|
+
padding: 1.75rem;
|
|
10
|
+
margin: 0 0 2rem;
|
|
11
|
+
background:
|
|
12
|
+
linear-gradient(135deg, rgba(31, 119, 180, 0.12), rgba(255, 127, 14, 0.08)),
|
|
13
|
+
var(--pst-color-background);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.mrax-hero-inner {
|
|
17
|
+
display: grid;
|
|
18
|
+
grid-template-columns: 150px minmax(0, 1fr);
|
|
19
|
+
gap: 1.75rem;
|
|
20
|
+
align-items: center;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.mrax-hero-mark {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
justify-content: center;
|
|
27
|
+
min-width: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.mrax-hero-mark img {
|
|
31
|
+
display: block;
|
|
32
|
+
width: 150px;
|
|
33
|
+
max-width: 100%;
|
|
34
|
+
height: auto;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.mrax-hero-title {
|
|
38
|
+
max-width: 760px;
|
|
39
|
+
margin: 0;
|
|
40
|
+
color: var(--pst-color-heading);
|
|
41
|
+
font-size: 2rem;
|
|
42
|
+
line-height: 1.1;
|
|
43
|
+
font-weight: 750;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.mrax-hero-copy {
|
|
47
|
+
max-width: 780px;
|
|
48
|
+
margin: 1rem 0 0;
|
|
49
|
+
font-size: 1.05rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.mrax-hero-actions {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-wrap: wrap;
|
|
55
|
+
gap: 0.75rem;
|
|
56
|
+
margin-top: 1.4rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.mrax-hero a.mrax-button {
|
|
60
|
+
display: inline-block;
|
|
61
|
+
border: 1px solid var(--pst-color-border);
|
|
62
|
+
border-radius: 7px;
|
|
63
|
+
padding: 0.55rem 0.85rem;
|
|
64
|
+
font-weight: 700;
|
|
65
|
+
text-decoration: none;
|
|
66
|
+
background: var(--pst-color-background);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.mrax-hero a.mrax-button,
|
|
70
|
+
.mrax-hero a.mrax-button:visited {
|
|
71
|
+
color: var(--pst-color-primary);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.mrax-hero a.mrax-button:hover {
|
|
75
|
+
text-decoration: none;
|
|
76
|
+
border-color: var(--pst-color-primary);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.mrax-hero a.mrax-button-primary,
|
|
80
|
+
.mrax-hero a.mrax-button-primary:visited {
|
|
81
|
+
background: #4bb4c5;
|
|
82
|
+
border-color: #4bb4c5;
|
|
83
|
+
color: #06131f !important;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.mrax-hero a.mrax-button-primary:hover {
|
|
87
|
+
background: #60c0cf;
|
|
88
|
+
border-color: #60c0cf;
|
|
89
|
+
color: #06131f !important;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@media (max-width: 720px) {
|
|
93
|
+
.mrax-hero {
|
|
94
|
+
padding: 1.25rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.mrax-hero-inner {
|
|
98
|
+
grid-template-columns: 1fr;
|
|
99
|
+
gap: 1rem;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.mrax-hero-mark {
|
|
103
|
+
justify-content: flex-start;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.mrax-hero-mark img {
|
|
107
|
+
width: 112px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.mrax-hero-title {
|
|
111
|
+
font-size: 1.55rem;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Constrain line lengths for readability */
|
|
116
|
+
.bd-article {
|
|
117
|
+
max-width: 980px;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Light card styling for lists */
|
|
121
|
+
.toctree-wrapper ul {
|
|
122
|
+
list-style: none;
|
|
123
|
+
padding-left: 0;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.toctree-wrapper ul li {
|
|
127
|
+
background: #f8f9fb;
|
|
128
|
+
border: 1px solid #e1e5ea;
|
|
129
|
+
border-radius: 8px;
|
|
130
|
+
padding: 10px 12px;
|
|
131
|
+
margin-bottom: 8px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.toctree-wrapper ul li a {
|
|
135
|
+
font-weight: 600;
|
|
136
|
+
color: var(--pst-color-primary);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* Soften code blocks */
|
|
140
|
+
div.highlight pre {
|
|
141
|
+
border-radius: 6px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.notebook-embed {
|
|
145
|
+
margin: 16px 0;
|
|
146
|
+
border: 1px solid #e1e5ea;
|
|
147
|
+
border-radius: 8px;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.04);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.notebook-embed iframe {
|
|
153
|
+
display: block;
|
|
154
|
+
width: 100%;
|
|
155
|
+
background: #fff;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.bd-article > section[id] + h1[id] {
|
|
159
|
+
display: none;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Header logo: larger image, hide text label */
|
|
163
|
+
.navbar-brand .logo__image {
|
|
164
|
+
height: 52px;
|
|
165
|
+
max-height: 52px;
|
|
166
|
+
width: auto;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.navbar-brand .logo__title {
|
|
170
|
+
display: none;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@media (min-width: 960px) {
|
|
174
|
+
.bd-header__inner {
|
|
175
|
+
align-items: center;
|
|
176
|
+
flex-wrap: nowrap;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.navbar-header-items__start {
|
|
180
|
+
flex: 0 0 auto;
|
|
181
|
+
max-width: none;
|
|
182
|
+
width: auto;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.navbar-header-items {
|
|
186
|
+
align-items: center;
|
|
187
|
+
display: flex;
|
|
188
|
+
flex: 1 1 auto;
|
|
189
|
+
flex-wrap: nowrap;
|
|
190
|
+
max-width: none;
|
|
191
|
+
min-width: 0;
|
|
192
|
+
width: auto;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.navbar-header-items__center {
|
|
196
|
+
flex: 1 1 auto;
|
|
197
|
+
min-width: 0;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.bd-navbar-elements {
|
|
201
|
+
flex-wrap: nowrap;
|
|
202
|
+
white-space: nowrap;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.navbar-header-items__end {
|
|
206
|
+
flex: 0 0 auto;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* Dark theme tweaks */
|
|
211
|
+
html[data-theme="dark"] .toctree-wrapper ul li {
|
|
212
|
+
background: #1f2733;
|
|
213
|
+
border-color: #2e3a4a;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
html[data-theme="dark"] .toctree-wrapper ul li a {
|
|
217
|
+
color: var(--pst-color-primary);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
html[data-theme="dark"] .notebook-embed {
|
|
221
|
+
border-color: #2e3a4a;
|
|
222
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
html[data-theme="dark"] .notebook-embed iframe {
|
|
226
|
+
background: #0f141c;
|
|
227
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Post-fit Analysis
|
|
2
|
+
=================
|
|
3
|
+
|
|
4
|
+
The analysis toolbox provides reusable utilities for extracting ROI statistics, computing
|
|
5
|
+
ROI timecourses, and summarizing/comparing groups from batch outputs. The API is designed
|
|
6
|
+
to stay modular: ROI definitions are independent of how you load data, and group statistics
|
|
7
|
+
work on long-form tables so you can extend or replace individual steps.
|
|
8
|
+
|
|
9
|
+
ROI statistics
|
|
10
|
+
--------------
|
|
11
|
+
|
|
12
|
+
Compute per-map ROI summaries (mean, variance, etc.) from fitted parameter maps:
|
|
13
|
+
|
|
14
|
+
.. code-block:: python
|
|
15
|
+
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
from mrax.analysis import ROI, collect_roi_stats
|
|
19
|
+
from mrax.data_struct import load_study_results
|
|
20
|
+
|
|
21
|
+
data = load_study_results("batch_output/subj_a/study_manifest.json")
|
|
22
|
+
maps = data["experiments"]["t1_ir"]["fitted_maps"]
|
|
23
|
+
|
|
24
|
+
mask = np.zeros((16, 16), dtype=bool)
|
|
25
|
+
mask[4:12, 4:12] = True
|
|
26
|
+
roi = ROI("center", mask)
|
|
27
|
+
|
|
28
|
+
rows = collect_roi_stats(maps, [roi], stats=("mean", "variance"))
|
|
29
|
+
for row in rows:
|
|
30
|
+
print(row["map"], row["roi"], row["stat"], row["value"], row.get("unit", ""))
|
|
31
|
+
|
|
32
|
+
Timecourse extraction
|
|
33
|
+
---------------------
|
|
34
|
+
|
|
35
|
+
Extract an ROI timecourse by reducing across spatial dimensions. If the data array is
|
|
36
|
+
``(frames, x, y)`` or ``(non_spatial..., x, y)``, the ROI mask is aligned to the spatial
|
|
37
|
+
axes automatically:
|
|
38
|
+
|
|
39
|
+
.. code-block:: python
|
|
40
|
+
|
|
41
|
+
from mrax.analysis import extract_timecourse
|
|
42
|
+
|
|
43
|
+
mr_image = data["experiments"]["t1_ir"]["mr_image"]
|
|
44
|
+
timecourse = extract_timecourse(mr_image, roi, stat="mean")
|
|
45
|
+
print(timecourse.shape)
|
|
46
|
+
|
|
47
|
+
Group summaries and comparisons
|
|
48
|
+
-------------------------------
|
|
49
|
+
|
|
50
|
+
Group analysis utilities build on the batch output layout. Provide group members as
|
|
51
|
+
manifest paths or study folder names inside ``output_root``:
|
|
52
|
+
|
|
53
|
+
.. code-block:: python
|
|
54
|
+
|
|
55
|
+
from mrax.analysis import analyze_groups
|
|
56
|
+
|
|
57
|
+
groups = {
|
|
58
|
+
"control": ["subj_a", "subj_b"],
|
|
59
|
+
"treated": ["subj_c", "subj_d"],
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
results = analyze_groups(
|
|
63
|
+
groups,
|
|
64
|
+
output_root="batch_output",
|
|
65
|
+
experiment_name="t1_ir",
|
|
66
|
+
rois=[roi],
|
|
67
|
+
map_names=["t1"],
|
|
68
|
+
stats=("mean",),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
subject_rows = results["subject_stats"]
|
|
72
|
+
group_summary = results["group_summary"]
|
|
73
|
+
comparisons = results["comparisons"]
|
|
74
|
+
|
|
75
|
+
Plotting summaries
|
|
76
|
+
------------------
|
|
77
|
+
|
|
78
|
+
The analysis functions return plain Python rows and arrays. Use your plotting library
|
|
79
|
+
of choice to visualize the outputs. For example, the group summary table can be
|
|
80
|
+
converted to a bar plot with ``matplotlib``:
|
|
81
|
+
|
|
82
|
+
.. code-block:: python
|
|
83
|
+
|
|
84
|
+
import matplotlib.pyplot as plt
|
|
85
|
+
|
|
86
|
+
rows = [
|
|
87
|
+
row for row in results["group_summary"]
|
|
88
|
+
if row["map"] == "t1" and row["roi"] == "center" and row["stat"] == "mean"
|
|
89
|
+
]
|
|
90
|
+
plt.bar([row["group"] for row in rows], [row["mean"] for row in rows])
|
|
91
|
+
plt.ylabel("T1 (ms)")
|
|
92
|
+
|
|
93
|
+
See the analysis notebook for an end-to-end demo using synthetic data and batch outputs.
|