thyra 3.0.0__tar.gz → 3.0.2__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 (97) hide show
  1. {thyra-3.0.0 → thyra-3.0.2}/PKG-INFO +4 -4
  2. {thyra-3.0.0 → thyra-3.0.2}/README.md +1 -1
  3. {thyra-3.0.0 → thyra-3.0.2}/pyproject.toml +5 -3
  4. {thyra-3.0.0 → thyra-3.0.2}/thyra/__init__.py +1 -1
  5. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/spatialdata/spatialdata_3d_converter.py +8 -3
  6. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/spatialdata/streaming_converter.py +29 -4
  7. {thyra-3.0.0 → thyra-3.0.2}/LICENSE +0 -0
  8. {thyra-3.0.0 → thyra-3.0.2}/thyra/__main__.py +0 -0
  9. {thyra-3.0.0 → thyra-3.0.2}/thyra/alignment/__init__.py +0 -0
  10. {thyra-3.0.0 → thyra-3.0.2}/thyra/alignment/affine.py +0 -0
  11. {thyra-3.0.0 → thyra-3.0.2}/thyra/alignment/teaching_points.py +0 -0
  12. {thyra-3.0.0 → thyra-3.0.2}/thyra/config.py +0 -0
  13. {thyra-3.0.0 → thyra-3.0.2}/thyra/convert.py +0 -0
  14. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/__init__.py +0 -0
  15. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/spatialdata/__init__.py +0 -0
  16. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/spatialdata/_chunking.py +0 -0
  17. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/spatialdata/base_spatialdata_converter.py +0 -0
  18. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/spatialdata/converter.py +0 -0
  19. {thyra-3.0.0 → thyra-3.0.2}/thyra/converters/spatialdata/spatialdata_2d_converter.py +0 -0
  20. {thyra-3.0.0 → thyra-3.0.2}/thyra/core/__init__.py +0 -0
  21. {thyra-3.0.0 → thyra-3.0.2}/thyra/core/base_converter.py +0 -0
  22. {thyra-3.0.0 → thyra-3.0.2}/thyra/core/base_extractor.py +0 -0
  23. {thyra-3.0.0 → thyra-3.0.2}/thyra/core/base_reader.py +0 -0
  24. {thyra-3.0.0 → thyra-3.0.2}/thyra/core/registry.py +0 -0
  25. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/__init__.py +0 -0
  26. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/extractors/__init__.py +0 -0
  27. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/extractors/bruker_extractor.py +0 -0
  28. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/extractors/imzml_extractor.py +0 -0
  29. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/extractors/waters_extractor.py +0 -0
  30. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/ontology/__init__.py +0 -0
  31. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/ontology/_ims.py +0 -0
  32. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/ontology/_ms.py +0 -0
  33. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/ontology/_uo.py +0 -0
  34. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/ontology/cache.py +0 -0
  35. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/types.py +0 -0
  36. {thyra-3.0.0 → thyra-3.0.2}/thyra/metadata/validator.py +0 -0
  37. {thyra-3.0.0 → thyra-3.0.2}/thyra/preview.py +0 -0
  38. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/__init__.py +0 -0
  39. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/__init__.py +0 -0
  40. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/base_bruker_reader.py +0 -0
  41. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/folder_structure.py +0 -0
  42. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/mis_parser.py +0 -0
  43. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/rapiflex/__init__.py +0 -0
  44. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/rapiflex/rapiflex_reader.py +0 -0
  45. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/__init__.py +0 -0
  46. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/__init__.py +0 -0
  47. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/dll/LICENCE-BRUKER.txt +0 -0
  48. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/dll/README.md +0 -0
  49. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/dll/timsdata.dll +0 -0
  50. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/dll/timsdata.so +0 -0
  51. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/dll_manager.py +0 -0
  52. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/platform_detector.py +0 -0
  53. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/sdk/sdk_functions.py +0 -0
  54. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/timstof_reader.py +0 -0
  55. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/utils/__init__.py +0 -0
  56. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/utils/batch_processor.py +0 -0
  57. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/utils/coordinate_cache.py +0 -0
  58. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/utils/mass_axis_builder.py +0 -0
  59. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/bruker/timstof/utils/memory_manager.py +0 -0
  60. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/imzml/__init__.py +0 -0
  61. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/imzml/imzml_reader.py +0 -0
  62. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/__init__.py +0 -0
  63. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/imaging_grid.py +0 -0
  64. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/lib/MLReader.dll +0 -0
  65. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/lib/MassLynxRaw.dll +0 -0
  66. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/lib/libMLReader.so +0 -0
  67. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/lib/libMassLynxRaw.so +0 -0
  68. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/masslynx_lib.py +0 -0
  69. {thyra-3.0.0 → thyra-3.0.2}/thyra/readers/waters/waters_reader.py +0 -0
  70. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/__init__.py +0 -0
  71. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/common_axis.py +0 -0
  72. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/constants.py +0 -0
  73. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/data_characteristics.py +0 -0
  74. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/decision_tree.py +0 -0
  75. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/gaps.py +0 -0
  76. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/instrument_detectors.py +0 -0
  77. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/mass_axis/__init__.py +0 -0
  78. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/mass_axis/base_generator.py +0 -0
  79. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/mass_axis/fticr_generator.py +0 -0
  80. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/mass_axis/linear_generator.py +0 -0
  81. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/mass_axis/linear_tof_generator.py +0 -0
  82. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/mass_axis/orbitrap_generator.py +0 -0
  83. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/mass_axis/reflector_tof_generator.py +0 -0
  84. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/strategies/__init__.py +0 -0
  85. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/strategies/base.py +0 -0
  86. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/strategies/nearest_neighbor.py +0 -0
  87. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/strategies/tic_preserving.py +0 -0
  88. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/tic.py +0 -0
  89. {thyra-3.0.0 → thyra-3.0.2}/thyra/resampling/types.py +0 -0
  90. {thyra-3.0.0 → thyra-3.0.2}/thyra/tools/__init__.py +0 -0
  91. {thyra-3.0.0 → thyra-3.0.2}/thyra/tools/check_ontology.py +0 -0
  92. {thyra-3.0.0 → thyra-3.0.2}/thyra/tools/make_example_data.py +0 -0
  93. {thyra-3.0.0 → thyra-3.0.2}/thyra/utils/__init__.py +0 -0
  94. {thyra-3.0.0 → thyra-3.0.2}/thyra/utils/bruker_exceptions.py +0 -0
  95. {thyra-3.0.0 → thyra-3.0.2}/thyra/utils/logging_config.py +0 -0
  96. {thyra-3.0.0 → thyra-3.0.2}/thyra/utils/windows_paths.py +0 -0
  97. {thyra-3.0.0 → thyra-3.0.2}/thyra/utils/zarr_atomic_write.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: thyra
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: A modern Python library for converting Mass Spectrometry Imaging (MSI) data into SpatialData/Zarr format - your portal to spatial omics
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -42,8 +42,8 @@ Requires-Dist: tqdm (>=4.50.0)
42
42
  Requires-Dist: zarr (>=3.1.4,<3.2)
43
43
  Project-URL: Bug Tracker, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/issues
44
44
  Project-URL: Changelog, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/CHANGELOG.md
45
- Project-URL: Contributing, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/CONTRIBUTING.md
46
- Project-URL: Documentation, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra#readme
45
+ Project-URL: Contributing, https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/contributing/
46
+ Project-URL: Documentation, https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/
47
47
  Project-URL: Discussions, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/discussions
48
48
  Project-URL: Homepage, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra
49
49
  Project-URL: Repository, https://github.com/M4i-Imaging-Mass-Spectrometry/thyra
@@ -83,7 +83,7 @@ for a full walkthrough, including the published example dataset
83
83
  - **Memory Efficient**: Handles large datasets (100+ GB) through streaming processing
84
84
  - **Optical Alignment**: Automatic MSI-to-optical image registration for Bruker data
85
85
  - **Multi-Region Support**: Handles slides with multiple tissue sections
86
- - **Resampling**: Physics-aware mass axis resampling (enabled by default)
86
+ - **Resampling**: Physics-aware mass axis resampling (on by default in the CLI; opt-in from the Python API)
87
87
  - **3D Support**: Process volume data or treat as 2D slices
88
88
  - **Cross-Platform**: Windows, macOS, and Linux
89
89
 
@@ -32,7 +32,7 @@ for a full walkthrough, including the published example dataset
32
32
  - **Memory Efficient**: Handles large datasets (100+ GB) through streaming processing
33
33
  - **Optical Alignment**: Automatic MSI-to-optical image registration for Bruker data
34
34
  - **Multi-Region Support**: Handles slides with multiple tissue sections
35
- - **Resampling**: Physics-aware mass axis resampling (enabled by default)
35
+ - **Resampling**: Physics-aware mass axis resampling (on by default in the CLI; opt-in from the Python API)
36
36
  - **3D Support**: Process volume data or treat as 2D slices
37
37
  - **Cross-Platform**: Windows, macOS, and Linux
38
38
 
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [tool.poetry]
6
6
  name = "thyra"
7
- version = "3.0.0"
7
+ version = "3.0.2"
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 = ["Theodoros Visvikis <t.visvikis@maastrichtuniversity.nl>"]
10
10
  maintainers = ["Theodoros Visvikis <t.visvikis@maastrichtuniversity.nl>"]
@@ -12,7 +12,7 @@ license = "MIT"
12
12
  readme = "README.md"
13
13
  homepage = "https://github.com/M4i-Imaging-Mass-Spectrometry/thyra"
14
14
  repository = "https://github.com/M4i-Imaging-Mass-Spectrometry/thyra"
15
- documentation = "https://github.com/M4i-Imaging-Mass-Spectrometry/thyra#readme"
15
+ documentation = "https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/"
16
16
  keywords = [
17
17
  "mass-spectrometry",
18
18
  "imaging",
@@ -50,7 +50,9 @@ packages = [{include = "thyra"}]
50
50
  "Bug Tracker" = "https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/issues"
51
51
  "Discussions" = "https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/discussions"
52
52
  "Changelog" = "https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/CHANGELOG.md"
53
- "Contributing" = "https://github.com/M4i-Imaging-Mass-Spectrometry/thyra/blob/main/CONTRIBUTING.md"
53
+ # There is no CONTRIBUTING.md at the repository root; the guide lives at
54
+ # docs/contributing.md and is published as this page.
55
+ "Contributing" = "https://M4i-Imaging-Mass-Spectrometry.github.io/thyra/contributing/"
54
56
 
55
57
  [tool.poetry.dependencies]
56
58
  python = ">=3.12, <3.14"
@@ -36,7 +36,7 @@ warnings.filterwarnings(
36
36
  category=FutureWarning,
37
37
  )
38
38
 
39
- __version__ = "3.0.0"
39
+ __version__ = "3.0.2"
40
40
 
41
41
  # Import key components - avoid wildcard imports
42
42
  try:
@@ -272,12 +272,17 @@ class SpatialData3DConverter(BaseSpatialDataConverter):
272
272
  n_x, n_y, n_z = self._dimensions
273
273
 
274
274
  if n_z > 1:
275
- # True 3D TIC image
275
+ # True 3D TIC image. The accumulator is indexed [y, x, z] (see
276
+ # _create_data_structures), while Image3DModel declares
277
+ # (c, z, y, x) -- so the axes have to be *moved*. This used to
278
+ # relabel the shape instead, which reshapes nothing and left
279
+ # every volume whose extents were not all equal permuted: a
280
+ # 5(x) x 3(y) x 2(z) acquisition was stored as (1, 3, 5, 2).
276
281
  tic_values = data_structures["tic_values"]
277
- z_size, y_size, x_size = tic_values.shape
282
+ tic_values_zyx = np.transpose(tic_values, (2, 0, 1))
278
283
 
279
284
  # Add channel dimension for 3D image
280
- tic_values_with_channel = tic_values.reshape(1, z_size, y_size, x_size)
285
+ tic_values_with_channel = tic_values_zyx[np.newaxis, ...]
281
286
 
282
287
  # The image is intrinsically in raster pixel indices.
283
288
  # Scale into physical micrometers so "global" agrees with
@@ -461,6 +461,7 @@ class StreamingSpatialDataConverter(BaseSpatialDataConverter):
461
461
  nnz_per_row = np.zeros(n_rows, dtype=np.int64)
462
462
  total_nnz = 0
463
463
  pixel_count = 0
464
+ n_out_of_bounds = 0
464
465
 
465
466
  region_map, region_total, region_count = self._init_region_accumulators(n_cols)
466
467
 
@@ -476,11 +477,22 @@ class StreamingSpatialDataConverter(BaseSpatialDataConverter):
476
477
  mz_indices, resampled_ints = self._process_spectrum(mzs, intensities)
477
478
  nnz = len(mz_indices)
478
479
 
479
- nnz_per_row[pixel_idx] = nnz
480
- total_nnz += nnz
481
-
480
+ # The row count and the TIC are both indexed by grid
481
+ # position, so both need the bounds check: a coordinate
482
+ # outside the declared dimensions would otherwise wrap
483
+ # round and land on an unrelated pixel. Unlike the PCS
484
+ # pre-scan the guard sits outside the `nnz > 0` test,
485
+ # because this assignment is unconditional -- a wrapped
486
+ # empty spectrum would overwrite a real row's count with
487
+ # zero. total_nnz travels with nnz_per_row so that
488
+ # indptr[-1] keeps matching the array size derived from
489
+ # it; pass 2 skips the same spectra.
482
490
  if 0 <= y < n_y and 0 <= x < n_x:
491
+ nnz_per_row[pixel_idx] = nnz
492
+ total_nnz += nnz
483
493
  tic_values[y, x] = float(np.sum(resampled_ints))
494
+ else:
495
+ n_out_of_bounds += 1
484
496
 
485
497
  if nnz > 0:
486
498
  np.add.at(total_intensity, mz_indices, resampled_ints)
@@ -500,6 +512,15 @@ class StreamingSpatialDataConverter(BaseSpatialDataConverter):
500
512
  pbar.update(1)
501
513
 
502
514
  logger.info(f"Pass 1 complete: {total_nnz:,} total non-zeros")
515
+ if n_out_of_bounds:
516
+ logger.warning(
517
+ "%d spectra sat outside the declared %dx%d grid and were "
518
+ "skipped. Previously they were written to a wrapped-round "
519
+ "row index, silently overwriting an unrelated pixel.",
520
+ n_out_of_bounds,
521
+ n_x,
522
+ n_y,
523
+ )
503
524
 
504
525
  # Build indptr from nnz counts
505
526
  indptr = np.zeros(n_rows + 1, dtype=np.int64)
@@ -628,7 +649,11 @@ class StreamingSpatialDataConverter(BaseSpatialDataConverter):
628
649
  mz_indices, resampled_ints = self._process_spectrum(mzs, intensities)
629
650
  nnz = len(mz_indices)
630
651
 
631
- if nnz > 0:
652
+ # Same bounds check as pass 1, and it has to be the same
653
+ # one: that pass reserved no room for a spectrum outside
654
+ # the grid, so writing it here would overrun the row it
655
+ # wrapped onto and displace that row's own entries.
656
+ if nnz > 0 and 0 <= y < n_y and 0 <= x < n_x:
632
657
  pos = write_pos[pixel_idx]
633
658
  positions = np.arange(pos, pos + nnz)
634
659
  buf_positions.append(positions)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes