@@ -1018,6 +1018,23 @@ def _render_points(
10181018 )
10191019
10201020
1021+ def _normalize_dtype_to_float (arr : np .ndarray ) -> np .ndarray :
1022+ """Normalize an integer or float array to float64 in [0, 1] for matplotlib.
1023+
1024+ - uint8 → divide by 255
1025+ - other int/uint dtypes → divide by dtype max
1026+ - float → clip to [0, 1]
1027+ """
1028+ if arr .dtype == np .uint8 :
1029+ return arr .astype (np .float64 ) / 255.0
1030+ if arr .dtype .kind == "u" :
1031+ return arr .astype (np .float64 ) / np .iinfo (arr .dtype ).max
1032+ if arr .dtype .kind == "i" :
1033+ return np .clip (arr .astype (np .float64 ) / np .iinfo (arr .dtype ).max , 0 , 1 )
1034+ result : np .ndarray = np .clip (arr , 0 , 1 ).astype (np .float64 )
1035+ return result
1036+
1037+
10211038def _is_rgb_image (channel_coords : list [Any ]) -> tuple [bool , bool ]:
10221039 """Check if channel coordinates indicate an RGB(A) image.
10231040
@@ -1112,28 +1129,27 @@ def _render_images(
11121129 isinstance (render_params .cmap_params , CmapParams ) and not render_params .cmap_params .cmap_is_default
11131130 )
11141131 if is_rgb and palette is None and not got_multiple_cmaps and not has_explicit_cmap :
1132+ # Warn if user passed norm= that will be ignored in the RGB(A) path
1133+ if isinstance (render_params .cmap_params , CmapParams ):
1134+ _norm = render_params .cmap_params .norm
1135+ if isinstance (_norm , Normalize ) and (_norm .vmin is not None or _norm .vmax is not None ):
1136+ logger .warning (
1137+ "Image detected as RGB(A) and will be rendered directly. "
1138+ "The 'norm' parameter is ignored for RGB images. "
1139+ "To apply normalization, specify a 'cmap' to use the multi-channel path."
1140+ )
1141+
11151142 coord_map = {str (c ).lower (): c for c in channels }
11161143 ordered = [coord_map [ch ] for ch in ("r" , "g" , "b" )]
11171144 stacked = np .moveaxis (img .sel (c = ordered ).values , 0 , - 1 )
11181145
1119- # Normalize to [0, 1] for matplotlib: uint8 → /255, other int dtypes → /max, float → clip
1120- if stacked .dtype == np .uint8 :
1121- stacked = stacked .astype (np .float64 ) / 255.0
1122- elif stacked .dtype .kind in ("u" , "i" ):
1123- stacked = stacked .astype (np .float64 ) / np .iinfo (stacked .dtype ).max
1124- else :
1125- stacked = np .clip (stacked , 0 , 1 )
1146+ # Normalize to [0, 1] for matplotlib
1147+ stacked = _normalize_dtype_to_float (stacked )
11261148
11271149 show_kwargs : dict [str , Any ] = {"zorder" : render_params .zorder }
11281150
11291151 if has_alpha and render_params .alpha == 1.0 :
1130- alpha_raw = img .sel (c = coord_map ["a" ]).values
1131- if alpha_raw .dtype == np .uint8 :
1132- alpha_layer = alpha_raw .astype (np .float64 ) / 255.0
1133- elif alpha_raw .dtype .kind in ("u" , "i" ):
1134- alpha_layer = alpha_raw .astype (np .float64 ) / np .iinfo (alpha_raw .dtype ).max
1135- else :
1136- alpha_layer = np .clip (alpha_raw .astype (np .float64 ), 0 , 1 )
1152+ alpha_layer = _normalize_dtype_to_float (img .sel (c = coord_map ["a" ]).values )
11371153 stacked = np .concatenate ([stacked , alpha_layer [..., np .newaxis ]], axis = - 1 )
11381154 else :
11391155 show_kwargs ["alpha" ] = render_params .alpha
0 commit comments