Skip to content

Releases: SpatialPathology/InSituPy

0.12.0b6

0.12.0b6 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 09 Jul 18:33

Release Notes - InSituPy 0.12.0b6

PyPI: pip install insitupy-spatial==0.12.0b6


Summary

Multi-unit-layer support for the napari viewer, several data-integrity fixes, and a fail-fast
guard against accidentally re-constructing an InSituData on top of an already-saved project.


New Features

  • Multiple named spatial units layers - InSituData.units now holds a
    MultiSpatialUnitsData container, so a sample can carry more than one units layer (e.g.
    Visium spots and niches) via add_units(data, key=...); crop() now crops all of them.
  • napari viewer - units layer selector to switch between multiple unit keys; searchable
    type-ahead on the cells/units key fields; "Show" buttons gated on a valid selection.

Bug Fixes

  • Fixed InSituData(path) silently fabricating a new UID on a saved-project path; now raises InSituDataConstructorPathError pointing at InSituData.read().
  • Fixed cells/units shifting relative to the image after crop-by-region (negative shape bounds weren't clamped).
  • Fixed build_table()/to_anndata() silently dropping a sample when two samples shared a label_col value.
  • Hardened autodetect_obs_names matching so it no longer truncates barcodes or fails on concat_on_disk output.
  • Fixed InSituExperiment subsetting inconsistency: __getitem__/query() now always return a view, and .filters.apply() now actually deep-copies.
  • Fixed the napari transcript viewer's thread-race IndexError and a point-size inconsistency.
  • Fixed a zoom-out border artifact on cells-as-points and Transcripts layers (napari 0.7 default).
  • Fixed cell/nucleus label mis-coloring in the napari viewer after filtering without sync().
  • Fixed a hidden units layer staying hidden after re-selecting its key.
  • Fixed two bugs in the units save/load path (missing attribute; mismatched on-disk format).

Breaking Changes

  • build_table()/to_anndata() unique-obs_names shape unified: both methods now append the uid ("{name}-{uid}") instead of in_memory prepending a positional index.
  • import_from_anndata's strip_uid_prefix parameter renamed to autodetect_obs_names (no deprecated alias).

Dependency Changes

  • napari bumped to >=0.7.0,<0.8.0.
  • Python floor raised to >=3.12.0,<4.0 (required by zarr>=3.2.1).

Internal

  • Stopped tracking .mcp.json; documented self-serve MCP client setup for contributors.
  • Revised the MCP Server tutorial; synced its Python version reference to 3.13.

Full Changelog: 0.12.0b5...0.12.0b6

0.12.0b5

0.12.0b5 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 02 Jul 18:24

Release Notes - InSituPy 0.12.0b5

PyPI: pip install insitupy-spatial==0.12.0b5


Summary

Color-system consistency release: a new layer-aware exp.colors API keeps plotting and the
napari viewer in sync, several color-rendering bugs are fixed, and a tifffile/zarr
incompatibility that broke lazy image reads is resolved.


New Features

  • exp.colors — layer-aware color store that writes through to every sample's .uns,
    keeping sync_colors, pl.spatial, pl.cellular_composition, and show() consistent.
  • napari viewer — Show-widget layers now reuse by display scope instead of by exact name.
  • pl.embedding/umap/pca/tsne — new palette, vcenter, subplot_width/subplot_height parameters.
  • pl.spatial — new nan_color parameter (matches pl.embedding).

Bug Fixes

  • Continuous values in the napari "cells"/"nuclei" mode no longer misrender as a slow, categorical-style legend.
  • Fixed KeyError on integer-category columns in points-mode color mapping.
  • Fixed duplicate napari layers accumulating on repeated "Show" calls, and reused layers staying hidden after recoloring.
  • Fixed pl.spatial/sync_colors crashes on object columns mixing strings with NaN.
  • Fixed stale layout state (e.g. figsize) leaking across successive pl.spatial calls.
  • Fixed tifffile/zarr 3.2.x incompatibility that broke all lazy (aszarr=True) image reads.
  • Fixed write_ome_tiff() silently writing non-OME TIFFs.

Dependency Changes

  • tifffile pinned to >=2026.5.2,<2027.0.0.

Internal

  • Test suite cleanup: removed one obsolete test, collected two previously-uncollected smoke
    suites, fixed two test/implementation mismatches.
  • Full suite verified green: 687 passed, 0 failed, 0 errors.

Full Changelog: 0.12.0b4...0.12.0b5

0.12.0b4

0.12.0b4 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 25 Jun 09:57

Release Notes — InSituPy 0.12.0b4

Date: 2026-06-25
PyPI: pip install insitupy-spatial==0.12.0b4
Previous release: 0.12.0b3


Summary

This release is centred on multi-sample analysis workflows. One of the main additions is a
flexible filter layer system (InSituExperiment filters): users can define named sample
subsets — including composite filters that combine multiple base filters with AND/OR logic —
and use them to scope any downstream analysis without modifying the underlying experiment.
Alongside filters, a new cross-sample table workflow (build_table() / .table[...] /
import_from_table()) enables concatenation of cell tables across all samples into a single
AnnData, with results writable back to individual samples and full support for multi-panel
experiments with differing gene sets. Experiment management gains three new methods —
replace(), remove(), and reload() — and each dataset now carries a stable UID that
persists across saves, reloads, and reorders, making filter and merge-back operations robust
to experiment restructuring.

On the analysis side, QC is redesigned around the new qc_summary() method, and the
embedding plots (umap, pca, tsne) gain highlight/dim parameters for
focus-on-subset visualisation, a layer parameter to plot from any AnnData layer, and several
rendering options. The save pipeline received its most thorough hardening to date: atomic
swaps, collect-then-raise error handling, and guards against path-less dataset corruption make
save/saveas reliable even after hard crashes.


New Features

Cross-sample table workflow

  • Added InSituExperiment.build_table() to concatenate cell tables across all samples into a single AnnData, with support for union or inner gene sets across panels.
  • Results are accessible via .table[cells_layer] (bracket accessor) and can be written back to samples with import_from_table().
  • InSituExperimentView.table works on filtered subsets of the experiment.
  • concat_on_disk option builds the table by writing per-sample H5AD files and concatenating them, avoiding peak RAM for large experiments.
  • A build_params.json sidecar tracks the parameters used to build each stored table.

QC redesign

  • New InSituExperiment.qc_summary() method returns a tidy DataFrame of per-sample QC metrics.
  • calculate_mad_thresholds moved to the new insitupy.experimental submodule; the insitupy.pp alias is deprecated with a warning.

Embedding plot enhancements (isp.pl.embedding / umap / pca / tsne)

  • highlight parameter: colour a subset of cells, grey out the rest.
  • dim parameter: inverse of highlight — grey out the specified cells.
  • "Other" legend entry automatically added for dimmed/highlighted background points.
  • layer parameter: plot expression values from any AnnData layer (not just .X).
  • render_mode="matplotlib" for matplotlib-native rendering as an alternative to datashader.
  • point_edge_color, point_edge_width, and rasterized parameters added.
  • nan_color parameter to control colour of NaN values in categorical columns.
  • Scanpy colour palette fallback for categories already coloured in .uns.

Experiment management

  • InSituData.uid — each dataset now has a stable unique identifier that persists across saves and reloads.
  • InSituExperiment.replace(uid, new_data) — replace a dataset in an experiment by UID.
  • InSituExperiment.remove(uid) — remove a dataset from an experiment.
  • InSituExperiment.reload() — reload all datasets from disk without re-reading the experiment.
  • InSituData.read() now auto-loads all available modalities by default.

Filter layer improvements

  • Composite filter layers that combine multiple base filters with AND/OR logic.
  • Improved repr distinguishes base filters from composite filters.

Metadata utilities

  • InSituExperiment.update_metadata() and rename_metadata_column() for in-place metadata edits.
  • unload() to release modality data from memory.
  • concat(mode='move') now supported on subsetted experiments.
  • from_config() accepts a DataFrame directly as metadata input.
  • Experiment metadata stored as metadata.parquet instead of metadata.csv (more robust, preserves dtypes).

napari interactive viewer

  • New GeometriesWidget with colour palettes and geometry registries for managing annotations in the viewer.
  • GeometriesWidget restructured: separate "Show" and "Add" panels, point size preservation.
  • Auto-naming of new geometry layers.
  • Single-layer regions: all region/annotation classes for a given key are merged into one napari layer, with a combined widget.

Shapes and geometry

  • ShapesData gains to_regions() / to_annotations() conversion methods.
  • scale_factor sentinel default with a descriptive ValueError when not set.

Image registration

  • Registration module refactored into a standalone register_images_standalone function; the ImageRegistration class is deprecated.
  • raise_on_insufficient_matches parameter added to control error vs. warning behaviour on low feature matches.

Save/load additions

  • InSituData partial save methods: save_geometries(), save_cells(), save_images().
  • InSituData gains conversion methods between modality types.

Repr improvements

  • InSituData.__repr__ now shows the dataset UID.
  • InSituExperiment.__repr__ now shows loaded modality counts per dataset.

Bug Fixes

Save pipeline hardening (major)

  • saveas() now uses a true atomic swap: moves old data aside to a backup before renaming the staging directory in; restores the backup if the swap fails. Previously, a crash during the swap could destroy both old and new copies.
  • InSituExperiment.save() now uses a collect-then-raise pattern: all datasets are attempted before raising, and a RuntimeError lists every failing UID. Experiment-level files are skipped on any failure.
  • InSituExperiment.save() no longer corrupts a path-less dataset's _path on failure; the pre-pass validates before assigning.
  • Path-less datasets (added via .add() without a prior save) are auto-assigned a free data-NNN slot and written via saveas() on the first save() call.
  • InSituExperimentView.save_filters() now merges filter masks back to parent samples by UID rather than positional index, preventing wrong-sample writes after a parent reorder.
  • saveas() recovers an orphaned .__ispy_bak__ backup left by a previous crash instead of silently deleting it.
  • InSituExperimentView save methods no longer mutate the parent experiment's filter state.

Memory and I/O

  • Prevented OOM when saving large lazy transcript datasets.
  • Fixed a pandas 2.x Copy-on-Write MemoryError in transcript cropping (_crop_transcripts now uses DataFrame.take()).
  • Fixed regions extending past image boundaries causing crop failures.
  • Fixed empty rows appearing in metadata.csv on Windows.

Interactive viewer

  • Fixed IndexError race condition in TranscriptViewerWidget.
  • Fixed .uns colour order being lost when switching to cells/labels display mode.
  • Fixed point annotation colour channel mismatch in geometry layers.
  • Fixed stale-key and uid-guard issues in interactive widgets; added "(all)" key option.
  • Fixed sync-order bug in geometry colour legend updates.

Other

  • Fixed H&E image registration crash and memory leak in registration QC.
  • Fixed circular import in containers/io.py.
  • Fixed MultiCellData.__getitem__ raising IndexError instead of KeyError for missing layer names.
  • Fixed best image pyramid level selection in quantify_signal when pixel sizes differ.
  • Corrected inverted unload() string normalisation and leiden flavour handling.

Dependency Changes

  • scipy pinned to >=1.14,<1.17 (1.17 introduced a breaking change).
  • zarr minimum bumped to 3.2.1.
  • Python minimum updated to >=3.11.0 (was >=3.10).
  • anndata added as an explicit dependency (>=0.12.0).

Documentation

  • New save/load tutorial (docs/tutorials/00_io/) covering full and partial saves, reload patterns, and when to use each method.
  • New cross-sample table tutorial with architecture diagram.
  • New filter workflow tutorial documenting base and composite filter layers.
  • MCP server tutorial (MCP_TUTORIAL.md) updated: Claude Code global config option added, ChatGPT section labelled as untested with feedback link, tool count corrected to 22, tools/mcp_server/README.md rewritten with uvx as the recommended path.

Internal / Refactoring

  • Geometry layers in napari migrated to the napari features API.
  • _concatenate_samples and _transfer_to_samples extracted as reusable helpers.
  • _clear_modality helper introduced, consolidating deleter and unload logic.
  • Transcript cropping intermediate code cleaned up after performance work.
  • Ruff linting applied and violations fixed across the codebase.
  • GitHub Actions release workflow now auto-detects pre-release tags (a, b, rc) and marks the GitHub Release accordingly.

Full Changelog: 0.12.0b3...0.12.0b4

0.11.4

Choose a tag to compare

@github-actions github-actions released this 14 Apr 18:27

Bug fixes

  • isp.pl.embedding / umap / pca / tsne: fixed silent mis-coloring of NaN
    cells in categorical obs columns.

    When a categorical column contained missing values, datashader encoded them with
    the sentinel code -1, which NumPy's negative indexing silently mapped to the last
    category's color bucket. Affected cells therefore appeared in the wrong color with
    no legend entry. The fix adds a nan_color parameter (default None): with
    nan_color=None NaN cells are excluded from the plot; with nan_color="lightgray"
    (or any color string) they are shown in that color with a dedicated "NaN" legend
    entry. The fix is applied consistently across all rendering backends (static
    datashader, interactive datashader, plotly, jscatter).

Full Changelog: 0.11.3...0.11.4

0.11.3

Choose a tag to compare

@github-actions github-actions released this 01 Apr 14:23

Bug fixes

  • quantify_signal: fixed pixel size mismatch between image and segmentation mask.
    When the image and the segmentation mask were stored at different physical resolutions
    (e.g. a high-resolution IF image at 0.2125 µm/px paired with a ProSeg mask at 1 µm/px),
    the function previously always used level-0 of both pyramids and then naively cropped them
    to the same pixel count, causing physically misaligned pixel pairing and incorrect intensity
    measurements. The function now selects the image pyramid level whose pixel size is closest
    to the mask pixel size, and applies a small nearest-neighbour zoom to the mask to cover any
    residual mismatch. This also reduces peak memory usage by avoiding loading the full-resolution
    image when the mask has coarser resolution.

  • Fixed hidden files causing errors during directory globbing.
    Files whose names start with . (e.g. .DS_Store) are now filtered out when scanning
    directories for input files such as GeoJSON boundaries.

Internal

  • Upgraded ReadTheDocs build environment to Python 3.13.

Full Changelog: 0.11.2...0.11.3

0.11.2

Choose a tag to compare

@github-actions github-actions released this 31 Mar 11:26

What's Changed

  • fix: make image metadata JSON-serializable before writing to Zarr store (backport to main) by @jwrth in #432

Full Changelog: 0.11.1...0.11.2

0.12.0b3

0.12.0b3 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 20 Mar 11:34

Dependency fixes

  • Pin pandas to <3.0.0: pandas 3.0.0 (released January 2026) changed the default string backend to Arrow-backed arrays (ArrowStringArray), which anndata 0.12.x cannot serialize to HDF5, causing an IORegistryError when saving data via saveas(). Added an explicit pandas (>=1.5.0,<3.0.0) constraint to prevent incompatible environments. Full pandas 3.0 support is expected once anndata 0.13.0 is released.

Full Changelog: 0.12.0b2...0.12.0b3

0.12.0b2

0.12.0b2 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 20 Mar 10:19

Bug fixes

  • Square image handling in scale_to_max_width: Fixed a crash when downscaling square images. The previous dimension computation used np.argmax/np.argmin to identify the long and short axes, which both return index 0 for a square image, leaving one dimension as None. Replaced with a uniform scale factor approach that works correctly for all aspect ratios. (#307)

Internal refactoring

  • Split the monolithic insitupy/containers/dataclasses.py into individual sub-modules (cell_data.py, boundaries_data.py, multi_cell_data.py, shapes_data.py, image_data.py, spatial_units_data.py). This is a non-breaking internal change — the public API is unchanged.
  • Removed the legacy insitupy/dataclasses/ package and the backward-compatibility shim, which had been superseded by the new module layout.
  • Removed unused insitupy/plotting/spatial_old.py.

Full Changelog: 0.12.0b1...0.12.0b2

0.12.0b1

0.12.0b1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 19 Mar 13:20

What's Changed

This beta release is a major code quality and usability overhaul based on a systematic code review, alongside a new MCP server integration.

MCP Server

  • Added insitupy-mcp as a uvx-installable entry point - Claude Desktop users can now activate InSituPy as an MCP server with a single config snippet
  • Expanded MCP tools: datasets guide, result types, interactive viewer guide, images API, SpatialData API
  • MCP server now covers tests/ directory and includes list_test_files tool

API Improvements

  • Standardized parameter names across plotting, tools, and IO (color→keys, save→savepath, slide_id→dataset_name, etc.) with deprecation aliases for backwards compatibility
  • Unified annotation_tuple and region_tuple parameter pattern
  • verbose default changed to False in preprocessing functions
  • Added .read() classmethods to all major data classes

Code Quality

  • ~310 public symbols now have Google-style docstrings
  • Replaced all print() calls with proper logging (~160 across 50+ files)
  • Replaced all assert statements with proper exceptions
  • Fixed several crash bugs in SpatialUnitsData.save(), ImageData.load/save()
  • Package structure: dataclasses/ renamed to containers/

Tests

  • Added test suites for IO readers, image IO, preprocessing, tools, spatialdata conversion, and plotting smoke tests
  • Removed/fixed broken legacy tests

Other

  • Version now read from importlib.metadata instead of hardcoded string
  • Image registration QC improvements by @jwrth in #423

Full Changelog: 0.11.1...0.12.0b1

0.11.1

Choose a tag to compare

@github-actions github-actions released this 26 Feb 14:59

What's Changed

Full Changelog: 0.11.0...0.11.1