napari-spatialdata 0.5.6__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.github/release.yml +1 -0
  2. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.github/workflows/test.yml +1 -1
  3. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.mypy.ini +0 -1
  4. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.pre-commit-config.yaml +9 -5
  5. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/PKG-INFO +19 -6
  6. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/README.md +13 -2
  7. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/conf.py +1 -1
  8. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/setup.cfg +5 -3
  9. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_model.py +1 -1
  10. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_scatterwidgets.py +1 -1
  11. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_version.py +16 -3
  12. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_view.py +1 -1
  13. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_viewer.py +8 -2
  14. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/utils/_test_utils.py +5 -9
  15. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/utils/_utils.py +1 -1
  16. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata.egg-info/PKG-INFO +19 -6
  17. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata.egg-info/requires.txt +6 -3
  18. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/conftest.py +5 -2
  19. napari_spatialdata-0.6.0/tests/plots/groundtruth/Images_can_add_element_image.png +0 -0
  20. napari_spatialdata-0.6.0/tests/plots/groundtruth/Images_can_add_element_label.png +0 -0
  21. napari_spatialdata-0.6.0/tests/plots/groundtruth/Images_can_add_element_multiple.png +0 -0
  22. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_cli.py +4 -0
  23. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_interactive.py +8 -1
  24. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_scatterwidgets.py +5 -0
  25. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_spatialdata.py +3 -1
  26. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_utils.py +2 -0
  27. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_viewer.py +5 -1
  28. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_widgets.py +5 -1
  29. napari_spatialdata-0.5.6/tests/plots/groundtruth/Images_can_add_element_image.png +0 -0
  30. napari_spatialdata-0.5.6/tests/plots/groundtruth/Images_can_add_element_label.png +0 -0
  31. napari_spatialdata-0.5.6/tests/plots/groundtruth/Images_can_add_element_multiple.png +0 -0
  32. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.github/BENCHMARK_FAIL_TEMPLATE.md +0 -0
  33. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.github/dependabot.yml +0 -0
  34. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.github/workflows/benchmarks.yml +0 -0
  35. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.github/workflows/benchmarks_report.yml +0 -0
  36. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.github/workflows/release.yml +0 -0
  37. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.gitignore +0 -0
  38. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.napari/DESCRIPTION.md +0 -0
  39. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/.readthedocs.yaml +0 -0
  40. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/LICENSE +0 -0
  41. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/MANIFEST.in +0 -0
  42. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/asv.conf.json +0 -0
  43. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/benchmarks/Readme.md +0 -0
  44. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/benchmarks/__init__.py +0 -0
  45. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/benchmarks/benchmark.in +0 -0
  46. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/benchmarks/benchmark.txt +0 -0
  47. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/benchmarks/benchmark_model.py +0 -0
  48. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/benchmarks/benchmark_qt_widget.py +0 -0
  49. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/Makefile +0 -0
  50. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/_static/.gitkeep +0 -0
  51. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/_templates/.gitkeep +0 -0
  52. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/_templates/autosummary/class.rst +0 -0
  53. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/api.md +0 -0
  54. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/changelog.md +0 -0
  55. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/cli.md +0 -0
  56. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/contributing.md +0 -0
  57. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/extensions/typed_returns.py +0 -0
  58. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/index.md +0 -0
  59. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/limitations.md +0 -0
  60. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/make.bat +0 -0
  61. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/notebooks/mibitof_analysis.ipynb +0 -0
  62. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/notebooks/nanostring_analysis.ipynb +0 -0
  63. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/notebooks/scatterwidget.ipynb +0 -0
  64. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/notebooks/scatterwidget_annotation.ipynb +0 -0
  65. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/notebooks/spatialdata.ipynb +0 -0
  66. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/references.bib +0 -0
  67. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/docs/references.md +0 -0
  68. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/examples/spatialdata_empty.py +0 -0
  69. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/examples/spatialdata_visium.py +0 -0
  70. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/pyproject.toml +0 -0
  71. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/__init__.py +0 -0
  72. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/__main__.py +0 -0
  73. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_annotationwidgets.py +0 -0
  74. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_interactive.py +0 -0
  75. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_reader.py +0 -0
  76. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_sdata_widgets.py +0 -0
  77. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/_widgets.py +0 -0
  78. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/constants/__init__.py +0 -0
  79. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/constants/_constants.py +0 -0
  80. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/constants/_pkg_constants.py +0 -0
  81. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/constants/_utils.py +0 -0
  82. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/constants/config.py +0 -0
  83. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/napari.yaml +0 -0
  84. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/resources/exclamation.png +0 -0
  85. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/resources/icons8-home-48.png +0 -0
  86. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/resources/icons8-pencil-drawing-50.png +0 -0
  87. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/resources/icons8-polygon-80.png +0 -0
  88. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/resources/icons8-rectangle-48.png +0 -0
  89. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/utils/__init__.py +0 -0
  90. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/utils/_categoricals_utils.py +0 -0
  91. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata/utils/_viewer_utils.py +0 -0
  92. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata.egg-info/SOURCES.txt +0 -0
  93. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata.egg-info/dependency_links.txt +0 -0
  94. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata.egg-info/entry_points.txt +0 -0
  95. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/src/napari_spatialdata.egg-info/top_level.txt +0 -0
  96. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/__init__.py +0 -0
  97. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_aaa.py +0 -0
  98. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tests/test_view.py +0 -0
  99. {napari_spatialdata-0.5.6 → napari_spatialdata-0.6.0}/tox.ini +0 -0
@@ -4,6 +4,7 @@ changelog:
4
4
  - release-ignore
5
5
  authors:
6
6
  - pre-commit-ci
7
+ - pre-commit-ci[bot]
7
8
  categories:
8
9
  - title: Added
9
10
  labels:
@@ -69,7 +69,7 @@ jobs:
69
69
  uses: actions/upload-artifact@v4
70
70
  with:
71
71
  name: plotting-results-${{ matrix.python-version }}-${{ matrix.platform }}
72
- path: /home/runner/work/napari-spatialdata/napari-spatialdata/tests/plots/*
72
+ path: /Users/runner/work/napari-spatialdata/napari-spatialdata/tests/plots/generated/*
73
73
 
74
74
  test_benchmarks:
75
75
  name: test benchmarks
@@ -1,7 +1,6 @@
1
1
  [mypy]
2
2
  mypy_path = napari-spatialdata
3
3
  python_version = 3.10
4
- plugins = numpy.typing.mypy_plugin
5
4
 
6
5
  ignore_errors = False
7
6
  warn_redundant_casts = True
@@ -7,7 +7,7 @@ default_stages:
7
7
  minimum_pre_commit_version: 2.9.3
8
8
  repos:
9
9
  - repo: https://github.com/pre-commit/mirrors-mypy
10
- rev: v1.15.0
10
+ rev: v1.17.1
11
11
  hooks:
12
12
  - id: mypy
13
13
  additional_dependencies: [numpy>=1.23]
@@ -22,7 +22,7 @@ repos:
22
22
  hooks:
23
23
  - id: prettier
24
24
  - repo: https://github.com/pre-commit/pre-commit-hooks
25
- rev: v5.0.0
25
+ rev: v6.0.0
26
26
  hooks:
27
27
  - id: detect-private-key
28
28
  - id: check-merge-conflict
@@ -30,8 +30,8 @@ repos:
30
30
  - id: check-symlinks
31
31
  - id: check-added-large-files
32
32
  - id: check-executables-have-shebangs
33
- - id: fix-encoding-pragma
34
- args: [--remove]
33
+ # - id: fix-encoding-pragma
34
+ # args: [--remove]
35
35
  - id: end-of-file-fixer
36
36
  - id: mixed-line-ending
37
37
  args: [--fix=lf]
@@ -49,7 +49,11 @@ repos:
49
49
  hooks:
50
50
  - id: blacken-docs
51
51
  - repo: https://github.com/astral-sh/ruff-pre-commit
52
- rev: v0.11.6
52
+ rev: v0.12.8
53
53
  hooks:
54
54
  - id: ruff
55
55
  args: [--fix, --exit-non-zero-on-fix]
56
+ - repo: https://github.com/asottile/pyupgrade
57
+ rev: v3.20.0
58
+ hooks:
59
+ - id: pyupgrade
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: napari-spatialdata
3
- Version: 0.5.6
3
+ Version: 0.6.0
4
4
  Summary: Interactive visualization of spatial omics data with napari
5
5
  Home-page: https://github.com/scverse/napari-spatialdata.git
6
6
  Author: giovanni palla
@@ -27,11 +27,11 @@ License-File: LICENSE
27
27
  Requires-Dist: anndata
28
28
  Requires-Dist: click
29
29
  Requires-Dist: cycler
30
- Requires-Dist: dask>=2024.4.1
30
+ Requires-Dist: dask<=2024.11.2,>=2024.4.1
31
31
  Requires-Dist: geopandas
32
32
  Requires-Dist: loguru
33
33
  Requires-Dist: matplotlib
34
- Requires-Dist: napari<0.5.6,>=0.4.19.post1
34
+ Requires-Dist: napari>=0.6.2
35
35
  Requires-Dist: napari-matplotlib
36
36
  Requires-Dist: numba
37
37
  Requires-Dist: numpy
@@ -50,6 +50,8 @@ Requires-Dist: typing_extensions>=4.8.0
50
50
  Requires-Dist: vispy
51
51
  Requires-Dist: xarray
52
52
  Requires-Dist: xarray-datatree
53
+ Provides-Extra: bermuda
54
+ Requires-Dist: bermuda; extra == "bermuda"
53
55
  Provides-Extra: test
54
56
  Requires-Dist: loguru; extra == "test"
55
57
  Requires-Dist: pytest; extra == "test"
@@ -72,7 +74,7 @@ Requires-Dist: sphinx-qt-documentation; extra == "doc"
72
74
  Requires-Dist: myst-nb; extra == "doc"
73
75
  Requires-Dist: squidpy; extra == "doc"
74
76
  Provides-Extra: readthedocs
75
- Requires-Dist: pydantic<2; extra == "readthedocs"
77
+ Requires-Dist: pydantic>2; extra == "readthedocs"
76
78
  Provides-Extra: pre
77
79
  Requires-Dist: spatialdata>=0.1.0-pre0; extra == "pre"
78
80
  Provides-Extra: all
@@ -91,10 +93,14 @@ Dynamic: license-file
91
93
  [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/scverse/napari-spatialdata/main.svg)](https://results.pre-commit.ci/latest/github/scverse/napari-spatialdata/main)
92
94
  [![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-spatialdata)](https://napari-hub.org/plugins/napari-spatialdata)
93
95
  [![DOI](https://zenodo.org/badge/477021400.svg)](https://zenodo.org/badge/latestdoi/477021400)
96
+ [![Documentation][badge-pypi]][link-pypi]
97
+ [![Anaconda-Server Badge](https://anaconda.org/conda-forge/napari-spatialdata/badges/version.svg)](https://anaconda.org/conda-forge/napari-spatialdata)
98
+
99
+ [badge-pypi]: https://badge.fury.io/py/napari-spatialdata.svg
100
+ [link-pypi]: https://pypi.org/project/napari-spatialdata/
94
101
 
95
102
  This repository contains a napari plugin for interactively exploring and annotating
96
- SpatialData objects. Here you can find the [napari-spatialdata documentation]
97
- (https://spatialdata.scverse.org/projects/napari/en/stable/notebooks/spatialdata.html). `napari-spatialdata` is part of the `SpatialData` ecosystem. To learn more about SpatialData, please see the [spatialdata documentation](https://spatialdata.scverse.org/).
103
+ SpatialData objects. Here you can find the [napari-spatialdata documentation](https://spatialdata.scverse.org/projects/napari/en/stable/notebooks/spatialdata.html). `napari-spatialdata` is part of the `SpatialData` ecosystem. To learn more about SpatialData, please see the [spatialdata documentation](https://spatialdata.scverse.org/).
98
104
 
99
105
  ## Installation
100
106
 
@@ -104,6 +110,13 @@ You can install `napari-spatialdata` via [pip]:
104
110
 
105
111
  The `all` command will install the qt bindings `PyQt5`.
106
112
 
113
+ Napari now also includes multiple triangulation backends. These improve the speed by which a napari 'Shapes' layer gets
114
+ loaded (this does not improve the speed of editing large numbers of shapes yet!). See also the napari
115
+ [documentation](https://napari.org/stable/guides/triangulation.html) and already slightly older [blog post](https://napari.org/island-dispatch/blog/triangles_speedup_beta.html). For installation via
116
+ pip:
117
+
118
+ pip install napari-spatialdata[all, bermuda]
119
+
107
120
  You can find more details on this in the [installation instructions](https://spatialdata.scverse.org/en/stable/installation.html).
108
121
 
109
122
  ## Using napari-spatialdata as default zarr reader
@@ -10,10 +10,14 @@
10
10
  [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/scverse/napari-spatialdata/main.svg)](https://results.pre-commit.ci/latest/github/scverse/napari-spatialdata/main)
11
11
  [![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-spatialdata)](https://napari-hub.org/plugins/napari-spatialdata)
12
12
  [![DOI](https://zenodo.org/badge/477021400.svg)](https://zenodo.org/badge/latestdoi/477021400)
13
+ [![Documentation][badge-pypi]][link-pypi]
14
+ [![Anaconda-Server Badge](https://anaconda.org/conda-forge/napari-spatialdata/badges/version.svg)](https://anaconda.org/conda-forge/napari-spatialdata)
15
+
16
+ [badge-pypi]: https://badge.fury.io/py/napari-spatialdata.svg
17
+ [link-pypi]: https://pypi.org/project/napari-spatialdata/
13
18
 
14
19
  This repository contains a napari plugin for interactively exploring and annotating
15
- SpatialData objects. Here you can find the [napari-spatialdata documentation]
16
- (https://spatialdata.scverse.org/projects/napari/en/stable/notebooks/spatialdata.html). `napari-spatialdata` is part of the `SpatialData` ecosystem. To learn more about SpatialData, please see the [spatialdata documentation](https://spatialdata.scverse.org/).
20
+ SpatialData objects. Here you can find the [napari-spatialdata documentation](https://spatialdata.scverse.org/projects/napari/en/stable/notebooks/spatialdata.html). `napari-spatialdata` is part of the `SpatialData` ecosystem. To learn more about SpatialData, please see the [spatialdata documentation](https://spatialdata.scverse.org/).
17
21
 
18
22
  ## Installation
19
23
 
@@ -23,6 +27,13 @@ You can install `napari-spatialdata` via [pip]:
23
27
 
24
28
  The `all` command will install the qt bindings `PyQt5`.
25
29
 
30
+ Napari now also includes multiple triangulation backends. These improve the speed by which a napari 'Shapes' layer gets
31
+ loaded (this does not improve the speed of editing large numbers of shapes yet!). See also the napari
32
+ [documentation](https://napari.org/stable/guides/triangulation.html) and already slightly older [blog post](https://napari.org/island-dispatch/blog/triangles_speedup_beta.html). For installation via
33
+ pip:
34
+
35
+ pip install napari-spatialdata[all, bermuda]
36
+
26
37
  You can find more details on this in the [installation instructions](https://spatialdata.scverse.org/en/stable/installation.html).
27
38
 
28
39
  ## Using napari-spatialdata as default zarr reader
@@ -23,7 +23,7 @@ print(napari_spatialdata.__file__) # noqa: T201
23
23
  info = metadata("napari-spatialdata")
24
24
  project_name = info["Name"]
25
25
  author = info["Author"]
26
- copyright = f"{datetime.now():%Y}, {author}."
26
+ copyright = f"{datetime.now():%Y}, {author}"
27
27
  version = info["Version"]
28
28
  repository_url = f"https://github.com/scverse/{project_name}"
29
29
 
@@ -34,11 +34,11 @@ install_requires =
34
34
  anndata
35
35
  click
36
36
  cycler
37
- dask>=2024.4.1
37
+ dask>=2024.4.1,<=2024.11.2
38
38
  geopandas
39
39
  loguru
40
40
  matplotlib
41
- napari>=0.4.19.post1,<0.5.6
41
+ napari>=0.6.2
42
42
  napari-matplotlib
43
43
  numba
44
44
  numpy
@@ -61,6 +61,8 @@ package_dir =
61
61
  =src
62
62
 
63
63
  [options.extras_require]
64
+ bermuda =
65
+ bermuda
64
66
  test =
65
67
  loguru
66
68
  pytest
@@ -83,7 +85,7 @@ doc =
83
85
  myst-nb
84
86
  squidpy
85
87
  readthedocs =
86
- pydantic<2
88
+ pydantic>2
87
89
  pre =
88
90
  spatialdata>=0.1.0-pre0
89
91
  all =
@@ -246,7 +246,7 @@ class DataModel:
246
246
  return self._adata_layer
247
247
 
248
248
  @adata_layer.setter
249
- def adata_layer(self, adata_layer: str) -> None:
249
+ def adata_layer(self, adata_layer: str | None) -> None:
250
250
  self._adata_layer = adata_layer
251
251
 
252
252
  @property
@@ -114,7 +114,7 @@ class ScatterListWidget(AListWidget):
114
114
  elif self.getAttribute() == "obsm":
115
115
  if TYPE_CHECKING:
116
116
  assert isinstance(text, int | str)
117
- self.text = text # type: ignore[assignment]
117
+ self.text = text
118
118
  super().setIndex(text)
119
119
 
120
120
  @property
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '0.5.6'
21
- __version_tuple__ = version_tuple = (0, 5, 6)
31
+ __version__ = version = '0.6.0'
32
+ __version_tuple__ = version_tuple = (0, 6, 0)
33
+
34
+ __commit_id__ = commit_id = 'gc95e3e271'
@@ -426,7 +426,7 @@ class QtAdataViewWidget(QWidget):
426
426
  super().__init__()
427
427
 
428
428
  self._viewer = napari_viewer
429
- self._model = model if model else napari_viewer.window._dock_widgets["SpatialData"].widget().viewer_model._model
429
+ self._model = model if model else napari_viewer.window.dock_widgets["SpatialData"].viewer_model.model
430
430
 
431
431
  self._select_layer()
432
432
  self._viewer.layers.selection.events.changed.connect(self._select_layer)
@@ -18,7 +18,7 @@ from shapely import Polygon
18
18
  from spatialdata import get_element_annotators, get_element_instances
19
19
  from spatialdata._core.query.relational_query import _left_join_spatialelement_table
20
20
  from spatialdata._types import ArrayLike
21
- from spatialdata.models import PointsModel, ShapesModel, TableModel, force_2d, get_channels
21
+ from spatialdata.models import PointsModel, ShapesModel, TableModel, force_2d, get_channel_names
22
22
  from spatialdata.transformations import Affine, Identity
23
23
 
24
24
  from napari_spatialdata._model import DataModel
@@ -52,6 +52,12 @@ class SpatialDataViewer(QObject):
52
52
  self.sdata = sdata
53
53
  self._model = DataModel()
54
54
  self._layer_event_caches: dict[str, list[dict[str, Any]]] = {}
55
+ self.viewer.bind_key("Ctrl-L", self._inherit_metadata, overwrite=True)
56
+
57
+ logger.warning(
58
+ "Due to Shift-L being used as shortcut in napari, it is being deprecated and might not link a new layer"
59
+ " to an existing SpatialData object in the viewer. Please use ⌘-L on MacOS or else Ctrl-L.",
60
+ )
55
61
  self.viewer.bind_key("Shift-L", self._inherit_metadata, overwrite=True)
56
62
  self.viewer.bind_key("Shift-E", self._save_to_sdata, overwrite=True)
57
63
  self.viewer.layers.events.inserted.connect(self._on_layer_insert)
@@ -467,7 +473,7 @@ class SpatialDataViewer(QObject):
467
473
  affine = _get_transform(sdata.images[original_name], selected_cs)
468
474
  rgb_image, rgb = _adjust_channels_order(element=sdata.images[original_name])
469
475
 
470
- channels = ("RGB(A)",) if rgb else get_channels(sdata.images[original_name])
476
+ channels = ("RGB(A)",) if rgb else get_channel_names(sdata.images[original_name])
471
477
 
472
478
  adata = AnnData(shape=(0, len(channels)), var=pd.DataFrame(index=channels))
473
479
 
@@ -71,26 +71,22 @@ def click_list_widget_item(
71
71
  raise ValueError(f"{click} is not a valid click")
72
72
 
73
73
 
74
- def take_screenshot(viewer: napari.Viewer, canvas_only: bool = False) -> ArrayLike | Any:
75
- """Take screenshot of the Napari viewer.
74
+ def export_figure(viewer: napari.Viewer) -> ArrayLike | Any:
75
+ """Export figure from the data displayed in the Napari viewer.
76
76
 
77
77
  Parameters
78
78
  ----------
79
79
  viewer
80
80
  Instance of napari Viewer.
81
- canvas_only
82
- If True, only the canvas is saved, not the viewer window.
83
81
 
84
82
  Returns
85
83
  -------
86
- The screenshot as an array.
84
+ The exported figure as an array.
87
85
  """
88
- logger.info("Taking screenshot of viewer")
89
- # to distinguish between the black of the image background and the black of the napari background (now white)
90
- # TODO (melonora): remove when napari allows for getting rid of margins.
86
+ logger.info("Export figure of data in viewer canvas")
91
87
  old_theme = viewer.theme
92
88
  viewer.theme = "light"
93
- interactive_screenshot = viewer.screenshot(canvas_only=canvas_only, size=(202, 284))
89
+ interactive_screenshot = viewer.export_figure()
94
90
  viewer.theme = old_theme
95
91
  viewer.close()
96
92
 
@@ -487,7 +487,7 @@ def get_napari_version() -> packaging.version.Version:
487
487
 
488
488
 
489
489
  @contextmanager
490
- def block_signals(widget: QObject) -> Generator[None, None, None]:
490
+ def block_signals(widget: QObject) -> Generator[None]:
491
491
  try:
492
492
  widget.blockSignals(True)
493
493
  yield
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: napari-spatialdata
3
- Version: 0.5.6
3
+ Version: 0.6.0
4
4
  Summary: Interactive visualization of spatial omics data with napari
5
5
  Home-page: https://github.com/scverse/napari-spatialdata.git
6
6
  Author: giovanni palla
@@ -27,11 +27,11 @@ License-File: LICENSE
27
27
  Requires-Dist: anndata
28
28
  Requires-Dist: click
29
29
  Requires-Dist: cycler
30
- Requires-Dist: dask>=2024.4.1
30
+ Requires-Dist: dask<=2024.11.2,>=2024.4.1
31
31
  Requires-Dist: geopandas
32
32
  Requires-Dist: loguru
33
33
  Requires-Dist: matplotlib
34
- Requires-Dist: napari<0.5.6,>=0.4.19.post1
34
+ Requires-Dist: napari>=0.6.2
35
35
  Requires-Dist: napari-matplotlib
36
36
  Requires-Dist: numba
37
37
  Requires-Dist: numpy
@@ -50,6 +50,8 @@ Requires-Dist: typing_extensions>=4.8.0
50
50
  Requires-Dist: vispy
51
51
  Requires-Dist: xarray
52
52
  Requires-Dist: xarray-datatree
53
+ Provides-Extra: bermuda
54
+ Requires-Dist: bermuda; extra == "bermuda"
53
55
  Provides-Extra: test
54
56
  Requires-Dist: loguru; extra == "test"
55
57
  Requires-Dist: pytest; extra == "test"
@@ -72,7 +74,7 @@ Requires-Dist: sphinx-qt-documentation; extra == "doc"
72
74
  Requires-Dist: myst-nb; extra == "doc"
73
75
  Requires-Dist: squidpy; extra == "doc"
74
76
  Provides-Extra: readthedocs
75
- Requires-Dist: pydantic<2; extra == "readthedocs"
77
+ Requires-Dist: pydantic>2; extra == "readthedocs"
76
78
  Provides-Extra: pre
77
79
  Requires-Dist: spatialdata>=0.1.0-pre0; extra == "pre"
78
80
  Provides-Extra: all
@@ -91,10 +93,14 @@ Dynamic: license-file
91
93
  [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/scverse/napari-spatialdata/main.svg)](https://results.pre-commit.ci/latest/github/scverse/napari-spatialdata/main)
92
94
  [![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-spatialdata)](https://napari-hub.org/plugins/napari-spatialdata)
93
95
  [![DOI](https://zenodo.org/badge/477021400.svg)](https://zenodo.org/badge/latestdoi/477021400)
96
+ [![Documentation][badge-pypi]][link-pypi]
97
+ [![Anaconda-Server Badge](https://anaconda.org/conda-forge/napari-spatialdata/badges/version.svg)](https://anaconda.org/conda-forge/napari-spatialdata)
98
+
99
+ [badge-pypi]: https://badge.fury.io/py/napari-spatialdata.svg
100
+ [link-pypi]: https://pypi.org/project/napari-spatialdata/
94
101
 
95
102
  This repository contains a napari plugin for interactively exploring and annotating
96
- SpatialData objects. Here you can find the [napari-spatialdata documentation]
97
- (https://spatialdata.scverse.org/projects/napari/en/stable/notebooks/spatialdata.html). `napari-spatialdata` is part of the `SpatialData` ecosystem. To learn more about SpatialData, please see the [spatialdata documentation](https://spatialdata.scverse.org/).
103
+ SpatialData objects. Here you can find the [napari-spatialdata documentation](https://spatialdata.scverse.org/projects/napari/en/stable/notebooks/spatialdata.html). `napari-spatialdata` is part of the `SpatialData` ecosystem. To learn more about SpatialData, please see the [spatialdata documentation](https://spatialdata.scverse.org/).
98
104
 
99
105
  ## Installation
100
106
 
@@ -104,6 +110,13 @@ You can install `napari-spatialdata` via [pip]:
104
110
 
105
111
  The `all` command will install the qt bindings `PyQt5`.
106
112
 
113
+ Napari now also includes multiple triangulation backends. These improve the speed by which a napari 'Shapes' layer gets
114
+ loaded (this does not improve the speed of editing large numbers of shapes yet!). See also the napari
115
+ [documentation](https://napari.org/stable/guides/triangulation.html) and already slightly older [blog post](https://napari.org/island-dispatch/blog/triangles_speedup_beta.html). For installation via
116
+ pip:
117
+
118
+ pip install napari-spatialdata[all, bermuda]
119
+
107
120
  You can find more details on this in the [installation instructions](https://spatialdata.scverse.org/en/stable/installation.html).
108
121
 
109
122
  ## Using napari-spatialdata as default zarr reader
@@ -1,11 +1,11 @@
1
1
  anndata
2
2
  click
3
3
  cycler
4
- dask>=2024.4.1
4
+ dask<=2024.11.2,>=2024.4.1
5
5
  geopandas
6
6
  loguru
7
7
  matplotlib
8
- napari<0.5.6,>=0.4.19.post1
8
+ napari>=0.6.2
9
9
  napari-matplotlib
10
10
  numba
11
11
  numpy
@@ -28,6 +28,9 @@ xarray-datatree
28
28
  [all]
29
29
  napari[pyqt5]
30
30
 
31
+ [bermuda]
32
+ bermuda
33
+
31
34
  [doc]
32
35
  sphinx>=4.5
33
36
  sphinx-book-theme>=1.0.0
@@ -47,7 +50,7 @@ squidpy
47
50
  spatialdata>=0.1.0-pre0
48
51
 
49
52
  [readthedocs]
50
- pydantic<2
53
+ pydantic>2
51
54
 
52
55
  [test]
53
56
  loguru
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  import random
4
5
  import string
5
6
  from abc import ABC, ABCMeta
@@ -22,7 +23,9 @@ from spatialdata._types import ArrayLike
22
23
  from spatialdata.datasets import blobs
23
24
  from spatialdata.models import TableModel
24
25
 
25
- from napari_spatialdata.utils._test_utils import save_image, take_screenshot
26
+ from napari_spatialdata.utils._test_utils import export_figure, save_image
27
+
28
+ OFFSCREEN = os.environ.get("QT_QPA_PLATFORM", "") == "offscreen"
26
29
 
27
30
  HERE: Path = Path(__file__).parent
28
31
 
@@ -214,7 +217,7 @@ class PlotTester(ABC):
214
217
  out_path = ACTUAL / f"{basename}.png"
215
218
 
216
219
  viewer = napari.current_viewer()
217
- save_image(take_screenshot(viewer, canvas_only=True), out_path)
220
+ save_image(export_figure(viewer), str(out_path))
218
221
 
219
222
  if tolerance is None:
220
223
  # see https://github.com/theislab/squidpy/pull/302
@@ -1,5 +1,6 @@
1
1
  from pathlib import Path
2
2
 
3
+ import pytest
3
4
  from click.testing import CliRunner
4
5
  from napari.viewer import Viewer
5
6
  from spatialdata.datasets import blobs
@@ -14,6 +15,7 @@ def test_view_exists():
14
15
  Viewer.close_all()
15
16
 
16
17
 
18
+ @pytest.mark.usefixtures("mock_app_model")
17
19
  def test_view_path_not_exists():
18
20
  runner = CliRunner()
19
21
  with runner.isolated_filesystem():
@@ -26,6 +28,8 @@ def test_view_path_not_exists():
26
28
  Viewer.close_all()
27
29
 
28
30
 
31
+ # added due to this https://github.com/napari/napari/issues/8214#issuecomment-3188565917
32
+ @pytest.mark.usefixtures("mock_app_model")
29
33
  def test_view_path_is_dir():
30
34
  runner = CliRunner()
31
35
  with runner.isolated_filesystem():
@@ -11,13 +11,15 @@ from spatialdata import SpatialData
11
11
  from spatialdata.models import Image2DModel
12
12
 
13
13
  from napari_spatialdata._interactive import Interactive
14
- from tests.conftest import PlotTester, PlotTesterMeta
14
+ from tests.conftest import OFFSCREEN, PlotTester, PlotTesterMeta
15
15
 
16
16
  ARM_PROBLEM = (
17
17
  parse_version(version("numpy")) < parse_version("2") and sys.platform == "darwin" and platform.machine() == "arm64"
18
18
  )
19
19
 
20
20
 
21
+ @pytest.mark.skipif(OFFSCREEN, reason="Not running in offscreen mode")
22
+ @pytest.mark.usefixtures("mock_app_model")
21
23
  class TestImages(PlotTester, metaclass=PlotTesterMeta):
22
24
  def test_plot_can_add_element_image(self, sdata_blobs: SpatialData):
23
25
  blobs_image = Image2DModel.parse(sdata_blobs["blobs_image"], c_coords=("r", "g", "b"))
@@ -51,6 +53,8 @@ class TestImages(PlotTester, metaclass=PlotTesterMeta):
51
53
  Viewer.close_all()
52
54
 
53
55
 
56
+ @pytest.mark.skipif(OFFSCREEN, reason="Not running in offscreen mode")
57
+ @pytest.mark.usefixtures("mock_app_model")
54
58
  def test_plot_can_add_element_switch_cs(sdata_blobs: SpatialData):
55
59
  i = Interactive(sdata=sdata_blobs, headless=True)
56
60
  i.add_element(element="blobs_image", element_coordinate_system="global", view_element_system=True)
@@ -59,6 +63,8 @@ def test_plot_can_add_element_switch_cs(sdata_blobs: SpatialData):
59
63
  Viewer.close_all()
60
64
 
61
65
 
66
+ @pytest.mark.skipif(OFFSCREEN, reason="Not running in offscreen mode")
67
+ @pytest.mark.usefixtures("mock_app_model")
62
68
  class TestInteractive(PlotTester, metaclass=PlotTesterMeta):
63
69
  def test_get_layer_existing(self, sdata_blobs: SpatialData):
64
70
  i = Interactive(sdata=sdata_blobs, headless=True)
@@ -88,6 +94,7 @@ class TestInteractive(PlotTester, metaclass=PlotTesterMeta):
88
94
  Viewer.close_all()
89
95
 
90
96
 
97
+ @pytest.mark.skipif(OFFSCREEN, reason="Not running in offscreen mode")
91
98
  @pytest.mark.skipif(ARM_PROBLEM, reason="Test will segfault on ARM with numpy < 2")
92
99
  @pytest.mark.use_thread_loader
93
100
  def test_load_data_in_thread(make_napari_viewer: Callable[[], Viewer], sdata_blobs: SpatialData, qtbot: QtBot) -> None:
@@ -7,6 +7,9 @@ from shapely.geometry import Polygon
7
7
  from napari_spatialdata._model import DataModel
8
8
  from napari_spatialdata._scatterwidgets import PlotWidget
9
9
 
10
+ pytestmark = pytest.mark.usefixtures("mock_app_model")
11
+
12
+
10
13
  DATA_LEN = 100
11
14
 
12
15
 
@@ -281,6 +284,8 @@ def test_add_roi_to_plot(qtbot, plot_widget, prepare_discrete_test_data):
281
284
  assert len(rois) == 1, "There should be exactly one ROI in the scatter_plot"
282
285
 
283
286
 
287
+ # sometimes this test fails due to a faulty clean-up, for example in the last failing
288
+ # commit here: https://github.com/scverse/napari-spatialdata/pull/360
284
289
  def test_remove_roi_double_click(qtbot, plot_widget, prepare_discrete_test_data):
285
290
  """Test changing coordinates and removing ROI."""
286
291
  roi = pg.RectROI([0, 0], [1, 1])
@@ -24,6 +24,7 @@ from napari_spatialdata import QtAdataViewWidget
24
24
  from napari_spatialdata._sdata_widgets import CoordinateSystemWidget, ElementWidget, SdataWidget
25
25
  from napari_spatialdata.constants import config
26
26
  from napari_spatialdata.utils._test_utils import click_list_widget_item, get_center_pos_listitem
27
+ from tests.conftest import OFFSCREEN
27
28
 
28
29
  RNG = np.random.default_rng(seed=0)
29
30
 
@@ -94,6 +95,7 @@ def test_sdatawidget_labels(qtbot, make_napari_viewer: Any, blobs_extra_cs: Spat
94
95
  assert widget.viewer_model.viewer.layers[0].metadata.get("region_key") is not None
95
96
 
96
97
 
98
+ @pytest.mark.skipif(OFFSCREEN, reason="Not running in offscreen mode")
97
99
  def test_sdatawidget_points(caplog, make_napari_viewer: Any, blobs_extra_cs: SpatialData):
98
100
  config.POINT_THRESHOLD = 400
99
101
  blobs_extra_cs.points["many_points"] = PointsModel.parse(
@@ -133,7 +135,7 @@ def test_sdatawidget_points(caplog, make_napari_viewer: Any, blobs_extra_cs: Spa
133
135
  with caplog.at_level(logging.INFO):
134
136
  assert (
135
137
  "Subsampling points because the number of points exceeds the currently supported 400."
136
- in caplog.records[0].message
138
+ in caplog.records[1].message
137
139
  )
138
140
  assert widget.viewer_model.viewer.layers[1].metadata.get("adata").n_obs == 400
139
141
  del blobs_extra_cs.points["many_points"]
@@ -15,6 +15,7 @@ from napari_spatialdata.utils._utils import (
15
15
  _position_cluster_labels,
16
16
  _set_palette,
17
17
  )
18
+ from tests.conftest import OFFSCREEN
18
19
 
19
20
 
20
21
  def test_get_categorical(adata_labels: AnnData):
@@ -84,6 +85,7 @@ def test_min_max_norm(vec: np.ndarray) -> None:
84
85
  assert (out.min(), out.max()) == (0, 1)
85
86
 
86
87
 
88
+ @pytest.mark.skipif(OFFSCREEN, reason="Not running in offscreen mode")
87
89
  def test_logger(caplog, prepare_continuous_test_data, adata_labels: AnnData, make_napari_viewer: Any):
88
90
  from napari_spatialdata._model import DataModel
89
91
  from napari_spatialdata._scatterwidgets import PlotWidget
@@ -1,4 +1,5 @@
1
1
  import re
2
+ import sys
2
3
  from pathlib import Path
3
4
 
4
5
  import numpy as np
@@ -32,7 +33,10 @@ def test_metadata_inheritance(qtbot, make_napari_viewer: any):
32
33
  layers = widget.viewer_model.viewer.layers
33
34
  sdatas = [layer.metadata["sdata"] for layer in layers if "sdata" in layer.metadata]
34
35
  assert all(sdatas[0] is sdata for sdata in sdatas[1:])
35
- qtbot.keyPress(viewer.window._qt_viewer, Qt.Key_L, Qt.ShiftModifier)
36
+ if sys.platform == "darwin":
37
+ qtbot.keyPress(viewer.window._qt_viewer, Qt.Key_L, Qt.MetaModifier)
38
+ else:
39
+ qtbot.keyPress(viewer.window._qt_viewer, Qt.Key_L, Qt.ControlModifier)
36
40
 
37
41
  # Now we did let the shapes layer inherit sdata from another layer. The number of unique spatialdata objects
38
42
  # should still be one.
@@ -91,7 +91,7 @@ def test_change_layer(
91
91
  sdata_blobs: SpatialData,
92
92
  ) -> None:
93
93
  table = sdata_blobs["table"].copy()
94
- table.obs["region"] = "blobs_labels"
94
+ table.obs["region"] = pd.Categorical(["blobs_labels"] * table.n_obs)
95
95
  table.uns["spatialdata_attrs"]["region"] = "blobs_labels"
96
96
  table.var_names = pd.Index([i + "_second" for i in table.var_names])
97
97
  sdata_blobs["second_table"] = table
@@ -267,6 +267,7 @@ def test_layer_selection(make_napari_viewer: Any, image: ArrayLike, widget: Any,
267
267
  assert widget.model.adata.n_obs == 0
268
268
 
269
269
 
270
+ @pytest.mark.usefixtures("mock_app_model")
270
271
  def test_export_no_rois(adata_labels):
271
272
  """Test export for no rois situation."""
272
273
 
@@ -277,6 +278,7 @@ def test_export_no_rois(adata_labels):
277
278
  assert scatter_widget.status_label.text() == "Status: No rois selected."
278
279
 
279
280
 
281
+ @pytest.mark.usefixtures("mock_app_model")
280
282
  def test_export_no_name(adata_labels, mocker):
281
283
  """Test export - no column name provided."""
282
284
 
@@ -290,6 +292,7 @@ def test_export_no_name(adata_labels, mocker):
290
292
  assert scatter_widget._model.adata.obs.equals(adata_labels.obs)
291
293
 
292
294
 
295
+ @pytest.mark.usefixtures("mock_app_model")
293
296
  def test_new_annotation(adata_labels, annotation_values, mocker):
294
297
  """Test export - adding a new annotation."""
295
298
 
@@ -304,6 +307,7 @@ def test_new_annotation(adata_labels, annotation_values, mocker):
304
307
  assert np.array_equal(scatter_widget._model.adata.obs.test, annotation_values)
305
308
 
306
309
 
310
+ @pytest.mark.usefixtures("mock_app_model")
307
311
  def test_old_annotation(adata_labels, annotation_values, mocker):
308
312
  """Test updating existing annotation."""
309
313