@@ -180,11 +180,11 @@ def _reparse_points(
180180
181181def _warn_groups_ignored_continuous (
182182 groups : str | list [str ] | None ,
183- colortype : ColorType ,
183+ color_spec : ColorSpec ,
184184 col_for_color : str | None ,
185185) -> None :
186186 """Warn when ``groups`` is set but coloring is continuous (no categorical source)."""
187- if groups is not None and colortype == "continuous" and col_for_color is not None :
187+ if groups is not None and color_spec . is_continuous and col_for_color is not None :
188188 logger .warning (
189189 f"`groups` is ignored when coloring by continuous column '{ col_for_color } '. "
190190 "`groups` filters categories of the column specified via `color`; "
@@ -204,22 +204,21 @@ def _reject_continuous_color_under_density(
204204 sdata_filt : sd .SpatialData ,
205205 element : str ,
206206 col_for_color : str | None ,
207- colortype : ColorType ,
208- color_vector : Any ,
207+ color_spec : ColorSpec ,
209208) -> None :
210209 """Raise before any materialization if density+continuous-color was requested.
211210
212- Only ``continuous`` coloring is rejected; categorical and none are fine. When the colortype
213- is not yet decisive we read the dtype from the dask source (points element column) or the
214- pre-computed color vector — neither forces a ``.compute()``.
211+ Only ``continuous`` coloring is rejected; categorical and none are fine. We read the dtype from
212+ the dask source (points element column) or the pre-computed color vector — neither forces a
213+ ``.compute()``.
215214 """
216- if col_for_color is None or colortype != "continuous" :
215+ if col_for_color is None or not color_spec . is_continuous :
217216 return
218217 points_columns = sdata_filt .points [element ].columns
219218 if col_for_color in points_columns :
220219 dtype = sdata_filt .points [element ][col_for_color ].dtype
221220 else :
222- dtype = getattr (color_vector , "dtype" , None )
221+ dtype = getattr (color_spec . color_vector , "dtype" , None )
223222 if dtype is None or _is_categorical_like_dtype (dtype ):
224223 return
225224 raise ValueError (
@@ -262,15 +261,14 @@ def _warn_missing_groups(
262261
263262def _warn_groups (
264263 groups : str | list [str ] | None ,
265- colortype : ColorType ,
266- color_source_vector : pd .Categorical | None ,
264+ color_spec : ColorSpec ,
267265 col_for_color : str | None ,
268266) -> None :
269267 """Emit the two groups-related warnings every ``_render_*`` preamble shares."""
270- _warn_groups_ignored_continuous (groups , colortype , col_for_color )
268+ _warn_groups_ignored_continuous (groups , color_spec , col_for_color )
271269 # only a categorical source has `.categories`; the none state (na-array source) must not reach it
272- if groups is not None and colortype == "categorical" :
273- _warn_missing_groups (groups , color_source_vector , col_for_color )
270+ if groups is not None and color_spec . is_categorical :
271+ _warn_missing_groups (groups , color_spec . source_vector , col_for_color )
274272
275273
276274def _split_colorbar_params (
@@ -684,13 +682,11 @@ def _render_shapes(
684682 )
685683 outline_color_spec = outline_color_spec .align_to_length (_n_shapes , render_params .cmap_params .na_color )
686684
687- _warn_groups (groups , colortype , color_spec . source_vector , col_for_color )
685+ _warn_groups (groups , color_spec , col_for_color )
688686
689- # When groups are specified, filter out non-matching elements by default.
690- # Only show non-matching elements if the user explicitly sets na_color.
691- _na = render_params .cmap_params .na_color
692- if groups is not None and color_spec .is_categorical and (_na .default_color_set or _na .is_fully_transparent ()):
693- keep = color_spec .source_vector .isin (groups )
687+ # groups filters to matching categories by default; a visible na_color keeps non-matching rows.
688+ keep = color_spec .groups_keep_mask (groups , render_params .cmap_params .na_color )
689+ if keep is not None :
694690 color_spec = color_spec .filter (keep )
695691 shapes = shapes [keep ].reset_index (drop = True )
696692 if len (shapes ) == 0 :
@@ -862,7 +858,7 @@ def _render_shapes(
862858
863859 transformed_element [col_for_color ] = color_vector if color_source_vector is None else color_source_vector
864860 # Render shapes with datashader
865- color_by_categorical = col_for_color is not None and color_source_vector is not None
861+ color_by_categorical = color_spec . is_categorical
866862 if color_by_categorical :
867863 cat_series = transformed_element [col_for_color ]
868864 if not isinstance (cat_series .dtype , pd .CategoricalDtype ):
@@ -1430,16 +1426,13 @@ def _render_points(
14301426 col_for_color ,
14311427 )
14321428
1433- _warn_groups (groups , colortype , color_spec . source_vector , col_for_color )
1429+ _warn_groups (groups , color_spec , col_for_color )
14341430
1435- # When groups are specified, filter out non-matching elements by default.
1436- # Only show non-matching elements if the user explicitly sets na_color.
1437- _na = render_params .cmap_params .na_color
1438- if groups is not None and color_spec .is_categorical and (_na .default_color_set or _na .is_fully_transparent ()):
1439- keep = color_spec .source_vector .isin (groups )
1431+ # groups filters to matching categories by default; a visible na_color keeps non-matching rows.
1432+ keep = color_spec .groups_keep_mask (groups , render_params .cmap_params .na_color )
1433+ if keep is not None :
14401434 color_spec = color_spec .filter (keep )
1441- n_points = int (keep .sum ())
1442- if n_points == 0 :
1435+ if int (keep .sum ()) == 0 :
14431436 return
14441437 # filter the materialized points, adata, and re-register in sdata_filt
14451438 points = points [keep ].reset_index (drop = True )
@@ -1457,7 +1450,7 @@ def _render_points(
14571450
14581451 if render_params .density :
14591452 method = "datashader"
1460- _reject_continuous_color_under_density (sdata_filt , element , col_for_color , colortype , color_vector )
1453+ _reject_continuous_color_under_density (sdata_filt , element , col_for_color , color_spec )
14611454 elif method is None :
14621455 method = "datashader" if n_points > 10000 else "matplotlib"
14631456
@@ -2253,7 +2246,6 @@ def _render_labels(
22532246 coordinate_system = coordinate_system ,
22542247 )
22552248 colortype = color_spec .colortype
2256- categorical = color_spec .is_categorical
22572249
22582250 # Outline color lookup must run BEFORE any masking so the returned vector aligns to
22592251 # the original instance_id. The same masks applied to fill below are then applied
@@ -2291,18 +2283,12 @@ def _render_labels(
22912283 if outline_color_spec is not None :
22922284 outline_color_spec = outline_color_spec .filter (mask )
22932285
2294- _warn_groups (groups , colortype , color_spec . source_vector , col_for_color )
2286+ _warn_groups (groups , color_spec , col_for_color )
22952287
22962288 # When groups are specified, zero out non-matching label IDs so they render as background.
22972289 # Only show non-matching labels if the user explicitly sets na_color.
2298- _na = render_params .cmap_params .na_color
2299- if (
2300- groups is not None
2301- and categorical
2302- and color_spec .source_vector is not None
2303- and (_na .default_color_set or _na .is_fully_transparent ())
2304- ):
2305- keep_vec = color_spec .source_vector .isin (groups )
2290+ keep_vec = color_spec .groups_keep_mask (groups , render_params .cmap_params .na_color )
2291+ if keep_vec is not None :
23062292 matching_ids = instance_id [keep_vec ]
23072293 keep_mask = np .isin (label .values , matching_ids )
23082294 label = label .copy ()
@@ -2400,8 +2386,10 @@ def _draw_labels(
24002386 cax = ax .imshow (
24012387 labels ,
24022388 rasterized = True ,
2403- cmap = None if categorical else render_params .cmap_params .cmap ,
2404- norm = None if categorical else _resolve_continuous_norm (color_vector , render_params .cmap_params ),
2389+ cmap = None if color_spec .is_categorical else render_params .cmap_params .cmap ,
2390+ norm = None
2391+ if color_spec .is_categorical
2392+ else _resolve_continuous_norm (color_vector , render_params .cmap_params ),
24052393 alpha = alpha ,
24062394 origin = "lower" ,
24072395 zorder = render_params .zorder ,
0 commit comments