Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 37 additions & 37 deletions docs/assets/js/celldega.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions js/utils/scale_bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const create_scale_bar = (micronsPerPixel, tech) => {
const rev_labelColor = labelColor === 'white' ? 'black' : 'white';

const container = document.createElement('div');
container.className = 'celldega-scale-bar';
container.style.position = 'absolute';
container.style.bottom = '10px';
container.style.left = '10px';
Expand Down
6 changes: 5 additions & 1 deletion js/viz/landscape_ist.js
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,11 @@ export const landscape_ist = async (
const defaultMicronsPerPixel = PIXEL_SIZE_MICRONS[tech];
const micronsPerPixel = defaultMicronsPerPixel ?? userMicronsPerPixel;

if (micronsPerPixel) {
// Only show the scale bar when explicitly enabled. Defaults to the value the
// Python widget resolves from whether a real transformation matrix was passed
// (identity fallback => hidden, since the pixel->micron scale is unknown).
const display_scalebar = ini_model.get('display_scalebar');
if (micronsPerPixel && display_scalebar !== false) {
viz_state.scale_bar = create_scale_bar(micronsPerPixel, tech);
root.appendChild(viz_state.scale_bar.container);
}
Expand Down
3 changes: 2 additions & 1 deletion js/viz/yearbook.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@
const micronsPerPixel = defaultMicronsPerPixel ?? userMicronsPerPixel;
viz_state.yearbook.micronsPerPixel = micronsPerPixel;

if (micronsPerPixel) {
const display_scalebar = ini_model.get('display_scalebar');
if (micronsPerPixel && display_scalebar !== false) {
viz_state.scale_bar = create_scale_bar(micronsPerPixel, tech);
root.appendChild(viz_state.scale_bar.container);
}
Expand Down Expand Up @@ -575,11 +576,11 @@
}

const geneCounts = viz_state.yearbook.geneCountScratch;
const activeGeneIds = viz_state.yearbook.activeGeneIds;

Check warning on line 579 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality

Use object destructuring

Check warning on line 579 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality / quality

Use object destructuring
activeGeneIds.length = 0;

for (let i = 0; i < trxCompact.geneIds.length; i++) {
const positions = trxCompact.positions;

Check warning on line 583 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality

Use object destructuring

Check warning on line 583 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality / quality

Use object destructuring
const x = positions[i * trxCompact.size];
const y = positions[i * trxCompact.size + 1];
const inPortrait = centers.some((center) => {
Expand Down Expand Up @@ -636,11 +637,11 @@
}

const cellCounts = viz_state.yearbook.cellCountScratch;
const activeCellIds = viz_state.yearbook.activeCellIds;

Check warning on line 640 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality

Use object destructuring

Check warning on line 640 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality / quality

Use object destructuring
activeCellIds.length = 0;

for (let i = 0; i < cellCompact.categoryIds.length; i++) {
const positions = cellCompact.positions;

Check warning on line 644 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality

Use object destructuring

Check warning on line 644 in js/viz/yearbook.js

View workflow job for this annotation

GitHub Actions / quality / quality

Use object destructuring
const x = positions[i * cellCompact.size];
const y = positions[i * cellCompact.size + 1];
const inPortrait = centers.some((center) => {
Expand Down
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ dependencies = [
"requests",
"scanpy~=1.10.0",
"shapely~=2.0.0",
"setuptools",
# Pin <81: setuptools 81+ removed pkg_resources, which xarray_schema
# (a spatialdata/squidpy transitive dep) still imports at import time.
"setuptools<81",
"spatialdata",
"spatialdata_io~=0.1.0",
"squidpy~=1.6.0",
Expand All @@ -48,7 +50,7 @@ dev = [
"pytest-html", # HTML coverage reports
"pytest-mock", # Mocking utilities
"pre-commit", # Git hooks automation
"setuptools",
"setuptools<81", # <81: keeps pkg_resources for xarray_schema
"build", # Package building
"twine", # PyPI publishing
# Documentation dependencies
Expand Down
25 changes: 25 additions & 0 deletions src/celldega/viz/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,11 @@ class Landscape(anywidget.AnyWidget):
cell_name_prefix (bool, optional): If True, cell names in adata.obs.index
are assumed to have a dataset prefix (e.g., "dataset-name_cell-name")
that should be trimmed when mapping to LandscapeFiles. Default: False.
display_scalebar (bool, optional): Whether to show the scale bar. If omitted,
it is shown only when a real transformation matrix is passed (via
``transform``) or loaded from ``micron_to_image_transform.csv`` — when the
identity fallback is used the pixel-to-micron scale is unknown, so the bar
is hidden. Pass True/False to force it on or off.

The AnnData input automatically extracts cell attributes (e.g., ``leiden``
clusters), the corresponding colors (or derives them when missing), and any
Expand Down Expand Up @@ -261,6 +266,10 @@ class Landscape(anywidget.AnyWidget):
scale_bar_microns_per_pixel = traitlets.Float(default_value=None, allow_none=True).tag(
sync=True
)
# Whether to show the scale bar. Resolved in __init__: defaults to True only
# when a real transformation matrix is passed/loaded (identity fallback => False),
# and can be overridden explicitly via the ``display_scalebar`` kwarg.
display_scalebar = traitlets.Bool(True).tag(sync=True)

nbhd = traitlets.Instance(gpd.GeoDataFrame, allow_none=True)
nbhd_geojson = traitlets.Dict({}).tag(sync=True)
Expand Down Expand Up @@ -301,6 +310,8 @@ def __init__(self, **kwargs):
nbhd_gdf = kwargs.pop("nbhd", None)
meta_nbhd_df = kwargs.pop("meta_nbhd", None)
transform = kwargs.pop("transform", None)
# None => auto (show only when a real transform is resolved); True/False => force.
display_scalebar = kwargs.pop("display_scalebar", None)
image_scale = kwargs.pop("image_scale", None)
nbhd_edit = kwargs.pop("nbhd_edit", False)
meta_cluster_df = None
Expand Down Expand Up @@ -368,16 +379,22 @@ def __init__(self, **kwargs):
base_path = (kwargs.get("base_url") or "") + "/"
path_transformation_matrix = base_path + "micron_to_image_transform.csv"

# Explicit signal for whether a real transform was resolved (vs. the identity
# fallback). Drives the scale bar default so it isn't shown against an unknown
# pixel->micron scale.
if transform is not None:
transformation_matrix = _coerce_transform_matrix(transform)
has_transform = True
else:
try:
transformation_matrix = pd.read_csv(
path_transformation_matrix, header=None, sep=r"\s+"
).values
transformation_matrix = _coerce_transform_matrix(transformation_matrix)
has_transform = True
except (FileNotFoundError, urllib.error.HTTPError, urllib.error.URLError):
transformation_matrix = np.eye(3) # Fallback for testing
has_transform = False
warnings.warn(
f"Transformation matrix not found at {path_transformation_matrix}. "
"Using identity.",
Expand Down Expand Up @@ -512,6 +529,11 @@ def _reset_index_for_parquet(df):

super().__init__(**kwargs)

# Auto (None) => show only when a real transform was resolved; else honor the override.
self.display_scalebar = (
has_transform if display_scalebar is None else bool(display_scalebar)
)

self.cell_attr = cell_attr

# store DataFrames locally without syncing to the frontend
Expand Down Expand Up @@ -769,6 +791,9 @@ class Yearbook(anywidget.AnyWidget):
scale_bar_microns_per_pixel = traitlets.Float(default_value=None, allow_none=True).tag(
sync=True
)
# Show the scale bar (Yearbook portraits use a fixed micron size, so this defaults
# to True). Set ``display_scalebar=False`` to hide it.
display_scalebar = traitlets.Bool(True).tag(sync=True)

# Pagination
current_page = traitlets.Int(0).tag(sync=True)
Expand Down
Loading