3333
3434from spatialdata_plot ._logging import _log_context , logger
3535from spatialdata_plot .pl ._color import (
36+ ColorSpec ,
3637 ColorType ,
37- _align_outline_vector_to_length ,
38- _apply_mask_to_outline_vectors ,
3938 _color_vector_to_rgba ,
4039 _get_colors_for_categorical_obs ,
4140 _get_linear_colormap ,
@@ -646,8 +645,7 @@ def _render_shapes(
646645
647646 col_for_outline_color = render_params .col_for_outline_color
648647 outline_table_name = render_params .outline_table_name
649- outline_color_source_vector : pd .Series | None = None
650- outline_color_vector : Any = None
648+ outline_color_spec : ColorSpec | None = None
651649 if col_for_outline_color is not None :
652650 # When the outline column lives in a table that hasn't been joined yet
653651 # (no fill table, or a different table than fill's), left-join it onto
@@ -675,51 +673,41 @@ def _render_shapes(
675673 table_layer = table_layer ,
676674 coordinate_system = coordinate_system ,
677675 )
678- outline_color_source_vector , outline_color_vector = (
679- outline_color_spec .source_vector ,
680- outline_color_spec .color_vector ,
681- )
682676 # Cross-table case: if fill and outline tables differ and the outline table does
683677 # not annotate every row of the (fill-joined) element, the vector length will
684678 # differ from the rendered element row count. Warn + align so per-shape lookup stays
685679 # well-defined.
686680 _n_shapes = len (sdata_filt [element ])
687- if outline_color_vector is not None and len (outline_color_vector ) != _n_shapes :
681+ if len (outline_color_spec . color_vector ) != _n_shapes :
688682 logger .warning (
689683 f"Outline column '{ col_for_outline_color } ' does not fully annotate "
690684 f"element '{ element } ' under its fill-joined alignment "
691- f"({ len (outline_color_vector )} of { _n_shapes } rows). Missing rows will use na_color."
692- )
693- outline_color_vector , outline_color_source_vector = _align_outline_vector_to_length (
694- outline_color_vector ,
695- outline_color_source_vector ,
696- _n_shapes ,
685+ f"({ len (outline_color_spec .color_vector )} of { _n_shapes } rows). Missing rows will use na_color."
697686 )
687+ outline_color_spec = outline_color_spec .align_to_length (_n_shapes , render_params .cmap_params .na_color )
698688
699689 _warn_groups (groups , colortype , color_spec .source_vector , col_for_color )
700690
701691 # When groups are specified, filter out non-matching elements by default.
702692 # Only show non-matching elements if the user explicitly sets na_color.
703693 _na = render_params .cmap_params .na_color
704- if (
705- groups is not None
706- and color_spec .source_vector is not None
707- and (_na .default_color_set or _na .is_fully_transparent ())
708- ):
694+ if groups is not None and color_spec .is_categorical and (_na .default_color_set or _na .is_fully_transparent ()):
709695 keep = color_spec .source_vector .isin (groups )
710696 color_spec = color_spec .filter (keep )
711697 shapes = shapes [keep ].reset_index (drop = True )
712698 if len (shapes ) == 0 :
713699 return
714700 sdata_filt [element ] = shapes
715- if outline_color_vector is not None :
716- outline_color_vector , outline_color_source_vector = _apply_mask_to_outline_vectors (
717- outline_color_vector , outline_color_source_vector , keep
718- )
701+ if outline_color_spec is not None :
702+ outline_color_spec = outline_color_spec .filter (keep )
719703
720- # carrier pipeline done; unpack the final vectors for the read/draw phase below
721704 color_spec = color_spec .apply_transfunc (render_params .transfunc )
722705 color_source_vector , color_vector = color_spec .source_vector , color_spec .color_vector
706+ outline_color_source_vector , outline_color_vector = (
707+ (outline_color_spec .source_vector , outline_color_spec .color_vector )
708+ if outline_color_spec is not None
709+ else (None , None )
710+ )
723711
724712 norm = render_params .cmap_params .fresh_norm ()
725713
@@ -1454,11 +1442,7 @@ def _render_points(
14541442 # When groups are specified, filter out non-matching elements by default.
14551443 # Only show non-matching elements if the user explicitly sets na_color.
14561444 _na = render_params .cmap_params .na_color
1457- if (
1458- groups is not None
1459- and color_spec .source_vector is not None
1460- and (_na .default_color_set or _na .is_fully_transparent ())
1461- ):
1445+ if groups is not None and color_spec .is_categorical and (_na .default_color_set or _na .is_fully_transparent ()):
14621446 keep = color_spec .source_vector .isin (groups )
14631447 color_spec = color_spec .filter (keep )
14641448 n_points = int (keep .sum ())
@@ -1469,7 +1453,6 @@ def _render_points(
14691453 adata = adata [keep ]
14701454 _reparse_points (sdata_filt , element , points , transformation_in_cs , coordinate_system , col_for_color )
14711455
1472- # carrier pipeline done; unpack the final vectors for the read/draw phase below
14731456 color_spec = color_spec .apply_transfunc (render_params .transfunc )
14741457 color_source_vector , color_vector = color_spec .source_vector , color_spec .color_vector
14751458
@@ -2284,8 +2267,7 @@ def _render_labels(
22842267 # to the outline vectors to keep lengths consistent.
22852268 col_for_outline_color = render_params .col_for_outline_color
22862269 outline_table_name = render_params .outline_table_name
2287- outline_color_source_vector : pd .Series | None = None
2288- outline_color_vector : Any = None
2270+ outline_color_spec : ColorSpec | None = None
22892271 if col_for_outline_color is not None :
22902272 outline_color_spec = resolve_color (
22912273 sdata = sdata_filt ,
@@ -2301,18 +2283,10 @@ def _render_labels(
23012283 render_type = "labels" ,
23022284 coordinate_system = coordinate_system ,
23032285 )
2304- outline_color_source_vector , outline_color_vector = (
2305- outline_color_spec .source_vector ,
2306- outline_color_spec .color_vector ,
2307- )
23082286 # Align to instance_id so the rasterize/groups masks (computed against
23092287 # instance_id) can be applied without IndexError when the outline table
23102288 # annotates a subset of the labels.
2311- outline_color_vector , outline_color_source_vector = _align_outline_vector_to_length (
2312- outline_color_vector ,
2313- outline_color_source_vector ,
2314- len (instance_id ),
2315- )
2289+ outline_color_spec = outline_color_spec .align_to_length (len (instance_id ), render_params .cmap_params .na_color )
23162290
23172291 # rasterize/downsampling can drop labels from the raster; remove their (now-absent) instance ids
23182292 # so per-instance colors stay aligned and as_points does not emit dots for dropped cells.
@@ -2321,10 +2295,8 @@ def _render_labels(
23212295 instance_id = instance_id [mask ]
23222296 if col_for_color is not None :
23232297 color_spec = color_spec .filter (mask )
2324- if outline_color_vector is not None :
2325- outline_color_vector , outline_color_source_vector = _apply_mask_to_outline_vectors (
2326- outline_color_vector , outline_color_source_vector , mask
2327- )
2298+ if outline_color_spec is not None :
2299+ outline_color_spec = outline_color_spec .filter (mask )
23282300
23292301 _warn_groups (groups , colortype , color_spec .source_vector , col_for_color )
23302302
@@ -2344,14 +2316,16 @@ def _render_labels(
23442316 label .values [~ keep_mask ] = 0
23452317 instance_id = instance_id [keep_vec ]
23462318 color_spec = color_spec .filter (keep_vec )
2347- if outline_color_vector is not None :
2348- outline_color_vector , outline_color_source_vector = _apply_mask_to_outline_vectors (
2349- outline_color_vector , outline_color_source_vector , keep_vec
2350- )
2319+ if outline_color_spec is not None :
2320+ outline_color_spec = outline_color_spec .filter (keep_vec )
23512321
2352- # carrier pipeline done; unpack the final vectors for the read/draw phase below
23532322 color_spec = color_spec .apply_transfunc (render_params .transfunc )
23542323 color_source_vector , color_vector = color_spec .source_vector , color_spec .color_vector
2324+ outline_color_source_vector , outline_color_vector = (
2325+ (outline_color_spec .source_vector , outline_color_spec .color_vector )
2326+ if outline_color_spec is not None
2327+ else (None , None )
2328+ )
23552329
23562330 if render_params .as_points :
23572331 # Fast mode: one dot per label at its centroid. Compute on the *rendered* raster (already
0 commit comments