thyra 4.0.0__tar.gz → 4.2.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.
- thyra-4.2.0/PKG-INFO +195 -0
- thyra-4.2.0/README.md +142 -0
- {thyra-4.0.0 → thyra-4.2.0}/pyproject.toml +10 -3
- thyra-4.2.0/thyra/__init__.py +110 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/__main__.py +30 -13
- thyra-4.2.0/thyra/converters/__init__.py +26 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/base_spatialdata_converter.py +105 -704
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/mobility_table.py +1 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/optical_image.py +18 -7
- {thyra-4.0.0/thyra/metadata → thyra-4.2.0/thyra/converters/spatialdata}/root_attrs.py +5 -5
- thyra-4.2.0/thyra/converters/spatialdata/sibling_tables.py +977 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/streaming_converter.py +53 -20
- {thyra-4.0.0/thyra/metadata → thyra-4.2.0/thyra/converters/spatialdata}/uns_assembler.py +55 -18
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/base_extractor.py +9 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/base_reader.py +21 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/msms.py +39 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/registry.py +115 -13
- {thyra-4.0.0 → thyra-4.2.0}/thyra/errors.py +5 -4
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/__init__.py +40 -7
- {thyra-4.0.0/thyra/resampling → thyra-4.2.0/thyra/metadata}/constants.py +16 -9
- thyra-4.2.0/thyra/metadata/document.py +114 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/bruker_extractor.py +362 -15
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/imzml_extractor.py +3 -3
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/mzpeak_extractor.py +1 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/phi_extractor.py +61 -16
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/solarix_extractor.py +2 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/waters_extractor.py +44 -15
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/ontology/_ms.py +1172 -512
- thyra-4.2.0/thyra/metadata/ontology/dump_obo_files.py +98 -0
- thyra-4.2.0/thyra/metadata/personal_data.py +288 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/__init__.py +18 -3
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/builder.py +601 -37
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/cli.py +83 -9
- thyra-4.2.0/thyra/metadata/schema/generate.py +78 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/models.py +429 -37
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/msi_metadata.linkml.yaml +77 -2
- thyra-4.0.0/thyra/metadata/schema/msi_metadata_schema_v0_6.json → thyra-4.2.0/thyra/metadata/schema/msi_metadata_schema_v0_9.json +294 -4
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/store_io.py +33 -17
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/validate.py +30 -21
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/vocab.py +31 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/types.py +5 -2
- thyra-4.2.0/thyra/readers/__init__.py +50 -0
- thyra-4.2.0/thyra/readers/bruker/__init__.py +77 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/folder_structure.py +1 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/rapiflex/rapiflex_reader.py +2 -2
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/timstof_reader.py +99 -13
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/imzml/imzml_reader.py +1 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/phi/event_stream.py +16 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/phi/phi_reader.py +11 -1
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/masslynx_lib.py +4 -0
- thyra-4.2.0/thyra/resampling/constants.py +26 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/data_characteristics.py +2 -1
- thyra-4.0.0/PKG-INFO +0 -224
- thyra-4.0.0/README.md +0 -172
- thyra-4.0.0/thyra/__init__.py +0 -48
- thyra-4.0.0/thyra/converters/__init__.py +0 -3
- thyra-4.0.0/thyra/metadata/schema/generate.py +0 -34
- thyra-4.0.0/thyra/readers/__init__.py +0 -23
- thyra-4.0.0/thyra/readers/bruker/__init__.py +0 -46
- {thyra-4.0.0 → thyra-4.2.0}/.gitignore +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/LICENSE +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/alignment/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/alignment/affine.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/alignment/teaching_points.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/config.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/convert.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/_chunking.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/converter.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/csc_assembly.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/fused_passes.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/mobility_heatmap.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/converters/spatialdata/msms_table.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/base_converter.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/conversion_state.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/drop_tally.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/frames.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/mass_axis.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/core/mobility.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/extractors/imzml_header_extractor.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/ontology/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/ontology/_ims.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/ontology/_uo.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/ontology/cache.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/schema/metaspace.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/uns_compat.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/metadata/validator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/preview.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/py.typed +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/base_bruker_reader.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/mis_parser.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/rapiflex/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/solarix/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/solarix/solarix_reader.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/dll/LICENCE-BRUKER.txt +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/dll/README.md +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/dll/timsdata.dll +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/dll/timsdata.so +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/dll_manager.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/platform_detector.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/timstof/sdk/sdk_functions.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/bruker/vendor_db.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/imzml/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/imzml/_pyimzml_compat.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/imzml/header.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/imzml/mobility_array.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/mzpeak/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/mzpeak/mzpeak_reader.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/phi/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/phi/mass_axis.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/phi/phi_header.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/imaging_grid.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/instrument.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/lib/MLReader.dll +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/lib/MassLynxRaw.dll +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/lib/libMLReader.so +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/lib/libMassLynxRaw.so +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/readers/waters/waters_reader.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/axis_planner.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/binning.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/common_axis.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/decision_tree.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/gaps.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/instrument_detectors.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/interpolation.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/base_generator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/fticr_generator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/linear_generator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/linear_tof_generator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/orbitrap_generator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/reflector_tof_generator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mass_axis/tof_generator.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/mobility_grid.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/strategies/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/strategies/base.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/strategies/nearest_neighbor.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/strategies/tic_preserving.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/tic.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/resampling/types.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/tools/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/tools/check_ontology.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/tools/make_example_data.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/utils/__init__.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/utils/bruker_exceptions.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/utils/imzml_coordinate_base.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/utils/logging_config.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/utils/pyimzml_direct.py +0 -0
- {thyra-4.0.0 → thyra-4.2.0}/thyra/utils/windows_paths.py +0 -0
thyra-4.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: thyra
|
|
3
|
+
Version: 4.2.0
|
|
4
|
+
Summary: A modern Python library for converting Mass Spectrometry Imaging (MSI) data into SpatialData/Zarr format - your portal to spatial omics
|
|
5
|
+
Project-URL: Homepage, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra
|
|
6
|
+
Project-URL: Repository, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra
|
|
7
|
+
Project-URL: Documentation, https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/issues
|
|
9
|
+
Project-URL: Discussions, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/discussions
|
|
10
|
+
Project-URL: Changelog, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Contributing, https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/contributing/
|
|
12
|
+
Author-email: Theodoros Visvikis <t.visvikis@maastrichtuniversity.nl>
|
|
13
|
+
Maintainer-email: Theodoros Visvikis <t.visvikis@maastrichtuniversity.nl>
|
|
14
|
+
License-Expression: MIT
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Keywords: bioinformatics,bruker,data-conversion,imaging,imzml,mass-spectrometry,msi,omics,scientific-computing,spatial-omics,spatialdata,zarr
|
|
17
|
+
Classifier: Development Status :: 4 - Beta
|
|
18
|
+
Classifier: Environment :: Console
|
|
19
|
+
Classifier: Intended Audience :: Science/Research
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
25
|
+
Classifier: Topic :: File Formats
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
28
|
+
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
|
|
29
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
30
|
+
Classifier: Typing :: Typed
|
|
31
|
+
Requires-Python: <3.15,>=3.12
|
|
32
|
+
Requires-Dist: anndata<0.14,>=0.13.2
|
|
33
|
+
Requires-Dist: click<9,>=8.1
|
|
34
|
+
Requires-Dist: dask<2026.8,>=2026.3.0
|
|
35
|
+
Requires-Dist: defusedxml>=0.7.1
|
|
36
|
+
Requires-Dist: geopandas>=0.9.0
|
|
37
|
+
Requires-Dist: imagecodecs>=2024.1.1
|
|
38
|
+
Requires-Dist: numpy<3,>=2.0.0
|
|
39
|
+
Requires-Dist: ome-zarr<0.19,>=0.16.0
|
|
40
|
+
Requires-Dist: pandas<4,>=2.0.0
|
|
41
|
+
Requires-Dist: pillow>=10.1
|
|
42
|
+
Requires-Dist: psutil>=5.0.0
|
|
43
|
+
Requires-Dist: pydantic<3,>=2.7
|
|
44
|
+
Requires-Dist: pyimzml>=1.4.0
|
|
45
|
+
Requires-Dist: scipy>=1.7.0
|
|
46
|
+
Requires-Dist: shapely>=2.0.0
|
|
47
|
+
Requires-Dist: spatialdata<0.9,>=0.8.0
|
|
48
|
+
Requires-Dist: tifffile>=2026.5.2
|
|
49
|
+
Requires-Dist: tqdm>=4.50.0
|
|
50
|
+
Requires-Dist: xarray>=2024.10.0
|
|
51
|
+
Requires-Dist: zarr<3.5,>=3.4.0
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
|
|
54
|
+
<p align="center">
|
|
55
|
+
<img src="docs/assets/thyra-logotype.svg" alt="Thyra" width="420">
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
[](https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/actions/workflows/tests.yml)
|
|
59
|
+
[](https://pypi.org/project/thyra/)
|
|
60
|
+
[](https://www.python.org/downloads/)
|
|
61
|
+
[](https://opensource.org/licenses/MIT)
|
|
62
|
+
[](https://github.com/psf/black)
|
|
63
|
+
[](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra)
|
|
64
|
+
[](https://colab.research.google.com/github/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/notebooks/Thyra_Validation_Workflow.ipynb)
|
|
65
|
+
|
|
66
|
+
**Thyra converts imaging mass spectrometry data into one open format.** It
|
|
67
|
+
reads the files your instrument writes (Bruker, Waters, PHI, or imzML from any
|
|
68
|
+
vendor) and saves them in [SpatialData](https://spatialdata.scverse.org/),
|
|
69
|
+
which analysis and viewing tools can read. You do not need to know how to
|
|
70
|
+
program.
|
|
71
|
+
|
|
72
|
+
**[Documentation](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra)** | [Install](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/install/) | [Your first conversion](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/getting-started/) | [Tutorial](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/tutorial/) | [Technical reference](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/technical-reference/)
|
|
73
|
+
|
|
74
|
+

|
|
75
|
+
|
|
76
|
+
<sub>A sagittal mouse brain section converted with Thyra: the total ion current
|
|
77
|
+
and two ion images. MALDI-MSI data from
|
|
78
|
+
[10.5281/zenodo.18326569](https://doi.org/10.5281/zenodo.18326569),
|
|
79
|
+
CC-BY-4.0.</sub>
|
|
80
|
+
|
|
81
|
+
## Quick start
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
uv tool install --python 3.13 thyra # or: pip install thyra (Python 3.12 to 3.14)
|
|
85
|
+
thyra-example-data example_data/synthetic_brain.imzML # makes a small example dataset
|
|
86
|
+
thyra example_data/synthetic_brain.imzML example_data/synthetic_brain.zarr
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
New to the terminal or to uv? The
|
|
90
|
+
[Install](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/install/) page
|
|
91
|
+
walks you through every step. To try Thyra with nothing installed, open the
|
|
92
|
+
[notebook in Google Colab](https://colab.research.google.com/github/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/notebooks/Thyra_Validation_Workflow.ipynb).
|
|
93
|
+
The [Tutorial](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/tutorial/)
|
|
94
|
+
also converts the published example dataset
|
|
95
|
+
([10.5281/zenodo.18326569](https://doi.org/10.5281/zenodo.18326569)).
|
|
96
|
+
|
|
97
|
+
## What you can convert
|
|
98
|
+
|
|
99
|
+
| Your instrument | Point Thyra at |
|
|
100
|
+
|---|---|
|
|
101
|
+
| Bruker timsTOF or solariX | the folder ending in `.d` |
|
|
102
|
+
| Bruker rapifleX | the acquisition folder |
|
|
103
|
+
| Waters (MassLynx) | the folder ending in `.raw` |
|
|
104
|
+
| PHI nanoTOF (ToF-SIMS) | the file ending in `.raw` |
|
|
105
|
+
| Any instrument that exports imzML | the `.imzML` file, with its `.ibd` file next to it |
|
|
106
|
+
| mzPeak (experimental) | the `.mzpeak` file |
|
|
107
|
+
|
|
108
|
+
Thyra reads timsTOF and Waters data on Windows and Linux; everything else
|
|
109
|
+
also works on macOS. Shimadzu support is in development: until then, export
|
|
110
|
+
imzML from IMAGEREVEAL MS.
|
|
111
|
+
|
|
112
|
+
PHI mosaic, MS/MS and depth-profiling acquisitions have so far been tested
|
|
113
|
+
only on synthetic files. If you have real data in those modes, please get in
|
|
114
|
+
touch.
|
|
115
|
+
|
|
116
|
+
## What you get
|
|
117
|
+
|
|
118
|
+
One folder ending in `.zarr`, holding:
|
|
119
|
+
|
|
120
|
+
- the spectrum of every pixel, on one shared m/z axis
|
|
121
|
+
- an image of the total ion current (TIC)
|
|
122
|
+
- the optical image of the slide, when the acquisition has one
|
|
123
|
+
- ion mobility and MS/MS data from Bruker timsTOF, when the acquisition has them
|
|
124
|
+
- a validated description of the acquisition, ready for METASPACE
|
|
125
|
+
|
|
126
|
+
Thyra handles datasets larger than your computer's memory, slides with
|
|
127
|
+
several regions, and 3D data.
|
|
128
|
+
|
|
129
|
+
## From Python
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from thyra import convert_msi
|
|
133
|
+
import spatialdata as sd
|
|
134
|
+
|
|
135
|
+
convert_msi("data/sample.imzML", "output/sample.zarr")
|
|
136
|
+
|
|
137
|
+
sdata = sd.read_zarr("output/sample.zarr")
|
|
138
|
+
table = sdata.tables["msi_dataset_z0"] # one row per pixel, one column per m/z bin
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The acquisition description has its own commands:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
thyra metadata raw_data.d # describe a dataset without converting it
|
|
145
|
+
thyra validate output.zarr # check a result against the schema
|
|
146
|
+
thyra export-metaspace output.zarr --merge sample.json # METASPACE submission file
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Every option, format and output detail is in the
|
|
150
|
+
[Technical reference](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/technical-reference/).
|
|
151
|
+
|
|
152
|
+
## Development
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
git clone https://github.com/M4i-Imaging-Mass-Spectrometry/thyra.git
|
|
156
|
+
cd thyra
|
|
157
|
+
uv sync
|
|
158
|
+
uv run pre-commit install
|
|
159
|
+
uv run pytest
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
CI runs the same hooks on every pull request. Installing them locally shows
|
|
163
|
+
you a failure before you push.
|
|
164
|
+
|
|
165
|
+
## Contributing
|
|
166
|
+
|
|
167
|
+
See [CONTRIBUTING.md](docs/contributing.md) for guidelines.
|
|
168
|
+
|
|
169
|
+
## License
|
|
170
|
+
|
|
171
|
+
MIT -- see [LICENSE](LICENSE).
|
|
172
|
+
|
|
173
|
+
## Citation
|
|
174
|
+
|
|
175
|
+
```bibtex
|
|
176
|
+
@software{thyra2024,
|
|
177
|
+
title = {Thyra: Modern Mass Spectrometry Imaging Data Conversion},
|
|
178
|
+
author = {Visvikis, Theodoros},
|
|
179
|
+
year = {2024},
|
|
180
|
+
url = {https://github.com/M4i-Imaging-Mass-Spectrometry/thyra}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Acknowledgments
|
|
185
|
+
|
|
186
|
+
- Built with [SpatialData](https://spatialdata.scverse.org/) ecosystem
|
|
187
|
+
- Powered by [Zarr](https://zarr.readthedocs.io/) for efficient storage
|
|
188
|
+
- Uses [pyimzML](https://github.com/alexandrovteam/pyimzML) for ImzML parsing
|
|
189
|
+
|
|
190
|
+
### Visual identity
|
|
191
|
+
|
|
192
|
+
Logomark and logotype designed by **Nepsis Scriptorium**.
|
|
193
|
+
|
|
194
|
+
[](https://www.instagram.com/nepsis.scriptorium/)
|
|
195
|
+
[](mailto:nepsisscriptorium@gmail.com)
|
thyra-4.2.0/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/thyra-logotype.svg" alt="Thyra" width="420">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
[](https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/actions/workflows/tests.yml)
|
|
6
|
+
[](https://pypi.org/project/thyra/)
|
|
7
|
+
[](https://www.python.org/downloads/)
|
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
|
9
|
+
[](https://github.com/psf/black)
|
|
10
|
+
[](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra)
|
|
11
|
+
[](https://colab.research.google.com/github/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/notebooks/Thyra_Validation_Workflow.ipynb)
|
|
12
|
+
|
|
13
|
+
**Thyra converts imaging mass spectrometry data into one open format.** It
|
|
14
|
+
reads the files your instrument writes (Bruker, Waters, PHI, or imzML from any
|
|
15
|
+
vendor) and saves them in [SpatialData](https://spatialdata.scverse.org/),
|
|
16
|
+
which analysis and viewing tools can read. You do not need to know how to
|
|
17
|
+
program.
|
|
18
|
+
|
|
19
|
+
**[Documentation](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra)** | [Install](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/install/) | [Your first conversion](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/getting-started/) | [Tutorial](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/tutorial/) | [Technical reference](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/technical-reference/)
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
<sub>A sagittal mouse brain section converted with Thyra: the total ion current
|
|
24
|
+
and two ion images. MALDI-MSI data from
|
|
25
|
+
[10.5281/zenodo.18326569](https://doi.org/10.5281/zenodo.18326569),
|
|
26
|
+
CC-BY-4.0.</sub>
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uv tool install --python 3.13 thyra # or: pip install thyra (Python 3.12 to 3.14)
|
|
32
|
+
thyra-example-data example_data/synthetic_brain.imzML # makes a small example dataset
|
|
33
|
+
thyra example_data/synthetic_brain.imzML example_data/synthetic_brain.zarr
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
New to the terminal or to uv? The
|
|
37
|
+
[Install](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/install/) page
|
|
38
|
+
walks you through every step. To try Thyra with nothing installed, open the
|
|
39
|
+
[notebook in Google Colab](https://colab.research.google.com/github/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/notebooks/Thyra_Validation_Workflow.ipynb).
|
|
40
|
+
The [Tutorial](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/tutorial/)
|
|
41
|
+
also converts the published example dataset
|
|
42
|
+
([10.5281/zenodo.18326569](https://doi.org/10.5281/zenodo.18326569)).
|
|
43
|
+
|
|
44
|
+
## What you can convert
|
|
45
|
+
|
|
46
|
+
| Your instrument | Point Thyra at |
|
|
47
|
+
|---|---|
|
|
48
|
+
| Bruker timsTOF or solariX | the folder ending in `.d` |
|
|
49
|
+
| Bruker rapifleX | the acquisition folder |
|
|
50
|
+
| Waters (MassLynx) | the folder ending in `.raw` |
|
|
51
|
+
| PHI nanoTOF (ToF-SIMS) | the file ending in `.raw` |
|
|
52
|
+
| Any instrument that exports imzML | the `.imzML` file, with its `.ibd` file next to it |
|
|
53
|
+
| mzPeak (experimental) | the `.mzpeak` file |
|
|
54
|
+
|
|
55
|
+
Thyra reads timsTOF and Waters data on Windows and Linux; everything else
|
|
56
|
+
also works on macOS. Shimadzu support is in development: until then, export
|
|
57
|
+
imzML from IMAGEREVEAL MS.
|
|
58
|
+
|
|
59
|
+
PHI mosaic, MS/MS and depth-profiling acquisitions have so far been tested
|
|
60
|
+
only on synthetic files. If you have real data in those modes, please get in
|
|
61
|
+
touch.
|
|
62
|
+
|
|
63
|
+
## What you get
|
|
64
|
+
|
|
65
|
+
One folder ending in `.zarr`, holding:
|
|
66
|
+
|
|
67
|
+
- the spectrum of every pixel, on one shared m/z axis
|
|
68
|
+
- an image of the total ion current (TIC)
|
|
69
|
+
- the optical image of the slide, when the acquisition has one
|
|
70
|
+
- ion mobility and MS/MS data from Bruker timsTOF, when the acquisition has them
|
|
71
|
+
- a validated description of the acquisition, ready for METASPACE
|
|
72
|
+
|
|
73
|
+
Thyra handles datasets larger than your computer's memory, slides with
|
|
74
|
+
several regions, and 3D data.
|
|
75
|
+
|
|
76
|
+
## From Python
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from thyra import convert_msi
|
|
80
|
+
import spatialdata as sd
|
|
81
|
+
|
|
82
|
+
convert_msi("data/sample.imzML", "output/sample.zarr")
|
|
83
|
+
|
|
84
|
+
sdata = sd.read_zarr("output/sample.zarr")
|
|
85
|
+
table = sdata.tables["msi_dataset_z0"] # one row per pixel, one column per m/z bin
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The acquisition description has its own commands:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
thyra metadata raw_data.d # describe a dataset without converting it
|
|
92
|
+
thyra validate output.zarr # check a result against the schema
|
|
93
|
+
thyra export-metaspace output.zarr --merge sample.json # METASPACE submission file
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Every option, format and output detail is in the
|
|
97
|
+
[Technical reference](https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/technical-reference/).
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git clone https://github.com/M4i-Imaging-Mass-Spectrometry/thyra.git
|
|
103
|
+
cd thyra
|
|
104
|
+
uv sync
|
|
105
|
+
uv run pre-commit install
|
|
106
|
+
uv run pytest
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
CI runs the same hooks on every pull request. Installing them locally shows
|
|
110
|
+
you a failure before you push.
|
|
111
|
+
|
|
112
|
+
## Contributing
|
|
113
|
+
|
|
114
|
+
See [CONTRIBUTING.md](docs/contributing.md) for guidelines.
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT -- see [LICENSE](LICENSE).
|
|
119
|
+
|
|
120
|
+
## Citation
|
|
121
|
+
|
|
122
|
+
```bibtex
|
|
123
|
+
@software{thyra2024,
|
|
124
|
+
title = {Thyra: Modern Mass Spectrometry Imaging Data Conversion},
|
|
125
|
+
author = {Visvikis, Theodoros},
|
|
126
|
+
year = {2024},
|
|
127
|
+
url = {https://github.com/M4i-Imaging-Mass-Spectrometry/thyra}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Acknowledgments
|
|
132
|
+
|
|
133
|
+
- Built with [SpatialData](https://spatialdata.scverse.org/) ecosystem
|
|
134
|
+
- Powered by [Zarr](https://zarr.readthedocs.io/) for efficient storage
|
|
135
|
+
- Uses [pyimzML](https://github.com/alexandrovteam/pyimzML) for ImzML parsing
|
|
136
|
+
|
|
137
|
+
### Visual identity
|
|
138
|
+
|
|
139
|
+
Logomark and logotype designed by **Nepsis Scriptorium**.
|
|
140
|
+
|
|
141
|
+
[](https://www.instagram.com/nepsis.scriptorium/)
|
|
142
|
+
[](mailto:nepsisscriptorium@gmail.com)
|
|
@@ -4,14 +4,14 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "thyra"
|
|
7
|
-
version = "4.
|
|
7
|
+
version = "4.2.0"
|
|
8
8
|
description = "A modern Python library for converting Mass Spectrometry Imaging (MSI) data into SpatialData/Zarr format - your portal to spatial omics"
|
|
9
9
|
authors = [{ name = "Theodoros Visvikis", email = "t.visvikis@maastrichtuniversity.nl" }]
|
|
10
10
|
maintainers = [{ name = "Theodoros Visvikis", email = "t.visvikis@maastrichtuniversity.nl" }]
|
|
11
11
|
license = "MIT"
|
|
12
12
|
license-files = ["LICENSE"]
|
|
13
13
|
readme = "README.md"
|
|
14
|
-
requires-python = ">=3.12, <3.
|
|
14
|
+
requires-python = ">=3.12, <3.15"
|
|
15
15
|
keywords = [
|
|
16
16
|
"mass-spectrometry",
|
|
17
17
|
"imaging",
|
|
@@ -34,6 +34,7 @@ classifiers = [
|
|
|
34
34
|
"Programming Language :: Python :: 3",
|
|
35
35
|
"Programming Language :: Python :: 3.12",
|
|
36
36
|
"Programming Language :: Python :: 3.13",
|
|
37
|
+
"Programming Language :: Python :: 3.14",
|
|
37
38
|
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
|
38
39
|
"Topic :: Scientific/Engineering :: Information Analysis",
|
|
39
40
|
"Topic :: Scientific/Engineering :: Medical Science Apps.",
|
|
@@ -329,7 +330,7 @@ dev = [
|
|
|
329
330
|
]
|
|
330
331
|
docs = [
|
|
331
332
|
"mkdocs>=1.6, <2",
|
|
332
|
-
"mkdocs-material>=9.
|
|
333
|
+
"mkdocs-material>=9.7", # navigation.path, content.tooltips
|
|
333
334
|
"mkdocs-jupyter>=0.25, <1", # renders docs/*.ipynb as site pages
|
|
334
335
|
"mkdocstrings[python]>=0.27",
|
|
335
336
|
]
|
|
@@ -480,6 +481,12 @@ module = [
|
|
|
480
481
|
ignore_missing_imports = true
|
|
481
482
|
|
|
482
483
|
|
|
484
|
+
[tool.black]
|
|
485
|
+
# Black otherwise infers every version in `requires-python` and, whenever the
|
|
486
|
+
# newest is above the interpreter running it, prints a warning on each run.
|
|
487
|
+
# Formatting follows the oldest target either way, so this changes no output.
|
|
488
|
+
target-version = ["py312"]
|
|
489
|
+
|
|
483
490
|
[tool.isort]
|
|
484
491
|
profile = "black"
|
|
485
492
|
multi_line_output = 3
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""MSIConverter - Convert Mass Spectrometry Imaging data to SpatialData/Zarr format.
|
|
2
|
+
|
|
3
|
+
This package provides tools for converting MSI data from various formats
|
|
4
|
+
(ImzML, Bruker) into the modern SpatialData/Zarr format with automatic
|
|
5
|
+
pixel size detection.
|
|
6
|
+
|
|
7
|
+
**Nothing heavy is imported here** (issue #381). This module used to import
|
|
8
|
+
the reader and converter packages for their registration side effects and
|
|
9
|
+
bind the public API eagerly, which cost 3.5 s and 3,580 modules --
|
|
10
|
+
``spatialdata``, ``dask`` and ``anndata`` among them -- before any caller
|
|
11
|
+
did any work. A parent package always initialises first, so that was also
|
|
12
|
+
the price of ``import thyra.metadata.schema``: the metadata layer depends
|
|
13
|
+
on none of it in source (every reference from ``thyra/metadata/`` to the
|
|
14
|
+
converter is ``TYPE_CHECKING``-guarded) and could not be used without it.
|
|
15
|
+
|
|
16
|
+
Two changes replaced it. The registry imports a format's module the first
|
|
17
|
+
time that format is looked up, from the table in
|
|
18
|
+
:mod:`thyra.core.registry`, so registration no longer needs a front door.
|
|
19
|
+
The public names below resolve on first attribute access (:pep:`562`), so
|
|
20
|
+
``thyra.convert_msi`` and ``from thyra import preview_msi`` still work and
|
|
21
|
+
still cost what they always did -- paid by the caller who asks for them.
|
|
22
|
+
|
|
23
|
+
``__version__`` stays an ordinary module attribute rather than joining
|
|
24
|
+
them. It is what ``python-semantic-release`` rewrites at release
|
|
25
|
+
(``version_variables`` in ``pyproject.toml``), and
|
|
26
|
+
``thyra.metadata.schema.builder`` reads it through ``from thyra import
|
|
27
|
+
__version__`` while building a document -- which is only affordable
|
|
28
|
+
because reaching this module is now free.
|
|
29
|
+
|
|
30
|
+
**Where a broken install now fails.** Issue #310 made ``spatialdata`` and
|
|
31
|
+
``defusedxml`` abort ``import thyra``, because both had been treated as
|
|
32
|
+
optional and the branch that fired swallowed the cause: the user's first
|
|
33
|
+
sign of trouble was ``No converter for format 'spatialdata'. Available:
|
|
34
|
+
[]``, naming no package and no reason. The swallowing is still gone and
|
|
35
|
+
nothing rewrites either ImportError; what moved is where it surfaces.
|
|
36
|
+
``spatialdata`` is imported by :mod:`thyra.converters`, which a conversion
|
|
37
|
+
reaches while resolving its output format, before it opens the input;
|
|
38
|
+
``defusedxml`` by ``thyra.readers.bruker.mis_parser``, which every Bruker
|
|
39
|
+
path reaches during format detection. Each raises at its own import with
|
|
40
|
+
its own traceback. Checking for them here instead would have cost the
|
|
41
|
+
metadata layer the very thing #381 is for: an implementation that only
|
|
42
|
+
writes the document would have to have ``spatialdata`` installed to import
|
|
43
|
+
the schema.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
# Suppress known warnings from dependencies
|
|
47
|
+
import importlib
|
|
48
|
+
import warnings
|
|
49
|
+
from typing import TYPE_CHECKING, Any, List
|
|
50
|
+
|
|
51
|
+
if TYPE_CHECKING: # pragma: no cover - for type checkers, not at runtime
|
|
52
|
+
from .convert import convert_msi
|
|
53
|
+
from .converters.spatialdata.converter import SpatialDataConverter
|
|
54
|
+
from .metadata.document import read_metadata_document
|
|
55
|
+
from .preview import MsiPreview, preview_msi
|
|
56
|
+
|
|
57
|
+
# Suppress remaining dependency warnings
|
|
58
|
+
warnings.filterwarnings("ignore", category=FutureWarning, module="dask")
|
|
59
|
+
warnings.filterwarnings("ignore", category=FutureWarning, module="spatialdata")
|
|
60
|
+
warnings.filterwarnings("ignore", category=RuntimeWarning, module="numba")
|
|
61
|
+
warnings.filterwarnings(
|
|
62
|
+
"ignore", message="pkg_resources is deprecated", category=UserWarning
|
|
63
|
+
)
|
|
64
|
+
warnings.filterwarnings(
|
|
65
|
+
"ignore",
|
|
66
|
+
message="The legacy Dask DataFrame implementation is deprecated",
|
|
67
|
+
category=FutureWarning,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
__version__ = "4.2.0"
|
|
71
|
+
|
|
72
|
+
#: Public name -> the module that defines it, imported on first access.
|
|
73
|
+
_LAZY_ATTRS = {
|
|
74
|
+
"MsiPreview": ".preview",
|
|
75
|
+
"SpatialDataConverter": ".converters.spatialdata.converter",
|
|
76
|
+
"convert_msi": ".convert",
|
|
77
|
+
"preview_msi": ".preview",
|
|
78
|
+
"read_metadata_document": ".metadata.document",
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#: Subpackages ``import thyra`` used to bind as attributes on its way to
|
|
82
|
+
#: registering their contents. Kept reachable as ``thyra.readers`` and
|
|
83
|
+
#: ``thyra.converters`` for code that never imported them by name.
|
|
84
|
+
_LAZY_SUBMODULES = ("converters", "readers")
|
|
85
|
+
|
|
86
|
+
# Expose main API
|
|
87
|
+
__all__ = [
|
|
88
|
+
"__version__",
|
|
89
|
+
"convert_msi",
|
|
90
|
+
"preview_msi",
|
|
91
|
+
"read_metadata_document",
|
|
92
|
+
"MsiPreview",
|
|
93
|
+
"SpatialDataConverter",
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def __getattr__(name: str) -> Any:
|
|
98
|
+
"""Resolve a public name by importing the module that defines it."""
|
|
99
|
+
if name in _LAZY_SUBMODULES:
|
|
100
|
+
return importlib.import_module(f".{name}", __name__)
|
|
101
|
+
module_path = _LAZY_ATTRS.get(name)
|
|
102
|
+
if module_path is None:
|
|
103
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
104
|
+
value = getattr(importlib.import_module(module_path, __name__), name)
|
|
105
|
+
globals()[name] = value
|
|
106
|
+
return value
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def __dir__() -> List[str]:
|
|
110
|
+
return sorted(set(globals()) | set(__all__) | set(_LAZY_SUBMODULES))
|
|
@@ -16,6 +16,15 @@ The import block is ordered deliberately and carries ``# noqa: E402``: the
|
|
|
16
16
|
dependency warning configuration has to run before the libraries that emit
|
|
17
17
|
those warnings are imported, so the usual "imports first" rule is
|
|
18
18
|
inverted on purpose here.
|
|
19
|
+
|
|
20
|
+
**What it does not import at module scope is ``thyra.convert``** (issue
|
|
21
|
+
#381). Binding ``convert_msi`` here meant every invocation paid for the
|
|
22
|
+
converter, ``pandas`` and ``spatialdata`` before click had parsed a single
|
|
23
|
+
argument -- including ``thyra --version`` and the two subcommands,
|
|
24
|
+
``validate`` and ``metadata``, that never reach a converter at all. The
|
|
25
|
+
conversion command imports it where it calls it. Tests that replace the
|
|
26
|
+
conversion patch ``thyra.convert.convert_msi``, which is the function
|
|
27
|
+
rather than a second name for it.
|
|
19
28
|
"""
|
|
20
29
|
|
|
21
30
|
# Configure dependencies to suppress warnings BEFORE any imports
|
|
@@ -30,12 +39,6 @@ from uuid import uuid4 # noqa: E402
|
|
|
30
39
|
import click # noqa: E402
|
|
31
40
|
|
|
32
41
|
from thyra import __version__ # noqa: E402
|
|
33
|
-
from thyra.convert import ( # noqa: E402
|
|
34
|
-
convert_msi,
|
|
35
|
-
dataset_id_problem,
|
|
36
|
-
quarantine_partial_output,
|
|
37
|
-
)
|
|
38
|
-
from thyra.core.registry import detect_format # noqa: E402
|
|
39
42
|
from thyra.resampling.mobility_grid import MOBILITY_CHANNELS # noqa: E402
|
|
40
43
|
from thyra.utils.logging_config import setup_logging # noqa: E402
|
|
41
44
|
|
|
@@ -80,6 +83,8 @@ def _validate_basic_params(pixel_size: Optional[float], dataset_id: str) -> None
|
|
|
80
83
|
raise click.BadParameter(
|
|
81
84
|
"Pixel size must be a finite positive number", param_hint="pixel_size"
|
|
82
85
|
)
|
|
86
|
+
from thyra.convert import dataset_id_problem
|
|
87
|
+
|
|
83
88
|
# Emptiness used to be the whole check, so an id with a space or a
|
|
84
89
|
# slash was refused by SpatialData only at the write, after both
|
|
85
90
|
# passes over the source (issue #250).
|
|
@@ -207,6 +212,8 @@ def _validate_input_path(input: Path) -> None:
|
|
|
207
212
|
f"found: {ibd_path}"
|
|
208
213
|
)
|
|
209
214
|
elif input.is_dir() and input.suffix.lower() == ".d":
|
|
215
|
+
from thyra.core.registry import detect_format
|
|
216
|
+
|
|
210
217
|
# Several Bruker formats share the .d extension (timsTOF via
|
|
211
218
|
# analysis.tsf/.tdf, solariX via peaks.sqlite), so delegate to the
|
|
212
219
|
# registry's detection rather than duplicating the marker files
|
|
@@ -335,7 +342,11 @@ def _display_calibration_info(input: Path, use_recalibrated: bool) -> None:
|
|
|
335
342
|
else:
|
|
336
343
|
click.echo("\nUsing original calibration (--no-recalibrated flag set)")
|
|
337
344
|
|
|
338
|
-
click.echo(
|
|
345
|
+
click.echo(
|
|
346
|
+
"\nNote: this lists the states only; one cannot be chosen here. "
|
|
347
|
+
"Thyra uses the active state, or the original calibration with "
|
|
348
|
+
"--no-recalibrated."
|
|
349
|
+
)
|
|
339
350
|
click.echo("=" * 60 + "\n")
|
|
340
351
|
|
|
341
352
|
|
|
@@ -563,6 +574,8 @@ def _quarantine_partial_output(output: Path) -> None:
|
|
|
563
574
|
store already moved aside does not exist here, so this returns
|
|
564
575
|
immediately.
|
|
565
576
|
"""
|
|
577
|
+
from thyra.convert import quarantine_partial_output
|
|
578
|
+
|
|
566
579
|
quarantine_partial_output(output)
|
|
567
580
|
|
|
568
581
|
|
|
@@ -1048,9 +1061,10 @@ def main(
|
|
|
1048
1061
|
INPUT: Path to input MSI file or directory
|
|
1049
1062
|
OUTPUT: Path for output file
|
|
1050
1063
|
|
|
1051
|
-
Subcommands (each has its own --help): 'thyra
|
|
1052
|
-
|
|
1053
|
-
PATH'
|
|
1064
|
+
Subcommands (each has its own --help): 'thyra metadata INPUT'
|
|
1065
|
+
writes a raw source's metadata document without converting it;
|
|
1066
|
+
'thyra validate PATH' validates MSI metadata against the schema;
|
|
1067
|
+
'thyra export-metaspace PATH' writes the METASPACE submission JSON.
|
|
1054
1068
|
"""
|
|
1055
1069
|
# Validate all parameters
|
|
1056
1070
|
_validate_basic_params(pixel_size, dataset_id)
|
|
@@ -1090,6 +1104,9 @@ def main(
|
|
|
1090
1104
|
# If input folder has multiple .d datasets, let the user choose
|
|
1091
1105
|
input = _select_bruker_dataset(input)
|
|
1092
1106
|
|
|
1107
|
+
from thyra.convert import convert_msi
|
|
1108
|
+
from thyra.core.registry import detect_format
|
|
1109
|
+
|
|
1093
1110
|
# Before any work: say which of the given options this source ignores.
|
|
1094
1111
|
# Detection failures are left to the conversion, which reports them
|
|
1095
1112
|
# with the guidance the registry writes for each format.
|
|
@@ -1178,9 +1195,9 @@ def cli() -> None:
|
|
|
1178
1195
|
"""Console-script entry point: dispatch subcommands, else convert.
|
|
1179
1196
|
|
|
1180
1197
|
``thyra INPUT OUTPUT`` converts exactly as it always has; the
|
|
1181
|
-
metadata subcommands (``thyra
|
|
1182
|
-
export-metaspace``) are picked off by their first argument
|
|
1183
|
-
click sees it. Dispatch is hand-rolled rather than a
|
|
1198
|
+
metadata subcommands (``thyra metadata``, ``thyra validate``,
|
|
1199
|
+
``thyra export-metaspace``) are picked off by their first argument
|
|
1200
|
+
before click sees it. Dispatch is hand-rolled rather than a
|
|
1184
1201
|
``click.Group`` because a group cannot carry the two positional
|
|
1185
1202
|
arguments the conversion interface is documented with.
|
|
1186
1203
|
"""
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Converter plugins for MSI data output formats.
|
|
2
|
+
|
|
3
|
+
Importing this package is what pulls in ``spatialdata``, and through it
|
|
4
|
+
``dask`` and ``anndata``. It used to happen during ``import thyra``, for
|
|
5
|
+
the ``@register_converter`` side effect; the registry now imports
|
|
6
|
+
:mod:`thyra.converters.spatialdata.converter` the first time the
|
|
7
|
+
``spatialdata`` output format is resolved (issue #381), so this runs when
|
|
8
|
+
a conversion is actually being set up.
|
|
9
|
+
|
|
10
|
+
The Dask configuration below moved here from ``thyra/__init__.py`` for the
|
|
11
|
+
same reason: reading it there meant importing ``dask`` to silence a
|
|
12
|
+
``dask`` warning, on every import of anything under ``thyra``. It has to
|
|
13
|
+
be set before ``dask.dataframe`` is first imported, which is why it comes
|
|
14
|
+
before the subpackage import rather than after.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
import dask
|
|
19
|
+
|
|
20
|
+
# Configure Dask to use new query planning (silences legacy DataFrame
|
|
21
|
+
# warning)
|
|
22
|
+
dask.config.set({"dataframe.query-planning": True})
|
|
23
|
+
except ImportError:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
from . import spatialdata # noqa: E402,F401
|