# milume
Notebook widgets for spatial omics that stay in sync with Python.
- Install: `pip install milume`
- Documentation: https://ckmah.github.io/milume/docs/
- Repository: https://github.com/ckmah/milume
- Landmarks demo (molab): https://molab.marimo.io/github/ckmah/milume/blob/main/demos/landmarks.py
LandmarksWidget draws selections and landmarks on tissue coordinates in AnnData or
SpatialData.
---
# https://ckmah.github.io/milume/docs/api/landmarks.md
# LandmarksWidget API
Generated from `milume` sources. For narrative guides, see [Quickstart](../quickstart.md).
## `peek()`
```python
def peek(data, **kwargs) -> LandmarksWidget
```
Open a Milume surface on AnnData or SpatialData.
Main notebook entry point for interactive landmarks. Constructs
`LandmarksWidget` with the same keyword arguments.
#### Parameters
- **data, adata** — AnnData with spatial coordinates, or SpatialData (volume inferred). `milume.peek` names this argument `data`; `LandmarksWidget` names the same argument `adata`.
- **spatial_key** — `obsm` key for x/y coordinates (default `"spatial"`).
- **color** — `obs` column or `var_names` gene for point colour. When omitted, the first detected categorical column is used.
- **genes** — Genes to pack for view-only colouring. `None` (default) packs every `var_name`; pass a name or list to restrict the eager catalog.
- **table, image, labels** — SpatialData-only overrides for the inferred table, multiscale image, and labels layer.
- **contrast_limits** — SpatialData-only image contrast `(min, max)` for the Inspect cube.
#### Notes
The widget keeps a reference to `adata` (no `obs.copy()`, no full-`X`
densify at construct). Chrome follows the notebook cell width; height starts
at 720px and is resizable. Marker radius comes from median nearest-neighbor
distance. Neighbourhood expand runs in the browser from coordinates; no
`obsp` graphs are required.
UI chrome (mode, neighbourhoods, raster controls) stays in the browser and
is not part of the notebook API. Raster bins and probe scores are built
client-side from the eager gene, embedding, and category packs.
#### Returns
- **LandmarksWidget** — Widget handle `w`. Synced traitlets include `w.selections` and `w.landmarks`; join to `adata` with `get_obs_names` / `assign_obs_mask`.
#### Examples
```python
import milume
w = milume.peek(adata, color="cell_type")
w = milume.peek(sdata) # table, labels, image inferred
```
---
## Constructor parameters
#### Parameters
- **data, adata** — AnnData with spatial coordinates, or SpatialData (volume inferred). `milume.peek` names this argument `data`; `LandmarksWidget` names the same argument `adata`.
- **spatial_key** — `obsm` key for x/y coordinates (default `"spatial"`).
- **color** — `obs` column or `var_names` gene for point colour. When omitted, the first detected categorical column is used.
- **genes** — Genes to pack for view-only colouring. `None` (default) packs every `var_name`; pass a name or list to restrict the eager catalog.
- **table, image, labels** — SpatialData-only overrides for the inferred table, multiscale image, and labels layer.
- **contrast_limits** — SpatialData-only image contrast `(min, max)` for the Inspect cube.
#### Notes
The widget keeps a reference to `adata` (no `obs.copy()`, no full-`X`
densify at construct). Chrome follows the notebook cell width; height starts
at 720px and is resizable. Marker radius comes from median nearest-neighbor
distance. Neighbourhood expand runs in the browser from coordinates; no
`obsp` graphs are required.
UI chrome (mode, neighbourhoods, raster controls) stays in the browser and
is not part of the notebook API. Raster bins and probe scores are built
client-side from the eager gene, embedding, and category packs.
## Synced traitlets
These traitlets sync between Python and the browser. UI-only chrome (modes, sliders, undoredo) is not listed.
### Selection & landmarks
| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `selections` | List[Dict] | `[]` | Region dicts; join to adata via `get_obs_names` / `assign_obs_mask`. |
| `landmarks` | List[Dict] | `[]` | Committed landmark annotations (round-trip with GeoDataFrame helpers). |
| `selected_kind` | str | `""` | Active item kind (`""` when none). |
| `selected_index` | int | `-1` | Index of active selection or landmark (`-1` when none). |
| `selected_type_indices` | List[Int] | `[]` | Legend indices for multi type focus when kind is `type`. |
### Inspect (SpatialData)
| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `inspect_cx` | float | `None` | Inspect cube centre X (µm); `None` until placed. |
| `inspect_cy` | float | `None` | Inspect cube centre Y (µm); `None` until placed. |
| `inspect_size_um` | float | `300.0` | Inspect window side length (µm; 300 µm square). |
| `volume` | dict | — | SpatialData Inspect cube config (Python-set). |
| `volume_cut` | List[Float] | `[]` | µm cut box; browser writes on slider release. |
### View & coloring
| Name | Type | Default | Meaning |
| --- | --- | --- | --- |
| `active_category` | str | `""` | Category column mirrored from colour chrome. |
| `active_genes` | List[Unicode] | `[]` | View-only gene picks mirrored from chrome. |
### Advanced synced fields
Usually driven from notebook methods (`set_render_mode`, `set_raster_basis`, …) or browser chrome; documented for debugging and extensions.
#### Raster & render mode
## GeoDataFrame interchange
Convert `w.landmarks` to a durable GeoPandas table (and back). Control vertices live in a JSON `vertices` column; `geometry` is a GIS proxy. The widget does not own SpatialData — assign `sdata['landmarks'] = gdf` in the notebook if needed.
Requires optional `geopandas` and `shapely`.
### `landmarks_to_geodataframe()`
```python
def landmarks_to_geodataframe(landmarks: list[dict] | None)
```
Convert widget landmark dicts to a GeoDataFrame.
#### Parameters
- **landmarks** — Landmark dicts from `w.landmarks`, or `None` / `[]` for an empty frame with contract columns (`id`, `type`, `vertices`, …).
#### Returns
- **geopandas.GeoDataFrame** — Proxy `geometry` plus JSON `vertices` as the round-trip source of truth. Callers assign into SpatialData themselves (e.g. `sdata["landmarks"] = gdf`).
#### Examples
```python
import milume
w = milume.peek(adata)
gdf = milume.landmarks_to_geodataframe(w.landmarks)
len(gdf)
```
0
### `geodataframe_to_landmarks()`
```python
def geodataframe_to_landmarks(gdf)
```
Convert a landmarks GeoDataFrame back to widget dicts.
#### Parameters
- **gdf** — GeoDataFrame produced by `landmarks_to_geodataframe`, or `None` / zero rows.
#### Returns
- **list[dict]** — Widget landmark dicts suitable for `w.landmarks = ...`. Empty input yields `[]`.
#### Examples
```python
import milume
w = milume.peek(adata)
w.landmarks = milume.geodataframe_to_landmarks(
```
... milume.landmarks_to_geodataframe(w.landmarks)
... )
## Methods
Notebook helpers on the widget handle returned by `milume.peek`.
### `set_points()`
```python
def set_points(x: Any, y: Any, *, color: Any = None, color_map: dict[str, str] | None = None, legend_title: str | None = None, continuous_range: tuple[str, str] | None = None) -> None
```
Replace scatter points/colors.
### `set_expression()`
```python
def set_expression(expr: Any) -> None
```
Replace the eager gene catalog/matrix from a table (view-only).
Packs all columns immediately for the browser gene picker.
### `set_render_mode()`
```python
def set_render_mode(mode: str) -> None
```
Switch canvas between point scatter and spatial raster bins.
### `set_raster_basis()`
```python
def set_raster_basis(*, genes: str | None = None, embedding: str | None = None, composition: str | None = None) -> None
```
Select bin aggregation basis (genes / embedding / composition).
Pathway / `obs` score columns are deferred (plan slice A); use
`raster_obs_key` later via the same mean-into-bin path.
Bin feature matrices are built in the browser; this only updates traits.
### `clear_raster_query()`
```python
def clear_raster_query() -> None
```
Clear the pinned similarity query bin.
### `set_color()`
```python
def set_color(color: Any, *, color_map: dict[str, str] | None = None, legend_title: str | None = None, continuous_range: tuple[str, str] | None = None) -> None
```
Update point colors without changing x/y.
### `category_colors()`
```python
def category_colors(column: str | None = None) -> dict[str, str]
```
Label -> hex colour of a categorical column, as the map draws it.
Defaults to the active category. Use it to colour other views (plots,
the cube) the same way as the points.
### `clear_selections()`
```python
def clear_selections() -> None
```
Remove every selection from the widget.
### `clear_landmarks()`
```python
def clear_landmarks() -> None
```
Remove every landmark from the widget.
### `clear()`
```python
def clear() -> None
```
Remove all selections and landmarks.
### `select_type()`
```python
def select_type(index: int) -> None
```
Focus one category group in the active set (replaces a multi-select union).
The browser may set `selected_type_indices` to several groups; this
helper is the notebook path for single-group focus without fighting
front-end sync.
### `get_focus_obs_names()`
```python
def get_focus_obs_names(adata: Any, *, spatial_key: str = 'spatial') -> 'np.ndarray'
```
`obs_names` for the current type or selection focus (multi-type union).
### `get_obs_names()`
```python
def get_obs_names(adata: Any = None, selection_id: str | None = 'all', *, spatial_key: str = 'spatial') -> 'np.ndarray'
```
`obs_names` of cells inside `selection_id` (durable join key).
Uses `selection_mask` (geometry or stored `point_indices`).
Neighborhood expand is client-side; promote freezes membership into
`point_indices` before syncing.
With no `adata` the widget's own coordinates and names are used, so
the result cannot depend on which `spatial_key` you pass.
### `assign_obs_mask()`
```python
def assign_obs_mask(adata: Any, key: str, selection_id: str | None = 'all', *, spatial_key: str = 'spatial') -> None
```
Write a boolean column on `adata.obs` for the current selection.
# https://ckmah.github.io/milume/docs/index.md
# milume
**Explore spatial biology in your notebook.**
Layer images, cells, and transcripts in 3D, in one reactive widget.
```python
import milume
w = milume.peek(adata, color="cell_type")
```
## Agents
- [llms.txt](https://ckmah.github.io/milume/llms.txt) — page index
- [llms-full.txt](https://ckmah.github.io/milume/llms-full.txt) — bundled markdown
- Markdown mirrors: append `.md` to doc paths (for example `install.md`)
# https://ckmah.github.io/milume/docs/install.md
# Install
## pip
```bash
pip install milume
```
Requires Python 3.11+.
## From source
```bash
uv sync --extra demo --group dev
```
Use the `demo` extra for marimo notebooks and spatial-omics helpers used by
`demos/`.
## Quickstart
Format data as `AnnData` with coordinates in `obsm["spatial"]`, then open the
widget:
```python
import milume
w = milume.peek(adata, color="cell_type")
w # display in the notebook
```
Full walkthrough: [Quickstart](quickstart.md).
## Next
- [Quickstart](quickstart.md)
- [LandmarksWidget API](api/landmarks/)
- [Open Landmarks demo](https://molab.marimo.io/github/ckmah/milume/blob/main/demos/landmarks.py)
# https://ckmah.github.io/milume/docs/quickstart.md
# Quickstart
LandmarksWidget is the interactive surface for tissue coordinates in
`AnnData` or `SpatialData`. Open it with `milume.peek`, draw a selection, then
read hits back into the notebook with synced traitlets.

## Open the widget
Coordinates must live in `obsm["spatial"]` (or the table’s spatial key on
SpatialData):
```python
import milume
w = milume.peek(adata, color="cell_type")
w = milume.peek(sdata, color="cell_type") # table, labels, image inferred
```
## Use selections downstream
`w.selections` updates on every edit in the browser. After you draw a region,
join to observations by name (not row index):
```python
import pandas as pd
sel_id = w.selections[-1]["id"]
hits = w.get_obs_names(adata, sel_id)
adata.obs["in_lasso"] = adata.obs_names.isin(hits)
# or write a boolean column in one call
w.assign_obs_mask(adata, "in_lasso", selection_id=sel_id)
summary = pd.DataFrame({"cell_type": adata.obs.loc[hits, "cell_type"].value_counts()})
```
Landmarks (`w.landmarks`) are durable geometric annotations; selections are
analysis regions. See the [API reference](api/landmarks/) for traitlets and
methods.
# https://ckmah.github.io/milume/docs/tools/color-layers.md
# Color & layers
Switch the color panel between category, genes and embed; the map recolors to match.
{: .ml-caption }
```python
import milume
w = milume.peek(adata, color="cell_type", genes=["GeneA", "GeneB", "GeneC"])
w.active_category, w.active_genes
```
## Color tabs
The right panel has three pill tabs. They have no icons, so the table names each tab.
| | Tab | What it colors by |
|---|---|---|
| 1 | category | An `obs` category column. Expand it () to toggle single subcategories. |
| 2 | genes | Expression of the picked genes, with ridgeline densities and a blend legend. Pick genes in the field under the legend. |
| 3 | embed | An embedding (for example `X_pca`) mapped to RGB, with an RGB-cube legend. Choose the embedding from the dropdown. |
### genes
### embed
## Points ⇄ Raster
| | Control | What it does |
|---|---|---|
| | points/raster | Flip between drawing each cell as a point and aggregating cells into raster bins (). The icon shows the current mode. |
## Layers list
The left panel lists every selection and landmark.
| | Control | What it does |
|---|---|---|
| 1 | Selections | Click a row to make that selection active. |
| 2 | Landmarks | Click a row to select the landmark and open its context toolbar. |
| | Layer actions | Hide / Show, Rename, Delete. |
| | Collapse left panel ([) | Hide the list; see [Navigate](navigate.md). |
## Python
```python
w.set_render_mode("raster") # or "points"
w.category_colors("cell_type") # {label: hex}, as the map draws it
```
See [Methods](../api/landmarks.md#methods) for `set_color`, `set_raster_basis` and the rest.
## Related
Start with `milume.peek(...)`: see the [Quickstart](../quickstart.md).
# https://ckmah.github.io/milume/docs/tools/inspect-3d.md
# Inspect in 3D
Place a cube window on the map, then orbit and slice image, labels and transcripts together.
{: .ml-caption }
```python
import milume
w = milume.peek(sdata, image="mosaic", labels="cells") # press I, then click the tissue
w.volume_cut # cut-plane state after you slide the cross-section
```
## Entering Inspect
Press I or click Inspect, then click the tissue to place a cube window. The top pill shows the window size, Save window and Exit Inspect (Esc).
## Inspect toolbar
| | Control | What it does |
|---|---|---|
| 1 | Top / Iso / Side | Snap the camera to a top, oblique or side view. |
| 2 | Move | Drag to pan the cube window on the map. |
| | Reset view | Return the cube camera to its default. |
| 3 | Image | Show or hide the image layer. Right-click for palette, contrast, alpha, gamma and projection. |
| 4 | Labels | Show or hide the labels layer. Right-click for projection and fill. Cell outlines stay on. |
| 5 | Points | Show or hide the points layer. |
| | Cross-section | Slide a cut plane through the cube. |
## Cross-section
## Python
```python
w.inspect_cx, w.inspect_cy, w.inspect_size_um # window center and size
w.volume_cut # cut-plane state
```
See [Synced traitlets](../api/landmarks.md#synced-traitlets) for the volume fields, and pass `image=` / `labels=` to `milume.peek` in [Constructor parameters](../api/landmarks.md#constructor-parameters).
## Related
# https://ckmah.github.io/milume/docs/tools/landmarks.md
# Landmarks
Click to place landmark vertices, press Enter to finish, then widen a buffer around the line.
{: .ml-caption }
```python
import milume
w = milume.peek(adata) # press 3, click points, Enter
w.landmarks # list of landmark dicts
```
Landmarks are durable geometric annotations (points, lines, splines, shapes). Selections are analysis regions; see [Select regions](select-regions.md).
## Draw tools
The four landmark tools share one toolbar button. Click it to arm the last-used tool, or right-click it to pick another.
| | Control | What it does |
|---|---|---|
| | Point (1) | Click once to place a point. |
| | Line (2) | Click vertices of a polyline; press Enter to finish. |
| | Spline (3) | Click control points of a smooth curve; press Enter to finish. |
| | Shape (4) | Click vertices of a closed shape; press Enter to finish. |
| | Node (N) | Drag, insert or delete vertices of the selected landmark. |
## Context toolbar
Click a landmark with Select (V) to open its toolbar at the bottom of the map.
| | Control | What it does |
|---|---|---|
| | Line style | Toggle solid or dashed. |
| 1 | Color | Six swatches plus a custom color. |
| 2 | Tension | How tightly a spline follows its control points. |
| 3 | Buffer | Signed buffer width: negative is left or in, positive is right or out. Both sides makes it symmetric; Reset buffer sets it to 0. |
| 4 | Make selection from buffer | Turn the cells inside the buffer into a selection. |
| | Reverse | Flip the direction of a line or spline. |
| 5 | Convert type | Convert between Line, Spline and Shape. |
## Right-click menu
| | Control | What it does |
|---|---|---|
| | Hide / Show | Toggle the landmark's visibility. |
| | Rename | Give the landmark a new name. |
| | Duplicate | Copy the landmark. |
| | Delete (⌫) | Remove the landmark. |
| | Insert node | In Node mode, add a vertex where you right-clicked. |
| | Delete node (⌫) | In Node mode, remove the active vertex. |
## Python
`w.landmarks` updates on every edit. Convert to and from a GeoDataFrame (needs `geopandas`):
```python
from milume import landmarks_to_geodataframe, geodataframe_to_landmarks
gdf = landmarks_to_geodataframe(w.landmarks)
w.landmarks = geodataframe_to_landmarks(gdf)
```
See [GeoDataFrame interchange](../api/landmarks.md#geodataframe-interchange) in the API reference.
## Related
# https://ckmah.github.io/milume/docs/tools/measure.md
# Measure
Quantify landmarks and selections in Python. Every function returns a tidy `pandas.DataFrame` with one row per cell (or per group).
## Setup
Draw a landmark (for example a spline, key 3) and a selection, then build a GeoDataFrame from the widget (needs `geopandas`):
```python
import milume
from milume import landmarks_to_geodataframe
w = milume.peek(adata, color="cell_type")
gdf = landmarks_to_geodataframe(w.landmarks)
sel = w.get_obs_names(adata, w.selections[-1]["id"])
```
`obs_key` names the `obs` column to group cells by; every output has a `group` column with its values. When `obsm["spatial"]` has x, y and z, the outputs also carry `z` and `z_bin` (1 µm bins by default, `z_bin_size=None` turns them off).
## distances
`distances(adata, landmarks, *, obs_key, spatial_key="spatial", obs_names=None, z_bin_size=1.0)`
Per-cell distance to each landmark's geometry. A line or spline with a buffer only measures cells inside the buffer.
```python
from milume import distances
d = distances(adata, gdf, obs_key="cell_type")
d[["obs_name", "landmark_id", "group", "distance"]]
```
## composition
`composition(adata, landmarks, *, obs_key, spatial_key="spatial", obs_names=None, z_bin_size=1.0)`
Counts and proportions of each group inside a shape or a line's buffer.
```python
from milume import composition
c = composition(adata, gdf, obs_key="cell_type")
c.groupby("group")["count"].sum()
```
## along_positions
`along_positions(adata, landmarks, *, obs_key, spatial_key="spatial", obs_names=None, radius=None, z_bin_size=1.0)`
Projects cells onto a line or spline as a normalized arc position `s` from 0 (start) to 1 (end).
```python
from milume import along_positions
s = along_positions(adata, gdf, obs_key="cell_type")
s[["obs_name", "group", "s", "distance"]]
```
## enrichment
`enrichment(adata, obs_names, *, obs_key, background=None)`
Group composition of a cell subset (such as a selection) against a background, all cells by default.
```python
from milume import enrichment
e = enrichment(adata, sel, obs_key="cell_type")
e[["group", "count", "proportion", "background_proportion", "log2_enrichment"]]
```
## nearest_distances
`nearest_distances(adata, seeds, *, obs_key, spatial_key="spatial", obs_names=None)`
Distance from every cell to its nearest seed cell, in XY and in XYZ. Needs x, y, z in `obsm["spatial"]`.
```python
from milume import nearest_distances
n = nearest_distances(adata, sel, obs_key="cell_type")
n[["obs_name", "group", "seed", "distance_xy", "distance_xyz"]]
```
## write_obs
`write_obs(adata, df, column, value_col, *, obs_name_col="obs_name")`
Writes a per-cell measurement back into `adata.obs`, aligned by `obs_name`. Cells missing from `df` stay NaN.
```python
from milume import write_obs
write_obs(adata, d, "dist_to_landmark", "distance")
adata.obs["dist_to_landmark"].describe()
```
The new column works like any other `obs` column, for example in `scanpy` plots or as input to the next `peek`.
## Related
# https://ckmah.github.io/milume/docs/tools/navigate.md
# Navigate
Scroll to zoom, drag to pan, and press 0 to fit the whole tissue back in view.
{: .ml-caption }
```python
import milume
w = milume.peek(sdata) # press H to pan, = / - to zoom, 0 to reset
```
## Controls
| | Control | What it does |
|---|---|---|
| | Select (V) | Default tool. Click a selection or landmark to open its context toolbar. |
| | Move (H) | Drag anywhere to pan. Hold Space to pan with any tool. |
| | Zoom in (=) | Zoom in one step. The scroll wheel also zooms. |
| | Zoom out (-) | Zoom out one step. |
| | Reset view (0) | Fit all cells in view. |
| | Canvas rulers | Show coordinate rulers along the top and left edges. |
| | Full screen (F) | Fill the screen with the widget; Exit full screen returns. |
| | Collapse left / right panel ([ / ]) | Hide a side panel; Show left panel brings it back. |
| | Minimap | Drag the viewport box to pan; scroll on it to zoom. |
### Minimap
### Canvas rulers
## Keyboard shortcuts
| Action | Keys |
|---|---|
| Select | V |
| Move | H |
| Pan while held (any tool) | Space |
| Zoom in / out | = / - |
| Reset view | 0 |
| Full screen | F |
| Collapse left / right panel | [ / ] |
| Deselect, cancel a draft | Esc |
## Python
The active tool and the rulers are synced traitlets, so you can set them from a cell:
```python
w.mode = "move" # same as pressing H
w.show_rulers = True
```
See [Synced traitlets](../api/landmarks.md#synced-traitlets) for the full list.
## Related
# https://ckmah.github.io/milume/docs/tools/probe.md
# Probe
Hover a bin with Probe on; similar bins light up. Click to pin the query.
{: .ml-caption }
Probe compares raster bins, so switch the map to raster first ( points/raster; see [Color & layers](color-layers.md)).
```python
import milume
w = milume.peek(adata, genes=["GeneA", "GeneB", "GeneC"])
w.set_render_mode("raster") # then press P and hover
```
## Controls
| | Control | What it does |
|---|---|---|
| | Probe (P) | Hover a bin to color every bin by its similarity to it; click to pin that bin. |
| | Similarity legend | Color scale from 0 (dissimilar) to 1 (identical), shown in the right panel while Probe is on. |
| | Esc | Clear the probe. |
With the genes tab active, similarity uses the picked genes; pick at least one gene first, or hovering does nothing.
## Pinned query
## Python
```python
w.raster_similarity_enabled = True # similarity coloring without the Probe tool
w.raster_threshold = 0.5 # similarity cutoff for the map
w.raster_query_bin # pinned bin index, -1 when none
w.clear_raster_query()
```
See [Synced traitlets](../api/landmarks.md#synced-traitlets) and [Methods](../api/landmarks.md#methods).
## Related
# https://ckmah.github.io/milume/docs/tools/select-regions.md
# Select regions
Draw a lasso, square, circle or shape around cells, then read the selection back in Python.
{: .ml-caption }
```python
import milume
w = milume.peek(adata) # press L, then drag around some cells
sel_id = w.selections[-1]["id"]
```
## Controls
The four selection tools share one toolbar button. Click it to arm the last-used tool, or right-click it to pick another.
| | Control | What it does |
|---|---|---|
| | Lasso (L) | Drag a freehand outline. |
| | Square (R) | Drag a rectangle. |
| | Circle (O) | Drag an ellipse. |
| | Shape (G) | Click vertices of a polygon; press Enter to finish. |
| | Shape menu (right-click) | Choose which of the four tools the button arms. |
| | Layer actions | Rename, hide or delete the selection from the layers list. |
### Square and circle
### While a selection is active
The cells inside stay at full color and the right panel counts only them. A small toolbar at the bottom of the map offers Radius neighborhood and k-NN neighborhood around the selection, with Make selection to keep that neighborhood as a new selection. Press ⌫ or Delete to remove the active selection.
## Python
`w.selections` updates on every edit. Join hits to observations by name:
```python
hits = w.get_obs_names(adata, sel_id) # obs names inside
w.assign_obs_mask(adata, "in_region", selection_id=sel_id)
w.clear_selections()
```
See [Methods](../api/landmarks.md#methods) for the full signatures.
## Related