Spaces:
Sleeping
Sleeping
File size: 4,620 Bytes
0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 231c749 0ebe8a8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | import numpy as np
import xarray as xr
import gsw
import plotly.graph_objects as go
import pandas as pd
def get_valid_data(ds_prof):
def get_var(name):
adj_name = f"{name}_ADJUSTED"
if adj_name in ds_prof:
val = ds_prof[adj_name].values.flatten()
if not np.isnan(val).all():
return val
if name in ds_prof:
return ds_prof[name].values.flatten()
# Fallback if variable doesn't exist
if 'PRES' in ds_prof:
return np.full_like(ds_prof.PRES.values.flatten(), np.nan)
return np.array([])
if 'CYCLE_NUMBER' not in ds_prof or 'PRES' not in ds_prof:
return np.array([]), np.array([]), np.array([]), np.array([]), np.array([]), np.array([])
cycles_2d = np.repeat(ds_prof.CYCLE_NUMBER.values[:, np.newaxis], ds_prof.PRES.shape[1], axis=1)
dates_2d = np.repeat(ds_prof.JULD.values[:, np.newaxis], ds_prof.PRES.shape[1], axis=1)
lon = ds_prof.LONGITUDE.values
lat = ds_prof.LATITUDE.values
lon_2d = np.repeat(lon[:, np.newaxis], ds_prof.PRES.shape[1], axis=1)
lat_2d = np.repeat(lat[:, np.newaxis], ds_prof.PRES.shape[1], axis=1)
pres = get_var('PRES')
temp = get_var('TEMP')
psal = get_var('PSAL')
cycles = cycles_2d.flatten()
dates = dates_2d.flatten()
lon_flat = lon_2d.flatten()
lat_flat = lat_2d.flatten()
valid = ~np.isnan(pres) & ~np.isnan(temp) & ~np.isnan(psal) & ~np.isnat(dates)
pres = pres[valid]
temp = temp[valid]
psal = psal[valid]
cycles = cycles[valid]
dates = dates[valid]
lon_flat = lon_flat[valid]
lat_flat = lat_flat[valid]
SA = gsw.SA_from_SP(psal, pres, lon_flat, lat_flat)
CT = gsw.CT_from_t(SA, temp, pres)
rho = gsw.sigma0(SA, CT)
return cycles, dates, pres, temp, psal, rho
def _dark_layout(title, xlabel, ylabel, invert_y=False):
layout = dict(
title=title,
xaxis_title=xlabel,
yaxis_title=ylabel,
paper_bgcolor="rgba(0,0,0,0)",
plot_bgcolor="rgba(0,0,0,0)",
font=dict(family="Inter, sans-serif", color="#c8d6e5", size=12),
margin=dict(l=40, r=20, t=40, b=40),
xaxis=dict(gridcolor="rgba(255,255,255,0.1)", zerolinecolor="rgba(255,255,255,0.1)"),
yaxis=dict(gridcolor="rgba(255,255,255,0.1)", zerolinecolor="rgba(255,255,255,0.1)")
)
if xlabel == "Date":
layout["xaxis"]["tickformat"] = "%d/%m/%Y"
if invert_y:
layout["yaxis"]["autorange"] = "reversed"
return layout
def create_ts_diagram(cycles, temp, psal, wmo, title="T/S Diagram"):
fig = go.Figure()
fig.add_trace(go.Scattergl(
x=psal, y=temp,
mode='markers',
marker=dict(
size=4,
color=cycles,
colorscale='Jet',
showscale=True,
colorbar=dict(title="Profile<br>number")
),
customdata=np.stack((cycles,), axis=-1),
hovertemplate="<b>Cycle:</b> %{customdata[0]}<br><b>Sal:</b> %{x:.3f} PSU<br><b>Temp:</b> %{y:.3f}°C<extra></extra>"
))
fig.update_layout(**_dark_layout(title, "Practical Salinity (PSU)", "Temperature (°C)"))
return fig
def create_section_chart(dates, pres, z_var, z_label, title, wmo, cmap='Jet'):
fig = go.Figure()
fig.add_trace(go.Scattergl(
x=dates, y=pres,
mode='markers',
marker=dict(
size=5,
symbol='square',
color=z_var,
colorscale=cmap,
showscale=True,
colorbar=dict(title=z_label.replace(' ', '<br>', 1))
),
customdata=np.stack((z_var,), axis=-1),
hovertemplate="<b>Date:</b> %{x|%Y-%m-%d %H:%M}<br><b>Press:</b> %{y:.1f} dbar<br><b>" + z_label + ":</b> %{customdata[0]:.3f}<extra></extra>"
))
fig.update_layout(**_dark_layout(title, "Date", "Pressure (dbar)", invert_y=True))
return fig
def create_overlaid_profiles(x_var, pres, cycles, x_label, title, wmo, cmap='Jet'):
fig = go.Figure()
fig.add_trace(go.Scattergl(
x=x_var, y=pres,
mode='markers',
marker=dict(
size=3,
color=cycles,
colorscale=cmap,
showscale=True,
colorbar=dict(title="Profile<br>number")
),
customdata=np.stack((cycles,), axis=-1),
hovertemplate="<b>Cycle:</b> %{customdata[0]}<br><b>" + x_label + ":</b> %{x:.3f}<br><b>Press:</b> %{y:.1f} dbar<extra></extra>"
))
fig.update_layout(**_dark_layout(title, x_label, "Pressure (dbar)", invert_y=True))
return fig
|