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.
Files changed (119) hide show
  1. mrax-0.1.0/CITATION.cff +13 -0
  2. mrax-0.1.0/LICENSE +21 -0
  3. mrax-0.1.0/MANIFEST.in +13 -0
  4. mrax-0.1.0/MRax_logo.png +0 -0
  5. mrax-0.1.0/PKG-INFO +177 -0
  6. mrax-0.1.0/README.md +115 -0
  7. mrax-0.1.0/docs/_static/MRax_logo.png +0 -0
  8. mrax-0.1.0/docs/_static/MRax_logo_nav.png +0 -0
  9. mrax-0.1.0/docs/_static/MRax_logo_square.png +0 -0
  10. mrax-0.1.0/docs/_static/custom.css +227 -0
  11. mrax-0.1.0/docs/_templates/license-contact.html +4 -0
  12. mrax-0.1.0/docs/analysis.rst +93 -0
  13. mrax-0.1.0/docs/api.rst +422 -0
  14. mrax-0.1.0/docs/batch.rst +85 -0
  15. mrax-0.1.0/docs/bruker_import.rst +201 -0
  16. mrax-0.1.0/docs/conf.py +158 -0
  17. mrax-0.1.0/docs/gui.rst +185 -0
  18. mrax-0.1.0/docs/guides.rst +53 -0
  19. mrax-0.1.0/docs/importer_development.rst +259 -0
  20. mrax-0.1.0/docs/index.rst +98 -0
  21. mrax-0.1.0/docs/model_template.py +70 -0
  22. mrax-0.1.0/docs/models.rst +246 -0
  23. mrax-0.1.0/docs/notebooks.rst +39 -0
  24. mrax-0.1.0/docs/overview.rst +166 -0
  25. mrax-0.1.0/docs/preprocessing.rst +113 -0
  26. mrax-0.1.0/docs/pulseq_import.rst +106 -0
  27. mrax-0.1.0/docs/quantitative_fits.rst +139 -0
  28. mrax-0.1.0/docs/reconstruction.rst +209 -0
  29. mrax-0.1.0/docs/references.rst +130 -0
  30. mrax-0.1.0/docs/release_notes.rst +32 -0
  31. mrax-0.1.0/docs/roadmap.rst +16 -0
  32. mrax-0.1.0/docs/setup.rst +191 -0
  33. mrax-0.1.0/docs/storage.rst +83 -0
  34. mrax-0.1.0/docs/studies.rst +186 -0
  35. mrax-0.1.0/mrax/__init__.py +3 -0
  36. mrax-0.1.0/mrax/analysis/__init__.py +107 -0
  37. mrax-0.1.0/mrax/analysis/dce.py +273 -0
  38. mrax-0.1.0/mrax/analysis/dti.py +401 -0
  39. mrax-0.1.0/mrax/analysis/group.py +288 -0
  40. mrax-0.1.0/mrax/analysis/roi.py +279 -0
  41. mrax-0.1.0/mrax/analysis/saturation_transfer.py +218 -0
  42. mrax-0.1.0/mrax/analysis/stats.py +155 -0
  43. mrax-0.1.0/mrax/analysis/timecourse.py +134 -0
  44. mrax-0.1.0/mrax/analysis/timecourse_processing.py +391 -0
  45. mrax-0.1.0/mrax/core/__init__.py +22 -0
  46. mrax-0.1.0/mrax/core/batch.py +109 -0
  47. mrax-0.1.0/mrax/core/fit_sanity.py +480 -0
  48. mrax-0.1.0/mrax/core/loss_builder.py +921 -0
  49. mrax-0.1.0/mrax/core/runtime.py +24 -0
  50. mrax-0.1.0/mrax/core/study_runner.py +165 -0
  51. mrax-0.1.0/mrax/core/synthetic.py +139 -0
  52. mrax-0.1.0/mrax/data_struct/__init__.py +46 -0
  53. mrax-0.1.0/mrax/data_struct/dataset.py +36 -0
  54. mrax-0.1.0/mrax/data_struct/dimensions.py +485 -0
  55. mrax-0.1.0/mrax/data_struct/experiment.py +237 -0
  56. mrax-0.1.0/mrax/data_struct/joint.py +426 -0
  57. mrax-0.1.0/mrax/data_struct/model.py +333 -0
  58. mrax-0.1.0/mrax/data_struct/quantity.py +59 -0
  59. mrax-0.1.0/mrax/data_struct/storage.py +1032 -0
  60. mrax-0.1.0/mrax/data_struct/study.py +209 -0
  61. mrax-0.1.0/mrax/gui/__init__.py +39 -0
  62. mrax-0.1.0/mrax/gui/_deps.py +73 -0
  63. mrax-0.1.0/mrax/gui/app.py +13591 -0
  64. mrax-0.1.0/mrax/gui/masks.py +602 -0
  65. mrax-0.1.0/mrax/gui/models.py +288 -0
  66. mrax-0.1.0/mrax/gui/registration.py +631 -0
  67. mrax-0.1.0/mrax/gui/session.py +2680 -0
  68. mrax-0.1.0/mrax/io/__init__.py +42 -0
  69. mrax-0.1.0/mrax/io/bruker_import.py +6713 -0
  70. mrax-0.1.0/mrax/io/dipy.py +61 -0
  71. mrax-0.1.0/mrax/io/import_definitions.py +1005 -0
  72. mrax-0.1.0/mrax/io/nifti.py +281 -0
  73. mrax-0.1.0/mrax/io/pulseq_import.py +918 -0
  74. mrax-0.1.0/mrax/io/study_selection.py +164 -0
  75. mrax-0.1.0/mrax/library/__init__.py +45 -0
  76. mrax-0.1.0/mrax/library/default_experiments.py +158 -0
  77. mrax-0.1.0/mrax/library/default_models.py +1678 -0
  78. mrax-0.1.0/mrax/library/parameter_library.py +191 -0
  79. mrax-0.1.0/mrax/library/parameter_library.toml +159 -0
  80. mrax-0.1.0/mrax/opt/__init__.py +38 -0
  81. mrax-0.1.0/mrax/opt/ops.py +88 -0
  82. mrax-0.1.0/mrax/opt/optimizers.py +208 -0
  83. mrax-0.1.0/mrax/opt/regularizers.py +329 -0
  84. mrax-0.1.0/mrax/opt/wavelets.py +53 -0
  85. mrax-0.1.0/mrax/preprocessing/__init__.py +62 -0
  86. mrax-0.1.0/mrax/preprocessing/denoise.py +436 -0
  87. mrax-0.1.0/mrax/preprocessing/drift.py +898 -0
  88. mrax-0.1.0/mrax/preprocessing/motion.py +637 -0
  89. mrax-0.1.0/mrax/reco/__init__.py +87 -0
  90. mrax-0.1.0/mrax/reco/jax_fft.py +40 -0
  91. mrax-0.1.0/mrax/reco/observables.py +251 -0
  92. mrax-0.1.0/mrax/reco/pipeline.py +380 -0
  93. mrax-0.1.0/mrax/reco/processing.py +280 -0
  94. mrax-0.1.0/mrax/reco/utils.py +75 -0
  95. mrax-0.1.0/mrax/reco/variational.py +1736 -0
  96. mrax-0.1.0/mrax.egg-info/PKG-INFO +177 -0
  97. mrax-0.1.0/mrax.egg-info/SOURCES.txt +117 -0
  98. mrax-0.1.0/mrax.egg-info/dependency_links.txt +1 -0
  99. mrax-0.1.0/mrax.egg-info/entry_points.txt +2 -0
  100. mrax-0.1.0/mrax.egg-info/requires.txt +45 -0
  101. mrax-0.1.0/mrax.egg-info/top_level.txt +1 -0
  102. mrax-0.1.0/notebooks/analysis_toolbox.ipynb +1203 -0
  103. mrax-0.1.0/notebooks/getting_started.ipynb +581 -0
  104. mrax-0.1.0/notebooks/preprocessing_denoiser_benchmarks.ipynb +426 -0
  105. mrax-0.1.0/notebooks/pulseq_import_demo.ipynb +560 -0
  106. mrax-0.1.0/notebooks/reconstruction_pipeline.ipynb +187 -0
  107. mrax-0.1.0/notebooks/variational_reconstruction.ipynb +370 -0
  108. mrax-0.1.0/pyproject.toml +115 -0
  109. mrax-0.1.0/pyrightconfig.json +10 -0
  110. mrax-0.1.0/requirements-dev.txt +18 -0
  111. mrax-0.1.0/requirements.txt +14 -0
  112. mrax-0.1.0/setup.cfg +4 -0
  113. mrax-0.1.0/tests/test_core_workflows.py +186 -0
  114. mrax-0.1.0/tests/test_extended_release_workflows.py +174 -0
  115. mrax-0.1.0/tests/test_gui_workflows.py +282 -0
  116. mrax-0.1.0/tests/test_import_workflows.py +98 -0
  117. mrax-0.1.0/tests/test_preprocessing_workflows.py +69 -0
  118. mrax-0.1.0/tests/test_release_regressions.py +74 -0
  119. mrax-0.1.0/tests/test_timecourse_baseline.py +56 -0
@@ -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
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
+ ![MRax logo](MRax_logo.png)
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
+ ![MRax logo](MRax_logo.png)
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
@@ -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,4 @@
1
+ <p class="license-contact">
2
+ License: {{ license_name }}.
3
+ Contact: <a href="mailto:{{ contact_email }}">{{ contact_email }}</a>.
4
+ </p>
@@ -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.