2026-11-05 17:42:11
This commit is contained in:
74
zarrviewer
74
zarrviewer
@@ -43,7 +43,6 @@ def main():
|
|||||||
print(f"Error al abrir el Zarr: {e}", file=sys.stderr)
|
print(f"Error al abrir el Zarr: {e}", file=sys.stderr)
|
||||||
sys.exit(1)
|
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:
|
if len(sys.argv) == 2 or args.header:
|
||||||
print("="*60)
|
print("="*60)
|
||||||
print(f" ESTRUCTURA DEL ARCHIVO ZARR: {args.zarr_path}")
|
print(f" ESTRUCTURA DEL ARCHIVO ZARR: {args.zarr_path}")
|
||||||
@@ -54,13 +53,13 @@ def main():
|
|||||||
print(" VARIABLES DISPONIBLES PARA GRAFICAR (-v):")
|
print(" VARIABLES DISPONIBLES PARA GRAFICAR (-v):")
|
||||||
print("="*60)
|
print("="*60)
|
||||||
|
|
||||||
# Mostramos las variables y sus dimensiones para orientar al usuario
|
|
||||||
for var in ds.data_vars:
|
for var in ds.data_vars:
|
||||||
dims = ds[var].dims
|
dims = ds[var].dims
|
||||||
print(f" - {var} {list(dims)}")
|
print(f" - {var} {list(dims)}")
|
||||||
|
|
||||||
print("\nEjemplo de uso:")
|
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)
|
sys.exit(0)
|
||||||
|
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
@@ -85,15 +84,27 @@ def main():
|
|||||||
print("No se encontró una coordenada temporal.", file=sys.stderr)
|
print("No se encontró una coordenada temporal.", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
time_dim = ds[time_coord].dims[0]
|
# === CORRECCIÓN VITAL: Manejo de snapshot estático (0 dimensiones temporales) ===
|
||||||
times = ds[time_coord].values
|
dims_of_time = ds[time_coord].dims
|
||||||
total = len(times)
|
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"Usando coordenada temporal: '{time_coord}' (Eje dimensional: '{time_dim}')")
|
|
||||||
print(f"Total de frames en el Zarr: {total}\n")
|
print(f"Total de frames en el Zarr: {total}\n")
|
||||||
|
|
||||||
def format_time(t):
|
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:
|
if args.all:
|
||||||
for t in times:
|
for t in times:
|
||||||
@@ -141,24 +152,33 @@ def main():
|
|||||||
print(f"-> Detectado formato de mapa (Dimensiones: {other_dims}).")
|
print(f"-> Detectado formato de mapa (Dimensiones: {other_dims}).")
|
||||||
print(f"-> Extrayendo último frame ({ultimo_time_str})...")
|
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 = {}
|
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
|
lat_name, lon_name = None, None
|
||||||
for lat in ['lat', 'latitude', 'XLAT', 'xlat']:
|
for lat in ['lat', 'latitude', 'XLAT', 'xlat', 'y']:
|
||||||
if lat in ds.variables:
|
if lat in ds.variables or lat in ds.coords:
|
||||||
lat_name = lat
|
lat_name = lat
|
||||||
break
|
break
|
||||||
for lon in ['lon', 'longitude', 'XLONG', 'xlon']:
|
for lon in ['lon', 'longitude', 'XLONG', 'xlon', 'x']:
|
||||||
if lon in ds.variables:
|
if lon in ds.variables or lon in ds.coords:
|
||||||
lon_name = lon
|
lon_name = lon
|
||||||
break
|
break
|
||||||
|
|
||||||
if lat_name and lon_name:
|
if lat_name and lon_name:
|
||||||
print(f"-> Georreferencia detectada: '{lat_name}', '{lon_name}'. Aplicando ejes...")
|
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]
|
lat_arr = ds[lat_name]
|
||||||
lon_arr = ds[lon_name].isel({time_dim: -1}) if time_dim in ds[lon_name].dims else ds[lon_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})
|
ds_plot = ds_plot.assign_coords({lat_name: lat_arr, lon_name: lon_arr})
|
||||||
plot_kwargs['x'] = lon_name
|
plot_kwargs['x'] = lon_name
|
||||||
@@ -167,17 +187,13 @@ def main():
|
|||||||
plt.figure(figsize=(8, 10))
|
plt.figure(figsize=(8, 10))
|
||||||
cmap_choice = 'Blues' if var_name in ['tp', 'sd', 'snowc', 'RAINNC', 'RAINC'] else 'viridis'
|
cmap_choice = 'Blues' if var_name in ['tp', 'sd', 'snowc', 'RAINNC', 'RAINC'] else 'viridis'
|
||||||
plot_kwargs['cmap'] = cmap_choice
|
plot_kwargs['cmap'] = cmap_choice
|
||||||
|
|
||||||
# Achicar la barra de colores a la mitad
|
|
||||||
plot_kwargs['cbar_kwargs'] = {'shrink': 0.5}
|
plot_kwargs['cbar_kwargs'] = {'shrink': 0.5}
|
||||||
|
|
||||||
ds_plot.plot(**plot_kwargs)
|
ds_plot.plot(**plot_kwargs)
|
||||||
|
|
||||||
# Mantener proporción georeferenciada 1:1
|
|
||||||
plt.gca().set_aspect('equal')
|
plt.gca().set_aspect('equal')
|
||||||
|
|
||||||
plt.title(f"{var_name} | Frame: {ultimo_time_str}")
|
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)
|
# CASO B: Puntos / Estaciones (1D adicional)
|
||||||
elif len(other_dims) == 1:
|
elif len(other_dims) == 1:
|
||||||
@@ -187,9 +203,7 @@ def main():
|
|||||||
if dim_val_request is None:
|
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"Se detectó que la variable '{var_name}' está asociada a la dimensión: '{dim_name}'")
|
||||||
print(f"Valores posibles para {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(", ".join(map(str, dim_values)) + "\n")
|
||||||
|
|
||||||
print("Ejemplos de uso (cópialos y pégalos):")
|
print("Ejemplos de uso (cópialos y pégalos):")
|
||||||
for ex in dim_values[:3]:
|
for ex in dim_values[:3]:
|
||||||
print(f" zarrviewer {args.zarr_path} -v {var_name}:{ex}")
|
print(f" zarrviewer {args.zarr_path} -v {var_name}:{ex}")
|
||||||
@@ -206,29 +220,31 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
print(f"-> Detectada serie de tiempo para {dim_name} = {casted_val}")
|
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))
|
plt.figure(figsize=(10, 5))
|
||||||
ds_plot.plot.line(marker='o', linestyle='-', color='#1f77b4')
|
ds_plot.plot.line(marker='o', linestyle='-', color='#1f77b4')
|
||||||
plt.title(f"Serie de tiempo: {var_name} ({dim_name}: {casted_val})")
|
plt.title(f"Serie de tiempo: {var_name} ({dim_name}: {casted_val})")
|
||||||
plt.grid(True, linestyle='--', alpha=0.6)
|
plt.grid(True, linestyle='--', alpha=0.6)
|
||||||
|
|
||||||
nombre_imagen = f"serie_{var_name}_{casted_val}.png"
|
nombre_imagen = f"serie_{var_name}_{casted_val}.png"
|
||||||
|
|
||||||
# CASO C: Serie de tiempo global (0 dimensiones)
|
# CASO C: Serie de tiempo global (0 dimensiones)
|
||||||
else:
|
else:
|
||||||
print(f"-> Detectada serie de tiempo unidimensional global.")
|
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))
|
plt.figure(figsize=(10, 5))
|
||||||
ds_plot.plot.line(marker='o')
|
ds_plot.plot.line(marker='o')
|
||||||
plt.title(f"Serie global: {var_name}")
|
plt.title(f"Serie global: {var_name}")
|
||||||
plt.grid(True, linestyle='--', alpha=0.6)
|
plt.grid(True, linestyle='--', alpha=0.6)
|
||||||
|
|
||||||
nombre_imagen = f"serie_global_{var_name}.png"
|
nombre_imagen = f"serie_global_{var_name}.png"
|
||||||
|
|
||||||
plt.tight_layout()
|
plt.tight_layout()
|
||||||
|
|||||||
Reference in New Issue
Block a user