spatialdata 0.2.0rc1__tar.gz → 0.2.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 (111) hide show
  1. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.pre-commit-config.yaml +4 -4
  2. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.readthedocs.yaml +1 -0
  3. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/CHANGELOG.md +27 -1
  4. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/PKG-INFO +11 -7
  5. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/README.md +7 -3
  6. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/_version.py +2 -2
  7. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/pyproject.toml +3 -3
  8. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/centroids.py +7 -1
  9. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/rasterize_bins.py +11 -2
  10. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/relational_query.py +11 -3
  11. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/spatial_query.py +64 -64
  12. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/spatialdata.py +72 -12
  13. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/__init__.py +2 -2
  14. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/_utils.py +2 -62
  15. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/format.py +126 -19
  16. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/io_points.py +14 -13
  17. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/io_raster.py +39 -16
  18. spatialdata-0.2.2/src/spatialdata/_io/io_shapes.py +112 -0
  19. spatialdata-0.2.2/src/spatialdata/_io/io_table.py +95 -0
  20. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/io_zarr.py +4 -3
  21. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/dataloader/datasets.py +13 -9
  22. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/datasets.py +1 -1
  23. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/models/models.py +66 -29
  24. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/testing.py +1 -1
  25. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/ngff_transformations.py +4 -4
  26. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_rasterize_bins.py +12 -3
  27. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_transform.py +3 -2
  28. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/query/test_relational_query.py +13 -3
  29. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/query/test_spatial_query.py +113 -13
  30. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/test_centroids.py +11 -3
  31. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_format.py +16 -6
  32. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_readwrite.py +4 -4
  33. spatialdata-0.2.2/tests/io/test_versions.py +28 -0
  34. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/models/test_models.py +71 -0
  35. spatialdata-0.2.0rc1/src/spatialdata/_io/io_shapes.py +0 -88
  36. spatialdata-0.2.0rc1/src/spatialdata/_io/io_table.py +0 -30
  37. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.bumpversion.cfg +0 -0
  38. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.editorconfig +0 -0
  39. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/codecov.yml +0 -0
  40. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/workflows/build.yaml +0 -0
  41. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/workflows/release.yaml +0 -0
  42. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/workflows/test.yaml +0 -0
  43. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.gitignore +0 -0
  44. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.gitmodules +0 -0
  45. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.mypy.ini +0 -0
  46. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/Dockerfile +0 -0
  47. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/LICENSE +0 -0
  48. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/__init__.py +0 -0
  49. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/__main__.py +0 -0
  50. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/__init__.py +0 -0
  51. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/_deepcopy.py +0 -0
  52. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/_elements.py +0 -0
  53. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/_utils.py +0 -0
  54. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/concatenate.py +0 -0
  55. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/data_extent.py +0 -0
  56. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/__init__.py +0 -0
  57. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/_utils.py +0 -0
  58. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/aggregate.py +0 -0
  59. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/map.py +0 -0
  60. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/rasterize.py +0 -0
  61. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/transform.py +0 -0
  62. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/vectorize.py +0 -0
  63. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/__init__.py +0 -0
  64. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/_utils.py +0 -0
  65. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_logging.py +0 -0
  66. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_types.py +0 -0
  67. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_utils.py +0 -0
  68. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/dataloader/__init__.py +0 -0
  69. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/models/__init__.py +0 -0
  70. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/models/_utils.py +0 -0
  71. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/__init__.py +0 -0
  72. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/_utils.py +0 -0
  73. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/__init__.py +0 -0
  74. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/_utils.py +0 -0
  75. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/ngff_coordinate_system.py +0 -0
  76. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/operations.py +0 -0
  77. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/transformations.py +0 -0
  78. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/__init__.py +0 -0
  79. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/conftest.py +0 -0
  80. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/__init__.py +0 -0
  81. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/__init__.py +0 -0
  82. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_aggregations.py +0 -0
  83. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_map.py +0 -0
  84. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_rasterize.py +0 -0
  85. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_spatialdata_operations.py +0 -0
  86. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_vectorize.py +0 -0
  87. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/query/__init__.py +0 -0
  88. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/test_data_extent.py +0 -0
  89. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/test_deepcopy.py +0 -0
  90. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/data/multipolygon.json +0 -0
  91. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/data/points.json +0 -0
  92. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/data/polygon.json +0 -0
  93. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/dataloader/__init__.py +0 -0
  94. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/dataloader/test_datasets.py +0 -0
  95. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/datasets/__init__.py +0 -0
  96. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/datasets/test_datasets.py +0 -0
  97. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/__init__.py +0 -0
  98. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_metadata.py +0 -0
  99. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_multi_table.py +0 -0
  100. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_utils.py +0 -0
  101. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/models/__init__.py +0 -0
  102. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/__init__.py +0 -0
  103. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/__init__.py +0 -0
  104. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/conftest.py +0 -0
  105. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/test_ngff_coordinate_system.py +0 -0
  106. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/test_ngff_transformations.py +0 -0
  107. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/test_transformations.py +0 -0
  108. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/test_transformations_utils.py +0 -0
  109. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/utils/__init__.py +0 -0
  110. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/utils/test_element_utils.py +0 -0
  111. {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/utils/test_testing.py +0 -0
@@ -9,7 +9,7 @@ ci:
9
9
  skip: []
10
10
  repos:
11
11
  - repo: https://github.com/psf/black
12
- rev: 24.4.2
12
+ rev: 24.8.0
13
13
  hooks:
14
14
  - id: black
15
15
  - repo: https://github.com/pre-commit/mirrors-prettier
@@ -17,17 +17,17 @@ repos:
17
17
  hooks:
18
18
  - id: prettier
19
19
  - repo: https://github.com/asottile/blacken-docs
20
- rev: 1.16.0
20
+ rev: 1.18.0
21
21
  hooks:
22
22
  - id: blacken-docs
23
23
  - repo: https://github.com/pre-commit/mirrors-mypy
24
- rev: v1.10.0
24
+ rev: v1.11.1
25
25
  hooks:
26
26
  - id: mypy
27
27
  additional_dependencies: [numpy, types-requests]
28
28
  exclude: tests/|docs/
29
29
  - repo: https://github.com/astral-sh/ruff-pre-commit
30
- rev: v0.4.10
30
+ rev: v0.5.6
31
31
  hooks:
32
32
  - id: ruff
33
33
  args: [--fix, --exit-non-zero-on-fix]
@@ -13,6 +13,7 @@ python:
13
13
  path: .
14
14
  extra_requirements:
15
15
  - docs
16
+ - torch
16
17
  submodules:
17
18
  include:
18
19
  - "docs/tutorials/notebooks"
@@ -8,12 +8,37 @@ and this project adheres to [Semantic Versioning][].
8
8
  [keep a changelog]: https://keepachangelog.com/en/1.0.0/
9
9
  [semantic versioning]: https://semver.org/spec/v2.0.0.html
10
10
 
11
- ## [0.2.0] - 2024-xx-xx
11
+ ## [0.x.x] - 2024-xx-xx
12
+
13
+ ## [0.2.2] - 2024-08-07
14
+
15
+ # Major
16
+
17
+ - New disk format for shapes using `GeoParquet` (the change is backward compatible) #542
18
+
19
+ # Minor
20
+
21
+ - Add `return_background` as argument to `get_centroids` and `get_element_instances` #621
22
+ - Ability to save data using older disk formats #542
23
+
24
+ # Fixed
25
+
26
+ - Circles validation now checks for inf or nan radii #653
27
+ - Bug with table name in torch dataset #654 @LLehner
28
+
29
+ ## [0.2.1] - 2024-07-04
30
+
31
+ ### Minor
32
+
33
+ - Relaxing `spatial-image` package requirement #616
34
+
35
+ ## [0.2.0] - 2024-07-03
12
36
 
13
37
  ### Changed
14
38
 
15
39
  - Using `DataArray` directly instead of the subclass `SpatialImage` (removed install constraint for the `spatial_image` package) #587
16
40
  - Using `DataTree` directly instead of the subclass `MultiscaleSpatialImage` (removed install constraint for the `multiscale_spatial_image` package) #587
41
+ - Changed `element`parameter (deprecation in v0.3.0) of `transform_element_to_coordinate_system` to a string `element_name` #611
17
42
 
18
43
  ### Major
19
44
 
@@ -34,6 +59,7 @@ and this project adheres to [Semantic Versioning][].
34
59
  ### Fixed
35
60
 
36
61
  - Preserve channel names of multi-scale images in `transform` (#379)
62
+ - Fix `filter_by_coordinate_system` with SpatialData object having a table not annotating an element (#619)
37
63
 
38
64
  ## [0.1.2] - 2024-03-30
39
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: spatialdata
3
- Version: 0.2.0rc1
3
+ Version: 0.2.2
4
4
  Summary: Spatial data format.
5
5
  Project-URL: Documentation, https://spatialdata.scverse.org/en/latest
6
6
  Project-URL: Source, https://github.com/scverse/spatialdata.git
@@ -41,7 +41,7 @@ Requires-Python: >=3.9
41
41
  Requires-Dist: anndata>=0.9.1
42
42
  Requires-Dist: click
43
43
  Requires-Dist: dask-image
44
- Requires-Dist: dask>=2024.2.1
44
+ Requires-Dist: dask>=2024.4.1
45
45
  Requires-Dist: fsspec<=2023.6
46
46
  Requires-Dist: geopandas>=0.14
47
47
  Requires-Dist: multiscale-spatial-image>=1.0.0
@@ -56,7 +56,7 @@ Requires-Dist: scikit-image
56
56
  Requires-Dist: scipy
57
57
  Requires-Dist: setuptools
58
58
  Requires-Dist: shapely>=2.0.1
59
- Requires-Dist: spatial-image>=1.1.0
59
+ Requires-Dist: spatial-image>=1.0.0
60
60
  Requires-Dist: typing-extensions>=4.8.0
61
61
  Requires-Dist: xarray
62
62
  Requires-Dist: xarray-datatree
@@ -76,7 +76,7 @@ Requires-Dist: sphinx-pytest; extra == 'docs'
76
76
  Requires-Dist: sphinx>=4.5; extra == 'docs'
77
77
  Requires-Dist: sphinxcontrib-bibtex>=1.0.0; extra == 'docs'
78
78
  Provides-Extra: extra
79
- Requires-Dist: napari-spatialdata>=0.2.4; extra == 'extra'
79
+ Requires-Dist: napari-spatialdata[all]>=0.2.4; extra == 'extra'
80
80
  Requires-Dist: spatialdata-io; extra == 'extra'
81
81
  Requires-Dist: spatialdata-plot; extra == 'extra'
82
82
  Provides-Extra: test
@@ -135,13 +135,17 @@ Another useful resource to get started is the source code of the [`spatialdata-i
135
135
 
136
136
  ## Installation
137
137
 
138
- Check out the docs for more complete [installation instructions](https://spatialdata.scverse.org/en/latest/installation.html). To get started with the "batteries included" installation, you can install via pip:
138
+ Check out the docs for more complete [installation instructions](https://spatialdata.scverse.org/en/stable/installation.html). To get started with the "batteries included" installation, you can install via pip:
139
139
 
140
140
  ```bash
141
141
  pip install "spatialdata[extra]"
142
142
  ```
143
143
 
144
- Note: if you are using a Mac with an M1/M2 chip, please follow the installation instructions.
144
+ or via conda:
145
+
146
+ ```bash
147
+ mamba install -c conda-forge spatialdata napari-spatialdata spatialdata-io spatialdata-plot
148
+ ```
145
149
 
146
150
  ## Limitations
147
151
 
@@ -151,7 +155,7 @@ Note: if you are using a Mac with an M1/M2 chip, please follow the installation
151
155
 
152
156
  To get involved in the discussion, or if you need help to get started, you are welcome to use the following options.
153
157
 
154
- - <ins>Chat</ins> via [`scverse` Zulip](https://imagesc.zulipchat.com/#narrow/stream/329057-scverse/topic/segmentation) (public or 1 to 1).
158
+ - <ins>Chat</ins> via [`scverse` Zulip](https://scverse.zulipchat.com/#narrow/stream/315824-spatial) (public or 1 to 1).
155
159
  - <ins>Forum post</ins> in the [scverse discourse forum](https://discourse.scverse.org/).
156
160
  - <ins>Bug report/feature request</ins> via the [GitHub issue tracker][issue-tracker].
157
161
  - <ins>Zoom call</ins> as part of the SpatialData Community Meetings, held every 2 weeks on Thursday, [schedule here](https://hackmd.io/enWU826vRai-JYaL7TZaSw).
@@ -47,13 +47,17 @@ Another useful resource to get started is the source code of the [`spatialdata-i
47
47
 
48
48
  ## Installation
49
49
 
50
- Check out the docs for more complete [installation instructions](https://spatialdata.scverse.org/en/latest/installation.html). To get started with the "batteries included" installation, you can install via pip:
50
+ Check out the docs for more complete [installation instructions](https://spatialdata.scverse.org/en/stable/installation.html). To get started with the "batteries included" installation, you can install via pip:
51
51
 
52
52
  ```bash
53
53
  pip install "spatialdata[extra]"
54
54
  ```
55
55
 
56
- Note: if you are using a Mac with an M1/M2 chip, please follow the installation instructions.
56
+ or via conda:
57
+
58
+ ```bash
59
+ mamba install -c conda-forge spatialdata napari-spatialdata spatialdata-io spatialdata-plot
60
+ ```
57
61
 
58
62
  ## Limitations
59
63
 
@@ -63,7 +67,7 @@ Note: if you are using a Mac with an M1/M2 chip, please follow the installation
63
67
 
64
68
  To get involved in the discussion, or if you need help to get started, you are welcome to use the following options.
65
69
 
66
- - <ins>Chat</ins> via [`scverse` Zulip](https://imagesc.zulipchat.com/#narrow/stream/329057-scverse/topic/segmentation) (public or 1 to 1).
70
+ - <ins>Chat</ins> via [`scverse` Zulip](https://scverse.zulipchat.com/#narrow/stream/315824-spatial) (public or 1 to 1).
67
71
  - <ins>Forum post</ins> in the [scverse discourse forum](https://discourse.scverse.org/).
68
72
  - <ins>Bug report/feature request</ins> via the [GitHub issue tracker][issue-tracker].
69
73
  - <ins>Zoom call</ins> as part of the SpatialData Community Meetings, held every 2 weeks on Thursday, [schedule here](https://hackmd.io/enWU826vRai-JYaL7TZaSw).
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.2.0rc1'
16
- __version_tuple__ = version_tuple = (0, 2, 0)
15
+ __version__ = version = '0.2.2'
16
+ __version_tuple__ = version_tuple = (0, 2, 2)
@@ -25,7 +25,7 @@ dependencies = [
25
25
  "anndata>=0.9.1",
26
26
  "click",
27
27
  "dask-image",
28
- "dask>=2024.2.1",
28
+ "dask>=2024.4.1",
29
29
  "fsspec<=2023.6",
30
30
  "geopandas>=0.14",
31
31
  "multiscale_spatial_image>=1.0.0",
@@ -38,7 +38,7 @@ dependencies = [
38
38
  "rich",
39
39
  "setuptools",
40
40
  "shapely>=2.0.1",
41
- "spatial_image>=1.1.0",
41
+ "spatial_image>=1.0.0",
42
42
  "scikit-image",
43
43
  "scipy",
44
44
  "typing_extensions>=4.8.0",
@@ -73,7 +73,7 @@ torch = [
73
73
  "torch"
74
74
  ]
75
75
  extra = [
76
- "napari-spatialdata>=0.2.4",
76
+ "napari-spatialdata[all]>=0.2.4",
77
77
  "spatialdata-plot",
78
78
  "spatialdata-io",
79
79
  ]
@@ -35,6 +35,7 @@ def _validate_coordinate_system(e: SpatialElement, coordinate_system: str) -> No
35
35
  def get_centroids(
36
36
  e: SpatialElement,
37
37
  coordinate_system: str = "global",
38
+ return_background: bool = False,
38
39
  ) -> DaskDataFrame:
39
40
  """
40
41
  Get the centroids of the geometries contained in a SpatialElement, as a new Points element.
@@ -45,6 +46,8 @@ def get_centroids(
45
46
  The SpatialElement. Only points, shapes (circles, polygons and multipolygons) and labels are supported.
46
47
  coordinate_system
47
48
  The coordinate system in which the centroids are computed.
49
+ return_background
50
+ If True, the centroid of the background label (0) is included in the output.
48
51
 
49
52
  Notes
50
53
  -----
@@ -69,7 +72,7 @@ def _get_centroids_for_axis(xdata: xr.DataArray, axis: str) -> pd.DataFrame:
69
72
  -------
70
73
  pd.DataFrame
71
74
  A DataFrame containing one column, named after "axis", with the centroids of the labels along that axis.
72
- The index of the DataFrame is the collection of label values, sorted ascendingly.
75
+ The index of the DataFrame is the collection of label values, sorted in ascending order.
73
76
  """
74
77
  centroids: dict[int, float] = defaultdict(float)
75
78
  for i in xdata[axis]:
@@ -95,6 +98,7 @@ def _get_centroids_for_axis(xdata: xr.DataArray, axis: str) -> pd.DataFrame:
95
98
  def _(
96
99
  e: DataArray | DataTree,
97
100
  coordinate_system: str = "global",
101
+ return_background: bool = False,
98
102
  ) -> DaskDataFrame:
99
103
  """Get the centroids of a Labels element (2D or 3D)."""
100
104
  model = get_model(e)
@@ -110,6 +114,8 @@ def _(
110
114
  for axis in get_axes_names(e):
111
115
  dfs.append(_get_centroids_for_axis(e, axis))
112
116
  df = pd.concat(dfs, axis=1)
117
+ if not return_background and 0 in df.index:
118
+ df = df.drop(index=0) # drop the background label
113
119
  t = get_transformation(e, coordinate_system)
114
120
  centroids = PointsModel.parse(df, transformations={coordinate_system: t})
115
121
  return transform(centroids, to_coordinate_system=coordinate_system)
@@ -9,6 +9,7 @@ from dask.dataframe import DataFrame as DaskDataFrame
9
9
  from geopandas import GeoDataFrame
10
10
  from numpy.random import default_rng
11
11
  from scipy.sparse import csc_matrix
12
+ from shapely import MultiPolygon, Point, Polygon
12
13
  from skimage.transform import estimate_transform
13
14
  from xarray import DataArray
14
15
 
@@ -65,6 +66,9 @@ def rasterize_bins(
65
66
  The returned image will have one pixel for each bin, and a coordinate transformation to map the image to the
66
67
  original data orientation. In particular, the bins of Visium HD data are in a grid that is slightly rotated;
67
68
  the coordinate transformation will adjust for this, so that the returned data is aligned to the original geometries.
69
+
70
+ If `spatialdata-plot` is used to visualized the returned image, the parameter `scale='full'` needs to be passed to
71
+ `.render_shapes()`, to disable an automatic rasterization that would confict with the rasterization performed here.
68
72
  """
69
73
  element = sdata[bins]
70
74
  table = sdata.tables[table_name]
@@ -152,8 +156,13 @@ def rasterize_bins(
152
156
 
153
157
  src = np.stack([sub_table.obs[col_key] - min_col, sub_table.obs[row_key] - min_row], axis=1)
154
158
  if isinstance(sub_df, GeoDataFrame):
155
- sub_x = sub_df.geometry.x.values
156
- sub_y = sub_df.geometry.y.values
159
+ if isinstance(sub_df.iloc[0].geometry, Point):
160
+ sub_x = sub_df.geometry.x.values
161
+ sub_y = sub_df.geometry.y.values
162
+ else:
163
+ assert isinstance(sub_df.iloc[0].geometry, (Polygon, MultiPolygon))
164
+ sub_x = sub_df.centroid.x
165
+ sub_y = sub_df.centroid.y
157
166
  else:
158
167
  assert isinstance(sub_df, DaskDataFrame)
159
168
  sub_x = sub_df.x.compute().values
@@ -86,6 +86,7 @@ def _filter_table_by_element_names(table: AnnData | None, element_names: str | l
86
86
  @singledispatch
87
87
  def get_element_instances(
88
88
  element: SpatialElement,
89
+ return_background: bool = False,
89
90
  ) -> pd.Index:
90
91
  """
91
92
  Get the instances (index values) of the SpatialElement.
@@ -94,6 +95,8 @@ def get_element_instances(
94
95
  ----------
95
96
  element
96
97
  The SpatialElement.
98
+ return_background
99
+ If True, the background label (0) is included in the output.
97
100
 
98
101
  Returns
99
102
  -------
@@ -106,6 +109,7 @@ def get_element_instances(
106
109
  @get_element_instances.register(DataTree)
107
110
  def _(
108
111
  element: DataArray | DataTree,
112
+ return_background: bool = False,
109
113
  ) -> pd.Index:
110
114
  model = get_model(element)
111
115
  assert model in [Labels2DModel, Labels3DModel], "Expected a `Labels` element. Found an `Image` instead."
@@ -119,7 +123,10 @@ def _(
119
123
  xdata = next(iter(v))
120
124
  # can be slow
121
125
  instances = da.unique(xdata.data).compute()
122
- return pd.Index(np.sort(instances))
126
+ index = pd.Index(np.sort(instances))
127
+ if not return_background and 0 in index:
128
+ return index.drop(0) # drop the background label
129
+ return index
123
130
 
124
131
 
125
132
  @get_element_instances.register(GeoDataFrame)
@@ -568,7 +575,8 @@ def join_spatialelement_table(
568
575
  both the SpatialElement and table.
569
576
 
570
577
  For Points and Shapes elements every valid join for argument how is supported. For Labels elements only
571
- the ``'left'`` and ``'right_exclusive'`` joins are supported.
578
+ the ``'left'`` and ``'right_exclusive'`` joins are supported.
579
+ For Labels, the background label (0) is not included in the output and it will not be returned.
572
580
 
573
581
  Parameters
574
582
  ----------
@@ -896,7 +904,7 @@ def get_values(
896
904
  x = matched_table[:, value_key_values].X
897
905
  import scipy
898
906
 
899
- if isinstance(x, scipy.sparse.csr_matrix):
907
+ if isinstance(x, (scipy.sparse.csr_matrix, scipy.sparse.csc_matrix, scipy.sparse.coo_matrix)):
900
908
  x = x.todense()
901
909
  df = pd.DataFrame(x, columns=value_key_values)
902
910
  if origin == "obsm":
@@ -2,9 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import warnings
4
4
  from abc import abstractmethod
5
+ from collections.abc import Mapping
5
6
  from dataclasses import dataclass
6
7
  from functools import singledispatch
7
- from typing import Any, Callable
8
+ from typing import TYPE_CHECKING, Any, Callable
8
9
 
9
10
  import dask.array as da
10
11
  import dask.dataframe as dd
@@ -49,7 +50,7 @@ def _get_bounding_box_corners_in_intrinsic_coordinates(
49
50
  min_coordinate: list[Number] | ArrayLike,
50
51
  max_coordinate: list[Number] | ArrayLike,
51
52
  target_coordinate_system: str,
52
- ) -> tuple[ArrayLike, tuple[str, ...]]:
53
+ ) -> tuple[DataArray, tuple[str, ...]]:
53
54
  """Get all corners of a bounding box in the intrinsic coordinates of an element.
54
55
 
55
56
  Parameters
@@ -74,38 +75,58 @@ def _get_bounding_box_corners_in_intrinsic_coordinates(
74
75
 
75
76
  The axes of the intrinsic coordinate system.
76
77
  """
77
- from spatialdata.transformations import get_transformation
78
-
79
78
  min_coordinate = _parse_list_into_array(min_coordinate)
80
79
  max_coordinate = _parse_list_into_array(max_coordinate)
81
- # get the transformation from the element's intrinsic coordinate system
82
- # to the query coordinate space
83
- transform_to_query_space = get_transformation(element, to_coordinate_system=target_coordinate_system)
80
+
81
+ # compute the output axes of the transformation, remove c from input and output axes, return the matrix without c
82
+ # and then build an affine transformation from that
84
83
  m_without_c, input_axes_without_c, output_axes_without_c = _get_axes_of_tranformation(
85
84
  element, target_coordinate_system
86
85
  )
87
- axes, min_coordinate, max_coordinate = _adjust_bounding_box_to_real_axes(
86
+ spatial_transform = Affine(m_without_c, input_axes=input_axes_without_c, output_axes=output_axes_without_c)
87
+
88
+ # we identified 5 cases (see the responsible function for details), cases 1 and 5 correspond to invertible
89
+ # transformations; we focus on them
90
+ m_without_c_linear = m_without_c[:-1, :-1]
91
+ _ = _get_case_of_bounding_box_query(m_without_c_linear, input_axes_without_c, output_axes_without_c)
92
+
93
+ # adjust the bounding box to the real axes, dropping or adding eventually mismatching axes; the order of the axes is
94
+ # not adjusted
95
+ axes_adjusted, min_coordinate, max_coordinate = _adjust_bounding_box_to_real_axes(
88
96
  axes, min_coordinate, max_coordinate, output_axes_without_c
89
97
  )
98
+ if set(axes_adjusted) != set(output_axes_without_c):
99
+ raise ValueError("The axes of the bounding box must match the axes of the transformation.")
100
+
101
+ # let's get the bounding box corners and inverse transform then to the intrinsic coordinate system; since we are
102
+ # in case 1 or 5, the transformation is invertible
103
+ spatial_transform_bb_axes = Affine(
104
+ spatial_transform.to_affine_matrix(input_axes=input_axes_without_c, output_axes=axes_adjusted),
105
+ input_axes=input_axes_without_c,
106
+ output_axes=axes_adjusted,
107
+ )
90
108
 
91
- # get the coordinates of the bounding box corners
92
109
  bounding_box_corners = get_bounding_box_corners(
93
110
  min_coordinate=min_coordinate,
94
111
  max_coordinate=max_coordinate,
95
- axes=axes,
96
- ).data
97
-
98
- # transform the coordinates to the intrinsic coordinate system
99
- intrinsic_axes = get_axes_names(element)
100
- transform_to_intrinsic = transform_to_query_space.inverse().to_affine_matrix( # type: ignore[union-attr]
101
- input_axes=axes, output_axes=intrinsic_axes
112
+ axes=axes_adjusted,
102
113
  )
103
- rotation_matrix = transform_to_intrinsic[0:-1, 0:-1]
104
- translation = transform_to_intrinsic[0:-1, -1]
105
114
 
106
- intrinsic_bounding_box_corners = bounding_box_corners @ rotation_matrix.T + translation
115
+ inverse = spatial_transform_bb_axes.inverse()
116
+ if not isinstance(inverse, Affine):
117
+ raise RuntimeError("This should not happen")
118
+ rotation_matrix = inverse.matrix[0:-1, 0:-1]
119
+ translation = inverse.matrix[0:-1, -1]
120
+
121
+ intrinsic_bounding_box_corners = bounding_box_corners.data @ rotation_matrix.T + translation
107
122
 
108
- return intrinsic_bounding_box_corners, intrinsic_axes
123
+ return (
124
+ DataArray(
125
+ intrinsic_bounding_box_corners,
126
+ coords={"corner": range(len(bounding_box_corners)), "axis": list(inverse.output_axes)},
127
+ ),
128
+ input_axes_without_c,
129
+ )
109
130
 
110
131
 
111
132
  def _get_polygon_in_intrinsic_coordinates(
@@ -227,6 +248,11 @@ def _adjust_bounding_box_to_real_axes(
227
248
  M = np.finfo(np.float32).max - 1
228
249
  min_coordinate = np.append(min_coordinate, -M)
229
250
  max_coordinate = np.append(max_coordinate, M)
251
+ else:
252
+ indices = [axes_bb.index(ax) for ax in axes_out_without_c]
253
+ min_coordinate = min_coordinate[np.array(indices)]
254
+ max_coordinate = max_coordinate[np.array(indices)]
255
+ axes_bb = axes_out_without_c
230
256
  return axes_bb, min_coordinate, max_coordinate
231
257
 
232
258
 
@@ -407,6 +433,7 @@ def bounding_box_query(
407
433
  min_coordinate: list[Number] | ArrayLike,
408
434
  max_coordinate: list[Number] | ArrayLike,
409
435
  target_coordinate_system: str,
436
+ return_request_only: bool = False,
410
437
  filter_table: bool = True,
411
438
  **kwargs: Any,
412
439
  ) -> SpatialElement | SpatialData | None:
@@ -426,6 +453,9 @@ def bounding_box_query(
426
453
  filter_table
427
454
  If `True`, the table is filtered to only contain rows that are annotating regions
428
455
  contained within the bounding box.
456
+ return_request_only
457
+ If `True`, the function returns the bounding box coordinates in the target coordinate system.
458
+ Only valid with `DataArray` and `DataTree` elements.
429
459
 
430
460
  Returns
431
461
  -------
@@ -472,7 +502,8 @@ def _(
472
502
  min_coordinate: list[Number] | ArrayLike,
473
503
  max_coordinate: list[Number] | ArrayLike,
474
504
  target_coordinate_system: str,
475
- ) -> DataArray | DataTree | None:
505
+ return_request_only: bool = False,
506
+ ) -> DataArray | DataTree | Mapping[str, slice] | None:
476
507
  """Implement bounding box query for Spatialdata supported DataArray.
477
508
 
478
509
  Notes
@@ -493,48 +524,11 @@ def _(
493
524
  max_coordinate=max_coordinate,
494
525
  )
495
526
 
496
- # compute the output axes of the transformation, remove c from input and output axes, return the matrix without c
497
- # and then build an affine transformation from that
498
- m_without_c, input_axes_without_c, output_axes_without_c = _get_axes_of_tranformation(
499
- image, target_coordinate_system
500
- )
501
- spatial_transform = Affine(m_without_c, input_axes=input_axes_without_c, output_axes=output_axes_without_c)
502
-
503
- # we identified 5 cases (see the responsible function for details), cases 1 and 5 correspond to invertible
504
- # transformations; we focus on them
505
- m_without_c_linear = m_without_c[:-1, :-1]
506
- case = _get_case_of_bounding_box_query(m_without_c_linear, input_axes_without_c, output_axes_without_c)
507
- assert case in [1, 5]
508
-
509
- # adjust the bounding box to the real axes, dropping or adding eventually mismatching axes; the order of the axes is
510
- # not adjusted
511
- axes, min_coordinate, max_coordinate = _adjust_bounding_box_to_real_axes(
512
- axes, min_coordinate, max_coordinate, output_axes_without_c
513
- )
514
- assert set(axes) == set(output_axes_without_c)
515
-
516
- # since the order of the axes is arbitrary, let's adjust the affine transformation without c to match those axes
517
- spatial_transform_bb_axes = Affine(
518
- spatial_transform.to_affine_matrix(input_axes=input_axes_without_c, output_axes=axes),
519
- input_axes=input_axes_without_c,
520
- output_axes=axes,
521
- )
522
-
523
- # let's get the bounding box corners and inverse transform then to the intrinsic coordinate system; since we are
524
- # in case 1 or 5, the transformation is invertible
525
- bounding_box_corners = get_bounding_box_corners(
526
- min_coordinate=min_coordinate,
527
- max_coordinate=max_coordinate,
528
- axes=axes,
529
- )
530
- inverse = spatial_transform_bb_axes.inverse()
531
- assert isinstance(inverse, Affine)
532
- rotation_matrix = inverse.matrix[0:-1, 0:-1]
533
- translation = inverse.matrix[0:-1, -1]
534
- intrinsic_bounding_box_corners = DataArray(
535
- bounding_box_corners.data @ rotation_matrix.T + translation,
536
- coords={"corner": range(len(bounding_box_corners)), "axis": list(inverse.output_axes)},
527
+ intrinsic_bounding_box_corners, axes = _get_bounding_box_corners_in_intrinsic_coordinates(
528
+ image, axes, min_coordinate, max_coordinate, target_coordinate_system
537
529
  )
530
+ if TYPE_CHECKING:
531
+ assert isinstance(intrinsic_bounding_box_corners, DataArray)
538
532
 
539
533
  # build the request: now that we have the bounding box corners in the intrinsic coordinate system, we can use them
540
534
  # to build the request to query the raster data using the xarray APIs
@@ -555,6 +549,9 @@ def _(
555
549
  else:
556
550
  translation_vector.append(0)
557
551
 
552
+ if return_request_only:
553
+ return selection
554
+
558
555
  # query the data
559
556
  query_result = image.sel(selection)
560
557
  if isinstance(image, DataArray):
@@ -652,6 +649,7 @@ def _(
652
649
  max_coordinate=max_coordinate,
653
650
  target_coordinate_system=target_coordinate_system,
654
651
  )
652
+ intrinsic_bounding_box_corners = intrinsic_bounding_box_corners.data
655
653
  min_coordinate_intrinsic = intrinsic_bounding_box_corners.min(axis=0)
656
654
  max_coordinate_intrinsic = intrinsic_bounding_box_corners.max(axis=0)
657
655
 
@@ -722,14 +720,14 @@ def _(
722
720
  )
723
721
 
724
722
  # get the four corners of the bounding box
725
- (intrinsic_bounding_box_corners, intrinsic_axes) = _get_bounding_box_corners_in_intrinsic_coordinates(
723
+ (intrinsic_bounding_box_corners, _) = _get_bounding_box_corners_in_intrinsic_coordinates(
726
724
  element=polygons,
727
725
  axes=axes,
728
726
  min_coordinate=min_coordinate,
729
727
  max_coordinate=max_coordinate,
730
728
  target_coordinate_system=target_coordinate_system,
731
729
  )
732
-
730
+ intrinsic_bounding_box_corners = intrinsic_bounding_box_corners.data
733
731
  bounding_box_non_axes_aligned = Polygon(intrinsic_bounding_box_corners)
734
732
  indices = polygons.geometry.intersects(bounding_box_non_axes_aligned)
735
733
  queried = polygons[indices]
@@ -841,6 +839,7 @@ def _(
841
839
  image: DataArray | DataTree,
842
840
  polygon: Polygon | MultiPolygon,
843
841
  target_coordinate_system: str,
842
+ return_request_only: bool = False,
844
843
  **kwargs: Any,
845
844
  ) -> DataArray | DataTree | None:
846
845
  _check_deprecated_kwargs(kwargs)
@@ -852,6 +851,7 @@ def _(
852
851
  max_coordinate=[max_x, max_y],
853
852
  axes=("x", "y"),
854
853
  target_coordinate_system=target_coordinate_system,
854
+ return_request_only=return_request_only,
855
855
  )
856
856
 
857
857