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.
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.pre-commit-config.yaml +4 -4
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.readthedocs.yaml +1 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/CHANGELOG.md +27 -1
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/PKG-INFO +11 -7
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/README.md +7 -3
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/_version.py +2 -2
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/pyproject.toml +3 -3
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/centroids.py +7 -1
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/rasterize_bins.py +11 -2
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/relational_query.py +11 -3
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/spatial_query.py +64 -64
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/spatialdata.py +72 -12
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/__init__.py +2 -2
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/_utils.py +2 -62
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/format.py +126 -19
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/io_points.py +14 -13
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/io_raster.py +39 -16
- spatialdata-0.2.2/src/spatialdata/_io/io_shapes.py +112 -0
- spatialdata-0.2.2/src/spatialdata/_io/io_table.py +95 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_io/io_zarr.py +4 -3
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/dataloader/datasets.py +13 -9
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/datasets.py +1 -1
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/models/models.py +66 -29
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/testing.py +1 -1
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/ngff_transformations.py +4 -4
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_rasterize_bins.py +12 -3
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_transform.py +3 -2
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/query/test_relational_query.py +13 -3
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/query/test_spatial_query.py +113 -13
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/test_centroids.py +11 -3
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_format.py +16 -6
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_readwrite.py +4 -4
- spatialdata-0.2.2/tests/io/test_versions.py +28 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/models/test_models.py +71 -0
- spatialdata-0.2.0rc1/src/spatialdata/_io/io_shapes.py +0 -88
- spatialdata-0.2.0rc1/src/spatialdata/_io/io_table.py +0 -30
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.bumpversion.cfg +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.editorconfig +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/codecov.yml +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/workflows/build.yaml +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/workflows/release.yaml +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.github/workflows/test.yaml +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.gitignore +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.gitmodules +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/.mypy.ini +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/Dockerfile +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/LICENSE +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/__main__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/_deepcopy.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/_elements.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/concatenate.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/data_extent.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/aggregate.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/map.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/rasterize.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/transform.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/vectorize.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/query/_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_logging.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_types.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/dataloader/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/models/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/models/_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/ngff/ngff_coordinate_system.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/operations.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/transformations/transformations.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/conftest.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_aggregations.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_map.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_rasterize.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_spatialdata_operations.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/operations/test_vectorize.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/query/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/test_data_extent.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/core/test_deepcopy.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/data/multipolygon.json +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/data/points.json +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/data/polygon.json +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/dataloader/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/dataloader/test_datasets.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/datasets/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/datasets/test_datasets.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_metadata.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_multi_table.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/io/test_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/models/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/conftest.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/test_ngff_coordinate_system.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/ngff/test_ngff_transformations.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/test_transformations.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/transformations/test_transformations_utils.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/utils/__init__.py +0 -0
- {spatialdata-0.2.0rc1 → spatialdata-0.2.2}/tests/utils/test_element_utils.py +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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.
|
|
30
|
+
rev: v0.5.6
|
|
31
31
|
hooks:
|
|
32
32
|
- id: ruff
|
|
33
33
|
args: [--fix, --exit-non-zero-on-fix]
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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/
|
|
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
|
-
|
|
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://
|
|
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/
|
|
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
|
-
|
|
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://
|
|
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).
|
|
@@ -25,7 +25,7 @@ dependencies = [
|
|
|
25
25
|
"anndata>=0.9.1",
|
|
26
26
|
"click",
|
|
27
27
|
"dask-image",
|
|
28
|
-
"dask>=2024.
|
|
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.
|
|
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
|
|
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)
|
{spatialdata-0.2.0rc1 → spatialdata-0.2.2}/src/spatialdata/_core/operations/rasterize_bins.py
RENAMED
|
@@ -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
|
-
|
|
156
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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[
|
|
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
|
-
|
|
82
|
-
#
|
|
83
|
-
|
|
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
|
-
|
|
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=
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
497
|
-
|
|
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,
|
|
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
|
|