Skip to content

Commit 7ccbc11

Browse files
committed
fix(legend): correct the high-cardinality legend warning for custom palettes
The skipped-legend warning claimed points are "uniform grey" past the limit, but that only holds for scanpy's default palette — a custom cmap/palette gives distinct colors for >102 categories (verified: cmap='viridis' + 150 cats → 150 distinct colors). Reword to the palette-agnostic, true reasons (a per-entry legend that large is unreadable and O(categories^2) slow to build). The skip itself is unchanged and defensible regardless of palette.
1 parent 1799412 commit 7ccbc11

1 file changed

Lines changed: 7 additions & 8 deletions

File tree

src/spatialdata_plot/pl/utils.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -448,10 +448,9 @@ def _stack_categorical_legend(
448448
new_leg._sdata_column = column # type: ignore[attr-defined]
449449

450450

451-
# scanpy assigns distinguishable colors only up to len(default_102) categories; beyond that it warns
452-
# and colors every point uniform grey (_set_default_colors_for_categorical_obs). At that point a
453-
# per-entry legend is meaningless AND scanpy builds it in O(categories^2) (one autoscaling artist each,
454-
# dominating the render), so we skip it with a warning. Tied to scanpy's palette so the two stay in sync.
451+
# A per-entry legend past this many categories is unreadable, and scanpy builds it in O(categories^2)
452+
# (one autoscaling artist each), dominating the render — so skip it with a warning. Tied to scanpy's
453+
# default_102 palette, beyond which its *default* colors also stop being distinguishable (uniform grey).
455454
_MAX_LEGEND_CATEGORIES = len(palettes.default_102)
456455

457456

@@ -507,12 +506,12 @@ def _decorate_axs(
507506
if legend_loc in (None, "none"):
508507
pass # legend suppressed
509508
elif len(clusters) > _MAX_LEGEND_CATEGORIES:
510-
# Past scanpy's palette limit the points are all uniform grey anyway, so a per-entry legend
511-
# carries no information and (built in O(categories^2)) dominates the render. Skip it.
509+
# A per-entry legend this large is unreadable and scanpy builds it in O(categories^2)
510+
# (one autoscaling artist each), dominating the render. Skip it.
512511
logger.warning(
513512
f"Skipping the categorical legend for '{value_to_plot}': {len(clusters)} categories "
514-
f"exceed scanpy's {_MAX_LEGEND_CATEGORIES}-color palette (points are uniform grey past "
515-
f"that). Pass a `groups` subset to get a legend."
513+
f"exceed the {_MAX_LEGEND_CATEGORIES}-entry limit (unreadable and very slow to build). "
514+
f"Pass a `groups` subset to get a legend."
516515
)
517516
elif already:
518517
na_hex = na_color.get_hex() if (na_in_legend and pd.isnull(color_source_vector).any()) else None

0 commit comments

Comments
 (0)