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.
- pymiox-0.1.0/LICENSE +28 -0
- pymiox-0.1.0/MANIFEST.in +4 -0
- pymiox-0.1.0/PKG-INFO +87 -0
- pymiox-0.1.0/README.md +53 -0
- pymiox-0.1.0/miox/__init__.py +79 -0
- pymiox-0.1.0/miox/__main__.py +22 -0
- pymiox-0.1.0/miox/audit.py +143 -0
- pymiox-0.1.0/miox/cli.py +292 -0
- pymiox-0.1.0/miox/data.py +1260 -0
- pymiox-0.1.0/miox/matfile.py +94 -0
- pymiox-0.1.0/miox/meta/__init__.py +22 -0
- pymiox-0.1.0/miox/meta/keys.py +408 -0
- pymiox-0.1.0/miox/meta/meta.py +61 -0
- pymiox-0.1.0/miox/preview.py +454 -0
- pymiox-0.1.0/miox/processing.py +766 -0
- pymiox-0.1.0/miox/quicklook.py +1195 -0
- pymiox-0.1.0/miox/quicklook_pages.py +1307 -0
- pymiox-0.1.0/miox/readers/__init__.py +84 -0
- pymiox-0.1.0/miox/readers/bart_cfl.py +113 -0
- pymiox-0.1.0/miox/readers/base.py +380 -0
- pymiox-0.1.0/miox/readers/basis_folder.py +110 -0
- pymiox-0.1.0/miox/readers/biopac_acq.py +380 -0
- pymiox-0.1.0/miox/readers/brainvoyager.py +485 -0
- pymiox-0.1.0/miox/readers/brainvoyager_text.py +425 -0
- pymiox-0.1.0/miox/readers/bruker.py +563 -0
- pymiox-0.1.0/miox/readers/bruker_2dseq.py +150 -0
- pymiox-0.1.0/miox/readers/bruker_raw.py +368 -0
- pymiox-0.1.0/miox/readers/csdm.py +135 -0
- pymiox-0.1.0/miox/readers/dicom_derived.py +1102 -0
- pymiox-0.1.0/miox/readers/dicom_image.py +595 -0
- pymiox-0.1.0/miox/readers/dicom_mrs.py +528 -0
- pymiox-0.1.0/miox/readers/dmiwizard_map.py +66 -0
- pymiox-0.1.0/miox/readers/dsi_studio.py +102 -0
- pymiox-0.1.0/miox/readers/fastmri.py +103 -0
- pymiox-0.1.0/miox/readers/fida_mat.py +109 -0
- pymiox-0.1.0/miox/readers/fsl_mrs_basis.py +70 -0
- pymiox-0.1.0/miox/readers/fsl_mrs_dynamic.py +107 -0
- pymiox-0.1.0/miox/readers/fsl_vest.py +78 -0
- pymiox-0.1.0/miox/readers/gadgetron_array.py +66 -0
- pymiox-0.1.0/miox/readers/gava_midas_prior.py +90 -0
- pymiox-0.1.0/miox/readers/ge_pfile.py +162 -0
- pymiox-0.1.0/miox/readers/ge_pfile_raw.py +151 -0
- pymiox-0.1.0/miox/readers/ge_rdb.py +429 -0
- pymiox-0.1.0/miox/readers/ge_scanarchive.py +372 -0
- pymiox-0.1.0/miox/readers/ge_signa.py +516 -0
- pymiox-0.1.0/miox/readers/gipl.py +93 -0
- pymiox-0.1.0/miox/readers/inspector_basis.py +72 -0
- pymiox-0.1.0/miox/readers/ismrmrd.py +421 -0
- pymiox-0.1.0/miox/readers/jcamp.py +324 -0
- pymiox-0.1.0/miox/readers/jeol.py +242 -0
- pymiox-0.1.0/miox/readers/jmrui.py +109 -0
- pymiox-0.1.0/miox/readers/jnifti.py +244 -0
- pymiox-0.1.0/miox/readers/lcmodel_basis.py +116 -0
- pymiox-0.1.0/miox/readers/lcmodel_control.py +76 -0
- pymiox-0.1.0/miox/readers/lcmodel_output.py +257 -0
- pymiox-0.1.0/miox/readers/lcmodel_raw.py +201 -0
- pymiox-0.1.0/miox/readers/loader.py +391 -0
- pymiox-0.1.0/miox/readers/marss_basis.py +70 -0
- pymiox-0.1.0/miox/readers/metaimage.py +172 -0
- pymiox-0.1.0/miox/readers/mrd.py +514 -0
- pymiox-0.1.0/miox/readers/mrs_sim_basis.py +87 -0
- pymiox-0.1.0/miox/readers/mrtrix.py +205 -0
- pymiox-0.1.0/miox/readers/nibabel_image.py +272 -0
- pymiox-0.1.0/miox/readers/nifti_mrs.py +101 -0
- pymiox-0.1.0/miox/readers/nifti_sidecar_mrs.py +111 -0
- pymiox-0.1.0/miox/readers/nifti_zarr.py +80 -0
- pymiox-0.1.0/miox/readers/nmrml.py +227 -0
- pymiox-0.1.0/miox/readers/nmrpipe.py +164 -0
- pymiox-0.1.0/miox/readers/nrrd.py +275 -0
- pymiox-0.1.0/miox/readers/osprey_basis.py +79 -0
- pymiox-0.1.0/miox/readers/osprey_container.py +81 -0
- pymiox-0.1.0/miox/readers/philips_data_list.py +209 -0
- pymiox-0.1.0/miox/readers/philips_dicom_raw.py +137 -0
- pymiox-0.1.0/miox/readers/philips_examcard.py +194 -0
- pymiox-0.1.0/miox/readers/philips_list_raw.py +150 -0
- pymiox-0.1.0/miox/readers/philips_raw_lab.py +603 -0
- pymiox-0.1.0/miox/readers/philips_spar_sdat.py +170 -0
- pymiox-0.1.0/miox/readers/physio.py +453 -0
- pymiox-0.1.0/miox/readers/profit_basis.py +72 -0
- pymiox-0.1.0/miox/readers/pulseq.py +272 -0
- pymiox-0.1.0/miox/readers/pyamares_prior.py +88 -0
- pymiox-0.1.0/miox/readers/pyamares_result.py +57 -0
- pymiox-0.1.0/miox/readers/rf_pulse.py +166 -0
- pymiox-0.1.0/miox/readers/rnmrtk.py +82 -0
- pymiox-0.1.0/miox/readers/rs2d.py +196 -0
- pymiox-0.1.0/miox/readers/siemens_dicom_protocol.py +88 -0
- pymiox-0.1.0/miox/readers/siemens_protocol.py +352 -0
- pymiox-0.1.0/miox/readers/siemens_rda.py +84 -0
- pymiox-0.1.0/miox/readers/siemens_twix.py +277 -0
- pymiox-0.1.0/miox/readers/siemens_twix_raw.py +358 -0
- pymiox-0.1.0/miox/readers/simpson.py +98 -0
- pymiox-0.1.0/miox/readers/simulation.py +269 -0
- pymiox-0.1.0/miox/readers/sivic_ddf.py +145 -0
- pymiox-0.1.0/miox/readers/spant_rds.py +418 -0
- pymiox-0.1.0/miox/readers/sparky.py +104 -0
- pymiox-0.1.0/miox/readers/spinsolve.py +187 -0
- pymiox-0.1.0/miox/readers/spinwizard_basis.py +87 -0
- pymiox-0.1.0/miox/readers/spm_mat.py +110 -0
- pymiox-0.1.0/miox/readers/stimulate.py +156 -0
- pymiox-0.1.0/miox/readers/surfaces.py +262 -0
- pymiox-0.1.0/miox/readers/tarquin_dpt.py +86 -0
- pymiox-0.1.0/miox/readers/tarquin_output.py +182 -0
- pymiox-0.1.0/miox/readers/tecmag.py +111 -0
- pymiox-0.1.0/miox/readers/text_fid.py +66 -0
- pymiox-0.1.0/miox/readers/toppe.py +187 -0
- pymiox-0.1.0/miox/readers/topspin.py +306 -0
- pymiox-0.1.0/miox/readers/tractograms.py +285 -0
- pymiox-0.1.0/miox/readers/transforms.py +301 -0
- pymiox-0.1.0/miox/readers/varian.py +170 -0
- pymiox-0.1.0/miox/readers/varian_fdf.py +244 -0
- pymiox-0.1.0/miox/readers/varian_raw.py +339 -0
- pymiox-0.1.0/miox/readers/vasf.py +104 -0
- pymiox-0.1.0/miox/readers/vespa_prior.py +77 -0
- pymiox-0.1.0/miox/readers/vespa_viff.py +123 -0
- pymiox-0.1.0/miox/readers/vista.py +138 -0
- pymiox-0.1.0/miox/readers/vtk_legacy.py +294 -0
- pymiox-0.1.0/miox/readers/vtk_xml.py +161 -0
- pymiox-0.1.0/miox/readers/yarra.py +60 -0
- pymiox-0.1.0/miox/sniff.py +2044 -0
- pymiox-0.1.0/miox/viewer.py +990 -0
- pymiox-0.1.0/miox/yardl.py +604 -0
- pymiox-0.1.0/pymiox.egg-info/PKG-INFO +87 -0
- pymiox-0.1.0/pymiox.egg-info/SOURCES.txt +127 -0
- pymiox-0.1.0/pymiox.egg-info/dependency_links.txt +1 -0
- pymiox-0.1.0/pymiox.egg-info/entry_points.txt +2 -0
- pymiox-0.1.0/pymiox.egg-info/requires.txt +18 -0
- pymiox-0.1.0/pymiox.egg-info/top_level.txt +1 -0
- pymiox-0.1.0/pyproject.toml +65 -0
- 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.
|
pymiox-0.1.0/MANIFEST.in
ADDED
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
|
+
[](https://www.python.org/)
|
|
41
|
+
[](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
|
+
[](https://www.python.org/)
|
|
7
|
+
[](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("|", "\\|")
|