Masquer le nodata avant étalonnage colormap et colorbar en unités réelles
This commit is contained in:
@ -189,7 +189,8 @@ for _key, _info in RGB_LEGENDS.items():
|
|||||||
def _apply_colormap(data, tif_file, resolution=None):
|
def _apply_colormap(data, tif_file, resolution=None):
|
||||||
"""Apply the registered colormap normalization to data based on filename.
|
"""Apply the registered colormap normalization to data based on filename.
|
||||||
|
|
||||||
Returns (data, cmap, title, legend_label, description, is_rgb).
|
Returns (data, cmap, title, legend_label, description, is_rgb, vmin, vmax)
|
||||||
|
où vmin/vmax sont les bornes physiques de la plage rendue (None si sans objet).
|
||||||
"""
|
"""
|
||||||
name = str(tif_file).lower()
|
name = str(tif_file).lower()
|
||||||
|
|
||||||
@ -197,7 +198,7 @@ def _apply_colormap(data, tif_file, resolution=None):
|
|||||||
for key in RGB_LEGENDS:
|
for key in RGB_LEGENDS:
|
||||||
if key in name:
|
if key in name:
|
||||||
info = RGB_LEGENDS[key]
|
info = RGB_LEGENDS[key]
|
||||||
return data, None, info['title'], info['legend'], info['description'], True
|
return data, None, info['title'], info['legend'], info['description'], True, None, None
|
||||||
|
|
||||||
# Find matching colormap — sort by key length descending so 'mslrm' matches before 'lrm'
|
# Find matching colormap — sort by key length descending so 'mslrm' matches before 'lrm'
|
||||||
for key in sorted(COLORMAPS.keys(), key=len, reverse=True):
|
for key in sorted(COLORMAPS.keys(), key=len, reverse=True):
|
||||||
@ -208,7 +209,7 @@ def _apply_colormap(data, tif_file, resolution=None):
|
|||||||
|
|
||||||
if len(valid_data) == 0:
|
if len(valid_data) == 0:
|
||||||
logger.warning(f" Aucune donnée valide pour {Path(tif_file).name} — colormap ignorée")
|
logger.warning(f" Aucune donnée valide pour {Path(tif_file).name} — colormap ignorée")
|
||||||
return data, 'terrain', Path(tif_file).stem.replace('_', ' ').title(), '', '', False
|
return data, 'terrain', Path(tif_file).stem.replace('_', ' ').title(), '', '', False, None, None
|
||||||
|
|
||||||
vmin = vmax = None
|
vmin = vmax = None
|
||||||
|
|
||||||
@ -253,7 +254,7 @@ def _apply_colormap(data, tif_file, resolution=None):
|
|||||||
data = np.clip((data - vmin) / max(vmax - vmin, 0.001), 0, 1)
|
data = np.clip((data - vmin) / max(vmax - vmin, 0.001), 0, 1)
|
||||||
|
|
||||||
legend = info['legend'].format(vmin=vmin or 0, vmax=vmax or 0)
|
legend = info['legend'].format(vmin=vmin or 0, vmax=vmax or 0)
|
||||||
return data, info['cmap'], info['title'], legend, info['description'], False
|
return data, info['cmap'], info['title'], legend, info['description'], False, vmin, vmax
|
||||||
|
|
||||||
# Default: terrain colormap with percentile stretch
|
# Default: terrain colormap with percentile stretch
|
||||||
valid_data = np.asarray(data.compressed() if hasattr(data, 'compressed') else data.flatten())
|
valid_data = np.asarray(data.compressed() if hasattr(data, 'compressed') else data.flatten())
|
||||||
@ -265,7 +266,7 @@ def _apply_colormap(data, tif_file, resolution=None):
|
|||||||
span = max(p98 - p2, 1e-6)
|
span = max(p98 - p2, 1e-6)
|
||||||
data = np.clip((data - p2) / span, 0, 1)
|
data = np.clip((data - p2) / span, 0, 1)
|
||||||
title = Path(tif_file).stem.replace('_', ' ').title()
|
title = Path(tif_file).stem.replace('_', ' ').title()
|
||||||
return data, 'terrain', title, 'Altitude normalisée', '', False
|
return data, 'terrain', title, 'Altitude normalisée', '', False, p2, p98
|
||||||
|
|
||||||
|
|
||||||
def _download_location_map(min_x, max_x, min_y, max_y):
|
def _download_location_map(min_x, max_x, min_y, max_y):
|
||||||
@ -453,7 +454,7 @@ def tif_to_png(tif_file, vis_dir, resolution, keep_tif=False, source_info=None,
|
|||||||
nan_mask = nan_mask # keep for later
|
nan_mask = nan_mask # keep for later
|
||||||
|
|
||||||
# Apply colormap
|
# Apply colormap
|
||||||
data, cmap, title, legend_label, description, is_rgb_result = _apply_colormap(data, tif_file, resolution=resolution)
|
data, cmap, title, legend_label, description, is_rgb_result, cmap_vmin, cmap_vmax = _apply_colormap(data, tif_file, resolution=resolution)
|
||||||
|
|
||||||
# Apply NaN mask: make zones without data transparent
|
# Apply NaN mask: make zones without data transparent
|
||||||
has_nan_mask = nan_mask is not None and not is_rgb_result
|
has_nan_mask = nan_mask is not None and not is_rgb_result
|
||||||
@ -461,8 +462,12 @@ def tif_to_png(tif_file, vis_dir, resolution, keep_tif=False, source_info=None,
|
|||||||
# data is normalized 0-1 from _apply_colormap; apply cmap to get RGBA
|
# data is normalized 0-1 from _apply_colormap; apply cmap to get RGBA
|
||||||
# Save the colormap for colorbar before converting to RGBA
|
# Save the colormap for colorbar before converting to RGBA
|
||||||
saved_cmap = plt.get_cmap(cmap) if isinstance(cmap, str) else cmap
|
saved_cmap = plt.get_cmap(cmap) if isinstance(cmap, str) else cmap
|
||||||
saved_vmin = float(np.nanmin(data)) if not nan_mask.all() else 0
|
# Bornes physiques de la colorbar (unités réelles, pas 0-1)
|
||||||
saved_vmax = float(np.nanmax(data)) if not nan_mask.all() else 1
|
if cmap_vmin is not None and cmap_vmax is not None:
|
||||||
|
saved_vmin, saved_vmax = float(cmap_vmin), float(cmap_vmax)
|
||||||
|
else:
|
||||||
|
saved_vmin = float(np.nanmin(data)) if not nan_mask.all() else 0
|
||||||
|
saved_vmax = float(np.nanmax(data)) if not nan_mask.all() else 1
|
||||||
rgba = saved_cmap(data) # (H, W, 4) float RGBA
|
rgba = saved_cmap(data) # (H, W, 4) float RGBA
|
||||||
rgba[nan_mask, 3] = 0.0 # transparent where no data
|
rgba[nan_mask, 3] = 0.0 # transparent where no data
|
||||||
data = rgba
|
data = rgba
|
||||||
@ -806,9 +811,14 @@ def tif_to_crop(tif_file, vis_dir, resolution, keep_tif=False, quality=98, outpu
|
|||||||
data = np.moveaxis(data, 0, -1)
|
data = np.moveaxis(data, 0, -1)
|
||||||
else:
|
else:
|
||||||
data = src.read(1)
|
data = src.read(1)
|
||||||
|
# Nodata → NaN : sinon les pixels bord (ex. -9999, 3.4e38)
|
||||||
|
# polluent les percentiles d'étalonnage de la colormap
|
||||||
|
if src.nodata is not None:
|
||||||
|
data = data.astype(np.float32, copy=False)
|
||||||
|
data[data == src.nodata] = np.nan
|
||||||
|
|
||||||
# Apply colormap normalization
|
# Apply colormap normalization
|
||||||
data, cmap_name, title, legend_label, description, is_rgb_result = _apply_colormap(data, tif_file, resolution=resolution)
|
data, cmap_name, title, legend_label, description, is_rgb_result, _cvmin, _cvmax = _apply_colormap(data, tif_file, resolution=resolution)
|
||||||
|
|
||||||
if not is_rgb_result:
|
if not is_rgb_result:
|
||||||
data = np.where(np.isnan(data), 0.0, data)
|
data = np.where(np.isnan(data), 0.0, data)
|
||||||
|
|||||||
Reference in New Issue
Block a user