Test / app.py
purple-koala's picture
Update app.py
fd314da verified
raw
history blame
No virus
17.4 kB
import io
import math
# date=dataset['TIME']
from datetime import date, datetime, timedelta
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import cftime
import fsspec
import hvplot.xarray
import jdcal
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import panel as pn
import xarray as xr
from astropy.time import Time
from ipywidgets import (
Checkbox,
Dropdown,
FloatRangeSlider,
FloatSlider,
IntRangeSlider,
IntSlider,
interactive,
)
pn.extension()
#df = pd.read_csv("table.csv", index_col=None)
#df = df.sort_values(by="year")
#df2 = pd.read_csv("test_table.csv", index_col=None)
#file_names = df["file_name"].tolist()
#df = df.sort_values(by="year")
#years = sorted(df["year"].unique())
def greg_0h(jourjul):
# Julian days start and end at noon.
# Julian day 2440000 begins at 00 hours, May 23, 1968.
# Round the input Julian day number to avoid precision errors
fac = 10**9
jourjul = np.round(fac * jourjul + 0.5) / fac
# Calculate seconds in the day
secs = (jourjul % 1) * 24 * 3600
# Round seconds to avoid precision errors
secs = np.round(fac * secs + 0.5) / fac
# Gregorian calendar conversion
j = math.floor(jourjul) - 1721119
in_ = 4 * j - 1
y = math.floor(in_ / 146097)
j = in_ - 146097 * y
in_ = math.floor(j / 4)
in_ = 4 * in_ + 3
j = math.floor(in_ / 1461)
d = math.floor(((in_ - 1461 * j) + 4) / 4)
in_ = 5 * d - 3
m = math.floor(in_ / 153)
d = math.floor(((in_ - 153 * m) + 5) / 5)
y = y * 100 + j
if m < 10:
mo = m + 3
yr = y
else:
mo = m - 9
yr = y + 1
hour = math.floor(secs / 3600)
mins = math.floor((secs % 3600) / 60)
sec = int(secs % 60)
gtime = [yr, mo, d, hour, mins, sec]
return gtime
def fix_time(dataset):
from datetime import datetime, timedelta
time = dataset["TIME"]
time2 = time.dropna(dim="MAXT")
time2 = time2.reindex_like(time, method='nearest')
jourjul = [greg_0h(jourjul) for jourjul in time2.values]
date = [
datetime(jourjul[0], jourjul[1], jourjul[2], jourjul[3], jourjul[4], jourjul[5])
for jourjul in jourjul
]
return date
from datetime import datetime, timedelta
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import fsspec
import matplotlib.pyplot as plt
import numpy as np
import panel as pn
import xarray as xr
from ipywidgets import (
Checkbox,
FloatRangeSlider,
FloatSlider,
IntRangeSlider,
IntSlider,
interactive,
)
# Loaddonnées bathymétry data
fs = fsspec.filesystem("https")
bathy = xr.open_dataset(fs.open('https://data-eurogoship.ifremer.fr/bathymetrie/bathy6min.nc'))
import os
import pandas as pd
import panel as pn
import param
import xarray as xr
class SADCP_Viewer(param.Parameterized):
df = pd.read_csv("table.csv", index_col=None).sort_values(by="year")
file_names = df["file_name"].tolist()
years = sorted(df["year"].unique())
year_slider = pn.widgets.IntRangeSlider(
name="Year Range", start=df["year"].min(), end=df["year"].max()
)
file_dropdown = pn.widgets.Select(name="File Selector")
data_table = pn.widgets.Tabulator(df, name="metadata", height=200, width=300)
# data_table2 = pn.widgets.Tabulator(df2, name="metadata", height=900, width=400)
longitude_slider = pn.widgets.RangeSlider(
name="Longitude Range", start=-180, end=180, step=1
)
latitude_slider = pn.widgets.RangeSlider(
name="Latitude Range", start=-90, end=90, step=1
)
depth_range_slider = pn.widgets.IntRangeSlider(
start=100, end=300, value=(100, 300), step=1, name="Depth Range"
)
depth_2_checkbox = pn.widgets.Checkbox(value=False, name="Depth 2 Checkbox")
depth_3_checkbox = pn.widgets.Checkbox(value=False, name="Depth 3 Checkbox")
depth2_range_slider = pn.widgets.IntRangeSlider(
start=100, end=300, value=(100, 300), step=1, name="Depth 2 Range"
)
depth3_range_slider = pn.widgets.IntRangeSlider(
start=100, end=300, value=(100, 300), step=1, name="Depth 3 Range"
)
num_vectors_slider = pn.widgets.IntSlider(
start=40, end=800, step=1, value=100, name="Number of Vectors"
)
scale_factor_slider = pn.widgets.FloatSlider(
start=0.1, end=1, step=0.1, value=0.5, name="Scale Factor"
)
bathy_checkbox = pn.widgets.Checkbox(value=False, name="Bathy Checkbox")
plot = pn.pane.HoloViews()
plot_map = pn.pane.Matplotlib(width=800, height=600, sizing_mode="fixed")
data_table = pn.widgets.Tabulator(
width=400, height=200
)
metadata_table = pn.widgets.Tabulator(
width=600, height=800
)
download_button = pn.widgets.Button(name="Download", button_type="primary")
# plot = pn.Column()
def __init__(self, **params):
super(SADCP_Viewer, self).__init__(**params)
self.file_dropdown.objects = self.get_file_list()
self.file_dropdown.value = (
self.file_dropdown.objects[0] if self.file_dropdown.objects else None
)
self.update_name_options()
@param.depends("year_slider.value", "file_dropdown.value", watch=True)
def update_name_options(self):
start_year, end_year = self.year_slider.value
mask = (self.df["year"] >= start_year) & (self.df["year"] <= end_year)
sorted_df = self.df[mask].sort_values(by="year")
files = sorted_df["file_name"].unique().tolist()
self.file_dropdown.options = files
if files:
selected_file = self.file_dropdown.value
if not selected_file or selected_file not in files:
selected_file = files[0]
self.file_dropdown.value = selected_file
dataframe = sorted_df[sorted_df["file_name"] == selected_file].drop(
columns=["file_name", "title", "Conventions", "featureType", "date_update", "ADCP_beam_angle", "ADCP_ship_angle", "middle_bin1_depth", "heading_corr", "pitch_corr", "ampli_corr", "pitch_roll_used", "date_creation", "ADCP_type", "data_type"]
)
dataframe2 = sorted_df[sorted_df["file_name"] == selected_file].drop(
columns=["file_name","date_start","date_end","ADCP_frequency(kHz)","bin_length(meter)","year"])
data_dir = "https://data-eurogoship.ifremer.fr/copy_seadatanet/"
file_path = os.path.join(data_dir, selected_file)
file_path=fs.open(file_path)
self.ds = (
xr.open_dataset(
file_path, decode_cf=True, decode_times=False, engine="scipy"
)
.squeeze()
.set_coords(["LONGITUDE", "LATITUDE", "TIME", "PROFZ"])
.set_xindex("PROFZ")
.set_xindex("TIME")
)
lon_range = (
int(self.ds["LONGITUDE"].min().round() - 1),
int(self.ds["LONGITUDE"].max().round() + 1),
)
lat_range = (
int(self.ds["LATITUDE"].min().round() - 1),
int(self.ds["LATITUDE"].max().round() + 1),
)
self.depth1 = abs(self.ds.coords["PROFZ"])
date = fix_time(self.ds)
date = xr.DataArray(date, dims="MAXT")
# self.ds = self.ds.where(
# (self.ds.VCUR_SEADATANET_QC == 49)
# & (self.ds.UCUR_SEADATANET_QC == 49)
# & (self.ds.WCUR_SEADATANET_QC == 49)
# & (self.ds.ECUR_SEADATANET_QC == 49)
# & (self.ds.PGOOD_SEADATANET_QC == 49)
# & (self.ds.ECI_SEADATANET_QC == 49)
# & (self.ds.BOTTOM_DEPTH_SEADATANET_QC == 49),
# drop=True,)
self.ds = self.ds[
[
"USHIP",
"VSHIP",
"ROLL",
"PITCH",
"TR_TEMP",
"HEADING",
"U_BOTTOM",
"V_BOTTOM",
"UCUR",
"VCUR",
"WCUR",
"ECUR",
"PGOOD",
"ECI",
"BATHY",
"UTIDE",
"VTIDE",
"BOTTOM_DEPTH",
"TIME",
]
]
deph_range = (int(self.depth1.min()), int(self.depth1.max()))
# Ku_std_dataarray = xr.DataArray(Ku_std,dims='dim1')
# date=dataset.assign(TIME=date)
# dataset['TIME']=dataset['TIME'].assign_coords(dim=dataset.dims['MAXT'])
self.ds = self.ds.assign(TIME=date)
self.longitude_slider.start = lon_range[0]
self.longitude_slider.end = lon_range[1]
self.longitude_slider.value = lon_range
self.latitude_slider.start = lat_range[0]
self.latitude_slider.end = lat_range[1]
self.latitude_slider.value = lat_range
self.depth_range_slider.start = deph_range[0]
self.depth_range_slider.end = deph_range[1]
self.depth_range_slider.value = deph_range
self.depth2_range_slider.start = deph_range[0]
self.depth2_range_slider.end = deph_range[1]
self.depth2_range_slider.value = deph_range
self.depth3_range_slider.start = deph_range[0]
self.depth3_range_slider.end = deph_range[1]
self.depth3_range_slider.value = deph_range
# self.update_plots()
self.ds.close()
self.dataframe = dataframe.transpose()
self.dataframe2 = dataframe2.transpose()
# self.transposed_dataframe = dataframe.transpose()
self.data_table.value = self.dataframe
self.metadata_table.value = self.dataframe2
@param.depends(
"year_slider.value",
"file_dropdown.value",
"depth_range_slider.value",
"depth_2_checkbox.value",
"depth_3_checkbox.value",
"depth2_range_slider.value",
"depth3_range_slider.value",
"longitude_slider.value",
"latitude_slider.value",
"num_vectors_slider.value",
"scale_factor_slider.value",
"bathy_checkbox.value",
watch=True,
)
def update_plots(self):
self.ds_filtered = self.filter_data()
# vector_plot = self.vectors_plot()
other_plots = self.plots()
# self.plot_map = pn.pane.Matplotlib(vector_plot, width=800, height=600, sizing_mode="fixed")
self.plot = pn.Column(
*(pn.pane.HoloViews(plot, width=400, height=200) for plot in other_plots),
sizing_mode="stretch_width"
)
vector_plot = self.vectors_plot() # Update vector plot
self.plot_map.object = vector_plot
# other_plots = self.plots() # Update other plots
# self.plot.objects = [*(pn.pane.HoloViews(p, width=400, height=200) for p in other_plots)]
# self.plot.object=plot
return pn.Row(self.plot_map, self.plot, sizing_mode="stretch_both")
def filter_data(self):
return self.ds.where(
(self.ds.LONGITUDE >= self.longitude_slider.start)
& (self.ds.LONGITUDE <= self.longitude_slider.end)
& (self.ds.LATITUDE >= self.latitude_slider.start)
& (self.ds.LATITUDE <= self.latitude_slider.end),
drop=True,
)
def vectors_plot(self):
import hvplot.xarray
self.ds_filtered = self.filter_data()
# return self.ds_filtered['VSHIP'].hvplot(x='TIME',width=400, height=200) #if 'BATHY' in self.ds_filtered else hvplot.show(hvplot.text(0, 0, "No data available", fontsize=12))
fig, ax = plt.subplots(
figsize=(8, 7), subplot_kw={"projection": ccrs.Mercator()}
)
coords = ["LATITUDE", "LONGITUDE"]
corsen = max(1, self.ds_filtered.MAXT.size // self.num_vectors_slider.value)
self.ds_filtered = (
self.ds_filtered.reset_coords(coords)
.coarsen({"MAXT": corsen}, boundary="trim")
.mean()
.set_coords(coords)
)
# self.ds_filtered =self.ds_filtered.coarsen(MAXT = corsen, side = "center", boundary = "trim").mean()[["LONGITUDE", "LONGITUDE", "TIME"]].isel(MAXZ=0)
depth_filtered = self.ds_filtered.where(
(self.depth1 > self.depth_range_slider.value[0])
& (self.depth1 <= self.depth_range_slider.value[1])
)
lon = self.ds_filtered.coords["LONGITUDE"].values
lat = self.ds_filtered.coords["LATITUDE"].values
# skip = max(1, int(np.sqrt(lon.size) / self.num_vectors_slider.value))
# skip = (slice(None, None, skip), slice(None, None, skip))
# Moyenne des vecteurs de courant sur la plage de profondeur sélectionnée
u_mean = depth_filtered.UCUR.mean(dim="MAXZ", skipna=True)
v_mean = depth_filtered.VCUR.mean(dim="MAXZ", skipna=True)
ax.quiver(
lon,
lat,
u_mean * self.scale_factor_slider.value,
v_mean * self.scale_factor_slider.value,
color="blue",
scale=2,
width=0.001,
headwidth=3,
transform=ccrs.PlateCarree(),
)
if self.depth_2_checkbox.value:
depth_filtered = self.ds_filtered.where(
(self.depth1 > self.depth2_range_slider.value[0])
& (self.depth1 <= self.depth2_range_slider.value[1])
)
u_mean = depth_filtered.UCUR.mean(dim="MAXZ", skipna=True)
v_mean = depth_filtered.VCUR.mean(dim="MAXZ", skipna=True)
ax.quiver(
lon,
lat,
u_mean * self.scale_factor_slider.value,
v_mean * self.scale_factor_slider.value,
color="green",
scale=2,
width=0.001,
headwidth=3,
transform=ccrs.PlateCarree(),
)
if self.depth_3_checkbox.value:
depth_filtered = self.ds_filtered.where(
(self.depth1 > self.depth3_range_slider.value[0])
& (self.depth1 <= self.depth3_range_slider.value[1])
)
u_mean = depth_filtered.UCUR.mean(dim="MAXZ", skipna=True)
v_mean = depth_filtered.VCUR.mean(dim="MAXZ", skipna=True)
ax.quiver(
lon,
lat,
u_mean * self.scale_factor_slider.value,
v_mean * self.scale_factor_slider.value,
color="red",
scale=2,
width=0.001,
headwidth=3,
transform=ccrs.PlateCarree(),
)
ax.add_feature(cfeature.COASTLINE)
ax.add_feature(cfeature.BORDERS, linestyle=":")
ax.add_feature(cfeature.LAND, color="lightgray")
if self.bathy_checkbox.value:
contour_levels = [-2000]
ax.contour(
bathy.longitude,
bathy.latitude,
bathy.z,
levels=contour_levels,
colors="black",
transform=ccrs.PlateCarree(),
)
ax.set_extent(
[
self.longitude_slider.value[0],
self.longitude_slider.value[1],
self.latitude_slider.value[0],
self.latitude_slider.value[1],
]
)
ax.gridlines(draw_labels=True)
plt.ylabel("Latitude", fontsize=15, labelpad=35)
plt.xlabel("Longitude", fontsize=15, labelpad=20)
return fig
# pn.pane.Matplotlib(fig,width=800, height=600, sizing_mode="fixed", name="Plot")
# @param.depends( 'file_dropdown.value', 'longitude_slider.value', 'latitude_slider.value', watch=True)
def plots(self):
return [
self.ds_filtered["BATHY"].hvplot(x="TIME", width=400, height=200),
self.ds_filtered["USHIP"].hvplot(x="TIME", width=400, height=200),
self.ds_filtered["VSHIP"].hvplot(x="TIME", width=400, height=200),
self.ds_filtered["BOTTOM_DEPTH"].hvplot(x="TIME", width=400, height=200),
]
def get_file_list(self):
return self.file_names
# Instantiate the SADCP_Viewer class and create a template
explorer = SADCP_Viewer()
tabs = pn.Tabs(
("Plots", pn.Column(explorer.update_plots)),
(
"Metadata",
pn.Column(
explorer.metadata_table, explorer.download_button, height=500, margin=10
),
),
)
sidebar = [
"""This application, developed in the frame of Euro Go Shop, helps to interactively visualise and download ship ADCP data.""",
explorer.year_slider,
explorer.file_dropdown,
explorer.longitude_slider,
explorer.latitude_slider,
explorer.bathy_checkbox,
explorer.depth_range_slider,
explorer.depth_2_checkbox,
explorer.depth_3_checkbox,
explorer.depth2_range_slider,
explorer.depth3_range_slider,
explorer.num_vectors_slider,
explorer.scale_factor_slider,
explorer.data_table,
]
template = pn.template.FastListTemplate(title="SADCP data Viewer", sidebar=sidebar,main=[tabs])
template.servable()