Skip to main content

visualize histology images with umap

Project description

histomap

Napari dock widget to overlay tile polygons and table annotations from SpatialData onto an H&E image, and to interactively select cells in a 2D embedding (e.g., UMAP in AnnData.obsm) and visualize the selected regions on the H&E.

  • Overlay mode: color polygons on the H&E by an AnnData.obs column (categorical or numeric) from SpatialData.tables[<name>].
  • UMAP-lasso mode: open a 2D embedding from AnnData.obsm (e.g., X_umap), lasso points, and preview the corresponding tile polygons on the H&E; optionally save the selection back to obs.

Installation

# Recommended: use a fresh environment
conda create --name histomap python=3.11 -y
conda activate histomap

# If published on PyPI:
pip install histomap

# If installing from source in this repo:
# pip install -e .

Runtime dependencies (installed automatically if from PyPI)

  • napari, PyQt5, magicgui
  • geopandas, shapely
  • anndata, matplotlib, spatialdata
  • (Optional, for robust SVS reading) openslide-python, napari-openslide

Windows notes

  • If geopandas/shapely wheels fail, upgrade pip (pip install -U pip) and try again.
  • For OpenSlide, install the prebuilt binaries or use conda install -c conda-forge openslide openslide-python in the same environment.

Optional GPU acceleration (RAPIDS/cuML + CuPy)

The histomap.umap function auto-detects GPU and uses RAPIDS (cuML + CuPy) when available; otherwise it falls back to umap-learn on CPU. You do not need RAPIDS for CPU-only usage.

  • macOS: RAPIDS/CUDA is not supported; use CPU (umap-learn).
  • Linux with NVIDIA GPU: install RAPIDS packages into the same environment (versions must match your CUDA/driver).

Example using conda:

# Create a GPU environment (adjust Python/CUDA/RAPIDS versions to your system)
conda create --name histomap-gpu python=3.11 -y
conda activate histomap-gpu

# Install RAPIDS UMAP dependencies (channels may vary depending on versions)
conda install -c rapidsai -c conda-forge -c nvidia cuml cupy

# Then install histomap (CPU deps via pip) into the same env
pip install histomap  # or: pip install -e .

Verification:

python - <<'PY'
import cupy
print('CUDA devices:', cupy.cuda.runtime.getDeviceCount())
PY

If RAPIDS is present and a CUDA device is available, histomap.umap(...) will automatically use the GPU; otherwise it will run on CPU.


Quick start

import histomap as hm

Method 1 — Use a SpatialData object

import spatialdata as sd
import histomap as hm

sda = sd.read_zarr("/path/to/spatialdata.zarr")

# Preferred: pass the H&E path explicitly (best on Windows)
viewer = hm.histomap(
    sda,
    imagePath="/path/to/HE_image.svs",   # alias: imagePath="/path/to/HE_image.svs"
    # mpp=0.263049,                     # µm/px (optional; if tiles are in microns, scale=1/mpp is auto-applied)
)

# If you omit imagePath, histomap will try to parse a path from str(sda).
# If no path is found, you’ll see a dialog asking you to pass imagePath explicitly.

Typical workflow in the UI

  1. Click Open WSI in Viewer (if not already opened).
  2. Choose a Table (from sda.tables), Data axis (obs or obsm), and a column/key.
    • For obs: click Render Overlay to color polygons on the H&E.
    • For obsm (e.g., X_umap): click Open UMAP + Lasso, lasso points, and inspect the green Lasso preview on the H&E.
  3. Optionally enter a Layer name and obs column, then click Save selection to write labels into AnnData.obs and add a persistent overlay layer.

Method 2 — Use with lazyslide/wsidata

import lazyslide as zs
from wsidata import open_wsi
import histomap as hm

wsi = open_wsi("/path/to/HE_image.svs")

# Assuming tiling & feature extraction are already done, e.g.:
# zs.pp.tile_tissues(wsi, tile_px=256, mpp=0.5)
# zs.tl.feature_extraction(wsi, model='chief')

# Launch viewer and overlay tiles/annotations stored in wsi.tables / wsi.shapes
viewer = hm.histomap(wsi)

Parameters (entry point)

viewer = hm.histomap(
    sda_or_wsi,                        # SpatialData or compatible WSIData
    *,
    imagePath=None,                     # str | Path | None; preferred image to open (alias: imagePath)
    mpp=None,                          # float | None; µm/px. If provided and no explicit scale, applies scale=(1/mpp, 1/mpp)
    global_to_pixel_scale=None,        # (sx, sy) override for polygon transform
    global_to_pixel_translate=None,    # (tx, ty) override
    theme="dark",
    canvas_bg="white",
)

Precedence

  • If global_to_pixel_scale is provided, it overrides mpp.
  • If imagePath is provided, it overrides any path parsed from SpatialData.
  • If neither imagePath nor a parsable path exists, histomap shows a dialog explaining how to pass imagePath.

Data assumptions

  • sda.shapes["tiles"] is a GeoDataFrame with polygons; its index contains tile IDs.
  • sda.tables[<name>] is an AnnData where obs_names match the tile IDs (string-matched; dtype mismatches are handled).
  • For UMAP-lasso, AnnData.obsm[<key>] contains an (n_cells, 2+) embedding (e.g., X_umap).

Tips & alignment

  • Tiles already in pixels? Don’t pass mpp. Use Calibrate (fit tiles) if needed.
  • Tiles in microns? Pass mpp=<µm/px> and click Auto-align (use MPP) (or rely on the automatic scale if you didn’t override with global_to_pixel_scale).
  • The overlay layers inherit the image layer’s affine, so they remain aligned across pyramid levels.

Saving lasso selections (what gets written)

When you click Save selection:

  • The chosen obs column is created/normalized as plain Python strings (dtype=object) with no missing values.
  • Only selected rows receive the provided label (string). Non-selected rows remain unchanged (empty string by default).
  • A persistent overlay layer is added with the saved selection (the transient Lasso preview is removed).

Why object strings?
Writing pandas’ nullable string dtype (dtype="string") to Zarr requires opting in (anndata.settings.allow_write_nullable_strings=True). Using plain object strings avoids that requirement and is maximally portable.


Troubleshooting

❗️“boolean value of NA is ambiguous” during wsi.write() / SpatialData.write()

You likely have pd.NA or mixed types in AnnData.obs. Ensure no NA in string-like columns and that they are object strings.

❗️“allow_write_nullable_strings is False”

Either set:

import anndata as ad
ad.settings.allow_write_nullable_strings = True

or convert to object strings.

❗️Cannot overwrite/move files on Windows after closing the viewer

Clear layers before saving: viewer.layers.clear() and run garbage collection.

❗️No H&E appears and you see “H&E Image Missing”

Pass the image explicitly:

viewer = hm.histomap(sda, imagePath="/absolute/path/to/HnE.svs")

FAQ

Q: Do I need openslide?
A: Only if you’re opening .svs/WSI formats through Napari.

Q: Can I use a custom image and MPP without modifying the dock UI?
A: Yes—pass imagePath=... and mpp=... to hm.histomap(...).


Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

histomap-0.1.9.tar.gz (20.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

histomap-0.1.9-py3-none-any.whl (19.2 kB view details)

Uploaded Python 3

File details

Details for the file histomap-0.1.9.tar.gz.

File metadata

  • Download URL: histomap-0.1.9.tar.gz
  • Upload date:
  • Size: 20.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.14

File hashes

Hashes for histomap-0.1.9.tar.gz
Algorithm Hash digest
SHA256 a8e751cce58ebf8ec26a700fd6ca4c71937e7e23504e80aeb91590db9cd09ddc
MD5 324d33578f117e63481c74ac60f8bf5e
BLAKE2b-256 30b80fd0151a8fbb863ea1f79a5961db7e3a9276312c4e4f12de7ffc748ff0f0

See more details on using hashes here.

File details

Details for the file histomap-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: histomap-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 19.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.14

File hashes

Hashes for histomap-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 3e5559097eabfe347c37c4c1bfd76a45a8a9870ce0e2a13b65a63f5a59ae5fc5
MD5 74803bc3bf3a899ef0ed548730ba1e29
BLAKE2b-256 6ddae4e3a10dadc37b168ecb509eb32b70e5cde3c223e9f31dff57e00696caf6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page