MaldiAMRKit 0.18.0__tar.gz → 0.19.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0/MaldiAMRKit.egg-info}/PKG-INFO +10 -3
  2. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/MaldiAMRKit.egg-info/SOURCES.txt +1 -0
  3. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/MaldiAMRKit.egg-info/requires.txt +0 -1
  4. {maldiamrkit-0.18.0/MaldiAMRKit.egg-info → maldiamrkit-0.19.0}/PKG-INFO +10 -3
  5. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/README.md +9 -1
  6. maldiamrkit-0.19.0/maldiamrkit/__init__.py +38 -0
  7. maldiamrkit-0.19.0/maldiamrkit/_registry.py +124 -0
  8. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/alignment/raw_warping.py +5 -5
  9. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/__init__.py +5 -5
  10. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/example.yaml +1 -1
  11. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/dataset_layouts.py +29 -22
  12. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/input_layouts.py +5 -5
  13. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/dataset.py +12 -2
  14. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/drift/plots.py +0 -3
  15. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/evaluation/mic_regression.py +1 -1
  16. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/preprocessing/__init__.py +10 -0
  17. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/preprocessing/binning.py +68 -37
  18. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/preprocessing/preprocessing_pipeline.py +106 -19
  19. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/preprocessing/transformers.py +178 -1
  20. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/similarity/__init__.py +12 -1
  21. maldiamrkit-0.19.0/maldiamrkit/similarity/metrics.py +389 -0
  22. maldiamrkit-0.19.0/maldiamrkit/similarity/pairwise.py +159 -0
  23. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/susceptibility/breakpoint.py +5 -5
  24. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/requirements-docs.txt +0 -1
  25. maldiamrkit-0.18.0/maldiamrkit/__init__.py +0 -38
  26. maldiamrkit-0.18.0/maldiamrkit/similarity/metrics.py +0 -222
  27. maldiamrkit-0.18.0/maldiamrkit/similarity/pairwise.py +0 -97
  28. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/LICENSE +0 -0
  29. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/MaldiAMRKit.egg-info/dependency_links.txt +0 -0
  30. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/MaldiAMRKit.egg-info/entry_points.txt +0 -0
  31. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/MaldiAMRKit.egg-info/top_level.txt +0 -0
  32. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/_compat.py +0 -0
  33. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/alignment/__init__.py +0 -0
  34. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/alignment/peak_align.py +0 -0
  35. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/alignment/strategies.py +0 -0
  36. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/alignment/warping.py +0 -0
  37. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/cli.py +0 -0
  38. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/README.md +0 -0
  39. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.0.yaml +0 -0
  40. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.1.yaml +0 -0
  41. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.2.yaml +0 -0
  42. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v1.3.yaml +0 -0
  43. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v10.0.yaml +0 -0
  44. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v11.0.yaml +0 -0
  45. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v12.0.yaml +0 -0
  46. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v13.1.yaml +0 -0
  47. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v14.0.yaml +0 -0
  48. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v15.0.yaml +0 -0
  49. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v16.0.yaml +0 -0
  50. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v2.0.yaml +0 -0
  51. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v4.0.yaml +0 -0
  52. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v5.0.yaml +0 -0
  53. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v6.0.yaml +0 -0
  54. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v7.1.yaml +0 -0
  55. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v8.0.yaml +0 -0
  56. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v8.1.yaml +0 -0
  57. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/breakpoints/eucast/eucast_v9.0.yaml +0 -0
  58. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/builder.py +0 -0
  59. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/duplicates.py +0 -0
  60. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/loader.py +0 -0
  61. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/data/site_info.py +0 -0
  62. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/detection/__init__.py +0 -0
  63. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/detection/peak_detector.py +0 -0
  64. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/detection/peaklist.py +0 -0
  65. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/differential/__init__.py +0 -0
  66. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/differential/analysis.py +0 -0
  67. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/differential/plots.py +0 -0
  68. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/differential/stats.py +0 -0
  69. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/drift/__init__.py +0 -0
  70. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/drift/monitor.py +0 -0
  71. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/drift/pca_drift.py +0 -0
  72. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/drift/peak_drift.py +0 -0
  73. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/drift/reference.py +0 -0
  74. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/evaluation/__init__.py +0 -0
  75. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/evaluation/metrics.py +0 -0
  76. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/evaluation/splitting.py +0 -0
  77. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/filters.py +0 -0
  78. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/io/__init__.py +0 -0
  79. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/io/mic.py +0 -0
  80. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/io/readers.py +0 -0
  81. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/preprocessing/merging.py +0 -0
  82. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/preprocessing/pipeline.py +0 -0
  83. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/preprocessing/quality.py +0 -0
  84. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/py.typed +0 -0
  85. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/similarity/clustering.py +0 -0
  86. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/similarity/plots.py +0 -0
  87. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/spectrum.py +0 -0
  88. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/susceptibility/__init__.py +0 -0
  89. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/susceptibility/label_encoder.py +0 -0
  90. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/susceptibility/mic_encoder.py +0 -0
  91. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/visualization/__init__.py +0 -0
  92. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/visualization/_common.py +0 -0
  93. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/visualization/alignment_plots.py +0 -0
  94. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/visualization/exploratory_plots.py +0 -0
  95. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/visualization/peak_plots.py +0 -0
  96. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/maldiamrkit/visualization/spectrum_plots.py +0 -0
  97. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/pyproject.toml +0 -0
  98. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/requirements-batch.txt +0 -0
  99. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/requirements-dev.txt +0 -0
  100. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/requirements.txt +0 -0
  101. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/setup.cfg +0 -0
  102. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/tests/test_compat.py +0 -0
  103. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/tests/test_numerical_edge_cases.py +0 -0
  104. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/tests/test_peak_detector.py +0 -0
  105. {maldiamrkit-0.18.0 → maldiamrkit-0.19.0}/tests/test_peaklist.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MaldiAMRKit
3
- Version: 0.18.0
3
+ Version: 0.19.0
4
4
  Summary: A comprehensive toolkit for MALDI-TOF mass spectrometry data preprocessing for antimicrobial resistance (AMR) prediction purposes
5
5
  Author-email: Ettore Rocchi <ettore.rocchi3@unibo.it>
6
6
  License-Expression: MIT
@@ -39,7 +39,6 @@ Requires-Dist: tqdm>=4.60.0
39
39
  Provides-Extra: docs
40
40
  Requires-Dist: sphinx>=7.0.0; extra == "docs"
41
41
  Requires-Dist: pydata-sphinx-theme>=0.15.0; extra == "docs"
42
- Requires-Dist: sphinx-autodoc-typehints>=2.0.0; extra == "docs"
43
42
  Requires-Dist: sphinx-design>=0.6.0; extra == "docs"
44
43
  Requires-Dist: sphinxcontrib-typer>=0.5.0; extra == "docs"
45
44
  Requires-Dist: nbsphinx>=0.9.0; extra == "docs"
@@ -130,6 +129,12 @@ pip install -e .[dev]
130
129
  ### Alignment & Detection
131
130
  - **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra
132
131
  - **Peak Detection**: Local maxima and persistent homology methods
132
+ - **Peak Sets**: `PeakSet` / `PeakList` represent each spectrum as a variable-length `(m/z, intensity)` set for peak-set models, via `MaldiPeakDetector.transform_peaklist()` on binned spectra or `create_peakset_input()` at full m/z resolution; extraction is stateless per spectrum, so results are cacheable without leakage
133
+ - **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, so the reference stays fitted on the training split
134
+
135
+ ### Extensibility
136
+ - **Component Registries**: Plug your own components into the name-dispatched machinery - `register_spectral_metric()` for distance metrics (usable in `spectral_distance`, `pairwise_distances`, and `DriftMonitor`), `register_transformer()` to make `PreprocessingPipeline` configs holding custom transformers round-trip through JSON/YAML, and `register_binning_method()` for custom bin edges
137
+ - **Discovery & Safety**: `list_spectral_metrics()`, `list_transformers()`, `list_binning_methods()` report what is registered; built-ins are replaced only with an explicit `override=True`, and unregistering an overridden built-in restores the default
133
138
 
134
139
  ### Evaluation
135
140
  - **AMR Metrics**: VME, ME, sensitivity, specificity, categorical agreement, and `amr_classification_report` following EUCAST conventions
@@ -248,8 +253,10 @@ For more detailed examples, see the notebooks:
248
253
  - [Differential Analysis](notebooks/06_differential_analysis.ipynb) - R vs. S peak testing, volcano/Manhattan plots, and multi-drug comparison
249
254
  - [Drift Monitoring](notebooks/07_drift_monitoring.ipynb) - Baseline-anchored drift detection: reference similarity, PCA trajectory, peak stability, and effect-size drift
250
255
  - [Susceptibility](notebooks/08_susceptibility.ipynb) - `MICEncoder` + `BreakpointTable` for log2(MIC) regression targets, S/I/R categorisation with ATU, and `mic_regression_report` evaluation
256
+ - [Peak Sets](notebooks/09_peak_sets.ipynb) - `PeakSet` / `PeakList` extraction, ranking and padding, caching, and fit-free peak alignment
257
+ - [Custom Components](notebooks/10_custom_components.ipynb) - registering a custom distance metric and a custom transformer end-to-end
251
258
 
252
- Notebooks `01`-`03` and `08` run on the small example dataset bundled under [`data/`](data/) or are fully self-contained. Notebooks `04`-`07` need more samples and pull the real **MALDI-Kleb-AI** archive (Rocchi *et al.*, 2026; [Zenodo DOI 10.5281/zenodo.17405072](https://zenodo.org/records/17405072)) via the [`demo`](notebooks/_demo.py) helper. By default the helper restricts the dataset to the **Rome sub-cohort** (~470 spectra, single acquisition centre, no batch correction required); the 370 MB tarball is cached under `~/.cache/maldiamrkit/` on first use.
259
+ Notebooks `01`-`03` and `08`-`10` run on the small example dataset bundled under [`data/`](data/) or are fully self-contained. Notebooks `04`-`07` need more samples and pull the real **MALDI-Kleb-AI** archive (Rocchi *et al.*, 2026; [Zenodo DOI 10.5281/zenodo.17405072](https://zenodo.org/records/17405072)) via the [`demo`](notebooks/_demo.py) helper. By default the helper restricts the dataset to the **Rome sub-cohort** (~470 spectra, single acquisition centre, no batch correction required); the 370 MB tarball is cached under `~/.cache/maldiamrkit/` on first use.
253
260
 
254
261
  ## MaldiSuite Ecosystem
255
262
 
@@ -13,6 +13,7 @@ MaldiAMRKit.egg-info/requires.txt
13
13
  MaldiAMRKit.egg-info/top_level.txt
14
14
  maldiamrkit/__init__.py
15
15
  maldiamrkit/_compat.py
16
+ maldiamrkit/_registry.py
16
17
  maldiamrkit/cli.py
17
18
  maldiamrkit/dataset.py
18
19
  maldiamrkit/filters.py
@@ -27,7 +27,6 @@ hypothesis>=6.0.0
27
27
  [docs]
28
28
  sphinx>=7.0.0
29
29
  pydata-sphinx-theme>=0.15.0
30
- sphinx-autodoc-typehints>=2.0.0
31
30
  sphinx-design>=0.6.0
32
31
  sphinxcontrib-typer>=0.5.0
33
32
  nbsphinx>=0.9.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MaldiAMRKit
3
- Version: 0.18.0
3
+ Version: 0.19.0
4
4
  Summary: A comprehensive toolkit for MALDI-TOF mass spectrometry data preprocessing for antimicrobial resistance (AMR) prediction purposes
5
5
  Author-email: Ettore Rocchi <ettore.rocchi3@unibo.it>
6
6
  License-Expression: MIT
@@ -39,7 +39,6 @@ Requires-Dist: tqdm>=4.60.0
39
39
  Provides-Extra: docs
40
40
  Requires-Dist: sphinx>=7.0.0; extra == "docs"
41
41
  Requires-Dist: pydata-sphinx-theme>=0.15.0; extra == "docs"
42
- Requires-Dist: sphinx-autodoc-typehints>=2.0.0; extra == "docs"
43
42
  Requires-Dist: sphinx-design>=0.6.0; extra == "docs"
44
43
  Requires-Dist: sphinxcontrib-typer>=0.5.0; extra == "docs"
45
44
  Requires-Dist: nbsphinx>=0.9.0; extra == "docs"
@@ -130,6 +129,12 @@ pip install -e .[dev]
130
129
  ### Alignment & Detection
131
130
  - **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra
132
131
  - **Peak Detection**: Local maxima and persistent homology methods
132
+ - **Peak Sets**: `PeakSet` / `PeakList` represent each spectrum as a variable-length `(m/z, intensity)` set for peak-set models, via `MaldiPeakDetector.transform_peaklist()` on binned spectra or `create_peakset_input()` at full m/z resolution; extraction is stateless per spectrum, so results are cacheable without leakage
133
+ - **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, so the reference stays fitted on the training split
134
+
135
+ ### Extensibility
136
+ - **Component Registries**: Plug your own components into the name-dispatched machinery - `register_spectral_metric()` for distance metrics (usable in `spectral_distance`, `pairwise_distances`, and `DriftMonitor`), `register_transformer()` to make `PreprocessingPipeline` configs holding custom transformers round-trip through JSON/YAML, and `register_binning_method()` for custom bin edges
137
+ - **Discovery & Safety**: `list_spectral_metrics()`, `list_transformers()`, `list_binning_methods()` report what is registered; built-ins are replaced only with an explicit `override=True`, and unregistering an overridden built-in restores the default
133
138
 
134
139
  ### Evaluation
135
140
  - **AMR Metrics**: VME, ME, sensitivity, specificity, categorical agreement, and `amr_classification_report` following EUCAST conventions
@@ -248,8 +253,10 @@ For more detailed examples, see the notebooks:
248
253
  - [Differential Analysis](notebooks/06_differential_analysis.ipynb) - R vs. S peak testing, volcano/Manhattan plots, and multi-drug comparison
249
254
  - [Drift Monitoring](notebooks/07_drift_monitoring.ipynb) - Baseline-anchored drift detection: reference similarity, PCA trajectory, peak stability, and effect-size drift
250
255
  - [Susceptibility](notebooks/08_susceptibility.ipynb) - `MICEncoder` + `BreakpointTable` for log2(MIC) regression targets, S/I/R categorisation with ATU, and `mic_regression_report` evaluation
256
+ - [Peak Sets](notebooks/09_peak_sets.ipynb) - `PeakSet` / `PeakList` extraction, ranking and padding, caching, and fit-free peak alignment
257
+ - [Custom Components](notebooks/10_custom_components.ipynb) - registering a custom distance metric and a custom transformer end-to-end
251
258
 
252
- Notebooks `01`-`03` and `08` run on the small example dataset bundled under [`data/`](data/) or are fully self-contained. Notebooks `04`-`07` need more samples and pull the real **MALDI-Kleb-AI** archive (Rocchi *et al.*, 2026; [Zenodo DOI 10.5281/zenodo.17405072](https://zenodo.org/records/17405072)) via the [`demo`](notebooks/_demo.py) helper. By default the helper restricts the dataset to the **Rome sub-cohort** (~470 spectra, single acquisition centre, no batch correction required); the 370 MB tarball is cached under `~/.cache/maldiamrkit/` on first use.
259
+ Notebooks `01`-`03` and `08`-`10` run on the small example dataset bundled under [`data/`](data/) or are fully self-contained. Notebooks `04`-`07` need more samples and pull the real **MALDI-Kleb-AI** archive (Rocchi *et al.*, 2026; [Zenodo DOI 10.5281/zenodo.17405072](https://zenodo.org/records/17405072)) via the [`demo`](notebooks/_demo.py) helper. By default the helper restricts the dataset to the **Rome sub-cohort** (~470 spectra, single acquisition centre, no batch correction required); the 370 MB tarball is cached under `~/.cache/maldiamrkit/` on first use.
253
260
 
254
261
  ## MaldiSuite Ecosystem
255
262
 
@@ -73,6 +73,12 @@ pip install -e .[dev]
73
73
  ### Alignment & Detection
74
74
  - **Spectral Alignment**: Shift, linear, piecewise, DTW, quadratic, cubic, and LOWESS warping for both binned and raw full-resolution spectra
75
75
  - **Peak Detection**: Local maxima and persistent homology methods
76
+ - **Peak Sets**: `PeakSet` / `PeakList` represent each spectrum as a variable-length `(m/z, intensity)` set for peak-set models, via `MaldiPeakDetector.transform_peaklist()` on binned spectra or `create_peakset_input()` at full m/z resolution; extraction is stateless per spectrum, so results are cacheable without leakage
77
+ - **Fit-Free Peak Alignment**: `align_peaks()` warps a peak set onto caller-supplied reference peaks, so the reference stays fitted on the training split
78
+
79
+ ### Extensibility
80
+ - **Component Registries**: Plug your own components into the name-dispatched machinery - `register_spectral_metric()` for distance metrics (usable in `spectral_distance`, `pairwise_distances`, and `DriftMonitor`), `register_transformer()` to make `PreprocessingPipeline` configs holding custom transformers round-trip through JSON/YAML, and `register_binning_method()` for custom bin edges
81
+ - **Discovery & Safety**: `list_spectral_metrics()`, `list_transformers()`, `list_binning_methods()` report what is registered; built-ins are replaced only with an explicit `override=True`, and unregistering an overridden built-in restores the default
76
82
 
77
83
  ### Evaluation
78
84
  - **AMR Metrics**: VME, ME, sensitivity, specificity, categorical agreement, and `amr_classification_report` following EUCAST conventions
@@ -191,8 +197,10 @@ For more detailed examples, see the notebooks:
191
197
  - [Differential Analysis](notebooks/06_differential_analysis.ipynb) - R vs. S peak testing, volcano/Manhattan plots, and multi-drug comparison
192
198
  - [Drift Monitoring](notebooks/07_drift_monitoring.ipynb) - Baseline-anchored drift detection: reference similarity, PCA trajectory, peak stability, and effect-size drift
193
199
  - [Susceptibility](notebooks/08_susceptibility.ipynb) - `MICEncoder` + `BreakpointTable` for log2(MIC) regression targets, S/I/R categorisation with ATU, and `mic_regression_report` evaluation
200
+ - [Peak Sets](notebooks/09_peak_sets.ipynb) - `PeakSet` / `PeakList` extraction, ranking and padding, caching, and fit-free peak alignment
201
+ - [Custom Components](notebooks/10_custom_components.ipynb) - registering a custom distance metric and a custom transformer end-to-end
194
202
 
195
- Notebooks `01`-`03` and `08` run on the small example dataset bundled under [`data/`](data/) or are fully self-contained. Notebooks `04`-`07` need more samples and pull the real **MALDI-Kleb-AI** archive (Rocchi *et al.*, 2026; [Zenodo DOI 10.5281/zenodo.17405072](https://zenodo.org/records/17405072)) via the [`demo`](notebooks/_demo.py) helper. By default the helper restricts the dataset to the **Rome sub-cohort** (~470 spectra, single acquisition centre, no batch correction required); the 370 MB tarball is cached under `~/.cache/maldiamrkit/` on first use.
203
+ Notebooks `01`-`03` and `08`-`10` run on the small example dataset bundled under [`data/`](data/) or are fully self-contained. Notebooks `04`-`07` need more samples and pull the real **MALDI-Kleb-AI** archive (Rocchi *et al.*, 2026; [Zenodo DOI 10.5281/zenodo.17405072](https://zenodo.org/records/17405072)) via the [`demo`](notebooks/_demo.py) helper. By default the helper restricts the dataset to the **Rome sub-cohort** (~470 spectra, single acquisition centre, no batch correction required); the 370 MB tarball is cached under `~/.cache/maldiamrkit/` on first use.
196
204
 
197
205
  ## MaldiSuite Ecosystem
198
206
 
@@ -0,0 +1,38 @@
1
+ """MaldiAMRKit: MALDI-TOF preprocessing toolkit for AMR prediction.
2
+
3
+ Subpackage guide
4
+ ----------------
5
+ - ``maldiamrkit.data``: DatasetBuilder, DatasetLoader, InputLayout, DatasetLayout
6
+ - ``maldiamrkit.filters``: SpeciesFilter, DrugFilter, QualityFilter, MetadataFilter
7
+ - ``maldiamrkit.preprocessing``: PreprocessingPipeline, transformers, binning, quality, merging
8
+ - ``maldiamrkit.alignment``: Warping, RawWarping, create_raw_input, align_peaks, AlignmentStrategy, AlignmentMethod
9
+ - ``maldiamrkit.detection``: MaldiPeakDetector, PeakSet, PeakList, create_peakset_input
10
+ - ``maldiamrkit.evaluation``: AMR metrics (binary + mic_regression_report), splitting (LabelEncoder moved to susceptibility)
11
+ - ``maldiamrkit.susceptibility``: MICEncoder, BreakpointTable, BreakpointResult, LabelEncoder
12
+ - ``maldiamrkit.similarity``: spectral_distance, pairwise_distances, clustering, plots
13
+ - ``maldiamrkit.differential``: DifferentialAnalysis, plot_volcano, plot_manhattan, plot_drug_comparison
14
+ - ``maldiamrkit.drift``: DriftMonitor, plot_reference_drift, plot_pca_drift, plot_peak_stability, plot_effect_size_drift
15
+ - ``maldiamrkit.visualization``: plot_spectrum, plot_pseudogel, plot_peaks, plot_alignment, plot_pca, plot_tsne, plot_umap
16
+ - ``maldiamrkit.io``: read_spectrum, parse_mic_column
17
+
18
+ Examples
19
+ --------
20
+ >>> from maldiamrkit import MaldiSpectrum, MaldiSet
21
+ >>> from maldiamrkit.preprocessing import PreprocessingPipeline
22
+ >>> from maldiamrkit.alignment import Warping
23
+ >>> from maldiamrkit.data import DatasetBuilder, DatasetLoader, FlatLayout, DRIAMSLayout
24
+ >>> from maldiamrkit.susceptibility import MICEncoder, BreakpointTable
25
+ """
26
+
27
+ from .dataset import MaldiSet
28
+ from .spectrum import MaldiSpectrum
29
+
30
+ __version__ = "0.19.0"
31
+ __author__ = "Ettore Rocchi"
32
+
33
+ __all__ = [
34
+ "MaldiSet",
35
+ "MaldiSpectrum",
36
+ "__version__",
37
+ "__author__",
38
+ ]
@@ -0,0 +1,124 @@
1
+ """Shared machinery for the package's name-dispatched component registries.
2
+
3
+ The public registration APIs (``register_spectral_metric``,
4
+ ``register_transformer``, ``register_binning_method`` and their
5
+ ``unregister_*`` / ``list_*`` companions) are thin wrappers around one
6
+ :class:`_ComponentRegistry` instance per component kind, so the three
7
+ registries share a single implementation of the built-in protection,
8
+ override, restore, and name-resolution semantics.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from enum import Enum
14
+ from typing import Any, Callable
15
+
16
+
17
+ class _ComponentRegistry(dict):
18
+ """A ``name -> component`` mapping whose built-in entries are protected.
19
+
20
+ Behaves as a plain dict for lookups, while the mutation methods enforce
21
+ the registry contract:
22
+
23
+ - registering a new name is always allowed (re-registering a custom name
24
+ replaces it silently);
25
+ - replacing a built-in requires ``override=True``;
26
+ - unregistering an overridden built-in restores the default component;
27
+ - unregistering a pristine built-in is refused.
28
+
29
+ Parameters
30
+ ----------
31
+ kind : str
32
+ Full component noun used in error messages, e.g. ``"spectral
33
+ metric"``.
34
+ short : str
35
+ Short noun used where the messages already say the kind, e.g.
36
+ ``"metric"``.
37
+ register_fn : str
38
+ Name of the public registration function to point users at.
39
+ entries : dict
40
+ The built-in components. A copy is kept as the immutable set of
41
+ defaults that :meth:`unregister` can restore.
42
+ validate : callable, optional
43
+ Called with the candidate component before registration; should
44
+ raise ``TypeError`` for unacceptable components.
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ kind: str,
50
+ short: str,
51
+ register_fn: str,
52
+ entries: dict[str, Any],
53
+ validate: Callable[[Any], None] | None = None,
54
+ ) -> None:
55
+ super().__init__(entries)
56
+ self._kind = kind
57
+ self._short = short
58
+ self._register_fn = register_fn
59
+ self._validate = validate
60
+ self._defaults: dict[str, Any] = dict(entries)
61
+
62
+ @property
63
+ def defaults(self) -> dict[str, Any]:
64
+ """The built-in components (``name -> component``), never mutated."""
65
+ return self._defaults
66
+
67
+ def register(self, name: str, component: Any, *, override: bool = False) -> None:
68
+ if self._validate is not None:
69
+ self._validate(component)
70
+ if name in self._defaults and not override:
71
+ raise ValueError(
72
+ f"{name!r} is a built-in {self._kind}. "
73
+ "Pass override=True to replace it."
74
+ )
75
+ self[name] = component
76
+
77
+ def unregister(self, name: str) -> None:
78
+ if name in self._defaults:
79
+ default = self._defaults[name]
80
+ if self.get(name) is default:
81
+ raise ValueError(
82
+ f"Cannot unregister built-in {self._kind} {name!r}. "
83
+ f"Built-in {self._short}s are {sorted(self._defaults)}."
84
+ )
85
+ self[name] = default
86
+ return
87
+ try:
88
+ del self[name]
89
+ except KeyError:
90
+ raise KeyError(f"No {self._kind} named {name!r} is registered.") from None
91
+
92
+ def names(self) -> list[str]:
93
+ return sorted(self)
94
+
95
+ def resolve_key(
96
+ self,
97
+ value: Any,
98
+ enum_cls: type[Enum] | None = None,
99
+ *,
100
+ not_a: str = "valid",
101
+ ) -> str:
102
+ """Return the registry key for *value*, an enum member or a name.
103
+
104
+ Raises
105
+ ------
106
+ ValueError
107
+ If *value* names no registered component. The message lists the
108
+ registered names and points at the registration function.
109
+ """
110
+ if enum_cls is not None and isinstance(value, enum_cls):
111
+ key = value.value
112
+ else:
113
+ key = value
114
+ try:
115
+ known = key in self
116
+ except TypeError:
117
+ known = False
118
+ if not known:
119
+ raise ValueError(
120
+ f"{value!r} is not a {not_a} {self._kind}. Use one of "
121
+ f"{self.names()} or register a custom {self._short} with "
122
+ f"{self._register_fn}()."
123
+ )
124
+ return key
@@ -45,11 +45,11 @@ def create_raw_input(
45
45
  How to handle duplicate sample IDs (e.g. the same sample
46
46
  appearing in multiple year subdirectories):
47
47
 
48
- * ``"first"`` -- keep the first occurrence (default).
49
- * ``"last"`` -- keep the last occurrence.
50
- * ``"drop"`` -- remove all duplicates.
51
- * ``"keep_all"`` -- keep every replicate with ``_repN`` suffixes.
52
- * ``"average"`` -- keep all replicates and add an
48
+ * ``"first"``: keep the first occurrence (default).
49
+ * ``"last"``: keep the last occurrence.
50
+ * ``"drop"``: remove all duplicates.
51
+ * ``"keep_all"``: keep every replicate with ``_repN`` suffixes.
52
+ * ``"average"``: keep all replicates and add an
53
53
  ``_original_id`` column so that
54
54
  :meth:`RawWarping.transform` can group and average them.
55
55
 
@@ -2,11 +2,11 @@
2
2
 
3
3
  Submodules
4
4
  ----------
5
- - ``input_layouts`` -- :class:`InputLayout` adapters for :class:`DatasetBuilder`
6
- - ``dataset_layouts`` -- :class:`DatasetLayout` adapters for :class:`DatasetLoader`
7
- - ``builder`` -- :class:`DatasetBuilder`, :class:`ProcessingHandler`, :class:`BuildReport`
8
- - ``loader`` -- :class:`DatasetLoader`
9
- - ``site_info`` -- :class:`SiteInfo`, :class:`BuildInfo`, ``read_site_info``,
5
+ - ``input_layouts``: :class:`InputLayout` adapters for :class:`DatasetBuilder`
6
+ - ``dataset_layouts``: :class:`DatasetLayout` adapters for :class:`DatasetLoader`
7
+ - ``builder``: :class:`DatasetBuilder`, :class:`ProcessingHandler`, :class:`BuildReport`
8
+ - ``loader``: :class:`DatasetLoader`
9
+ - ``site_info``: :class:`SiteInfo`, :class:`BuildInfo`, ``read_site_info``,
10
10
  ``write_site_info`` (self-describing dataset manifest written at build time
11
11
  and consulted by :class:`DRIAMSLayout` at load time)
12
12
  """
@@ -1,4 +1,4 @@
1
- # Synthetic example breakpoint table -- NOT FOR CLINICAL USE.
1
+ # Synthetic example breakpoint table: NOT FOR CLINICAL USE.
2
2
  #
3
3
  # Used by tests, docs, and notebooks for shape demonstration only. The
4
4
  # values below are illustrative and have been deliberately simplified;
@@ -169,25 +169,28 @@ class DRIAMSLayout(DatasetLayout):
169
169
  The column is renamed to ``'Species'`` for downstream use.
170
170
  year : str, int, or None
171
171
  Restrict to a single year.
172
- metadata_dir : str, default="id"
173
- Subdirectory name containing metadata CSV files.
174
- metadata_suffix : str, default="_clean.csv"
175
- Filename suffix for metadata CSV files.
176
- spectrum_ext : str, default=".txt"
177
- File extension for spectrum files (including the dot).
172
+ metadata_dir : str, optional
173
+ Subdirectory name containing metadata CSV files. Taken from
174
+ ``site_info.json`` when the dataset has one, else ``"id"``.
175
+ metadata_suffix : str, optional
176
+ Filename suffix for metadata CSV files. Taken from
177
+ ``site_info.json`` when the dataset has one, else ``"_clean.csv"``.
178
+ spectrum_ext : str, optional
179
+ File extension for spectrum files (including the dot). Taken from
180
+ ``site_info.json`` when the dataset has one, else ``".txt"``.
178
181
  duplicate_strategy : str or DuplicateStrategy, default ``"first"``
179
182
  How to handle duplicate spectrum IDs (e.g. the same sample
180
183
  appearing in multiple year subdirectories):
181
184
 
182
- * ``"first"`` -- keep the first occurrence (default).
183
- * ``"last"`` -- keep the last occurrence.
184
- * ``"drop"`` -- remove all duplicates.
185
- * ``"keep_all"`` -- keep every replicate with ``_repN`` suffixes.
186
- * ``"average"`` -- tag replicates for downstream averaging.
185
+ * ``"first"``: keep the first occurrence (default).
186
+ * ``"last"``: keep the last occurrence.
187
+ * ``"drop"``: remove all duplicates.
188
+ * ``"keep_all"``: keep every replicate with ``_repN`` suffixes.
189
+ * ``"average"``: tag replicates for downstream averaging.
187
190
  id_transform : callable, optional
188
191
  Function mapping raw ``ID`` strings to a canonical *sample*
189
192
  identifier. When set, duplicates are detected on the
190
- transformed identifier rather than the raw one -- so
193
+ transformed identifier rather than the raw one, so
191
194
  technical-replicate files that share an underlying sample
192
195
  (e.g. DRIAMS ``UUID_MALDI1`` / ``UUID_MALDI2``) are
193
196
  recognized as duplicates by ``duplicate_strategy``. The raw
@@ -212,11 +215,15 @@ class DRIAMSLayout(DatasetLayout):
212
215
  collapse DRIAMS technical replicates (``_MALDI<N>``) to one row per
213
216
  underlying isolate via the active ``duplicate_strategy``. Ignored when
214
217
  an explicit ``id_transform`` is given (that always takes precedence).
215
- mz_min : float, default=2000.0
218
+ mz_min : float, optional
216
219
  Lower m/z edge to assign to bin index 0 when a ``binned_N/`` stage
217
- is loaded. Only consulted by :meth:`postprocess_spectrum`.
218
- mz_max : float, default=19997.0
219
- Upper m/z edge assigned to bin index ``N-1``.
220
+ is loaded. Only consulted by :meth:`postprocess_spectrum`. Taken
221
+ from the ``mz_range`` in ``site_info.json`` when the dataset has one,
222
+ else ``2000.0``.
223
+ mz_max : float, optional
224
+ Upper m/z edge assigned to bin index ``N-1``. Taken from the
225
+ ``mz_range`` in ``site_info.json`` when the dataset has one, else
226
+ ``19997.0``.
220
227
  normalize_tic : bool, default=False
221
228
  When ``True``, re-apply a TIC normalization
222
229
  (``intensity <- intensity / sum(intensity)``) to every loaded
@@ -224,7 +231,7 @@ class DRIAMSLayout(DatasetLayout):
224
231
  published DRIAMS / MS-UMG ``binned_6000/`` files do not sum
225
232
  to 1.0 on disk (empirically ~1.29 and ~1.36 respectively),
226
233
  despite the DRIAMS preprocessing script calling
227
- ``calibrateIntensity(method="TIC")`` before trimming -- the
234
+ ``calibrateIntensity(method="TIC")`` before trimming; the
228
235
  cause is somewhere in the upstream pipeline (MALDIquant version
229
236
  or an implicit scaling step) and has not been reproduced here.
230
237
  Enabling this kwarg gives sum=1.0 per spectrum, aligning DRIAMS
@@ -531,13 +538,13 @@ class MARISMaLayout(DatasetLayout):
531
538
  How to handle duplicate specimen identifiers (e.g. the same
532
539
  sample measured at multiple MALDI target positions):
533
540
 
534
- * ``"first"`` -- keep the first occurrence (default).
535
- * ``"last"`` -- keep the last occurrence.
536
- * ``"drop"`` -- remove all duplicates.
537
- * ``"keep_all"`` -- keep every replicate, appending the
541
+ * ``"first"``: keep the first occurrence (default).
542
+ * ``"last"``: keep the last occurrence.
543
+ * ``"drop"``: remove all duplicates.
544
+ * ``"keep_all"``: keep every replicate, appending the
538
545
  target-position value to the ID
539
546
  (``{identifier}_{target_position}``).
540
- * ``"average"`` -- tag replicates for downstream averaging
547
+ * ``"average"``: tag replicates for downstream averaging
541
548
  (adds ``_original_id`` column).
542
549
  id_transform : callable, optional
543
550
  Function mapping raw ``ID`` strings to a canonical *sample*
@@ -214,13 +214,13 @@ class BrukerTreeLayout(InputLayout):
214
214
  How to handle duplicate specimen identifiers (e.g. the same
215
215
  sample measured at multiple MALDI target positions):
216
216
 
217
- * ``"first"`` -- keep the first occurrence (default).
218
- * ``"last"`` -- keep the last occurrence.
219
- * ``"drop"`` -- remove all duplicates.
220
- * ``"keep_all"`` -- keep every replicate, appending the
217
+ * ``"first"``: keep the first occurrence (default).
218
+ * ``"last"``: keep the last occurrence.
219
+ * ``"drop"``: remove all duplicates.
220
+ * ``"keep_all"``: keep every replicate, appending the
221
221
  target-position value to the ID
222
222
  (``{identifier}_{target_position}``).
223
- * ``"average"`` -- tag replicates for downstream averaging
223
+ * ``"average"``: tag replicates for downstream averaging
224
224
  (adds ``_original_id`` column).
225
225
  validate : bool, default=True
226
226
  If ``True``, skip empty spectra (all-zero ``fid``) and warn
@@ -71,6 +71,16 @@ class MaldiSet:
71
71
  Additional keyword arguments for binning (e.g., custom_edges, adaptive_min_width).
72
72
  verbose : bool, default=False
73
73
  If True, print progress messages.
74
+ isolate_pattern : str or compiled regex, optional
75
+ Replicate suffix stripped from each spectrum ID to recover the
76
+ per-isolate group key used by :meth:`isolate_ids` and :attr:`groups`.
77
+ Normally stamped by the source layout at load time; falls back to the
78
+ DRIAMS ``_MALDI<N>`` suffix when neither this nor ``isolate_column``
79
+ is set.
80
+ isolate_column : str, optional
81
+ Metadata column already holding the isolate ID, used by
82
+ :meth:`isolate_ids` and :attr:`groups` in preference to
83
+ ``isolate_pattern``. Normally stamped by the source layout.
74
84
 
75
85
  Attributes
76
86
  ----------
@@ -517,8 +527,8 @@ class MaldiSet:
517
527
  layout when the set was loaded (e.g. ``_MALDI<N>`` for DRIAMS), else
518
528
  4. the DRIAMS ``_MALDI<N>`` suffix as a last-resort fallback.
519
529
 
520
- If the resolved pattern strips nothing from any ID -- every spectrum
521
- becomes its own group, giving no leakage protection -- a warning is
530
+ If the resolved pattern strips nothing from any ID (every spectrum
531
+ becomes its own group, giving no leakage protection), a warning is
522
532
  emitted pointing at ``pattern=`` / ``column=``.
523
533
 
524
534
  Parameters
@@ -164,9 +164,6 @@ def plot_pca_drift(
164
164
  else:
165
165
  sizes = 60.0
166
166
 
167
- # Polyline connecting consecutive windows (behind the scatter so
168
- # markers stay readable). No arrowheads -- direction comes from
169
- # the colorbar + optional baseline-end marker.
170
167
  if len(df) >= 2:
171
168
  ax.plot(
172
169
  x,
@@ -2,7 +2,7 @@
2
2
 
3
3
  Reports the metrics clinicians and ML practitioners actually look at when
4
4
  predicting MIC values on dilution series: RMSE in log2 dilutions, essential
5
- agreement (within ±1 dilution), and -- if breakpoints are provided --
5
+ agreement (within ±1 dilution), and, if breakpoints are provided,
6
6
  categorical agreement after re-binning to S/I/R.
7
7
  """
8
8
 
@@ -4,6 +4,7 @@ from .binning import (
4
4
  BinningMethod,
5
5
  bin_spectrum,
6
6
  get_bin_metadata,
7
+ list_binning_methods,
7
8
  register_binning_method,
8
9
  unregister_binning_method,
9
10
  )
@@ -21,21 +22,30 @@ from .transformers import (
21
22
  MzMultiTrimmer,
22
23
  MzTrimmer,
23
24
  PQNNormalizer,
25
+ PreprocessingStep,
24
26
  SavitzkyGolaySmooth,
25
27
  SNIPBaseline,
26
28
  SqrtTransform,
27
29
  TICNormalizer,
28
30
  TopHatBaseline,
31
+ list_transformers,
32
+ register_transformer,
33
+ unregister_transformer,
29
34
  )
30
35
 
31
36
  __all__ = [
32
37
  # Pipeline
33
38
  "PreprocessingPipeline",
39
+ "PreprocessingStep",
34
40
  "preprocess",
41
+ "list_transformers",
42
+ "register_transformer",
43
+ "unregister_transformer",
35
44
  # Binning
36
45
  "BinningMethod",
37
46
  "bin_spectrum",
38
47
  "get_bin_metadata",
48
+ "list_binning_methods",
39
49
  "register_binning_method",
40
50
  "unregister_binning_method",
41
51
  # Merging