Skip to content

Commit 2c36e0c

Browse files
authored
Version bump (#490)
* Version bump * Bump js version and update blobs notebook * Update script * Lint * Update
1 parent adb066c commit 2c36e0c

7 files changed

Lines changed: 82 additions & 52 deletions

File tree

.coveragerc_omit

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ omit =
1414
src/vitessce/data_utils/multivec.py
1515
src/vitessce/data_utils/spatialdata_points_zorder.py
1616
src/vitessce/widget_plugins/demo_plugin.py
17-
src/vitessce/widget_plugins/spatial_query.py
17+
src/vitessce/widget_plugins/spatial_query.py
18+
tests/*.py

docs/notebooks/spatial_data_blobs.ipynb

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
"outputs": [],
3131
"source": [
3232
"import spatialdata\n",
33-
"from os.path import join"
33+
"from os.path import join\n",
34+
"import pandas as pd\n",
35+
"from anndata import AnnData"
3436
]
3537
},
3638
{
@@ -39,7 +41,8 @@
3941
"metadata": {},
4042
"outputs": [],
4143
"source": [
42-
"sdata = spatialdata.datasets.blobs()"
44+
"sdata = spatialdata.datasets.blobs()\n",
45+
"sdata"
4346
]
4447
},
4548
{
@@ -48,7 +51,13 @@
4851
"metadata": {},
4952
"outputs": [],
5053
"source": [
51-
"spatialdata_filepath = join(\"data\", \"blobs.spatialdata.zarr\")"
54+
"# This blobs dataset only contains a table with a var.index corresponding to the shapes features.\n",
55+
"# We need to construct a table with a var.index corresponding to the points features:\n",
56+
"ddf = sdata.points[\"blobs_points\"]\n",
57+
"unique_gene_ids = ddf[\"genes\"].unique().compute().tolist()\n",
58+
"points_var_df = pd.DataFrame(index=unique_gene_ids, data=[], columns=[])\n",
59+
"points_table = AnnData(var=points_var_df, obs=None, X=None)\n",
60+
"sdata.tables['table_points'] = points_table"
5261
]
5362
},
5463
{
@@ -57,7 +66,7 @@
5766
"metadata": {},
5867
"outputs": [],
5968
"source": [
60-
"sdata.write(spatialdata_filepath, overwrite=True)"
69+
"spatialdata_filepath = join(\"data\", \"blobs.spatialdata.zarr\")"
6170
]
6271
},
6372
{
@@ -66,13 +75,7 @@
6675
"metadata": {},
6776
"outputs": [],
6877
"source": [
69-
"# Change data type of x and y columns from int64 to int32\n",
70-
"# Temporary workaround, will be resolved by https://github.com/vitessce/vitessce/issues/2292\n",
71-
"ddf = sdata[\"blobs_points\"]\n",
72-
"ddf[\"x\"] = ddf[\"x\"].astype('int32')\n",
73-
"ddf[\"y\"] = ddf[\"y\"].astype('int32')\n",
74-
"sdata[\"blobs_points_2\"] = ddf\n",
75-
"sdata.write_element(\"blobs_points_2\")"
78+
"sdata.write(spatialdata_filepath, overwrite=True)"
7679
]
7780
},
7881
{
@@ -112,23 +115,28 @@
112115
")\n",
113116
"# Add data to the configuration:\n",
114117
"wrapper = SpatialDataWrapper(\n",
115-
" sdata_store=spatialdata_filepath,\n",
118+
" sdata_path=spatialdata_filepath,\n",
116119
" # The following paths are relative to the root of the SpatialData zarr store on-disk.\n",
117120
" image_path=\"images/blobs_image\",\n",
118121
" obs_segmentations_path=\"labels/blobs_labels\",\n",
122+
" obs_embedding_paths=[\"tables/table/obsm/X_umap\"],\n",
123+
" obs_feature_matrix_path=\"tables/table/X\",\n",
119124
" coordinate_system=\"global\",\n",
120125
" coordination_values={\n",
121126
" \"obsType\": \"blob\",\n",
127+
" \"featureType\": \"channel\",\n",
122128
" \"fileUid\": \"my_unique_id\"\n",
123129
" }\n",
124130
")\n",
125131
"points_wrapper = SpatialDataWrapper(\n",
126-
" sdata_store=spatialdata_filepath,\n",
132+
" sdata_path=spatialdata_filepath,\n",
127133
" # The following paths are relative to the root of the SpatialData zarr store on-disk.\n",
128-
" obs_points_path=\"points/blobs_points_2\",\n",
134+
" obs_points_path=\"points/blobs_points\",\n",
135+
" obs_feature_matrix_path=\"tables/table_points/X\", # TODO\n",
129136
" coordinate_system=\"global\",\n",
130137
" coordination_values={\n",
131138
" \"obsType\": \"point\",\n",
139+
" \"featureType\": \"gene\",\n",
132140
" \"fileUid\": \"other_unique_id\"\n",
133141
" }\n",
134142
")\n",
@@ -169,6 +177,7 @@
169177
" 'segmentationChannel': CL([{\n",
170178
" 'spatialChannelVisible': True,\n",
171179
" 'obsType': 'blob',\n",
180+
" \"featureType\": \"channel\",\n",
172181
" }]),\n",
173182
" }]),\n",
174183
"}, scope_prefix=get_initial_coordination_scope_prefix(\"A\", \"obsSegmentations\"))\n",
@@ -177,7 +186,10 @@
177186
" 'pointLayer': CL([{\n",
178187
" \"fileUid\": \"other_unique_id\",\n",
179188
" \"obsType\": \"point\",\n",
189+
" \"featureType\": \"gene\",\n",
180190
" \"obsHighlight\": None,\n",
191+
" \"obsColorEncoding\": \"randomByFeature\",\n",
192+
" \"spatialLayerOpacity\": 1.0,\n",
181193
" }]),\n",
182194
"}, scope_prefix=get_initial_coordination_scope_prefix(\"A\", \"obsPoints\"))\n",
183195
"\n",

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "vitessce"
7-
version = "3.8.0"
7+
version = "3.8.1"
88
authors = [
99
{ name="Mark Keller", email="mark_keller@hms.harvard.edu" },
1010
]

src/vitessce/file_def_utils.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def gen_sdata_obs_segmentations_schema(options, path: str, table_path: str = "ta
147147
return options
148148

149149

150-
def gen_sdata_obs_points_schema(options, path: str, table_path: str = "tables/table", coordinate_system: Optional[str] = None) -> dict:
150+
def gen_sdata_obs_points_schema(options, path: str, table_path: str = "tables/table", coordinate_system: Optional[str] = None, feature_index_column: Optional[str] = None, morton_code_column: Optional[str] = None) -> dict:
151151
if path is not None:
152152
options["obsPoints"] = {
153153
"path": path
@@ -156,6 +156,10 @@ def gen_sdata_obs_points_schema(options, path: str, table_path: str = "tables/ta
156156
options["obsPoints"]['tablePath'] = table_path
157157
if coordinate_system is not None:
158158
options["obsPoints"]['coordinateSystem'] = coordinate_system
159+
if feature_index_column is not None:
160+
options["obsPoints"]['featureIndexColumn'] = feature_index_column
161+
if morton_code_column is not None:
162+
options["obsPoints"]['mortonCodeColumn'] = morton_code_column
159163
return options
160164

161165

src/vitessce/widget.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -729,7 +729,7 @@ class VitessceWidget(anywidget.AnyWidget):
729729

730730
next_port = DEFAULT_PORT
731731

732-
js_package_version = Unicode('3.9.0').tag(sync=True)
732+
js_package_version = Unicode('3.9.2').tag(sync=True)
733733
js_dev_mode = Bool(False).tag(sync=True)
734734
custom_js_url = Unicode('').tag(sync=True)
735735
plugin_esm = List(trait=Unicode(''), default_value=[]).tag(sync=True)
@@ -742,7 +742,7 @@ class VitessceWidget(anywidget.AnyWidget):
742742

743743
store_urls = List(trait=Unicode(''), default_value=[]).tag(sync=True)
744744

745-
def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.9.0', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, prefer_local=True, invoke_timeout=300000, invoke_batched=True, page_mode=False, page_esm=None, prevent_scroll=True, server_host=None):
745+
def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.9.2', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, prefer_local=True, invoke_timeout=300000, invoke_batched=True, page_mode=False, page_esm=None, prevent_scroll=True, server_host=None):
746746
"""
747747
Construct a new Vitessce widget. Not intended to be instantiated directly; instead, use ``VitessceConfig.widget``.
748748
@@ -876,7 +876,7 @@ def _plugin_command(self, params, buffers):
876876
# Launch Vitessce using plain HTML representation (no ipywidgets)
877877

878878

879-
def ipython_display(config, height=600, theme='auto', base_url=None, host_name=None, uid=None, port=None, proxy=False, js_package_version='3.9.0', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, page_mode=False, page_esm=None, server_host=None):
879+
def ipython_display(config, height=600, theme='auto', base_url=None, host_name=None, uid=None, port=None, proxy=False, js_package_version='3.9.2', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, page_mode=False, page_esm=None, server_host=None):
880880
from IPython.display import display, HTML
881881
uid_str = "vitessce" + get_uid_str(uid)
882882

src/vitessce/wrappers.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,7 @@ def auto_view_config(self, vc):
14071407

14081408
class SpatialDataWrapper(AnnDataWrapper):
14091409

1410-
def __init__(self, sdata_path: Optional[str] = None, sdata_url: Optional[str] = None, sdata_store: Optional[Union[str, zarr.storage.StoreLike]] = None, sdata_artifact: Optional[ln.Artifact] = None, image_path: Optional[str] = None, region: Optional[str] = None, coordinate_system: Optional[str] = None, obs_spots_path: Optional[str] = None, obs_segmentations_path: Optional[str] = None, obs_points_path: Optional[str] = None, table_path: str = "tables/table", is_zip=None, coordination_values=None, **kwargs):
1410+
def __init__(self, sdata_path: Optional[str] = None, sdata_url: Optional[str] = None, sdata_store: Optional[Union[str, zarr.storage.StoreLike]] = None, sdata_artifact: Optional[ln.Artifact] = None, image_path: Optional[str] = None, region: Optional[str] = None, coordinate_system: Optional[str] = None, obs_spots_path: Optional[str] = None, obs_segmentations_path: Optional[str] = None, obs_points_path: Optional[str] = None, obs_points_feature_index_column: Optional[str] = None, obs_points_morton_code_column: Optional[str] = None, table_path: str = "tables/table", is_zip=None, coordination_values=None, **kwargs):
14111411
"""
14121412
Wrap a SpatialData object.
14131413
@@ -1432,6 +1432,10 @@ def __init__(self, sdata_path: Optional[str] = None, sdata_url: Optional[str] =
14321432
:type obs_segmentations_path: Optional[str]
14331433
:param obs_points_path: Path to a points element, by default None
14341434
:type obs_points_path: Optional[str]
1435+
:param obs_points_feature_index_column: Column in the points dataframe that contains a feature index value (i.e., index into table.var.index to specify a gene) for each point, by default None
1436+
:type obs_points_feature_index_column: Optional[str]
1437+
:param obs_points_morton_code_column: Column in the points dataframe that contains a morton code for each point, by default None
1438+
:type obs_points_morton_code_column: Optional[str]
14351439
:param str feature_labels_path: Path to a table var column containing feature labels (e.g., alternate gene symbols), instead of the default index column of the `var` dataframe.
14361440
:param list[str] obs_embedding_paths: Column names like `['obsm/X_umap', 'obsm/X_pca']` for showing scatterplots
14371441
:param list[str] obs_embedding_names: Overriding names like `['UMAP', 'PCA']` for displaying above scatterplots
@@ -1466,6 +1470,8 @@ def __init__(self, sdata_path: Optional[str] = None, sdata_url: Optional[str] =
14661470
self._obs_spots_path = obs_spots_path
14671471
self._obs_segmentations_path = obs_segmentations_path
14681472
self._obs_points_path = obs_points_path
1473+
self._obs_points_feature_index_column = obs_points_feature_index_column
1474+
self._obs_points_morton_code_column = obs_points_morton_code_column
14691475
if self._adata_path is not None:
14701476
self.zarr_folder = 'spatialdata.zarr'
14711477
self.obs_type_label = None
@@ -1553,7 +1559,10 @@ def generator(base_url):
15531559
options = gen_sdata_obs_spots_schema(options, self._obs_spots_path, self._table_path, self._region, self._coordinate_system)
15541560
options = gen_sdata_image_schema(options, self._image_path, self._coordinate_system)
15551561
options = gen_sdata_obs_segmentations_schema(options, self._obs_segmentations_path, self._table_path, self._coordinate_system)
1556-
options = gen_sdata_obs_points_schema(options, self._obs_points_path, self._table_path, self._coordinate_system)
1562+
options = gen_sdata_obs_points_schema(
1563+
options, self._obs_points_path, self._table_path, self._coordinate_system,
1564+
self._obs_points_feature_index_column, self._obs_points_morton_code_column
1565+
)
15571566
options = gen_feature_labels_schema(self._feature_labels, options)
15581567
options = gen_obs_embedding_schema(options, self._mappings_obsm, self._mappings_obsm_names, self._mappings_obsm_dims)
15591568
if len(options.keys()) > 0:

tests/create_xenium_filtered_points.py

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,48 @@
88
from spatialdata import read_zarr, SpatialData
99

1010

11-
data_dir = "data"
12-
zip_filepath = join(data_dir, "xenium_rep1_io.spatialdata.zarr.zip")
13-
spatialdata_filepath = join(data_dir, "xenium_rep1_io.spatialdata.zarr")
11+
def create_xenium_filtered_points():
12+
# 1. Download and extract the Xenium dataset if not already present
13+
data_dir = "data"
14+
zip_filepath = join(data_dir, "xenium_rep1_io.spatialdata.zarr.zip")
15+
spatialdata_filepath = join(data_dir, "xenium_rep1_io.spatialdata.zarr")
1416

17+
if not isdir(spatialdata_filepath):
18+
if not isfile(zip_filepath):
19+
os.makedirs(data_dir, exist_ok=True)
20+
# zip_url = 'https://s3.embl.de/spatialdata/spatialdata-sandbox/xenium_rep1_io.zip'
21+
zip_url = 'https://s3.embl.de/spatialdata/spatialdata-sandbox/xenium_rep1_io_spatialdata_0.7.1.zip'
22+
urlretrieve(zip_url, zip_filepath)
23+
with zipfile.ZipFile(zip_filepath, "r") as zip_ref:
24+
zip_ref.extractall(data_dir)
25+
os.rename(join(data_dir, "data.zarr"), spatialdata_filepath)
1526

16-
if not isdir(spatialdata_filepath):
17-
if not isfile(zip_filepath):
18-
os.makedirs(data_dir, exist_ok=True)
19-
urlretrieve('https://s3.embl.de/spatialdata/spatialdata-sandbox/xenium_rep1_io.zip', zip_filepath)
20-
with zipfile.ZipFile(zip_filepath, "r") as zip_ref:
21-
zip_ref.extractall(data_dir)
22-
os.rename(join(data_dir, "data.zarr"), spatialdata_filepath)
27+
# This Xenium dataset has an AnnData "raw" element.
28+
# Reference: https://github.com/giovp/spatialdata-sandbox/issues/55
29+
raw_dir = join(spatialdata_filepath, "tables", "table", "raw")
30+
if isdir(raw_dir):
31+
shutil.rmtree(raw_dir)
2332

24-
# This Xenium dataset has an AnnData "raw" element.
25-
# Reference: https://github.com/giovp/spatialdata-sandbox/issues/55
26-
raw_dir = join(spatialdata_filepath, "tables", "table", "raw")
27-
if isdir(raw_dir):
28-
shutil.rmtree(raw_dir)
33+
sdata = read_zarr(spatialdata_filepath)
2934

30-
sdata = read_zarr(spatialdata_filepath)
35+
ddf = sdata.points["transcripts"]
3136

32-
ddf = sdata.points["transcripts"]
37+
# 2. Define a function to take every 100th row from a partition
3338

34-
# 2. Define a function to take every 100th row from a partition
39+
def select_every_200th(partition):
40+
# Each 'partition' is a Pandas DataFrame
41+
# .iloc[::100] is the efficient pandas way to get every 100th row
42+
return partition.iloc[::200]
3543

44+
# 3. Apply this function to every partition in the Dask DataFrame
45+
result = ddf.map_partitions(select_every_200th)
3646

37-
def select_every_200th(partition):
38-
# Each 'partition' is a Pandas DataFrame
39-
# .iloc[::100] is the efficient pandas way to get every 100th row
40-
return partition.iloc[::200]
47+
# 4. Compute the result to see it
48+
filtered_ddf = result[["x", "y", "z", "feature_name", "cell_id"]]
4149

50+
small_sdata = SpatialData(points={"transcripts": filtered_ddf})
4251

43-
# 3. Apply this function to every partition in the Dask DataFrame
44-
result = ddf.map_partitions(select_every_200th)
52+
small_sdata.write("xenium_rep1_io.points_only.spatialdata.zarr", overwrite=True)
4553

46-
# 4. Compute the result to see it
47-
filtered_ddf = result[["x", "y", "z", "feature_name", "cell_id"]]
48-
49-
small_sdata = SpatialData(points={"transcripts": filtered_ddf})
50-
51-
small_sdata.write("xenium_rep1_io.points_only.spatialdata.zarr", overwrite=True)
54+
# Uncomment to run.
55+
# create_xenium_filtered_points()

0 commit comments

Comments
 (0)