@@ -209,24 +209,50 @@ def _get_coordinate_system_mapping(sdata: SpatialData) -> dict[str, list[str]]:
209209 return mapping
210210
211211
212+ _MPL_SINGLE_LETTER_COLORS = frozenset ("bgrcmykw" )
213+
214+
212215def _is_color_like (color : Any ) -> bool :
213216 """Check if a value is a valid color.
214217
215- For discussion, see: https://github.com/scverse/spatialdata-plot/issues/327.
216- matplotlib accepts strings in [0, 1] as grey-scale values - therefore,
217- "0" and "1" are considered valid colors. However, we won't do that
218- so we're filtering these out.
218+ We reject several matplotlib shorthand notations that are likely to collide
219+ with column or gene names. For discussion, see:
220+
221+ - https://github.com/scverse/spatialdata-plot/issues/211
222+ - https://github.com/scverse/spatialdata-plot/issues/327
223+
224+ Rejected shorthands:
225+
226+ - Greyscale strings: ``"0"``, ``"0.5"``, ``"1"`` (floats in [0, 1])
227+ - Short hex: ``"#RGB"`` / ``"#RGBA"`` (only ``#RRGGBB`` / ``#RRGGBBAA`` accepted)
228+ - Single-letter colors: ``"b"``, ``"g"``, ``"r"``, ``"c"``, ``"m"``, ``"y"``, ``"k"``, ``"w"``
229+ - CN cycle notation: ``"C0"``, ``"C1"``, …
230+ - ``tab:`` prefixed colors: ``"tab:blue"``, ``"tab:orange"``, …
231+ - ``xkcd:`` prefixed colors: ``"xkcd:sky blue"``, …
219232 """
220233 if isinstance (color , str ):
234+ # greyscale strings
221235 try :
222236 num_value = float (color )
223237 if 0 <= num_value <= 1 :
224238 return False
225239 except ValueError :
226- # we're not dealing with what matplotlib considers greyscale
227240 pass
241+
242+ # short hex
228243 if color .startswith ("#" ) and len (color ) not in [7 , 9 ]:
229- # we only accept hex colors in the form #RRGGBB or #RRGGBBAA, not short forms as matplotlib does
244+ return False
245+
246+ # single-letter color shortcuts
247+ if color in _MPL_SINGLE_LETTER_COLORS :
248+ return False
249+
250+ # CN cycle notation (C0, C1, …)
251+ if len (color ) >= 2 and color [0 ] == "C" and color [1 :].isdigit ():
252+ return False
253+
254+ # tab: and xkcd: prefixed colors
255+ if color .startswith (("tab:" , "xkcd:" )):
230256 return False
231257
232258 return bool (colors .is_color_like (color ))
0 commit comments