From 6f68c5cd5cc3f371cfeccc4e2004c75310187eeb Mon Sep 17 00:00:00 2001 From: Mark Keller <7525285+keller-mark@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:42:35 -0400 Subject: [PATCH 1/2] Add notebook --- .../notebooks/widget_anndata_with_image.ipynb | 130 ++++++++++++++++++ src/vitessce/data_utils/ome.py | 8 +- 2 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 docs/notebooks/widget_anndata_with_image.ipynb diff --git a/docs/notebooks/widget_anndata_with_image.ipynb b/docs/notebooks/widget_anndata_with_image.ipynb new file mode 100644 index 00000000..f76d87f9 --- /dev/null +++ b/docs/notebooks/widget_anndata_with_image.ipynb @@ -0,0 +1,130 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "nbsphinx": "hidden" + }, + "source": [ + "# Vitessce Widget Tutorial" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualization of AnnData object containing an image in `uns`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: This approach to storing images within AnnData objects is no longer recommended now that [SpatialData](https://spatialdata.scverse.org/en/stable/) has been introduced." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import scanpy as sc\n", + "import numpy as np\n", + "from vitessce.data_utils import rgb_img_to_ome_zarr, VAR_CHUNK_SIZE\n", + "from vitessce import (\n", + " VitessceConfig,\n", + " AnnDataWrapper,\n", + " ImageOmeZarrWrapper,\n", + ")\n", + "from os.path import join" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "output_img = join(\"data\", \"V1_Human_Lymph_Node.ome.zarr\")\n", + "output_adata = join(\"data\", \"V1_Human_Lymph_Node.anndata.zarr\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "adata = sc.datasets.visium_sge(sample_id=\"V1_Human_Lymph_Node\", include_hires_tiff=True)\n", + "\n", + "# Write img_arr to OME-Zarr.\n", + "# Need to convert images from interleaved to non-interleaved (color axis should be first).\n", + "img_hires = adata.uns['spatial']['V1_Human_Lymph_Node']['images']['hires']\n", + "img_arr = np.transpose(img_hires, (2, 0, 1))\n", + "# Convert values from [0, 1] to [0, 255].\n", + "img_arr *= 255.0\n", + "\n", + "# First, save the image to an OME-Zarr image format\n", + "rgb_img_to_ome_zarr(img_arr, output_img, axes=\"cyx\", chunks=(1, 256, 256), img_name=\"Image\")\n", + "# Second, save the AnnData object to Zarr format\n", + "adata.write_zarr(output_adata, chunks=[adata.shape[0], VAR_CHUNK_SIZE])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vc = VitessceConfig(schema_version=\"1.0.17\", name=\"AnnData with image\")\n", + "dataset = vc.add_dataset(\"My dataset\").add_object(\n", + " AnnDataWrapper(\n", + " adata_path=output_adata,\n", + " \n", + " )\n", + ").add_object(\n", + " ImageOmeZarrWrapper(\n", + " img_path=output_img,\n", + " )\n", + ")\n", + "\n", + "spatial_view = vc.add_view(\"spatialBeta\", dataset=dataset)\n", + "lc_view = vc.add_view(\"layerControllerBeta\", dataset=dataset)\n", + "\n", + "vc.layout(spatial_view | lc_view);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "vw = vc.widget()\n", + "vw" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/src/vitessce/data_utils/ome.py b/src/vitessce/data_utils/ome.py index dafb9d13..e8debc15 100644 --- a/src/vitessce/data_utils/ome.py +++ b/src/vitessce/data_utils/ome.py @@ -99,7 +99,9 @@ def rgb_img_to_ome_zarr(img_arr, output_path, img_name="Image", chunks=(1, 256, z_root.attrs["omero"] = { "name": img_name, "version": "0.3", - "rdefs": {}, + "rdefs": { + "model": "color", + }, "channels": [ { "label": "R", @@ -156,7 +158,9 @@ def multiplex_img_to_ome_zarr(img_arr, channel_names, output_path, img_name="Ima z_root.attrs["omero"] = { "name": img_name, "version": "0.3", - "rdefs": {}, + "rdefs": { + "model": "greyscale", + }, "channels": [ { "label": channel_name, From c09f7d46cda61aac50559aecfb6e4d10ee27f366 Mon Sep 17 00:00:00 2001 From: Mark Keller <7525285+keller-mark@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:43:56 -0400 Subject: [PATCH 2/2] Fix tesT --- tests/test_ome_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_ome_utils.py b/tests/test_ome_utils.py index 4eae304f..85020be9 100644 --- a/tests/test_ome_utils.py +++ b/tests/test_ome_utils.py @@ -90,7 +90,9 @@ def test_rgb_img_to_ome_zarr(self): } ], 'name': 'Test', - 'rdefs': {}, + 'rdefs': { + "model": "color", + }, 'version': '0.3' } }