pymiox 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.

Potentially problematic release.


This version of pymiox might be problematic. Click here for more details.

Files changed (129) hide show
  1. pymiox-0.1.0/LICENSE +28 -0
  2. pymiox-0.1.0/MANIFEST.in +4 -0
  3. pymiox-0.1.0/PKG-INFO +87 -0
  4. pymiox-0.1.0/README.md +53 -0
  5. pymiox-0.1.0/miox/__init__.py +79 -0
  6. pymiox-0.1.0/miox/__main__.py +22 -0
  7. pymiox-0.1.0/miox/audit.py +143 -0
  8. pymiox-0.1.0/miox/cli.py +292 -0
  9. pymiox-0.1.0/miox/data.py +1260 -0
  10. pymiox-0.1.0/miox/matfile.py +94 -0
  11. pymiox-0.1.0/miox/meta/__init__.py +22 -0
  12. pymiox-0.1.0/miox/meta/keys.py +408 -0
  13. pymiox-0.1.0/miox/meta/meta.py +61 -0
  14. pymiox-0.1.0/miox/preview.py +454 -0
  15. pymiox-0.1.0/miox/processing.py +766 -0
  16. pymiox-0.1.0/miox/quicklook.py +1195 -0
  17. pymiox-0.1.0/miox/quicklook_pages.py +1307 -0
  18. pymiox-0.1.0/miox/readers/__init__.py +84 -0
  19. pymiox-0.1.0/miox/readers/bart_cfl.py +113 -0
  20. pymiox-0.1.0/miox/readers/base.py +380 -0
  21. pymiox-0.1.0/miox/readers/basis_folder.py +110 -0
  22. pymiox-0.1.0/miox/readers/biopac_acq.py +380 -0
  23. pymiox-0.1.0/miox/readers/brainvoyager.py +485 -0
  24. pymiox-0.1.0/miox/readers/brainvoyager_text.py +425 -0
  25. pymiox-0.1.0/miox/readers/bruker.py +563 -0
  26. pymiox-0.1.0/miox/readers/bruker_2dseq.py +150 -0
  27. pymiox-0.1.0/miox/readers/bruker_raw.py +368 -0
  28. pymiox-0.1.0/miox/readers/csdm.py +135 -0
  29. pymiox-0.1.0/miox/readers/dicom_derived.py +1102 -0
  30. pymiox-0.1.0/miox/readers/dicom_image.py +595 -0
  31. pymiox-0.1.0/miox/readers/dicom_mrs.py +528 -0
  32. pymiox-0.1.0/miox/readers/dmiwizard_map.py +66 -0
  33. pymiox-0.1.0/miox/readers/dsi_studio.py +102 -0
  34. pymiox-0.1.0/miox/readers/fastmri.py +103 -0
  35. pymiox-0.1.0/miox/readers/fida_mat.py +109 -0
  36. pymiox-0.1.0/miox/readers/fsl_mrs_basis.py +70 -0
  37. pymiox-0.1.0/miox/readers/fsl_mrs_dynamic.py +107 -0
  38. pymiox-0.1.0/miox/readers/fsl_vest.py +78 -0
  39. pymiox-0.1.0/miox/readers/gadgetron_array.py +66 -0
  40. pymiox-0.1.0/miox/readers/gava_midas_prior.py +90 -0
  41. pymiox-0.1.0/miox/readers/ge_pfile.py +162 -0
  42. pymiox-0.1.0/miox/readers/ge_pfile_raw.py +151 -0
  43. pymiox-0.1.0/miox/readers/ge_rdb.py +429 -0
  44. pymiox-0.1.0/miox/readers/ge_scanarchive.py +372 -0
  45. pymiox-0.1.0/miox/readers/ge_signa.py +516 -0
  46. pymiox-0.1.0/miox/readers/gipl.py +93 -0
  47. pymiox-0.1.0/miox/readers/inspector_basis.py +72 -0
  48. pymiox-0.1.0/miox/readers/ismrmrd.py +421 -0
  49. pymiox-0.1.0/miox/readers/jcamp.py +324 -0
  50. pymiox-0.1.0/miox/readers/jeol.py +242 -0
  51. pymiox-0.1.0/miox/readers/jmrui.py +109 -0
  52. pymiox-0.1.0/miox/readers/jnifti.py +244 -0
  53. pymiox-0.1.0/miox/readers/lcmodel_basis.py +116 -0
  54. pymiox-0.1.0/miox/readers/lcmodel_control.py +76 -0
  55. pymiox-0.1.0/miox/readers/lcmodel_output.py +257 -0
  56. pymiox-0.1.0/miox/readers/lcmodel_raw.py +201 -0
  57. pymiox-0.1.0/miox/readers/loader.py +391 -0
  58. pymiox-0.1.0/miox/readers/marss_basis.py +70 -0
  59. pymiox-0.1.0/miox/readers/metaimage.py +172 -0
  60. pymiox-0.1.0/miox/readers/mrd.py +514 -0
  61. pymiox-0.1.0/miox/readers/mrs_sim_basis.py +87 -0
  62. pymiox-0.1.0/miox/readers/mrtrix.py +205 -0
  63. pymiox-0.1.0/miox/readers/nibabel_image.py +272 -0
  64. pymiox-0.1.0/miox/readers/nifti_mrs.py +101 -0
  65. pymiox-0.1.0/miox/readers/nifti_sidecar_mrs.py +111 -0
  66. pymiox-0.1.0/miox/readers/nifti_zarr.py +80 -0
  67. pymiox-0.1.0/miox/readers/nmrml.py +227 -0
  68. pymiox-0.1.0/miox/readers/nmrpipe.py +164 -0
  69. pymiox-0.1.0/miox/readers/nrrd.py +275 -0
  70. pymiox-0.1.0/miox/readers/osprey_basis.py +79 -0
  71. pymiox-0.1.0/miox/readers/osprey_container.py +81 -0
  72. pymiox-0.1.0/miox/readers/philips_data_list.py +209 -0
  73. pymiox-0.1.0/miox/readers/philips_dicom_raw.py +137 -0
  74. pymiox-0.1.0/miox/readers/philips_examcard.py +194 -0
  75. pymiox-0.1.0/miox/readers/philips_list_raw.py +150 -0
  76. pymiox-0.1.0/miox/readers/philips_raw_lab.py +603 -0
  77. pymiox-0.1.0/miox/readers/philips_spar_sdat.py +170 -0
  78. pymiox-0.1.0/miox/readers/physio.py +453 -0
  79. pymiox-0.1.0/miox/readers/profit_basis.py +72 -0
  80. pymiox-0.1.0/miox/readers/pulseq.py +272 -0
  81. pymiox-0.1.0/miox/readers/pyamares_prior.py +88 -0
  82. pymiox-0.1.0/miox/readers/pyamares_result.py +57 -0
  83. pymiox-0.1.0/miox/readers/rf_pulse.py +166 -0
  84. pymiox-0.1.0/miox/readers/rnmrtk.py +82 -0
  85. pymiox-0.1.0/miox/readers/rs2d.py +196 -0
  86. pymiox-0.1.0/miox/readers/siemens_dicom_protocol.py +88 -0
  87. pymiox-0.1.0/miox/readers/siemens_protocol.py +352 -0
  88. pymiox-0.1.0/miox/readers/siemens_rda.py +84 -0
  89. pymiox-0.1.0/miox/readers/siemens_twix.py +277 -0
  90. pymiox-0.1.0/miox/readers/siemens_twix_raw.py +358 -0
  91. pymiox-0.1.0/miox/readers/simpson.py +98 -0
  92. pymiox-0.1.0/miox/readers/simulation.py +269 -0
  93. pymiox-0.1.0/miox/readers/sivic_ddf.py +145 -0
  94. pymiox-0.1.0/miox/readers/spant_rds.py +418 -0
  95. pymiox-0.1.0/miox/readers/sparky.py +104 -0
  96. pymiox-0.1.0/miox/readers/spinsolve.py +187 -0
  97. pymiox-0.1.0/miox/readers/spinwizard_basis.py +87 -0
  98. pymiox-0.1.0/miox/readers/spm_mat.py +110 -0
  99. pymiox-0.1.0/miox/readers/stimulate.py +156 -0
  100. pymiox-0.1.0/miox/readers/surfaces.py +262 -0
  101. pymiox-0.1.0/miox/readers/tarquin_dpt.py +86 -0
  102. pymiox-0.1.0/miox/readers/tarquin_output.py +182 -0
  103. pymiox-0.1.0/miox/readers/tecmag.py +111 -0
  104. pymiox-0.1.0/miox/readers/text_fid.py +66 -0
  105. pymiox-0.1.0/miox/readers/toppe.py +187 -0
  106. pymiox-0.1.0/miox/readers/topspin.py +306 -0
  107. pymiox-0.1.0/miox/readers/tractograms.py +285 -0
  108. pymiox-0.1.0/miox/readers/transforms.py +301 -0
  109. pymiox-0.1.0/miox/readers/varian.py +170 -0
  110. pymiox-0.1.0/miox/readers/varian_fdf.py +244 -0
  111. pymiox-0.1.0/miox/readers/varian_raw.py +339 -0
  112. pymiox-0.1.0/miox/readers/vasf.py +104 -0
  113. pymiox-0.1.0/miox/readers/vespa_prior.py +77 -0
  114. pymiox-0.1.0/miox/readers/vespa_viff.py +123 -0
  115. pymiox-0.1.0/miox/readers/vista.py +138 -0
  116. pymiox-0.1.0/miox/readers/vtk_legacy.py +294 -0
  117. pymiox-0.1.0/miox/readers/vtk_xml.py +161 -0
  118. pymiox-0.1.0/miox/readers/yarra.py +60 -0
  119. pymiox-0.1.0/miox/sniff.py +2044 -0
  120. pymiox-0.1.0/miox/viewer.py +990 -0
  121. pymiox-0.1.0/miox/yardl.py +604 -0
  122. pymiox-0.1.0/pymiox.egg-info/PKG-INFO +87 -0
  123. pymiox-0.1.0/pymiox.egg-info/SOURCES.txt +127 -0
  124. pymiox-0.1.0/pymiox.egg-info/dependency_links.txt +1 -0
  125. pymiox-0.1.0/pymiox.egg-info/entry_points.txt +2 -0
  126. pymiox-0.1.0/pymiox.egg-info/requires.txt +18 -0
  127. pymiox-0.1.0/pymiox.egg-info/top_level.txt +1 -0
  128. pymiox-0.1.0/pyproject.toml +65 -0
  129. pymiox-0.1.0/setup.cfg +4 -0
pymiox-0.1.0/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Julian P. Merkofer
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,4 @@
1
+ # Source-distribution contents: the package, licence and README only.
2
+ # Test data under tests/data is fetched by scripts/fetch_test_data.py and never shipped.
3
+ include LICENSE
4
+ include README.md
pymiox-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: pymiox
3
+ Version: 0.1.0
4
+ Summary: Open any MR file from any vendor into one object: data, geometry, all metadata.
5
+ Author-email: "J. P. Merkofer" <j.p.merkofer@tue.nl>
6
+ License-Expression: BSD-3-Clause
7
+ Project-URL: Repository, https://github.com/julianmer/MIOX
8
+ Keywords: MRS,MRI,spectroscopy,NIfTI-MRS,DICOM
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
13
+ Requires-Python: >=3.11
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: f90nml>=1.5
17
+ Requires-Dist: h5py>=3.10
18
+ Requires-Dist: mat-io>=1.0
19
+ Requires-Dist: matplotlib>=3.8
20
+ Requires-Dist: nibabel>=5.2
21
+ Requires-Dist: nifti-mrs>=1.4
22
+ Requires-Dist: nifti-mrs-plus>=0.2.1
23
+ Requires-Dist: nmrglue>=0.12
24
+ Requires-Dist: numpy>=1.26
25
+ Requires-Dist: pydicom>=3.0
26
+ Requires-Dist: python-gdcm>=3.2.6
27
+ Requires-Dist: spec2nii>=0.8.15
28
+ Requires-Dist: zarr>=2.18
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
31
+ Requires-Dist: ruff>=0.6; extra == "dev"
32
+ Requires-Dist: scipy>=1.15; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ <div align="center">
36
+ <img src="assets/logo.png" alt="MIOX Logo" width="100"/>
37
+ <h1 style="margin-top: 5px; margin-bottom: 5px;">MIOX</h1>
38
+ <p style="margin-top: 0px;"><em>Open any MR file from any vendor into one object: data, geometry, all metadata</em></p>
39
+
40
+ [![Python](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/)
41
+ [![License](https://img.shields.io/badge/license-BSD--3--Clause-green.svg)](LICENSE)
42
+ </div>
43
+
44
+ ---
45
+
46
+ MIOX reads MR spectroscopy, images, raw k-space, sequences, protocols, physiological recordings
47
+ and NMR data into one well-defined object each. It keeps the complete vendor header and records
48
+ where every standard key came from.
49
+
50
+ ```python
51
+ import miox
52
+ [d] = miox.load("meas.dat") # one object per dataset in the file
53
+ d.data, d.dims, d.dwelltime # complex FIDs in NIfTI-MRS order
54
+ d.meta["EchoTime"], d.meta.source["EchoTime"], d.meta.vendor
55
+ miox.view(d) # quick look in a window
56
+ ```
57
+
58
+ ## Installation
59
+
60
+ ```
61
+ pip install pymiox
62
+ ```
63
+
64
+ or, for development,
65
+
66
+ ```
67
+ git clone https://github.com/julianmer/MIOX.git
68
+ cd MIOX
69
+ uv sync --extra dev
70
+ ```
71
+
72
+ ## What it loads
73
+
74
+ | | Formats |
75
+ |---|---|
76
+ | **Spectroscopy** | Siemens twix, RDA and DICOM; Philips SPAR/SDAT, data/list and DICOM; UIH DICOM; GE P-file; Bruker; Varian; NIfTI-MRS; dcm2niix NIfTI with an MRS sidecar; LCModel .RAW; jMRUI text and binary; TARQUIN .dpt; VASF; Vespa VIFF; SIVIC DDF; FID-A .mat; text FIDs |
77
+ | **Images** | DICOM (classic, mosaic, enhanced, study folders); NIfTI with BIDS sidecar; NIfTI-Zarr; JNIfTI; Analyze; MGH; MINC 1 and 2; PAR/REC; AFNI; NRRD; MetaImage; GIPL; Vista; Stimulate; VTK; MRtrix; SIVIC IDF; DSI Studio src and fib; BrainVoyager VMR, V16, VTC, FMR, VMP, GLM and VOI; Bruker 2dseq; Varian fdf; GE Signa |
78
+ | **Raw k-space** | ISMRMRD; MRD v2; Siemens twix; GE P-file and ScanArchive; Philips raw/lab/sin; Bruker fid and rawdata; Varian fid; fastMRI; BART .cfl; Gadgetron array dumps |
79
+ | **Basis sets and priors** | LCModel .BASIS; FSL-MRS; SpinWizard; Osprey/MRSCloud; INSPECTOR; MARSS; ProFit; MRS-Sim; spant; metabolite folders; Vespa, GAVA, MIDAS and PyAMARES priors |
80
+ | **Fit results** | LCModel COORD, TABLE, CSV and PostScript tables; TARQUIN results and fit; PyAMARES; Osprey MRSCont; FSL-MRS dynamic; spant; DMIWizard maps |
81
+ | **Sequences and protocols** | Pulseq .seq; TOPPE; FSL-MRS simulator sequences; Siemens .pta and Bruker RF pulse shapes; Siemens .pro, .exar and printed protocols; Philips ExamCards; LCModel control files; Yarra modes and modules; SPM.mat, FSL and BrainVoyager designs and stimulation protocols |
82
+ | **Physio** | Siemens PMU; CMRR; Philips SCANPHYSLOG; GE; BIDS; HCP; BIOPAC AcqKnowledge |
83
+ | **Simulation** | KomaMRI, JEMRIS and MRiLab phantoms; JEMRIS signals and motion; SIMPSON |
84
+ | **NMR** | Bruker TopSpin; Varian/Agilent; JCAMP-DX; nmrML; JEOL Delta; Tecmag TNMR; NMRPipe; Sparky; CSDM; Magritek Spinsolve; RS2D; RNMRTK |
85
+ | **Tractograms** | TrackVis .trk; MRtrix .tck and .tsf; TRX; VTK polydata; DSI Studio .tt |
86
+ | **Surfaces** | FreeSurfer surfaces, per-vertex values, annotations and labels; GIFTI; BrainVoyager SRF, SMP, MTC, SSM and POI; MZ3 |
87
+ | **Transforms** | FreeSurfer LTA; ITK; AFNI; FSL FLIRT; BrainVoyager TRF |
pymiox-0.1.0/README.md ADDED
@@ -0,0 +1,53 @@
1
+ <div align="center">
2
+ <img src="assets/logo.png" alt="MIOX Logo" width="100"/>
3
+ <h1 style="margin-top: 5px; margin-bottom: 5px;">MIOX</h1>
4
+ <p style="margin-top: 0px;"><em>Open any MR file from any vendor into one object: data, geometry, all metadata</em></p>
5
+
6
+ [![Python](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/)
7
+ [![License](https://img.shields.io/badge/license-BSD--3--Clause-green.svg)](LICENSE)
8
+ </div>
9
+
10
+ ---
11
+
12
+ MIOX reads MR spectroscopy, images, raw k-space, sequences, protocols, physiological recordings
13
+ and NMR data into one well-defined object each. It keeps the complete vendor header and records
14
+ where every standard key came from.
15
+
16
+ ```python
17
+ import miox
18
+ [d] = miox.load("meas.dat") # one object per dataset in the file
19
+ d.data, d.dims, d.dwelltime # complex FIDs in NIfTI-MRS order
20
+ d.meta["EchoTime"], d.meta.source["EchoTime"], d.meta.vendor
21
+ miox.view(d) # quick look in a window
22
+ ```
23
+
24
+ ## Installation
25
+
26
+ ```
27
+ pip install pymiox
28
+ ```
29
+
30
+ or, for development,
31
+
32
+ ```
33
+ git clone https://github.com/julianmer/MIOX.git
34
+ cd MIOX
35
+ uv sync --extra dev
36
+ ```
37
+
38
+ ## What it loads
39
+
40
+ | | Formats |
41
+ |---|---|
42
+ | **Spectroscopy** | Siemens twix, RDA and DICOM; Philips SPAR/SDAT, data/list and DICOM; UIH DICOM; GE P-file; Bruker; Varian; NIfTI-MRS; dcm2niix NIfTI with an MRS sidecar; LCModel .RAW; jMRUI text and binary; TARQUIN .dpt; VASF; Vespa VIFF; SIVIC DDF; FID-A .mat; text FIDs |
43
+ | **Images** | DICOM (classic, mosaic, enhanced, study folders); NIfTI with BIDS sidecar; NIfTI-Zarr; JNIfTI; Analyze; MGH; MINC 1 and 2; PAR/REC; AFNI; NRRD; MetaImage; GIPL; Vista; Stimulate; VTK; MRtrix; SIVIC IDF; DSI Studio src and fib; BrainVoyager VMR, V16, VTC, FMR, VMP, GLM and VOI; Bruker 2dseq; Varian fdf; GE Signa |
44
+ | **Raw k-space** | ISMRMRD; MRD v2; Siemens twix; GE P-file and ScanArchive; Philips raw/lab/sin; Bruker fid and rawdata; Varian fid; fastMRI; BART .cfl; Gadgetron array dumps |
45
+ | **Basis sets and priors** | LCModel .BASIS; FSL-MRS; SpinWizard; Osprey/MRSCloud; INSPECTOR; MARSS; ProFit; MRS-Sim; spant; metabolite folders; Vespa, GAVA, MIDAS and PyAMARES priors |
46
+ | **Fit results** | LCModel COORD, TABLE, CSV and PostScript tables; TARQUIN results and fit; PyAMARES; Osprey MRSCont; FSL-MRS dynamic; spant; DMIWizard maps |
47
+ | **Sequences and protocols** | Pulseq .seq; TOPPE; FSL-MRS simulator sequences; Siemens .pta and Bruker RF pulse shapes; Siemens .pro, .exar and printed protocols; Philips ExamCards; LCModel control files; Yarra modes and modules; SPM.mat, FSL and BrainVoyager designs and stimulation protocols |
48
+ | **Physio** | Siemens PMU; CMRR; Philips SCANPHYSLOG; GE; BIDS; HCP; BIOPAC AcqKnowledge |
49
+ | **Simulation** | KomaMRI, JEMRIS and MRiLab phantoms; JEMRIS signals and motion; SIMPSON |
50
+ | **NMR** | Bruker TopSpin; Varian/Agilent; JCAMP-DX; nmrML; JEOL Delta; Tecmag TNMR; NMRPipe; Sparky; CSDM; Magritek Spinsolve; RS2D; RNMRTK |
51
+ | **Tractograms** | TrackVis .trk; MRtrix .tck and .tsf; TRX; VTK polydata; DSI Studio .tt |
52
+ | **Surfaces** | FreeSurfer surfaces, per-vertex values, annotations and labels; GIFTI; BrainVoyager SRF, SMP, MTC, SSM and POI; MZ3 |
53
+ | **Transforms** | FreeSurfer LTA; ITK; AFNI; FSL FLIRT; BrainVoyager TRF |
@@ -0,0 +1,79 @@
1
+ ####################################################################################################
2
+ # __init__.py #
3
+ ####################################################################################################
4
+ # #
5
+ # Authors: J. P. Merkofer (j.p.merkofer@tue.nl) #
6
+ # #
7
+ # Created: 01/10/26 #
8
+ # #
9
+ # Purpose: Package entry: the version and the top-level API. #
10
+ # #
11
+ ####################################################################################################
12
+
13
+
14
+ #*************#
15
+ # imports #
16
+ #*************#
17
+
18
+ # own
19
+ from miox.data import (
20
+ BasisSet,
21
+ FitResult,
22
+ MRImage,
23
+ MRSData,
24
+ NoiseCovariance,
25
+ Phantom,
26
+ PhysioData,
27
+ PriorSet,
28
+ Protocol,
29
+ Provenance,
30
+ PulseSequence,
31
+ RawData,
32
+ RelaxationData,
33
+ RFPulse,
34
+ Surface,
35
+ Tractogram,
36
+ Transform,
37
+ )
38
+ from miox.readers import IncompleteError, Loader, ReaderError, load
39
+ from miox.sniff import Format, Kind, Sniff, Sniffer, sniff
40
+
41
+ __version__ = "0.1.0"
42
+ __all__ = [
43
+ "BasisSet",
44
+ "FitResult",
45
+ "Format",
46
+ "IncompleteError",
47
+ "Kind",
48
+ "Loader",
49
+ "MRImage",
50
+ "MRSData",
51
+ "NoiseCovariance",
52
+ "Phantom",
53
+ "PhysioData",
54
+ "PriorSet",
55
+ "Protocol",
56
+ "Provenance",
57
+ "PulseSequence",
58
+ "RawData",
59
+ "ReaderError",
60
+ "RelaxationData",
61
+ "RFPulse",
62
+ "Sniff",
63
+ "Sniffer",
64
+ "Surface",
65
+ "Tractogram",
66
+ "Transform",
67
+ "__version__",
68
+ "load",
69
+ "sniff",
70
+ "view",
71
+ ]
72
+
73
+
74
+ def __getattr__(name: str):
75
+ if name == "view": # on first use: matplotlib adds about 0.3 s to every import
76
+ from miox.viewer import view
77
+
78
+ return view
79
+ raise AttributeError(f"module 'miox' has no attribute {name!r}")
@@ -0,0 +1,22 @@
1
+ ####################################################################################################
2
+ # __main__.py #
3
+ ####################################################################################################
4
+ # #
5
+ # Authors: J. P. Merkofer (j.p.merkofer@tue.nl) #
6
+ # #
7
+ # Created: 12/10/26 #
8
+ # #
9
+ # Purpose: ``python -m miox``: the command line, as the ``miox`` console script. #
10
+ # #
11
+ ####################################################################################################
12
+
13
+
14
+ #*************#
15
+ # imports #
16
+ #*************#
17
+ import sys
18
+
19
+ # own
20
+ from miox.cli import main
21
+
22
+ sys.exit(main())
@@ -0,0 +1,143 @@
1
+ ####################################################################################################
2
+ # audit.py #
3
+ ####################################################################################################
4
+ # #
5
+ # Authors: J. P. Merkofer (j.p.merkofer@tue.nl) #
6
+ # #
7
+ # Created: 01/10/26 #
8
+ # #
9
+ # Purpose: Coverage audit: every field of a file's vendor header, and whether a standard key, some #
10
+ # other key, or nothing is read from it. #
11
+ # #
12
+ ####################################################################################################
13
+
14
+
15
+ #*************#
16
+ # imports #
17
+ #*************#
18
+ from __future__ import annotations
19
+
20
+ import json
21
+ from dataclasses import dataclass
22
+ from enum import StrEnum
23
+ from pathlib import Path
24
+
25
+ # own
26
+ from miox.meta.keys import KeyTable
27
+ from miox.readers import Loader
28
+ from miox.sniff import Format
29
+
30
+
31
+ #**************************************************************************************************#
32
+ # Status #
33
+ #**************************************************************************************************#
34
+ # #
35
+ # What is read from a header field. #
36
+ # #
37
+ #**************************************************************************************************#
38
+ class Status(StrEnum):
39
+ STANDARD = "standard" # a key of the key table
40
+ OTHER = "other" # a key outside the key table, e.g. a user-defined NIfTI-MRS key
41
+ UNUSED = "unused" # nothing
42
+
43
+
44
+ #**************************************************************************************************#
45
+ # Field #
46
+ #**************************************************************************************************#
47
+ # #
48
+ # One field of an audited vendor header. #
49
+ # #
50
+ #**************************************************************************************************#
51
+ @dataclass(frozen=True)
52
+ class Field:
53
+ path: str
54
+ status: Status
55
+ key: str
56
+ """The key read from this field, empty if none."""
57
+ value: str
58
+ """Short preview of the value."""
59
+
60
+
61
+ #**************************************************************************************************#
62
+ # Coverage #
63
+ #**************************************************************************************************#
64
+ # #
65
+ # The audit of one file: all fields of its vendor header, with counts and a Markdown table. #
66
+ # #
67
+ #**************************************************************************************************#
68
+ @dataclass(frozen=True)
69
+ class Coverage:
70
+ path: Path
71
+ format: Format
72
+ fields: tuple[Field, ...]
73
+
74
+ def summary(self) -> dict[Status, int]:
75
+ counts = dict.fromkeys(Status, 0)
76
+ for f in self.fields:
77
+ counts[f.status] += 1
78
+ return counts
79
+
80
+ def to_markdown(self) -> str:
81
+ s = self.summary()
82
+ lines = [
83
+ f"# Coverage: `{self.path.name}` ({self.format})",
84
+ "",
85
+ f"{len(self.fields)} header fields: {s[Status.STANDARD]} read into standard keys, "
86
+ f"{s[Status.OTHER]} into other keys, {s[Status.UNUSED]} unused.",
87
+ "",
88
+ "| field | status | key | value |",
89
+ "|---|---|---|---|",
90
+ ]
91
+ for f in self.fields:
92
+ lines.append(f"| `{f.path}` | {f.status} | {f.key} | {f.value} |")
93
+ return "\n".join(lines) + "\n"
94
+
95
+
96
+ #**************************************************************************************************#
97
+ # Auditor #
98
+ #**************************************************************************************************#
99
+ # #
100
+ # Loads a file and matches its vendor header against the fields its keys were read from. A key #
101
+ # read from a nested block covers every field inside it. #
102
+ # #
103
+ #**************************************************************************************************#
104
+ class Auditor:
105
+ PREVIEW_LIMIT = 60 # characters of a value shown in the table
106
+
107
+ def __init__(self):
108
+ self.loader = Loader()
109
+ self.keys = KeyTable()
110
+
111
+ def audit(self, path: str | Path) -> Coverage:
112
+ """Audit the metadata coverage of one file (all datasets in it)."""
113
+ path = Path(path)
114
+ datasets = self.loader.load(path)
115
+ read_from = {} # vendor field -> key
116
+ for d in datasets:
117
+ read_from.update({field: key for key, field in d.meta.fields.items()})
118
+ fields = []
119
+ for field, value in datasets[0].meta.vendor_fields().items():
120
+ key = self._key(field, read_from)
121
+ if not key:
122
+ status = Status.UNUSED
123
+ elif key in self.keys:
124
+ status = Status.STANDARD
125
+ else:
126
+ status = Status.OTHER
127
+ fields.append(Field(field, status, key, self._preview(value)))
128
+ return Coverage(path, datasets[0].provenance.format, tuple(fields))
129
+
130
+ @staticmethod
131
+ def _key(field: str, read_from: dict[str, str]) -> str:
132
+ parts = field.split("/")
133
+ for n in range(len(parts), 0, -1):
134
+ key = read_from.get("/".join(parts[:n]))
135
+ if key:
136
+ return key
137
+ return ""
138
+
139
+ def _preview(self, value) -> str:
140
+ text = json.dumps(value, default=str)
141
+ if len(text) > self.PREVIEW_LIMIT:
142
+ text = text[: self.PREVIEW_LIMIT - 1] + "…"
143
+ return text.replace("|", "\\|")