spatialdata 0.2.5__tar.gz → 0.2.6__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 (113) hide show
  1. {spatialdata-0.2.5 → spatialdata-0.2.6}/.github/workflows/test.yaml +2 -2
  2. {spatialdata-0.2.5 → spatialdata-0.2.6}/.mypy.ini +1 -1
  3. {spatialdata-0.2.5 → spatialdata-0.2.6}/.pre-commit-config.yaml +6 -6
  4. {spatialdata-0.2.5 → spatialdata-0.2.6}/CHANGELOG.md +24 -2
  5. {spatialdata-0.2.5 → spatialdata-0.2.6}/PKG-INFO +6 -7
  6. {spatialdata-0.2.5 → spatialdata-0.2.6}/_version.py +2 -2
  7. {spatialdata-0.2.5 → spatialdata-0.2.6}/pyproject.toml +7 -7
  8. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/_deepcopy.py +1 -2
  9. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/centroids.py +3 -4
  10. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/concatenate.py +2 -2
  11. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/data_extent.py +5 -6
  12. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/_utils.py +2 -3
  13. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/aggregate.py +2 -3
  14. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/map.py +5 -6
  15. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/rasterize.py +1 -2
  16. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/rasterize_bins.py +3 -3
  17. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/transform.py +9 -7
  18. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/vectorize.py +4 -5
  19. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/query/_utils.py +3 -4
  20. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/query/relational_query.py +3 -4
  21. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/query/spatial_query.py +14 -9
  22. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/spatialdata.py +76 -9
  23. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_docs.py +2 -1
  24. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/_utils.py +24 -4
  25. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/format.py +2 -2
  26. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/io_points.py +2 -3
  27. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/io_raster.py +26 -23
  28. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/io_shapes.py +2 -3
  29. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/io_zarr.py +3 -4
  30. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_types.py +4 -9
  31. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_utils.py +40 -6
  32. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/dataloader/datasets.py +3 -4
  33. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/datasets.py +4 -5
  34. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/models/__init__.py +5 -2
  35. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/models/_utils.py +70 -12
  36. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/models/models.py +43 -30
  37. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/testing.py +4 -8
  38. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/_utils.py +5 -4
  39. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/ngff/ngff_coordinate_system.py +7 -7
  40. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/ngff/ngff_transformations.py +122 -120
  41. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/operations.py +7 -6
  42. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/transformations.py +17 -17
  43. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/conftest.py +2 -3
  44. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/test_aggregations.py +1 -3
  45. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/test_rasterize.py +1 -2
  46. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/test_transform.py +5 -6
  47. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/query/test_spatial_query.py +23 -8
  48. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/dataloader/__init__.py +1 -1
  49. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/test_format.py +4 -4
  50. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/test_metadata.py +32 -5
  51. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/test_pyramids_performance.py +5 -6
  52. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/test_readwrite.py +5 -4
  53. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/models/test_models.py +24 -3
  54. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/transformations/test_transformations.py +5 -5
  55. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/utils/test_element_utils.py +1 -2
  56. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/utils/test_testing.py +1 -2
  57. {spatialdata-0.2.5 → spatialdata-0.2.6}/.bumpversion.cfg +0 -0
  58. {spatialdata-0.2.5 → spatialdata-0.2.6}/.editorconfig +0 -0
  59. {spatialdata-0.2.5 → spatialdata-0.2.6}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  60. {spatialdata-0.2.5 → spatialdata-0.2.6}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  61. {spatialdata-0.2.5 → spatialdata-0.2.6}/.github/codecov.yml +0 -0
  62. {spatialdata-0.2.5 → spatialdata-0.2.6}/.github/workflows/build.yaml +0 -0
  63. {spatialdata-0.2.5 → spatialdata-0.2.6}/.github/workflows/release.yaml +0 -0
  64. {spatialdata-0.2.5 → spatialdata-0.2.6}/.gitignore +0 -0
  65. {spatialdata-0.2.5 → spatialdata-0.2.6}/.gitmodules +0 -0
  66. {spatialdata-0.2.5 → spatialdata-0.2.6}/.readthedocs.yaml +0 -0
  67. {spatialdata-0.2.5 → spatialdata-0.2.6}/Dockerfile +0 -0
  68. {spatialdata-0.2.5 → spatialdata-0.2.6}/LICENSE +0 -0
  69. {spatialdata-0.2.5 → spatialdata-0.2.6}/README.md +0 -0
  70. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/__init__.py +0 -0
  71. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/__main__.py +0 -0
  72. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/__init__.py +0 -0
  73. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/_elements.py +0 -0
  74. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/_utils.py +0 -0
  75. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/operations/__init__.py +0 -0
  76. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_core/query/__init__.py +0 -0
  77. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/__init__.py +0 -0
  78. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_io/io_table.py +0 -0
  79. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/_logging.py +0 -0
  80. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/dataloader/__init__.py +0 -0
  81. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/__init__.py +0 -0
  82. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/ngff/__init__.py +0 -0
  83. {spatialdata-0.2.5 → spatialdata-0.2.6}/src/spatialdata/transformations/ngff/_utils.py +0 -0
  84. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/__init__.py +0 -0
  85. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/__init__.py +0 -0
  86. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/__init__.py +0 -0
  87. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/test_map.py +0 -0
  88. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/test_rasterize_bins.py +0 -0
  89. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/test_spatialdata_operations.py +0 -0
  90. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/operations/test_vectorize.py +0 -0
  91. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/query/__init__.py +0 -0
  92. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/query/test_relational_query.py +0 -0
  93. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/test_centroids.py +0 -0
  94. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/test_data_extent.py +0 -0
  95. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/core/test_deepcopy.py +0 -0
  96. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/data/multipolygon.json +0 -0
  97. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/data/points.json +0 -0
  98. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/data/polygon.json +0 -0
  99. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/dataloader/test_datasets.py +0 -0
  100. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/datasets/__init__.py +0 -0
  101. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/datasets/test_datasets.py +0 -0
  102. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/__init__.py +0 -0
  103. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/test_multi_table.py +0 -0
  104. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/test_utils.py +0 -0
  105. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/io/test_versions.py +0 -0
  106. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/models/__init__.py +0 -0
  107. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/transformations/__init__.py +0 -0
  108. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/transformations/ngff/__init__.py +0 -0
  109. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/transformations/ngff/conftest.py +0 -0
  110. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/transformations/ngff/test_ngff_coordinate_system.py +0 -0
  111. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/transformations/ngff/test_ngff_transformations.py +0 -0
  112. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/transformations/test_transformations_utils.py +0 -0
  113. {spatialdata-0.2.5 → spatialdata-0.2.6}/tests/utils/__init__.py +0 -0
@@ -18,11 +18,11 @@ jobs:
18
18
  strategy:
19
19
  fail-fast: false
20
20
  matrix:
21
- python: ["3.9", "3.12"]
21
+ python: ["3.10", "3.12"]
22
22
  os: [ubuntu-latest]
23
23
  include:
24
24
  - os: macos-latest
25
- python: "3.9"
25
+ python: "3.10"
26
26
  - os: macos-latest
27
27
  python: "3.12"
28
28
  pip-flags: "--pre"
@@ -1,5 +1,5 @@
1
1
  [mypy]
2
- python_version = 3.9
2
+ python_version = 3.10
3
3
  plugins = numpy.typing.mypy_plugin
4
4
 
5
5
  ignore_errors = False
@@ -2,14 +2,14 @@ fail_fast: false
2
2
  default_language_version:
3
3
  python: python3
4
4
  default_stages:
5
- - commit
6
- - push
5
+ - pre-commit
6
+ - pre-push
7
7
  minimum_pre_commit_version: 2.16.0
8
8
  ci:
9
9
  skip: []
10
10
  repos:
11
11
  - repo: https://github.com/psf/black
12
- rev: 24.8.0
12
+ rev: 24.10.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.18.0
20
+ rev: 1.19.1
21
21
  hooks:
22
22
  - id: blacken-docs
23
23
  - repo: https://github.com/pre-commit/mirrors-mypy
24
- rev: v1.11.2
24
+ rev: v1.13.0
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.6.8
30
+ rev: v0.7.3
31
31
  hooks:
32
32
  - id: ruff
33
33
  args: [--fix, --exit-non-zero-on-fix]
@@ -8,13 +8,35 @@ 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.5] - 2024-06-11
11
+ ## [0.2.6] - 2024-11-26
12
+
13
+ ### Added
14
+
15
+ - Added `set_channel_names` method to `SpatialData` to change the channel names of an
16
+ image element in `SpatialData` #786
17
+ - Added `write_channel_names` method to `SpatialData` to overwrite channel metadata on disk
18
+ without overwriting the image array itself. #786
19
+
20
+ ### Changed
21
+
22
+ - Argument `c_coords` is moved out of kwargs for the `ImageModel`s. #779
23
+ - `get_channels` is marked for deprecation in `SpatialData` v0.3.0. Function is replaced
24
+ by `get_channel_names` #786
25
+ - Updated dependency of `multiscale-spatial-image` #792
26
+ - Adjust to new version of `xarray` with `DataTree` # 752
27
+
28
+ ### Fixed
29
+
30
+ - Updated deprecated default stages of `pre-commit` #771
31
+ - Preserve points `feature_key` during queries #794
32
+
33
+ ## [0.2.5] - 2024-11-06
12
34
 
13
35
  ### Fixed
14
36
 
15
37
  - Incompatibility issues due to newest release of `multiscale-spatial-image` #760
16
38
 
17
- ## [0.2.4] - 2024-06-11
39
+ ## [0.2.4] - 2024-11-06
18
40
 
19
41
  ### Major
20
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: spatialdata
3
- Version: 0.2.5
3
+ Version: 0.2.6
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
@@ -36,15 +36,14 @@ License: BSD 3-Clause License
36
36
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37
37
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
38
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
- License-File: LICENSE
40
- Requires-Python: >=3.9
39
+ Requires-Python: <3.13,>=3.10
41
40
  Requires-Dist: anndata>=0.9.1
42
41
  Requires-Dist: click
43
42
  Requires-Dist: dask-image
44
43
  Requires-Dist: dask>=2024.4.1
45
44
  Requires-Dist: fsspec<=2023.6
46
45
  Requires-Dist: geopandas>=0.14
47
- Requires-Dist: multiscale-spatial-image<2.0.0,>=1.0.0
46
+ Requires-Dist: multiscale-spatial-image>=2.0.2
48
47
  Requires-Dist: networkx
49
48
  Requires-Dist: numba
50
49
  Requires-Dist: numpy
@@ -59,16 +58,16 @@ Requires-Dist: setuptools
59
58
  Requires-Dist: shapely>=2.0.1
60
59
  Requires-Dist: spatial-image>=1.1.0
61
60
  Requires-Dist: typing-extensions>=4.8.0
62
- Requires-Dist: xarray-datatree
63
61
  Requires-Dist: xarray-schema
64
62
  Requires-Dist: xarray-spatial>=0.3.5
65
- Requires-Dist: xarray<2024.10.0
66
- Requires-Dist: zarr
63
+ Requires-Dist: xarray>=2024.10.0
64
+ Requires-Dist: zarr<3
67
65
  Provides-Extra: dev
68
66
  Requires-Dist: bump2version; extra == 'dev'
69
67
  Provides-Extra: docs
70
68
  Requires-Dist: ipython>=8.6.0; extra == 'docs'
71
69
  Requires-Dist: myst-nb; extra == 'docs'
70
+ Requires-Dist: sphinx-autobuild; extra == 'docs'
72
71
  Requires-Dist: sphinx-autodoc-typehints; extra == 'docs'
73
72
  Requires-Dist: sphinx-book-theme>=1.0.0; extra == 'docs'
74
73
  Requires-Dist: sphinx-copybutton; extra == 'docs'
@@ -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.5'
16
- __version_tuple__ = version_tuple = (0, 2, 5)
15
+ __version__ = version = '0.2.6'
16
+ __version_tuple__ = version_tuple = (0, 2, 6)
@@ -15,7 +15,7 @@ maintainers = [
15
15
  urls.Documentation = "https://spatialdata.scverse.org/en/latest"
16
16
  urls.Source = "https://github.com/scverse/spatialdata.git"
17
17
  urls.Home-page = "https://github.com/scverse/spatialdata.git"
18
- requires-python = ">=3.9"
18
+ requires-python = ">=3.10, <3.13" # include 3.13 once multiscale-spatial-image conflicts are resolved
19
19
  dynamic= [
20
20
  "version" # allow version to be set by git tags
21
21
  ]
@@ -28,7 +28,7 @@ dependencies = [
28
28
  "dask>=2024.4.1",
29
29
  "fsspec<=2023.6",
30
30
  "geopandas>=0.14",
31
- "multiscale_spatial_image>=1.0.0,<2.0.0",
31
+ "multiscale_spatial_image>=2.0.2",
32
32
  "networkx",
33
33
  "numba",
34
34
  "numpy",
@@ -43,11 +43,10 @@ dependencies = [
43
43
  "scikit-image",
44
44
  "scipy",
45
45
  "typing_extensions>=4.8.0",
46
- "xarray<2024.10.0",
47
- "xarray-datatree",
46
+ "xarray>=2024.10.0",
48
47
  "xarray-schema",
49
48
  "xarray-spatial>=0.3.5",
50
- "zarr",
49
+ "zarr<3",
51
50
  ]
52
51
 
53
52
  [project.optional-dependencies]
@@ -56,6 +55,7 @@ dev = [
56
55
  ]
57
56
  docs = [
58
57
  "sphinx>=4.5",
58
+ "sphinx-autobuild",
59
59
  "sphinx-book-theme>=1.0.0",
60
60
  "myst-nb",
61
61
  "sphinxcontrib-bibtex>=1.0.0",
@@ -102,7 +102,7 @@ filterwarnings = [
102
102
 
103
103
  [tool.black]
104
104
  line-length = 120
105
- target-version = ['py39']
105
+ target-version = ['py310']
106
106
  include = '\.pyi?$'
107
107
  exclude = '''
108
108
  (
@@ -147,7 +147,7 @@ exclude = [
147
147
  "setup.py",
148
148
  ]
149
149
  line-length = 120
150
- target-version = "py39"
150
+ target-version = "py310"
151
151
 
152
152
  [tool.ruff.lint]
153
153
  ignore = [
@@ -7,9 +7,8 @@ from anndata import AnnData
7
7
  from dask.array.core import Array as DaskArray
8
8
  from dask.array.core import from_array
9
9
  from dask.dataframe import DataFrame as DaskDataFrame
10
- from datatree import DataTree
11
10
  from geopandas import GeoDataFrame
12
- from xarray import DataArray
11
+ from xarray import DataArray, DataTree
13
12
 
14
13
  from spatialdata._core.spatialdata import SpatialData
15
14
  from spatialdata.models._utils import SpatialElement
@@ -7,10 +7,9 @@ import dask.array as da
7
7
  import pandas as pd
8
8
  import xarray as xr
9
9
  from dask.dataframe import DataFrame as DaskDataFrame
10
- from datatree import DataTree
11
10
  from geopandas import GeoDataFrame
12
11
  from shapely import MultiPolygon, Point, Polygon
13
- from xarray import DataArray
12
+ from xarray import DataArray, DataTree
14
13
 
15
14
  from spatialdata._core.operations.transform import transform
16
15
  from spatialdata.models import get_axes_names
@@ -86,7 +85,7 @@ def _get_centroids_for_axis(xdata: xr.DataArray, axis: str) -> pd.DataFrame:
86
85
  centroids[label_value] += count * i.values.item()
87
86
 
88
87
  all_labels_values, all_labels_counts = da.unique(xdata.data, return_counts=True)
89
- all_labels = dict(zip(all_labels_values.compute(), all_labels_counts.compute()))
88
+ all_labels = dict(zip(all_labels_values.compute(), all_labels_counts.compute(), strict=True))
90
89
  for label_value in centroids:
91
90
  centroids[label_value] /= all_labels[label_value]
92
91
  centroids = dict(sorted(centroids.items(), key=lambda x: x[0]))
@@ -132,7 +131,7 @@ def _(e: GeoDataFrame, coordinate_system: str = "global") -> DaskDataFrame:
132
131
  if isinstance(first_geometry, Point):
133
132
  xy = e.geometry.get_coordinates().values
134
133
  else:
135
- assert isinstance(first_geometry, (Polygon, MultiPolygon)), (
134
+ assert isinstance(first_geometry, Polygon | MultiPolygon), (
136
135
  f"Expected a GeoDataFrame either composed entirely of circles (Points with the `radius` column) or"
137
136
  f" Polygons/MultiPolygons. Found {type(first_geometry)} instead."
138
137
  )
@@ -51,7 +51,7 @@ def _concatenate_tables(
51
51
  raise ValueError("`instance_key` must be specified if tables have different instance keys")
52
52
 
53
53
  tables_l = []
54
- for table_region_key, table_instance_key, table in zip(region_keys, instance_keys, tables):
54
+ for table_region_key, table_instance_key, table in zip(region_keys, instance_keys, tables, strict=True):
55
55
  rename_dict = {}
56
56
  if table_region_key != region_key:
57
57
  rename_dict[table_region_key] = region_key
@@ -239,7 +239,7 @@ def _fix_ensure_unique_element_names(
239
239
  tables[new_name] = table
240
240
  tables_by_sdata.append(tables)
241
241
  sdatas_fixed = []
242
- for elements, tables in zip(elements_by_sdata, tables_by_sdata):
242
+ for elements, tables in zip(elements_by_sdata, tables_by_sdata, strict=True):
243
243
  sdata = SpatialData.init_from_elements(elements, tables=tables)
244
244
  sdatas_fixed.append(sdata)
245
245
  return sdatas_fixed
@@ -8,10 +8,9 @@ from typing import Union
8
8
  import numpy as np
9
9
  import pandas as pd
10
10
  from dask.dataframe import DataFrame as DaskDataFrame
11
- from datatree import DataTree
12
11
  from geopandas import GeoDataFrame
13
12
  from shapely import MultiPolygon, Point, Polygon
14
- from xarray import DataArray
13
+ from xarray import DataArray, DataTree
15
14
 
16
15
  from spatialdata._core.operations.transform import transform
17
16
  from spatialdata._core.spatialdata import SpatialData
@@ -71,7 +70,7 @@ def _get_extent_of_polygons_multipolygons(
71
70
  -------
72
71
  The bounding box description.
73
72
  """
74
- assert isinstance(shapes.geometry.iloc[0], (Polygon, MultiPolygon))
73
+ assert isinstance(shapes.geometry.iloc[0], Polygon | MultiPolygon)
75
74
  axes = get_axes_names(shapes)
76
75
  bounds = shapes["geometry"].bounds
77
76
  return {ax: (bounds[f"min{ax}"].min(), bounds[f"max{ax}"].max()) for ax in axes}
@@ -201,7 +200,7 @@ def _(
201
200
  new_max_coordinates_dict: dict[str, list[float]] = defaultdict(list)
202
201
  mask = [has_images, has_labels, has_points, has_shapes]
203
202
  include_spatial_elements = ["images", "labels", "points", "shapes"]
204
- include_spatial_elements = [i for (i, v) in zip(include_spatial_elements, mask) if v]
203
+ include_spatial_elements = [i for (i, v) in zip(include_spatial_elements, mask, strict=True) if v]
205
204
 
206
205
  if elements is None: # to shut up ruff
207
206
  elements = []
@@ -217,7 +216,7 @@ def _(
217
216
  assert isinstance(transformations, dict)
218
217
  coordinate_systems = list(transformations.keys())
219
218
  if coordinate_system in coordinate_systems:
220
- if isinstance(element_obj, (DaskDataFrame, GeoDataFrame)):
219
+ if isinstance(element_obj, DaskDataFrame | GeoDataFrame):
221
220
  extent = get_extent(element_obj, coordinate_system=coordinate_system, exact=exact)
222
221
  else:
223
222
  extent = get_extent(element_obj, coordinate_system=coordinate_system)
@@ -254,7 +253,7 @@ def _get_extent_of_shapes(e: GeoDataFrame) -> BoundingBoxDescription:
254
253
  first_geometry = e_temp["geometry"].iloc[0]
255
254
  if isinstance(first_geometry, Point):
256
255
  return _get_extent_of_circles(e)
257
- assert isinstance(first_geometry, (Polygon, MultiPolygon))
256
+ assert isinstance(first_geometry, Polygon | MultiPolygon)
258
257
  return _get_extent_of_polygons_multipolygons(e)
259
258
 
260
259
 
@@ -2,8 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from typing import TYPE_CHECKING
4
4
 
5
- from datatree import DataTree
6
- from xarray import DataArray
5
+ from xarray import DataArray, DataTree
7
6
 
8
7
  from spatialdata.models import SpatialElement
9
8
 
@@ -115,7 +114,7 @@ def transform_to_data_extent(
115
114
  }
116
115
 
117
116
  for _, element_name, element in sdata_raster.gen_spatial_elements():
118
- if isinstance(element, (DataArray, DataTree)):
117
+ if isinstance(element, DataArray | DataTree):
119
118
  rasterized = rasterize(
120
119
  element,
121
120
  axes=data_extent_axes,
@@ -10,11 +10,10 @@ import geopandas as gpd
10
10
  import numpy as np
11
11
  import pandas as pd
12
12
  from dask.dataframe import DataFrame as DaskDataFrame
13
- from datatree import DataTree
14
13
  from geopandas import GeoDataFrame
15
14
  from scipy import sparse
16
15
  from shapely import Point
17
- from xarray import DataArray
16
+ from xarray import DataArray, DataTree
18
17
  from xrspatial import zonal_stats
19
18
 
20
19
  from spatialdata._core.operations._utils import _parse_element
@@ -246,7 +245,7 @@ def _create_sdata_from_table_and_shapes(
246
245
  table = TableModel.parse(table, region=shapes_name, region_key=region_key, instance_key=instance_key)
247
246
 
248
247
  # labels case, needs conversion from str to int
249
- if isinstance(shapes, (DataArray, DataTree)):
248
+ if isinstance(shapes, DataArray | DataTree):
250
249
  table.obs[instance_key] = table.obs[instance_key].astype(int)
251
250
 
252
251
  if deepcopy:
@@ -1,15 +1,14 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Iterable, Mapping
3
+ from collections.abc import Callable, Iterable, Mapping
4
4
  from types import MappingProxyType
5
- from typing import TYPE_CHECKING, Any, Callable
5
+ from typing import TYPE_CHECKING, Any
6
6
 
7
7
  import dask.array as da
8
8
  from dask.array.overlap import coerce_depth
9
- from datatree import DataTree
10
- from xarray import DataArray
9
+ from xarray import DataArray, DataTree
11
10
 
12
- from spatialdata.models._utils import get_axes_names, get_channels, get_raster_model_from_data_dims
11
+ from spatialdata.models._utils import get_axes_names, get_channel_names, get_raster_model_from_data_dims
13
12
  from spatialdata.transformations import get_transformation
14
13
 
15
14
  __all__ = ["map_raster"]
@@ -122,7 +121,7 @@ def map_raster(
122
121
 
123
122
  if "c" in dims:
124
123
  if c_coords is None:
125
- c_coords = range(arr.shape[0]) if arr.shape[0] != len(get_channels(data)) else get_channels(data)
124
+ c_coords = range(arr.shape[0]) if arr.shape[0] != len(get_channel_names(data)) else get_channel_names(data)
126
125
  else:
127
126
  c_coords = None
128
127
  if transformations is None:
@@ -5,10 +5,9 @@ import datashader as ds
5
5
  import numpy as np
6
6
  from dask.array import Array as DaskArray
7
7
  from dask.dataframe import DataFrame as DaskDataFrame
8
- from datatree import DataTree
9
8
  from geopandas import GeoDataFrame
10
9
  from shapely import Point
11
- from xarray import DataArray
10
+ from xarray import DataArray, DataTree
12
11
 
13
12
  from spatialdata._core.operations._utils import _parse_element
14
13
  from spatialdata._core.operations.transform import transform
@@ -73,7 +73,7 @@ def rasterize_bins(
73
73
  """
74
74
  element = sdata[bins]
75
75
  table = sdata.tables[table_name]
76
- if not isinstance(element, (GeoDataFrame, DaskDataFrame)):
76
+ if not isinstance(element, GeoDataFrame | DaskDataFrame):
77
77
  raise ValueError("The bins should be a GeoDataFrame or a DaskDataFrame.")
78
78
 
79
79
  _, region_key, instance_key = get_table_keys(table)
@@ -94,7 +94,7 @@ def rasterize_bins(
94
94
  keys = ([value_key] if isinstance(value_key, str) else value_key) if value_key is not None else table.var_names
95
95
 
96
96
  if (value_key is None or any(key in table.var_names for key in keys)) and not isinstance(
97
- table.X, (csc_matrix, np.ndarray)
97
+ table.X, csc_matrix | np.ndarray
98
98
  ):
99
99
  raise ValueError(
100
100
  "To speed up bins rasterization, the X matrix in the table, when sparse, should be a csc_matrix matrix. "
@@ -162,7 +162,7 @@ def rasterize_bins(
162
162
  sub_x = sub_df.geometry.x.values
163
163
  sub_y = sub_df.geometry.y.values
164
164
  else:
165
- assert isinstance(sub_df.iloc[0].geometry, (Polygon, MultiPolygon))
165
+ assert isinstance(sub_df.iloc[0].geometry, Polygon | MultiPolygon)
166
166
  sub_x = sub_df.centroid.x
167
167
  sub_y = sub_df.centroid.y
168
168
  else:
@@ -10,15 +10,14 @@ import dask_image.ndinterp
10
10
  import numpy as np
11
11
  from dask.array.core import Array as DaskArray
12
12
  from dask.dataframe import DataFrame as DaskDataFrame
13
- from datatree import DataTree
14
13
  from geopandas import GeoDataFrame
15
14
  from shapely import Point
16
- from xarray import DataArray
15
+ from xarray import DataArray, Dataset, DataTree
17
16
 
18
17
  from spatialdata._core.spatialdata import SpatialData
19
18
  from spatialdata._types import ArrayLike
20
19
  from spatialdata.models import SpatialElement, get_axes_names, get_model
21
- from spatialdata.models._utils import DEFAULT_COORDINATE_SYSTEM, get_channels
20
+ from spatialdata.models._utils import DEFAULT_COORDINATE_SYSTEM, get_channel_names
22
21
  from spatialdata.transformations._utils import _get_scale, compute_coordinates, scale_radii
23
22
 
24
23
  if TYPE_CHECKING:
@@ -161,13 +160,13 @@ def _set_transformation_for_transformed_elements(
161
160
  assert to_coordinate_system is None
162
161
 
163
162
  to_prepend: BaseTransformation | None
164
- if isinstance(element, (DataArray, DataTree)):
163
+ if isinstance(element, DataArray | DataTree):
165
164
  if maintain_positioning:
166
165
  assert raster_translation is not None
167
166
  to_prepend = Sequence([raster_translation, transformation.inverse()])
168
167
  else:
169
168
  to_prepend = raster_translation
170
- elif isinstance(element, (GeoDataFrame, DaskDataFrame)):
169
+ elif isinstance(element, GeoDataFrame | DaskDataFrame):
171
170
  assert raster_translation is None
172
171
  to_prepend = transformation.inverse() if maintain_positioning else Identity()
173
172
  else:
@@ -368,7 +367,7 @@ def _(
368
367
  channel_names = None
369
368
  elif schema in (Image2DModel, Image3DModel):
370
369
  kwargs = {}
371
- channel_names = get_channels(data)
370
+ channel_names = get_channel_names(data)
372
371
  else:
373
372
  raise ValueError(f"DataTree with schema {schema} not supported")
374
373
 
@@ -393,8 +392,11 @@ def _(
393
392
  raster_translation = raster_translation_single_scale
394
393
  # we set a dummy empty dict for the transformation that will be replaced with the correct transformation for
395
394
  # each scale later in this function, when calling set_transformation()
396
- transformed_dict[k] = DataArray(transformed_dask, dims=xdata.dims, name=xdata.name, attrs={TRANSFORM_KEY: {}})
395
+ transformed_dict[k] = Dataset(
396
+ {"image": DataArray(transformed_dask, dims=xdata.dims, name=xdata.name, attrs={TRANSFORM_KEY: {}})}
397
+ )
397
398
  if channel_names is not None:
399
+ # This expression returns a dataset now.
398
400
  transformed_dict[k] = transformed_dict[k].assign_coords(c=channel_names)
399
401
 
400
402
  # mypy thinks that schema could be ShapesModel, PointsModel, ...
@@ -9,11 +9,10 @@ import pandas as pd
9
9
  import shapely
10
10
  import skimage.measure
11
11
  from dask.dataframe import DataFrame as DaskDataFrame
12
- from datatree import DataTree
13
12
  from geopandas import GeoDataFrame
14
13
  from shapely import MultiPolygon, Point, Polygon
15
14
  from skimage.measure._regionprops import RegionProperties
16
- from xarray import DataArray
15
+ from xarray import DataArray, DataTree
17
16
 
18
17
  from spatialdata._core.centroids import get_centroids
19
18
  from spatialdata._core.operations.aggregate import aggregate
@@ -106,7 +105,7 @@ def _(element: DataArray | DataTree, **kwargs: Any) -> GeoDataFrame:
106
105
  @to_circles.register(GeoDataFrame)
107
106
  def _(element: GeoDataFrame, **kwargs: Any) -> GeoDataFrame:
108
107
  assert len(kwargs) == 0
109
- if isinstance(element.geometry.iloc[0], (Polygon, MultiPolygon)):
108
+ if isinstance(element.geometry.iloc[0], Polygon | MultiPolygon):
110
109
  radius = np.sqrt(element.geometry.area / np.pi)
111
110
  centroids = _get_centroids(element)
112
111
  obs = pd.DataFrame({"radius": radius})
@@ -258,7 +257,7 @@ def _dissolve_on_overlaps(label: int, group: GeoDataFrame) -> GeoDataFrame:
258
257
 
259
258
  @to_polygons.register(GeoDataFrame)
260
259
  def _(gdf: GeoDataFrame, buffer_resolution: int = 16) -> GeoDataFrame:
261
- if isinstance(gdf.geometry.iloc[0], (Polygon, MultiPolygon)):
260
+ if isinstance(gdf.geometry.iloc[0], Polygon | MultiPolygon):
262
261
  return gdf
263
262
  if isinstance(gdf.geometry.iloc[0], Point):
264
263
  ShapesModel.validate_shapes_not_mixed_types(gdf)
@@ -274,7 +273,7 @@ def _(gdf: GeoDataFrame, buffer_resolution: int = 16) -> GeoDataFrame:
274
273
  # TODO replace with a function to copy the metadata (the parser could also do this): https://github.com/scverse/spatialdata/issues/258
275
274
  buffered_df.attrs[ShapesModel.TRANSFORM_KEY] = gdf.attrs[ShapesModel.TRANSFORM_KEY]
276
275
  return buffered_df
277
- assert isinstance(gdf.geometry.iloc[0], (Polygon, MultiPolygon))
276
+ assert isinstance(gdf.geometry.iloc[0], Polygon | MultiPolygon)
278
277
  return gdf
279
278
  raise RuntimeError("Unsupported geometry type: " f"{type(gdf.geometry.iloc[0])}")
280
279
 
@@ -5,8 +5,7 @@ from typing import Any
5
5
  import numba as nb
6
6
  import numpy as np
7
7
  from anndata import AnnData
8
- from datatree import DataTree
9
- from xarray import DataArray
8
+ from xarray import DataArray, Dataset, DataTree
10
9
 
11
10
  from spatialdata._core._elements import Tables
12
11
  from spatialdata._core.spatialdata import SpatialData
@@ -96,7 +95,7 @@ def get_bounding_box_corners(
96
95
  return output.squeeze().drop_vars("box")
97
96
 
98
97
 
99
- @nb.njit(parallel=False, nopython=True)
98
+ @nb.jit(parallel=False, nopython=True)
100
99
  def _create_slices_and_translation(
101
100
  min_values: nb.types.Array,
102
101
  max_values: nb.types.Array,
@@ -138,7 +137,7 @@ def _process_data_tree_query_result(query_result: DataTree) -> DataTree | None:
138
137
  if len(scales_to_keep) == 0:
139
138
  return None
140
139
 
141
- d = {k: d[k] for k in scales_to_keep}
140
+ d = {k: Dataset({"image": d[k]}) for k in scales_to_keep}
142
141
  result = DataTree.from_dict(d)
143
142
 
144
143
  # Rechunk the data to avoid irregular chunks
@@ -13,9 +13,8 @@ import numpy as np
13
13
  import pandas as pd
14
14
  from anndata import AnnData
15
15
  from dask.dataframe import DataFrame as DaskDataFrame
16
- from datatree import DataTree
17
16
  from geopandas import GeoDataFrame
18
- from xarray import DataArray
17
+ from xarray import DataArray, DataTree
19
18
 
20
19
  from spatialdata._core.spatialdata import SpatialData
21
20
  from spatialdata._types import ArrayLike
@@ -653,7 +652,7 @@ def join_spatialelement_table(
653
652
  if sdata is not None:
654
653
  elements_dict = _create_sdata_elements_dict_for_join(sdata, spatial_element_names)
655
654
  else:
656
- derived_sdata = SpatialData.from_elements_dict(dict(zip(spatial_element_names, spatial_elements)))
655
+ derived_sdata = SpatialData.from_elements_dict(dict(zip(spatial_element_names, spatial_elements, strict=True)))
657
656
  element_types = ["labels", "shapes", "points"]
658
657
  elements_dict = defaultdict(lambda: defaultdict(dict))
659
658
  for element_type in element_types:
@@ -919,7 +918,7 @@ def get_values(
919
918
  x = matched_table[:, value_key_values].X
920
919
  import scipy
921
920
 
922
- if isinstance(x, (scipy.sparse.csr_matrix, scipy.sparse.csc_matrix, scipy.sparse.coo_matrix)):
921
+ if isinstance(x, scipy.sparse.csr_matrix | scipy.sparse.csc_matrix | scipy.sparse.coo_matrix):
923
922
  x = x.todense()
924
923
  df = pd.DataFrame(x, columns=value_key_values)
925
924
  if origin == "obsm":