From e23122a66d5fc07c07a20ebd127b6798e7581198 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 5 Nov 2026 17:42:11 -0300 Subject: [PATCH] 2026-11-05 17:42:11 --- zarrviewer | 76 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/zarrviewer b/zarrviewer index 3ca5ad3..0d37ce3 100755 --- a/zarrviewer +++ b/zarrviewer @@ -43,7 +43,6 @@ def main(): print(f"Error al abrir el Zarr: {e}", file=sys.stderr) sys.exit(1) - # 1. Si no hay más argumentos que el archivo (o si se pidió el header), mostramos información útil. if len(sys.argv) == 2 or args.header: print("="*60) print(f" ESTRUCTURA DEL ARCHIVO ZARR: {args.zarr_path}") @@ -54,13 +53,13 @@ def main(): print(" VARIABLES DISPONIBLES PARA GRAFICAR (-v):") print("="*60) - # Mostramos las variables y sus dimensiones para orientar al usuario for var in ds.data_vars: dims = ds[var].dims print(f" - {var} {list(dims)}") print("\nEjemplo de uso:") - print(f" zarrviewer {args.zarr_path} -v {list(ds.data_vars)[0]}") + if len(ds.data_vars) > 0: + print(f" zarrviewer {args.zarr_path} -v {list(ds.data_vars)[0]}") sys.exit(0) # ===================================================================== @@ -85,15 +84,27 @@ def main(): print("No se encontró una coordenada temporal.", file=sys.stderr) sys.exit(1) - time_dim = ds[time_coord].dims[0] - times = ds[time_coord].values - total = len(times) - - print(f"Usando coordenada temporal: '{time_coord}' (Eje dimensional: '{time_dim}')") + # === CORRECCIÓN VITAL: Manejo de snapshot estático (0 dimensiones temporales) === + dims_of_time = ds[time_coord].dims + if len(dims_of_time) > 0: + time_dim = dims_of_time[0] + times = ds[time_coord].values + total = len(times) + print(f"Usando coordenada temporal: '{time_coord}' (Eje dimensional: '{time_dim}')") + else: + # Es un único frame estático + time_dim = None + times = [ds[time_coord].values[()]] + total = 1 + print(f"Usando coordenada temporal: '{time_coord}' (Snapshot estático, sin eje)") + print(f"Total de frames en el Zarr: {total}\n") def format_time(t): - return pd.to_datetime(t).strftime("%Y-%m-%d %H:%M") + try: + return pd.to_datetime(t).strftime("%Y-%m-%d %H:%M") + except: + return str(t) if args.all: for t in times: @@ -141,24 +152,33 @@ def main(): print(f"-> Detectado formato de mapa (Dimensiones: {other_dims}).") print(f"-> Extrayendo último frame ({ultimo_time_str})...") - ds_plot = ds[var_name].isel({time_dim: -1}) + # Cortamos en tiempo SOLO si la variable depende del tiempo + ds_plot = ds[var_name] + if time_dim and time_dim in ds_plot.dims: + ds_plot = ds_plot.isel({time_dim: -1}) + plot_kwargs = {} - # Búsqueda oportunista de georreferencia + # Buscamos georreferencia (agregué 'y' y 'x' para que use los de UTM por defecto) lat_name, lon_name = None, None - for lat in ['lat', 'latitude', 'XLAT', 'xlat']: - if lat in ds.variables: + for lat in ['lat', 'latitude', 'XLAT', 'xlat', 'y']: + if lat in ds.variables or lat in ds.coords: lat_name = lat break - for lon in ['lon', 'longitude', 'XLONG', 'xlon']: - if lon in ds.variables: + for lon in ['lon', 'longitude', 'XLONG', 'xlon', 'x']: + if lon in ds.variables or lon in ds.coords: lon_name = lon break if lat_name and lon_name: print(f"-> Georreferencia detectada: '{lat_name}', '{lon_name}'. Aplicando ejes...") - lat_arr = ds[lat_name].isel({time_dim: -1}) if time_dim in ds[lat_name].dims else ds[lat_name] - lon_arr = ds[lon_name].isel({time_dim: -1}) if time_dim in ds[lon_name].dims else ds[lon_name] + lat_arr = ds[lat_name] + if time_dim and time_dim in lat_arr.dims: + lat_arr = lat_arr.isel({time_dim: -1}) + + lon_arr = ds[lon_name] + if time_dim and time_dim in lon_arr.dims: + lon_arr = lon_arr.isel({time_dim: -1}) ds_plot = ds_plot.assign_coords({lat_name: lat_arr, lon_name: lon_arr}) plot_kwargs['x'] = lon_name @@ -167,17 +187,13 @@ def main(): plt.figure(figsize=(8, 10)) cmap_choice = 'Blues' if var_name in ['tp', 'sd', 'snowc', 'RAINNC', 'RAINC'] else 'viridis' plot_kwargs['cmap'] = cmap_choice - - # Achicar la barra de colores a la mitad plot_kwargs['cbar_kwargs'] = {'shrink': 0.5} ds_plot.plot(**plot_kwargs) - # Mantener proporción georeferenciada 1:1 plt.gca().set_aspect('equal') - plt.title(f"{var_name} | Frame: {ultimo_time_str}") - nombre_imagen = f"mapa_{var_name}_{pd.to_datetime(times[-1]).strftime('%Y%m%d_%H%M')}.png" + nombre_imagen = f"mapa_{var_name}.png" if time_dim is None else f"mapa_{var_name}_{pd.to_datetime(times[-1]).strftime('%Y%m%d_%H%M')}.png" # CASO B: Puntos / Estaciones (1D adicional) elif len(other_dims) == 1: @@ -187,9 +203,7 @@ def main(): if dim_val_request is None: print(f"Se detectó que la variable '{var_name}' está asociada a la dimensión: '{dim_name}'") print(f"Valores posibles para {dim_name}:") - # Imprimir valores con salto de línea para facilitar el uso print(", ".join(map(str, dim_values)) + "\n") - print("Ejemplos de uso (cópialos y pégalos):") for ex in dim_values[:3]: print(f" zarrviewer {args.zarr_path} -v {var_name}:{ex}") @@ -206,29 +220,31 @@ def main(): sys.exit(1) print(f"-> Detectada serie de tiempo para {dim_name} = {casted_val}") - print(f"-> Extrayendo los últimos {args.npoints} registros...") + ds_plot = ds[var_name].sel({dim_name: casted_val}) - ds_plot = ds[var_name].sel({dim_name: casted_val}).isel({time_dim: slice(-args.npoints, None)}) + if time_dim and time_dim in ds_plot.dims: + print(f"-> Extrayendo los últimos {args.npoints} registros...") + ds_plot = ds_plot.isel({time_dim: slice(-args.npoints, None)}) plt.figure(figsize=(10, 5)) ds_plot.plot.line(marker='o', linestyle='-', color='#1f77b4') plt.title(f"Serie de tiempo: {var_name} ({dim_name}: {casted_val})") plt.grid(True, linestyle='--', alpha=0.6) - nombre_imagen = f"serie_{var_name}_{casted_val}.png" # CASO C: Serie de tiempo global (0 dimensiones) else: print(f"-> Detectada serie de tiempo unidimensional global.") - print(f"-> Extrayendo los últimos {args.npoints} registros...") + ds_plot = ds[var_name] - ds_plot = ds[var_name].isel({time_dim: slice(-args.npoints, None)}) + if time_dim and time_dim in ds_plot.dims: + print(f"-> Extrayendo los últimos {args.npoints} registros...") + ds_plot = ds_plot.isel({time_dim: slice(-args.npoints, None)}) plt.figure(figsize=(10, 5)) ds_plot.plot.line(marker='o') plt.title(f"Serie global: {var_name}") plt.grid(True, linestyle='--', alpha=0.6) - nombre_imagen = f"serie_global_{var_name}.png" plt.tight_layout()