Spaces:
Build error
Build error
Upload 2 files
Browse files- app.py +125 -323
- requirements.txt +3 -4
app.py
CHANGED
@@ -1,212 +1,67 @@
|
|
1 |
-
import cftime
|
2 |
-
import fsspec
|
3 |
-
|
4 |
-
import matplotlib.pyplot as plt
|
5 |
import numpy as np
|
6 |
import pandas as pd
|
7 |
import panel as pn
|
8 |
import xarray as xr
|
9 |
-
from ipywidgets import (
|
10 |
-
Checkbox,
|
11 |
-
# FloatRangeSlider,
|
12 |
-
FloatSlider,
|
13 |
-
IntRangeSlider,
|
14 |
-
IntSlider,
|
15 |
-
# interactive,
|
16 |
-
)
|
17 |
-
|
18 |
-
|
19 |
import param
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
# Round the input Julian day number to avoid precision errors
|
29 |
-
fac = 10**9
|
30 |
-
jourjul = np.round(fac * jourjul + 0.5) / fac
|
31 |
-
|
32 |
-
# Calculate seconds in the day
|
33 |
-
secs = (jourjul % 1) * 24 * 3600
|
34 |
-
|
35 |
-
# Round seconds to avoid precision errors
|
36 |
-
secs = np.round(fac * secs + 0.5) / fac
|
37 |
-
|
38 |
-
# Gregorian calendar conversion
|
39 |
-
j = math.floor(jourjul) - 1721119
|
40 |
-
in_ = 4 * j - 1
|
41 |
-
y = math.floor(in_ / 146097)
|
42 |
-
j = in_ - 146097 * y
|
43 |
-
in_ = math.floor(j / 4)
|
44 |
-
in_ = 4 * in_ + 3
|
45 |
-
j = math.floor(in_ / 1461)
|
46 |
-
d = math.floor(((in_ - 1461 * j) + 4) / 4)
|
47 |
-
in_ = 5 * d - 3
|
48 |
-
m = math.floor(in_ / 153)
|
49 |
-
d = math.floor(((in_ - 153 * m) + 5) / 5)
|
50 |
-
y = y * 100 + j
|
51 |
-
if m < 10:
|
52 |
-
mo = m + 3
|
53 |
-
yr = y
|
54 |
-
else:
|
55 |
-
mo = m - 9
|
56 |
-
yr = y + 1
|
57 |
-
|
58 |
-
hour = math.floor(secs / 3600)
|
59 |
-
mins = math.floor((secs % 3600) / 60)
|
60 |
-
sec = int(secs % 60)
|
61 |
-
|
62 |
-
gtime = [yr, mo, d, hour, mins, sec]
|
63 |
-
|
64 |
-
return gtime
|
65 |
-
|
66 |
-
|
67 |
-
def fix_time(ds):
|
68 |
-
from datetime import datetime, timedelta
|
69 |
-
|
70 |
-
time = ds["TIME"]
|
71 |
-
time2 = time.dropna(dim="MAXT")
|
72 |
-
time2 = time2.reindex_like(time, method="nearest")
|
73 |
-
jourjul = [greg_0h(jourjul) for jourjul in time2.values]
|
74 |
-
date = [
|
75 |
-
datetime(jourjul[0], jourjul[1], jourjul[2], jourjul[3], jourjul[4], jourjul[5])
|
76 |
-
for jourjul in jourjul
|
77 |
-
]
|
78 |
-
date = xr.DataArray(date, dims="MAXT")
|
79 |
-
return ds.assign(TIME=date)
|
80 |
-
|
81 |
-
@pn.cache(max_items=32,policy='LRU',per_session=True)
|
82 |
-
def load_csv():
|
83 |
-
df = pd.read_csv('./data/zarr_table.csv',index_col=None)
|
84 |
-
df.sort_values(by="year") #inplace=True)
|
85 |
-
return df
|
86 |
-
|
87 |
-
@pn.cache(max_items=4,policy='LRU',per_session=True)
|
88 |
-
def load_bathymetry():
|
89 |
-
#url="https://data-eurogoship.ifremer.fr/bathymetrie/bathy6min.nc"
|
90 |
-
#fs = fsspec.filesystem("https")
|
91 |
-
return xr.open_dataset('./data/bathy6min.nc', decode_times=False, use_cftime=True)
|
92 |
-
|
93 |
-
@pn.cache(max_items=16,policy='LRU',per_session=True)
|
94 |
-
def load_zarr(selected_file):
|
95 |
-
from datatree import open_datatree
|
96 |
-
tree= open_datatree('./data/1H_file.zarr', engine='zarr')
|
97 |
-
return tree[selected_file+"/"].ds
|
98 |
-
|
99 |
-
def filter_df(sorted_df,selected_file):
|
100 |
-
dataframe = sorted_df[sorted_df["file_name"] == selected_file].drop(
|
101 |
-
columns=[
|
102 |
-
"file_name",
|
103 |
-
"title",
|
104 |
-
"Conventions",
|
105 |
-
"featureType",
|
106 |
-
"date_update",
|
107 |
-
"ADCP_beam_angle",
|
108 |
-
"ADCP_ship_angle",
|
109 |
-
"middle_bin1_depth",
|
110 |
-
"heading_corr",
|
111 |
-
"pitch_corr",
|
112 |
-
"ampli_corr",
|
113 |
-
"pitch_roll_used",
|
114 |
-
"date_creation",
|
115 |
-
"ADCP_type",
|
116 |
-
"data_type",
|
117 |
-
]
|
118 |
-
)
|
119 |
-
dataframe2 = sorted_df[sorted_df["file_name"] == selected_file].drop(
|
120 |
-
columns=[
|
121 |
-
"file_name",
|
122 |
-
"date_start",
|
123 |
-
"date_end",
|
124 |
-
"ADCP_frequency(kHz)",
|
125 |
-
"bin_length(meter)",
|
126 |
-
"year",
|
127 |
-
]
|
128 |
-
)
|
129 |
-
return dataframe.transpose(), dataframe2.transpose()
|
130 |
|
131 |
-
def quiver_depth_filterd(ax,ds_filtered, depth1, depth_range_slider, scale_factor_slider, color="blue"):
|
132 |
-
import cartopy.crs as ccrs
|
133 |
-
depth_filtered = ds_filtered.where(
|
134 |
-
(depth1 > depth_range_slider.value[0])
|
135 |
-
& (depth1 <= depth_range_slider.value[1])
|
136 |
-
)
|
137 |
|
138 |
-
lon = ds_filtered.coords["LONGITUDE"].values
|
139 |
-
lat = ds_filtered.coords["LATITUDE"].values
|
140 |
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
width=0.001,
|
153 |
-
headwidth=3,
|
154 |
-
transform=ccrs.PlateCarree(),
|
155 |
-
)
|
156 |
|
157 |
-
|
158 |
df = load_csv()
|
159 |
bathy = load_bathymetry()
|
|
|
160 |
file_names = df["file_name"].tolist()
|
161 |
years = sorted(df["year"].unique())
|
162 |
|
163 |
-
|
164 |
-
|
165 |
-
)
|
166 |
file_dropdown = pn.widgets.Select(name="File Selector")
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
longitude_slider = pn.widgets.RangeSlider(
|
171 |
-
name="Longitude Range", start=-180, end=180, step=1
|
172 |
-
)
|
173 |
-
latitude_slider = pn.widgets.RangeSlider(
|
174 |
-
name="Latitude Range", start=-90, end=90, step=1
|
175 |
-
)
|
176 |
-
|
177 |
-
depth_range_slider = pn.widgets.IntRangeSlider(
|
178 |
-
start=100, end=300, value=(100, 300), step=1, name="Depth Range"
|
179 |
-
)
|
180 |
depth_2_checkbox = pn.widgets.Checkbox(value=False, name="Depth 2 Checkbox")
|
181 |
depth_3_checkbox = pn.widgets.Checkbox(value=False, name="Depth 3 Checkbox")
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
)
|
186 |
-
depth3_range_slider = pn.widgets.IntRangeSlider(
|
187 |
-
start=100, end=300, value=(100, 300), step=1, name="Depth 3 Range"
|
188 |
-
)
|
189 |
-
|
190 |
-
num_vectors_slider = pn.widgets.IntSlider(
|
191 |
-
start=40, end=800, step=1, value=100, name="Number of Vectors"
|
192 |
-
)
|
193 |
-
scale_factor_slider = pn.widgets.FloatSlider(
|
194 |
-
start=0.1, end=1, step=0.1, value=0.5, name="Scale Factor"
|
195 |
-
)
|
196 |
bathy_checkbox = pn.widgets.Checkbox(value=False, name="Bathy Checkbox")
|
197 |
|
198 |
-
|
199 |
-
plot_map = pn.pane.Matplotlib(width=800, height=600, sizing_mode="fixed")
|
200 |
-
|
201 |
data_table = pn.widgets.Tabulator(width=400, height=200)
|
202 |
-
|
203 |
metadata_table = pn.widgets.Tabulator(width=600, height=800)
|
|
|
204 |
download_button = pn.widgets.Button(name="Download", button_type="primary")
|
205 |
-
# plot = pn.Column()
|
206 |
|
207 |
def __init__(self, **params):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
super(SADCP_Viewer, self).__init__(**params)
|
209 |
-
self.file_dropdown.objects = self.
|
210 |
self.file_dropdown.value = (
|
211 |
self.file_dropdown.objects[0] if self.file_dropdown.objects else None
|
212 |
)
|
@@ -214,54 +69,50 @@ class SADCP_Viewer(param.Parameterized):
|
|
214 |
|
215 |
@param.depends("year_slider.value", "file_dropdown.value", watch=True)
|
216 |
def update_name_options(self):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
start_year, end_year = self.year_slider.value
|
|
|
|
|
218 |
mask = (self.df["year"] >= start_year) & (self.df["year"] <= end_year)
|
219 |
sorted_df = self.df[mask].sort_values(by="year")
|
|
|
|
|
220 |
files = sorted_df["file_name"].unique().tolist()
|
221 |
-
|
|
|
222 |
self.file_dropdown.options = files
|
|
|
223 |
if files:
|
224 |
selected_file = self.file_dropdown.value
|
|
|
|
|
225 |
if not selected_file or selected_file not in files:
|
226 |
selected_file = files[0]
|
227 |
self.file_dropdown.value = selected_file
|
228 |
-
|
229 |
-
|
230 |
-
self.
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
self.
|
245 |
-
self.longitude_slider.value = lon_range
|
246 |
-
|
247 |
-
self.latitude_slider.start = lat_range[0]
|
248 |
-
self.latitude_slider.end = lat_range[1]
|
249 |
-
self.latitude_slider.value = lat_range
|
250 |
-
|
251 |
-
self.depth_range_slider.start = deph_range[0]
|
252 |
-
self.depth_range_slider.end = deph_range[1]
|
253 |
-
self.depth_range_slider.value = deph_range
|
254 |
-
|
255 |
-
self.depth2_range_slider.start = deph_range[0]
|
256 |
-
self.depth2_range_slider.end = deph_range[1]
|
257 |
-
self.depth2_range_slider.value = deph_range
|
258 |
-
|
259 |
-
self.depth3_range_slider.start = deph_range[0]
|
260 |
-
self.depth3_range_slider.end = deph_range[1]
|
261 |
-
self.depth3_range_slider.value = deph_range
|
262 |
-
|
263 |
-
# self.update_plots()
|
264 |
-
self.ds.close()
|
265 |
|
266 |
@param.depends(
|
267 |
"year_slider.value",
|
@@ -269,117 +120,60 @@ class SADCP_Viewer(param.Parameterized):
|
|
269 |
"depth_range_slider.value",
|
270 |
"depth_2_checkbox.value",
|
271 |
"depth_3_checkbox.value",
|
272 |
-
"
|
273 |
-
"
|
274 |
"longitude_slider.value",
|
275 |
"latitude_slider.value",
|
276 |
"num_vectors_slider.value",
|
277 |
"scale_factor_slider.value",
|
278 |
"bathy_checkbox.value",
|
279 |
-
watch=False,
|
280 |
-
)
|
281 |
def update_plots(self):
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
288 |
*(pn.pane.HoloViews(plot, width=400, height=200) for plot in other_plots),
|
289 |
sizing_mode="stretch_width"
|
290 |
)
|
291 |
-
vector_plot = self.vectors_plot() # Update vector plot
|
292 |
-
self.plot_map.object = vector_plot
|
293 |
-
# other_plots = self.plots() # Update other plots
|
294 |
-
# self.plot.objects = [*(pn.pane.HoloViews(p, width=400, height=200) for p in other_plots)]
|
295 |
-
# self.plot.object=plot
|
296 |
-
|
297 |
-
return pn.Row(self.plot_map, self.plot, sizing_mode="stretch_both")
|
298 |
-
|
299 |
-
def filter_data(self):
|
300 |
-
return self.ds.where(
|
301 |
-
(self.ds.LONGITUDE >= self.longitude_slider.start)
|
302 |
-
& (self.ds.LONGITUDE <= self.longitude_slider.end)
|
303 |
-
& (self.ds.LATITUDE >= self.latitude_slider.start)
|
304 |
-
& (self.ds.LATITUDE <= self.latitude_slider.end),
|
305 |
-
drop=True,
|
306 |
-
)
|
307 |
-
|
308 |
-
def vectors_plot(self):
|
309 |
-
import cartopy.crs as ccrs
|
310 |
-
import cartopy.feature as cfeature
|
311 |
|
312 |
-
|
|
|
313 |
|
314 |
-
# 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))
|
315 |
-
|
316 |
-
fig, ax = plt.subplots(
|
317 |
-
figsize=(8, 7), subplot_kw={"projection": ccrs.Mercator()}
|
318 |
-
)
|
319 |
-
coords = ["LATITUDE", "LONGITUDE"]
|
320 |
-
corsen = max(1, self.ds_filtered.MAXT.size // self.num_vectors_slider.value)
|
321 |
-
self.ds_filtered = (
|
322 |
-
self.ds_filtered.reset_coords(coords)
|
323 |
-
.coarsen({"MAXT": corsen}, boundary="trim")
|
324 |
-
.mean()
|
325 |
-
.set_coords(coords)
|
326 |
-
)
|
327 |
-
|
328 |
-
# self.ds_filtered =self.ds_filtered.coarsen(MAXT = corsen, side = "center", boundary = "trim").mean()[["LONGITUDE", "LONGITUDE", "TIME"]].isel(MAXZ=0)
|
329 |
-
|
330 |
-
quiver_depth_filterd(ax,self.ds_filtered, self.depth1, self.depth_range_slider,self.scale_factor_slider,color="blue")
|
331 |
-
|
332 |
-
if self.depth_2_checkbox.value:
|
333 |
-
quiver_depth_filterd(ax,self.ds_filtered, self.depth1, self.depth2_range_slider,self.scale_factor_slider,color="green")
|
334 |
-
|
335 |
-
if self.depth_3_checkbox.value:
|
336 |
-
quiver_depth_filterd(ax,self.ds_filtered, self.depth1, self.depth3_range_slider,self.scale_factor_slider,color="red")
|
337 |
-
|
338 |
-
ax.add_feature(cfeature.COASTLINE)
|
339 |
-
ax.add_feature(cfeature.BORDERS, linestyle=":")
|
340 |
-
ax.add_feature(cfeature.LAND, color="lightgray")
|
341 |
-
|
342 |
-
if self.bathy_checkbox.value:
|
343 |
-
contour_levels = [-1000]
|
344 |
-
ax.contour(
|
345 |
-
self.bathy.longitude,
|
346 |
-
self.bathy.latitude,
|
347 |
-
self.bathy.z,
|
348 |
-
levels=contour_levels,
|
349 |
-
colors="black",
|
350 |
-
transform=ccrs.PlateCarree(),
|
351 |
-
)
|
352 |
-
|
353 |
-
ax.set_extent(
|
354 |
-
[
|
355 |
-
self.longitude_slider.value[0],
|
356 |
-
self.longitude_slider.value[1],
|
357 |
-
self.latitude_slider.value[0],
|
358 |
-
self.latitude_slider.value[1],
|
359 |
-
]
|
360 |
-
)
|
361 |
-
ax.gridlines(draw_labels=True)
|
362 |
-
plt.ylabel("Latitude", fontsize=15, labelpad=35)
|
363 |
-
plt.xlabel("Longitude", fontsize=15, labelpad=20)
|
364 |
-
plt.close()
|
365 |
-
return fig
|
366 |
-
|
367 |
-
# pn.pane.Matplotlib(fig,width=800, height=600, sizing_mode="fixed", name="Plot")
|
368 |
-
|
369 |
-
# @param.depends( 'file_dropdown.value', 'longitude_slider.value', 'latitude_slider.value', watch=True)
|
370 |
-
def hvplot_plots(self):
|
371 |
-
import hvplot.xarray
|
372 |
-
return [
|
373 |
-
self.ds_filtered["BATHY"].max(dim="MAXZ").hvplot(x="TIME", width=400, height=200),
|
374 |
-
self.ds_filtered["USHIP"].max(dim="MAXZ").hvplot(x="TIME", width=400, height=200),
|
375 |
-
self.ds_filtered["VSHIP"].max(dim="MAXZ").hvplot(x="TIME", width=400, height=200),
|
376 |
-
self.ds_filtered["BOTTOM_DEPTH"].max(dim="MAXZ").hvplot(x="TIME", width=400, height=200),
|
377 |
-
|
378 |
-
]
|
379 |
-
|
380 |
-
def get_file_list(self):
|
381 |
-
return self.file_names
|
382 |
|
|
|
|
|
383 |
|
384 |
explorer = SADCP_Viewer()
|
385 |
# Instantiate the SADCP_Viewer class and create a template
|
@@ -394,6 +188,7 @@ tabs = pn.Tabs(
|
|
394 |
)
|
395 |
|
396 |
sidebar = [
|
|
|
397 |
"""This application, developed in the frame of Euro Go Shop, helps to interactively visualise and download ship ADCP data.""",
|
398 |
explorer.year_slider,
|
399 |
explorer.file_dropdown,
|
@@ -403,14 +198,21 @@ sidebar = [
|
|
403 |
explorer.depth_range_slider,
|
404 |
explorer.depth_2_checkbox,
|
405 |
explorer.depth_3_checkbox,
|
406 |
-
explorer.
|
407 |
-
explorer.
|
408 |
explorer.num_vectors_slider,
|
409 |
explorer.scale_factor_slider,
|
410 |
explorer.data_table,
|
|
|
|
|
|
|
|
|
|
|
411 |
]
|
|
|
412 |
template = pn.template.FastListTemplate(
|
413 |
-
title="SADCP data Viewer",
|
|
|
|
|
414 |
)
|
415 |
template.servable()
|
416 |
-
|
|
|
|
|
|
|
|
|
|
|
1 |
import numpy as np
|
2 |
import pandas as pd
|
3 |
import panel as pn
|
4 |
import xarray as xr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
import param
|
6 |
|
7 |
+
import hvplot.xarray
|
8 |
+
import matplotlib.pyplot as plt
|
9 |
+
import cartopy.crs as ccrs
|
10 |
+
import cartopy.feature as cfeature
|
11 |
+
from datatree import open_datatree
|
12 |
+
from xsadcp import get_range, load_csv, load_bathymetry, load_zarr, load_file, filter_df, filter_data, quiver_depth_filtered, bathy_uship_vship_bottom_depth, corsen_data, vectors_plot, fix_time, transform_netCDF, get_info, get_file_names, open_ds
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
|
|
|
|
15 |
|
16 |
+
class SADCP_Viewer(param.Parameterized):
|
17 |
+
"""
|
18 |
+
A parameterized class for viewing SADCP data.
|
19 |
|
20 |
+
This class provides widgets for selecting data parameters, updating data based on selections,
|
21 |
+
and generating plots to visualize the SADCP data.
|
22 |
+
|
23 |
+
Available functions:
|
24 |
+
- update_name_options: Update dropdown options and slider ranges based on selected years and file.
|
25 |
+
- update_plots: Update plots based on selected data and parameters.
|
26 |
+
"""
|
|
|
|
|
|
|
|
|
27 |
|
28 |
+
# Load data and initialize widgets
|
29 |
df = load_csv()
|
30 |
bathy = load_bathymetry()
|
31 |
+
tree=load_zarr()
|
32 |
file_names = df["file_name"].tolist()
|
33 |
years = sorted(df["year"].unique())
|
34 |
|
35 |
+
# Widgets for selecting data parameters
|
36 |
+
year_slider = pn.widgets.IntRangeSlider(name="Year Range", start=df["year"].min(), end=df["year"].max())
|
|
|
37 |
file_dropdown = pn.widgets.Select(name="File Selector")
|
38 |
+
longitude_slider = pn.widgets.RangeSlider(name="Longitude Range", start=-180, end=180, step=1)
|
39 |
+
latitude_slider = pn.widgets.RangeSlider(name="Latitude Range", start=-90, end=90, step=1)
|
40 |
+
depth_range_slider = pn.widgets.IntRangeSlider(start=100, end=300, value=(100, 300), step=1, name="Depth Range")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
depth_2_checkbox = pn.widgets.Checkbox(value=False, name="Depth 2 Checkbox")
|
42 |
depth_3_checkbox = pn.widgets.Checkbox(value=False, name="Depth 3 Checkbox")
|
43 |
+
depth_2_range_slider = pn.widgets.IntRangeSlider(start=100, end=300, value=(100, 300), step=1, name="Depth 2 Range")
|
44 |
+
depth_3_range_slider = pn.widgets.IntRangeSlider(start=100, end=300, value=(100, 300), step=1, name="Depth 3 Range")
|
45 |
+
num_vectors_slider = pn.widgets.IntSlider(start=40, end=800, step=1, value=100, name="Number of Vectors")
|
46 |
+
scale_factor_slider = pn.widgets.FloatSlider(start=0.1, end=1, step=0.1, value=0.5, name="Scale Factor")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
bathy_checkbox = pn.widgets.Checkbox(value=False, name="Bathy Checkbox")
|
48 |
|
49 |
+
|
|
|
|
|
50 |
data_table = pn.widgets.Tabulator(width=400, height=200)
|
|
|
51 |
metadata_table = pn.widgets.Tabulator(width=600, height=800)
|
52 |
+
# Download button is not working : TODO
|
53 |
download_button = pn.widgets.Button(name="Download", button_type="primary")
|
|
|
54 |
|
55 |
def __init__(self, **params):
|
56 |
+
"""
|
57 |
+
Initialize the SADCP_Viewer class.
|
58 |
+
|
59 |
+
Parameters:
|
60 |
+
**params: Additional parameters to be passed to the superclass.
|
61 |
+
"""
|
62 |
+
|
63 |
super(SADCP_Viewer, self).__init__(**params)
|
64 |
+
self.file_dropdown.objects = self.file_names
|
65 |
self.file_dropdown.value = (
|
66 |
self.file_dropdown.objects[0] if self.file_dropdown.objects else None
|
67 |
)
|
|
|
69 |
|
70 |
@param.depends("year_slider.value", "file_dropdown.value", watch=True)
|
71 |
def update_name_options(self):
|
72 |
+
"""
|
73 |
+
Update dropdown options and slider ranges based on selected years and file.
|
74 |
+
|
75 |
+
This function updates the dropdown options and slider ranges based on the selected years
|
76 |
+
and file. It also loads the selected file's data and adjusts slider ranges accordingly.
|
77 |
+
|
78 |
+
"""
|
79 |
+
# Extract selected start and end years
|
80 |
start_year, end_year = self.year_slider.value
|
81 |
+
|
82 |
+
# Filter DataFrame based on selected years and sort by year
|
83 |
mask = (self.df["year"] >= start_year) & (self.df["year"] <= end_year)
|
84 |
sorted_df = self.df[mask].sort_values(by="year")
|
85 |
+
|
86 |
+
# Get unique file names
|
87 |
files = sorted_df["file_name"].unique().tolist()
|
88 |
+
|
89 |
+
# Update file dropdown options
|
90 |
self.file_dropdown.options = files
|
91 |
+
|
92 |
if files:
|
93 |
selected_file = self.file_dropdown.value
|
94 |
+
|
95 |
+
# Set default selected file if not selected or not in options
|
96 |
if not selected_file or selected_file not in files:
|
97 |
selected_file = files[0]
|
98 |
self.file_dropdown.value = selected_file
|
99 |
+
|
100 |
+
# Update data table and metadata table based on selected file
|
101 |
+
self.data_table.value, self.metadata_table.value = filter_df(sorted_df, selected_file)
|
102 |
+
|
103 |
+
# Load selected file's data
|
104 |
+
self.ds = load_file(self.tree,selected_file)
|
105 |
+
|
106 |
+
# Update slider ranges for longitude, latitude, and depth
|
107 |
+
for slider, coord in zip([self.longitude_slider, self.latitude_slider, self.depth_range_slider,
|
108 |
+
self.depth_2_range_slider, self.depth_3_range_slider],
|
109 |
+
[self.ds.LONGITUDE, self.ds.LATITUDE, self.ds.PROFZ,self.ds.PROFZ,self.ds.PROFZ]):
|
110 |
+
coord_range = get_range(coord)
|
111 |
+
slider.start, slider.end, slider.value = coord_range[0], coord_range[1], coord_range
|
112 |
+
|
113 |
+
|
114 |
+
# Close dataset to free up resources
|
115 |
+
# self.ds.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
|
117 |
@param.depends(
|
118 |
"year_slider.value",
|
|
|
120 |
"depth_range_slider.value",
|
121 |
"depth_2_checkbox.value",
|
122 |
"depth_3_checkbox.value",
|
123 |
+
"depth_2_range_slider.value",
|
124 |
+
"depth_3_range_slider.value",
|
125 |
"longitude_slider.value",
|
126 |
"latitude_slider.value",
|
127 |
"num_vectors_slider.value",
|
128 |
"scale_factor_slider.value",
|
129 |
"bathy_checkbox.value",
|
130 |
+
watch=False,)
|
|
|
131 |
def update_plots(self):
|
132 |
+
"""
|
133 |
+
This function updates the plots based on the selected data and parameters.
|
134 |
+
|
135 |
+
The function filters the data, generates additional plots, and updates the main vector plot based on the selected parameters.
|
136 |
+
|
137 |
+
Returns:
|
138 |
+
pn.Row: A Panel row containing the updated map plot and additional plots.
|
139 |
+
|
140 |
+
"""
|
141 |
+
# Filter the data
|
142 |
+
self.ds_filtered = filter_data(self.ds,self.longitude_slider.value,self.latitude_slider.value)
|
143 |
+
|
144 |
+
# Prepare the plots shown in left
|
145 |
+
# Update vector plots
|
146 |
+
vector_plot = vectors_plot(self.ds_filtered, self.bathy,
|
147 |
+
self.longitude_slider.value, self.latitude_slider.value,
|
148 |
+
self.depth_range_slider.value, self.depth_2_range_slider.value, self.depth_3_range_slider.value,
|
149 |
+
self.scale_factor_slider.value,self.num_vectors_slider.value,
|
150 |
+
depth_2_checkbox= self.depth_2_checkbox.value,
|
151 |
+
depth_3_checkbox= self.depth_3_checkbox.value,
|
152 |
+
bathy_checkbox=self.bathy_checkbox.value,
|
153 |
+
)
|
154 |
+
|
155 |
+
|
156 |
+
# Generate plots which will be plotted on the left row.
|
157 |
+
self.plot_left = pn.Column(
|
158 |
+
# Here adjust the style option later TODO
|
159 |
+
# https://panel.holoviz.org/how_to/styling/matplotlib.html
|
160 |
+
pn.pane.Matplotlib(vector_plot, dpi=144),
|
161 |
+
# Add here the hvplot block of contour TODO
|
162 |
+
sizing_mode="stretch_both")
|
163 |
+
|
164 |
+
# Generate additional plots which will be plotted on the right row.
|
165 |
+
other_plots = bathy_uship_vship_bottom_depth(self.ds_filtered)
|
166 |
+
self.plot_right = pn.Column(
|
167 |
*(pn.pane.HoloViews(plot, width=400, height=200) for plot in other_plots),
|
168 |
sizing_mode="stretch_width"
|
169 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
|
171 |
+
# Return a Panel row containing the updated map plot and additional plots
|
172 |
+
return pn.Row(self.plot_left, self.plot_right, sizing_mode="stretch_both")
|
173 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
|
175 |
+
pn.extension("tabulator")
|
176 |
+
pn.config.theme = 'dark'
|
177 |
|
178 |
explorer = SADCP_Viewer()
|
179 |
# Instantiate the SADCP_Viewer class and create a template
|
|
|
188 |
)
|
189 |
|
190 |
sidebar = [
|
191 |
+
pn.panel('./EuroGO-SHIP_logo_wide_tagline_1.2.png',width=300 ),
|
192 |
"""This application, developed in the frame of Euro Go Shop, helps to interactively visualise and download ship ADCP data.""",
|
193 |
explorer.year_slider,
|
194 |
explorer.file_dropdown,
|
|
|
198 |
explorer.depth_range_slider,
|
199 |
explorer.depth_2_checkbox,
|
200 |
explorer.depth_3_checkbox,
|
201 |
+
explorer.depth_2_range_slider,
|
202 |
+
explorer.depth_3_range_slider,
|
203 |
explorer.num_vectors_slider,
|
204 |
explorer.scale_factor_slider,
|
205 |
explorer.data_table,
|
206 |
+
"""You can consult detailed information on this data in the metadata tab shown on the right.
|
207 |
+
To download full dataset, please go to https://cdi.seadatanet.org/search
|
208 |
+
and search with LOCAL_CDI_ID indicated above.""",
|
209 |
+
#pn.panel('https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png', ),
|
210 |
+
#width=10)
|
211 |
]
|
212 |
+
|
213 |
template = pn.template.FastListTemplate(
|
214 |
+
title="SADCP data Viewer", logo='https://avatars.githubusercontent.com/u/123177533?s=200&v=4',
|
215 |
+
sidebar=sidebar, main=[tabs]
|
216 |
+
|
217 |
)
|
218 |
template.servable()
|
|
requirements.txt
CHANGED
@@ -1,9 +1,7 @@
|
|
1 |
panel
|
2 |
jupyter
|
3 |
-
transformers
|
4 |
numpy
|
5 |
-
|
6 |
-
aiohttp
|
7 |
cartopy
|
8 |
cftime
|
9 |
hvplot
|
@@ -11,4 +9,5 @@ xarray==2024.2.0
|
|
11 |
scipy
|
12 |
matplotlib
|
13 |
xarray-datatree
|
14 |
-
zarr
|
|
|
|
1 |
panel
|
2 |
jupyter
|
|
|
3 |
numpy
|
4 |
+
fsspec
|
|
|
5 |
cartopy
|
6 |
cftime
|
7 |
hvplot
|
|
|
9 |
scipy
|
10 |
matplotlib
|
11 |
xarray-datatree
|
12 |
+
zarr
|
13 |
+
lxml
|