Skip to content

Commit 5da19a8

Browse files
SpatialDataWrapper v2 (#373)
* (refactor): separate out schema creation * (feat): initial pass at spatial data * (feat): working notebook minus spots (maybe a vitessce bug?) * (fix): try to get spots to appear * (chore): comment out other stuff to make widget show more * Fix visium config * (feat): firstt pass at `from_spatialdata_object` * (refactor): refactor `from_spatialdata_object` and util funcs from static methods * (feat): add url capability * (temp): spatial data fixes * (chore): change variable names * (chore): fix notebooks * (refactor): `path`->`elem` * (chore): more clean ups and fixes * (refactor): small name changes * (refactor): revert public changes * (fix): revert `.ipynb` files * (chore): fix last final args * (fix): name * (fix): remove `request_init` completely and fix `setup.cfg` * (fix): adapt to api * (chore): remove erroneous notebook * (fix): add type support * (chore): add test * (fix): automatic lint * (fix): add default for `obsEmbedding` * (fix): redefinition * (fix): `path` and `embeddingType` swapped * (fix): add annotattions to `utils.py` * (chore): add `spatialdata` dep * (fix): oops, comma for `toml` * (fix): no more python3.8 bc of spatialdata * (fix): remove whitespace * (api): small api cleanups * (fix): args bug * (fix): try spatialdata from master * (chore): lint * (chore): try `spatialdata` update * (fix): `image_elem` usage + table key * (chore): update SpatialData * (fix): `shapes_elem` * (fix): capitalize name of obs set * (fix): use table for spots * (fix): capitalization * (fix): first letter only * (fix): check `self._coordination_values` * (chore): add `obsSets` check * SpatialData changes into original SpatialData branch (#374) * Try again * Fix bugs * Lint * Update * Omit * Update pyproject.toml * Keller mark/spatial data2 (#375) * Try again * Fix bugs * Lint * Update * Omit * Add test * JS version --------- Co-authored-by: ilan-gold <[email protected]>
1 parent bc5e21c commit 5da19a8

File tree

12 files changed

+779
-102
lines changed

12 files changed

+779
-102
lines changed

.coveragerc_omit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
omit =
33
vitessce/config.py
44
vitessce/export.py
5+
vitessce/file_def_utils.py
56
vitessce/routes.py
67
vitessce/widget.py
78
vitessce/wrappers.py

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
runs-on: ubuntu-latest
88
strategy:
99
matrix:
10-
version: ['3.8', '3.12']
10+
version: ['3.9', '3.12']
1111
steps:
1212
- uses: actions/checkout@v2
1313
- uses: actions/setup-python@v2

docs/notebooks/spatial_data.ipynb

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {
6+
"nbsphinx": "hidden"
7+
},
8+
"source": [
9+
"# Vitessce Widget Tutorial"
10+
]
11+
},
12+
{
13+
"cell_type": "markdown",
14+
"metadata": {},
15+
"source": [
16+
"# Visualization of SpatialData Object"
17+
]
18+
},
19+
{
20+
"cell_type": "markdown",
21+
"metadata": {},
22+
"source": [
23+
"## 1. Import dependencies\n",
24+
"\n",
25+
"We need to import the classes and functions that we will be using from the corresponding packages."
26+
]
27+
},
28+
{
29+
"cell_type": "code",
30+
"execution_count": null,
31+
"metadata": {},
32+
"outputs": [],
33+
"source": [
34+
"%load_ext autoreload\n",
35+
"%autoreload 2\n",
36+
"\n",
37+
"from pathlib import Path\n",
38+
"from urllib.request import urlretrieve\n",
39+
"import dask\n",
40+
"\n",
41+
"dask.config.set({'dataframe.query-planning-warning': False})\n",
42+
"\n",
43+
"from spatialdata import read_zarr\n",
44+
"import scanpy as sc\n",
45+
"\n",
46+
"from vitessce import (\n",
47+
" VitessceConfig,\n",
48+
" Component as cm,\n",
49+
" CoordinationType as ct,\n",
50+
" CoordinationLevel as CL,\n",
51+
" AbstractWrapper,\n",
52+
" SpatialDataWrapper,\n",
53+
" get_initial_coordination_scope_prefix\n",
54+
")\n",
55+
"from vitessce.data_utils import (\n",
56+
" optimize_adata,\n",
57+
" VAR_CHUNK_SIZE,\n",
58+
")\n",
59+
"import zipfile\n"
60+
]
61+
},
62+
{
63+
"cell_type": "code",
64+
"execution_count": null,
65+
"metadata": {},
66+
"outputs": [],
67+
"source": [
68+
"zip_filepath = Path(\"data/visium.spatialdata.zarr.zip\")\n",
69+
"spatialdata_filepath = zip_filepath.with_suffix('')\n",
70+
"if not zip_filepath.exists():\n",
71+
" spatialdata_filepath.parent.mkdir(exist_ok=True)\n",
72+
" urlretrieve('https://s3.embl.de/spatialdata/spatialdata-sandbox/visium_associated_xenium_io.zip', zip_filepath)\n",
73+
"if not spatialdata_filepath.exists():\n",
74+
" with zipfile.ZipFile(zip_filepath,\"r\") as zip_ref:\n",
75+
" zip_ref.extractall(spatialdata_filepath.parent)\n",
76+
" (spatialdata_filepath.parent / \"data.zarr\").rename(spatialdata_filepath)"
77+
]
78+
},
79+
{
80+
"cell_type": "markdown",
81+
"metadata": {},
82+
"source": [
83+
"## 3. Load the data\n",
84+
"\n",
85+
"Note: this function may print a `FutureWarning`"
86+
]
87+
},
88+
{
89+
"cell_type": "code",
90+
"execution_count": null,
91+
"metadata": {},
92+
"outputs": [],
93+
"source": [
94+
"spatialdata = read_zarr(spatialdata_filepath)"
95+
]
96+
},
97+
{
98+
"cell_type": "code",
99+
"execution_count": null,
100+
"metadata": {},
101+
"outputs": [],
102+
"source": [
103+
"spatialdata"
104+
]
105+
},
106+
{
107+
"cell_type": "markdown",
108+
"metadata": {},
109+
"source": [
110+
"## 4. Create the Vitessce widget configuration\n",
111+
"\n",
112+
"Vitessce needs to know which pieces of data we are interested in visualizing, the visualization types we would like to use, and how we want to coordinate (or link) the views."
113+
]
114+
},
115+
{
116+
"cell_type": "markdown",
117+
"metadata": {},
118+
"source": [
119+
"### 4.1. Instantiate a `VitessceConfig` object\n",
120+
"\n",
121+
"Use the `VitessceConfig` constructor to create an instance."
122+
]
123+
},
124+
{
125+
"cell_type": "code",
126+
"execution_count": null,
127+
"metadata": {},
128+
"outputs": [],
129+
"source": [
130+
"vc = VitessceConfig(schema_version=\"1.0.16\", name='Visium SpatialData Demo (visium_associated_xenium_io)', description='From https://spatialdata.scverse.org/en/latest/tutorials/notebooks/datasets/README.html')"
131+
]
132+
},
133+
{
134+
"cell_type": "markdown",
135+
"metadata": {},
136+
"source": [
137+
"### 4.2. Add a dataset to the `VitessceConfig` instance\n",
138+
"\n",
139+
"In Vitessce, a dataset is a container for one file per data type. The `.add_dataset(name)` method on the `vc` instance sets up and returns a new dataset instance.\n",
140+
"\n",
141+
"Then, we can call the dataset's `.add_object(wrapper_object)` method to attach a \"data wrapper\" instance to our new dataset. For example, the `AnnDataWrapper` helps to configure AnnData Zarr stores for use in the Vitessce configuration.\n",
142+
"\n",
143+
"Dataset wrapper classes may require additional parameters to resolve ambiguities. For instance, `AnnData` objects may store multiple clusterings or cell type annotation columns in the `adata.obs` dataframe. We can use the parameter `obs_set_paths` to tell Vitessce that certain columns of the `obs` dataframe correspond to cell type annotations or cell clusterings."
144+
]
145+
},
146+
{
147+
"cell_type": "code",
148+
"execution_count": null,
149+
"metadata": {},
150+
"outputs": [],
151+
"source": [
152+
"[wrapper] = SpatialDataWrapper.from_object(\n",
153+
" spatialdata,\n",
154+
" table_keys_to_image_elems={\"table\": \"images/CytAssist_FFPE_Human_Breast_Cancer_full_image\"},\n",
155+
")"
156+
]
157+
},
158+
{
159+
"cell_type": "code",
160+
"execution_count": null,
161+
"metadata": {},
162+
"outputs": [],
163+
"source": [
164+
"dataset = vc.add_dataset(name='Breast Cancer Visium').add_object(wrapper)"
165+
]
166+
},
167+
{
168+
"cell_type": "code",
169+
"execution_count": null,
170+
"metadata": {},
171+
"outputs": [],
172+
"source": [
173+
"spatial = vc.add_view(\"spatialBeta\", dataset=dataset)\n",
174+
"feature_list = vc.add_view(cm.FEATURE_LIST, dataset=dataset)\n",
175+
"layer_controller = vc.add_view(\"layerControllerBeta\", dataset=dataset)\n",
176+
"vc.link_views_by_dict([spatial, layer_controller], {\n",
177+
" 'imageLayer': CL([{\n",
178+
" 'photometricInterpretation': 'RGB',\n",
179+
" }]),\n",
180+
"}, scope_prefix=get_initial_coordination_scope_prefix(\"A\", \"image\"))\n",
181+
"vc.link_views_by_dict([spatial, layer_controller], {\n",
182+
" 'spotLayer': CL([{\n",
183+
" 'obsType': 'spot',\n",
184+
" }]),\n",
185+
"}, scope_prefix=get_initial_coordination_scope_prefix(\"A\", \"obsSpots\"))\n",
186+
"obs_sets = vc.add_view(cm.OBS_SETS, dataset=dataset)\n",
187+
"vc.link_views([spatial, layer_controller, feature_list, obs_sets], ['obsType'], [wrapper.obs_type_label])"
188+
]
189+
},
190+
{
191+
"cell_type": "markdown",
192+
"metadata": {},
193+
"source": [
194+
"### 4.4. Define the visualization layout\n",
195+
"\n",
196+
"The `vc.layout(view_concat)` method allows us to specify how our views will be arranged in the layout grid in the widget. The `|` and `/` characters are magic syntax for `hconcat(v1, v2)` and `vconcat(v1, v2)`, respectively."
197+
]
198+
},
199+
{
200+
"cell_type": "code",
201+
"execution_count": null,
202+
"metadata": {},
203+
"outputs": [],
204+
"source": [
205+
"vc.layout(spatial | (feature_list / layer_controller / obs_sets));"
206+
]
207+
},
208+
{
209+
"cell_type": "code",
210+
"execution_count": null,
211+
"metadata": {
212+
"scrolled": true
213+
},
214+
"outputs": [],
215+
"source": [
216+
"vw = vc.widget()\n",
217+
"vw"
218+
]
219+
},
220+
{
221+
"cell_type": "code",
222+
"execution_count": null,
223+
"metadata": {},
224+
"outputs": [],
225+
"source": [
226+
"vw.close()\n"
227+
]
228+
},
229+
{
230+
"cell_type": "code",
231+
"execution_count": null,
232+
"metadata": {},
233+
"outputs": [],
234+
"source": [
235+
"vc.to_dict(\"\")"
236+
]
237+
},
238+
{
239+
"cell_type": "code",
240+
"execution_count": null,
241+
"metadata": {},
242+
"outputs": [],
243+
"source": []
244+
}
245+
],
246+
"metadata": {
247+
"kernelspec": {
248+
"display_name": "Python 3 (ipykernel)",
249+
"language": "python",
250+
"name": "python3"
251+
},
252+
"language_info": {
253+
"codemirror_mode": {
254+
"name": "ipython",
255+
"version": 3
256+
},
257+
"file_extension": ".py",
258+
"mimetype": "text/x-python",
259+
"name": "python",
260+
"nbconvert_exporter": "python",
261+
"pygments_lexer": "ipython3",
262+
"version": "3.9.0"
263+
}
264+
},
265+
"nbformat": 4,
266+
"nbformat_minor": 4
267+
}

pyproject.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,21 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "vitessce"
7-
version = "3.4.0"
7+
version = "3.4.1"
88
authors = [
99
{ name="Mark Keller", email="[email protected]" },
1010
]
1111
description = "Jupyter widget facilitating interactive visualization of spatial single-cell data with Vitessce"
1212
readme = "README.md"
1313
license = {file = "LICENSE"}
14-
requires-python = ">=3.7"
14+
requires-python = ">=3.9"
1515
keywords = ["ipython", "jupyter", "widgets"]
1616
classifiers = [
1717
'Development Status :: 4 - Beta',
1818
'Framework :: IPython',
1919
'Intended Audience :: Developers',
2020
'Intended Audience :: Science/Research',
2121
'Topic :: Multimedia :: Graphics',
22-
'Programming Language :: Python :: 3.8',
2322
'Programming Language :: Python :: 3.9',
2423
'Programming Language :: Python :: 3.10',
2524
'Programming Language :: Python :: 3.11',
@@ -34,8 +33,9 @@ dependencies = [
3433
'black>=21.11b1',
3534
'numpy>=1.21.2,<2.0',
3635
'anndata>=0.7.8,<0.11',
36+
'spatialdata>=0.2.2',
3737
'scanpy>=1.9.3',
38-
'ome-zarr==0.8.3',
38+
'ome-zarr>=0.8.3',
3939
'tifffile>=2020.10.1',
4040
'jsonschema>=3.2',
4141
'tqdm>=4.1.0'
@@ -81,7 +81,7 @@ all = [
8181
'starlette==0.14.0',
8282
'generate-tiff-offsets>=0.1.7',
8383
'kerchunk>=0.2.6',
84-
'fsspec>=2023.12.2',
84+
'fsspec',
8585

8686
# aiofiles is not explicitly referenced in our code,
8787
# but it is an implicit dependency of starlette==0.14.0.

setup.cfg

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,16 @@ per-file-ignores =
88
vitessce/data_utils/__init__.py: F401
99
vitessce/widget_plugins/__init__.py: F401
1010
ignore =
11-
E501, # Ignore line too long
12-
W605, # Ignore invalid escape sequence '\*'
13-
W503, # Ignore line break before binary operator: Skim down the left edge to understand intent.
14-
E127 # Ignore continuation line over-indented for visual indent
15-
E128 # Ignore continuation line under-indented for visual indent
11+
# Ignore line too long
12+
E501,
13+
# Ignore invalid escape sequence '\*'
14+
W605,
15+
# Ignore line break before binary operator: Skim down the left edge to understand intent.
16+
W503,
17+
# Ignore continuation line over-indented for visual indent
18+
E127
19+
# Ignore continuation line under-indented for visual indent
20+
E128
1621
exclude =
1722
./js/node_modules/,
1823
./docs/notebooks/.ipynb_checkpoints/,

0 commit comments

Comments
 (0)