purple-koala commited on
Commit
d1e1878
·
verified ·
1 Parent(s): b76d537

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +472 -120
app.py CHANGED
@@ -1,147 +1,499 @@
1
  import io
2
- import random
3
- from typing import List, Tuple
4
 
5
- import aiohttp
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  import panel as pn
7
- from PIL import Image
8
- from transformers import CLIPModel, CLIPProcessor
 
 
 
 
 
 
 
9
 
10
- pn.extension(design="bootstrap", sizing_mode="stretch_width")
 
 
 
 
 
11
 
12
- ICON_URLS = {
13
- "brand-github": "https://github.com/holoviz/panel",
14
- "brand-twitter": "https://twitter.com/Panel_Org",
15
- "brand-linkedin": "https://www.linkedin.com/company/panel-org",
16
- "message-circle": "https://discourse.holoviz.org/",
17
- "brand-discord": "https://discord.gg/AXRHnJU6sP",
18
- }
19
 
 
20
 
21
- async def random_url(_):
22
- pet = random.choice(["cat", "dog"])
23
- api_url = f"https://api.the{pet}api.com/v1/images/search"
24
- async with aiohttp.ClientSession() as session:
25
- async with session.get(api_url) as resp:
26
- return (await resp.json())[0]["url"]
27
 
28
 
29
- @pn.cache
30
- def load_processor_model(
31
- processor_name: str, model_name: str
32
- ) -> Tuple[CLIPProcessor, CLIPModel]:
33
- processor = CLIPProcessor.from_pretrained(processor_name)
34
- model = CLIPModel.from_pretrained(model_name)
35
- return processor, model
36
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- async def open_image_url(image_url: str) -> Image:
39
- async with aiohttp.ClientSession() as session:
40
- async with session.get(image_url) as resp:
41
- return Image.open(io.BytesIO(await resp.read()))
 
42
 
 
 
 
 
 
 
43
 
44
- def get_similarity_scores(class_items: List[str], image: Image) -> List[float]:
45
- processor, model = load_processor_model(
46
- "openai/clip-vit-base-patch32", "openai/clip-vit-base-patch32"
47
  )
48
- inputs = processor(
49
- text=class_items,
50
- images=[image],
51
- return_tensors="pt", # pytorch tensors
52
  )
53
- outputs = model(**inputs)
54
- logits_per_image = outputs.logits_per_image
55
- class_likelihoods = logits_per_image.softmax(dim=1).detach().numpy()
56
- return class_likelihoods[0]
57
-
58
-
59
- async def process_inputs(class_names: List[str], image_url: str):
60
- """
61
- High level function that takes in the user inputs and returns the
62
- classification results as panel objects.
63
- """
64
- try:
65
- main.disabled = True
66
- if not image_url:
67
- yield "##### ⚠️ Provide an image URL"
68
- return
69
-
70
- yield "##### ⚙ Fetching image and running model..."
71
- try:
72
- pil_img = await open_image_url(image_url)
73
- img = pn.pane.Image(pil_img, height=400, align="center")
74
- except Exception as e:
75
- yield f"##### 😔 Something went wrong, please try a different URL!"
76
- return
77
-
78
- class_items = class_names.split(",")
79
- class_likelihoods = get_similarity_scores(class_items, pil_img)
80
 
81
- # build the results column
82
- results = pn.Column("##### 🎉 Here are the results!", img)
 
83
 
84
- for class_item, class_likelihood in zip(class_items, class_likelihoods):
85
- row_label = pn.widgets.StaticText(
86
- name=class_item.strip(), value=f"{class_likelihood:.2%}", align="center"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  )
88
- row_bar = pn.indicators.Progress(
89
- value=int(class_likelihood * 100),
90
- sizing_mode="stretch_width",
91
- bar_color="secondary",
92
- margin=(0, 10),
93
- design=pn.theme.Material,
 
 
 
 
 
 
 
94
  )
95
- results.append(pn.Column(row_label, row_bar))
96
- yield results
97
- finally:
98
- main.disabled = False
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- # create widgets
102
- randomize_url = pn.widgets.Button(name="Randomize URL", align="end")
103
 
104
- image_url = pn.widgets.TextInput(
105
- name="Image URL to classify",
106
- value=pn.bind(random_url, randomize_url),
107
- )
108
- class_names = pn.widgets.TextInput(
109
- name="Comma separated class names",
110
- placeholder="Enter possible class names, e.g. cat, dog",
111
- value="cat, dog, parrot",
112
- )
113
 
114
- input_widgets = pn.Column(
115
- "##### 😊 Click randomize or paste a URL to start classifying!",
116
- pn.Row(image_url, randomize_url),
117
- class_names,
118
- )
119
 
120
- # add interactivity
121
- interactive_result = pn.panel(
122
- pn.bind(process_inputs, image_url=image_url, class_names=class_names),
123
- height=600,
124
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
- # add footer
127
- footer_row = pn.Row(pn.Spacer(), align="center")
128
- for icon, url in ICON_URLS.items():
129
- href_button = pn.widgets.Button(icon=icon, width=35, height=35)
130
- href_button.js_on_click(code=f"window.open('{url}')")
131
- footer_row.append(href_button)
132
- footer_row.append(pn.Spacer())
133
-
134
- # create dashboard
135
- main = pn.WidgetBox(
136
- input_widgets,
137
- interactive_result,
138
- footer_row,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  )
140
 
141
- title = "Panel Demo - Image Classification"
142
- pn.template.BootstrapTemplate(
143
- title=title,
144
- main=main,
145
- main_max_width="min(50%, 698px)",
146
- header_background="#F08080",
147
- ).servable(title=title)
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import io
2
+ import math
 
3
 
4
+ # date=dataset['TIME']
5
+ from datetime import date, datetime, timedelta
6
+
7
+ import cartopy.crs as ccrs
8
+ import cartopy.feature as cfeature
9
+ import cftime
10
+ import fsspec
11
+ import hvplot.xarray
12
+ import jdcal
13
+ import matplotlib.pyplot as plt
14
+ import numpy as np
15
+ import pandas as pd
16
+ import panel as pn
17
+ import xarray as xr
18
+ from astropy.time import Time
19
+ from ipywidgets import (
20
+ Checkbox,
21
+ Dropdown,
22
+ FloatRangeSlider,
23
+ FloatSlider,
24
+ IntRangeSlider,
25
+ IntSlider,
26
+ interactive,
27
+ )
28
+
29
+ pn.extension()
30
+
31
+ #df = pd.read_csv("table.csv", index_col=None)
32
+ #df = df.sort_values(by="year")
33
+ #df2 = pd.read_csv("test_table.csv", index_col=None)
34
+ #file_names = df["file_name"].tolist()
35
+ #df = df.sort_values(by="year")
36
+ #years = sorted(df["year"].unique())
37
+
38
+
39
+ def greg_0h(jourjul):
40
+ # Julian days start and end at noon.
41
+ # Julian day 2440000 begins at 00 hours, May 23, 1968.
42
+
43
+ # Round the input Julian day number to avoid precision errors
44
+ fac = 10**9
45
+ jourjul = np.round(fac * jourjul + 0.5) / fac
46
+
47
+ # Calculate seconds in the day
48
+ secs = (jourjul % 1) * 24 * 3600
49
+
50
+ # Round seconds to avoid precision errors
51
+ secs = np.round(fac * secs + 0.5) / fac
52
+
53
+ # Gregorian calendar conversion
54
+ j = math.floor(jourjul) - 1721119
55
+ in_ = 4 * j - 1
56
+ y = math.floor(in_ / 146097)
57
+ j = in_ - 146097 * y
58
+ in_ = math.floor(j / 4)
59
+ in_ = 4 * in_ + 3
60
+ j = math.floor(in_ / 1461)
61
+ d = math.floor(((in_ - 1461 * j) + 4) / 4)
62
+ in_ = 5 * d - 3
63
+ m = math.floor(in_ / 153)
64
+ d = math.floor(((in_ - 153 * m) + 5) / 5)
65
+ y = y * 100 + j
66
+ if m < 10:
67
+ mo = m + 3
68
+ yr = y
69
+ else:
70
+ mo = m - 9
71
+ yr = y + 1
72
+
73
+ hour = math.floor(secs / 3600)
74
+ mins = math.floor((secs % 3600) / 60)
75
+ sec = int(secs % 60)
76
+
77
+ gtime = [yr, mo, d, hour, mins, sec]
78
+
79
+ return gtime
80
+
81
+
82
+ def fix_time(dataset):
83
+ from datetime import datetime, timedelta
84
+
85
+ time = dataset["TIME"]
86
+ time2 = time.dropna(dim="MAXT")
87
+ time2 = time2.reindex_like(time, method='nearest')
88
+ jourjul = [greg_0h(jourjul) for jourjul in time2.values]
89
+ date = [
90
+ datetime(jourjul[0], jourjul[1], jourjul[2], jourjul[3], jourjul[4], jourjul[5])
91
+ for jourjul in jourjul
92
+ ]
93
+
94
+ return date
95
+
96
+ from datetime import datetime, timedelta
97
+
98
+ import cartopy.crs as ccrs
99
+ import cartopy.feature as cfeature
100
+ import fsspec
101
+ import matplotlib.pyplot as plt
102
+ import numpy as np
103
  import panel as pn
104
+ import xarray as xr
105
+ from ipywidgets import (
106
+ Checkbox,
107
+ FloatRangeSlider,
108
+ FloatSlider,
109
+ IntRangeSlider,
110
+ IntSlider,
111
+ interactive,
112
+ )
113
 
114
+ # Loaddonnées bathymétry data
115
+ fs = fsspec.filesystem("https")
116
+ # bathy = xr.open_dataset(fs.open('https://data-eurogoship.ifremer.fr/bathymetrie/bathy6min.nc'))
117
+ bathy = xr.open_dataset(
118
+ "/Users/lfranc/Desktop/lea/CASCADE/exploitation/bathymetrie/bathy6min.nc"
119
+ )
120
 
 
 
 
 
 
 
 
121
 
122
+ import os
123
 
124
+ import pandas as pd
125
+ import panel as pn
126
+ import param
127
+ import xarray as xr
 
 
128
 
129
 
130
+ class SADCP_Viewer(param.Parameterized):
131
+ df = pd.read_csv("table.csv", index_col=None).sort_values(by="year")
132
+ file_names = df["file_name"].tolist()
133
+ years = sorted(df["year"].unique())
 
 
 
134
 
135
+ year_slider = pn.widgets.IntRangeSlider(
136
+ name="Year Range", start=df["year"].min(), end=df["year"].max()
137
+ )
138
+ file_dropdown = pn.widgets.Select(name="File Selector")
139
+ data_table = pn.widgets.Tabulator(df, name="metadata", height=200, width=300)
140
+ # data_table2 = pn.widgets.Tabulator(df2, name="metadata", height=900, width=400)
141
+
142
+ longitude_slider = pn.widgets.RangeSlider(
143
+ name="Longitude Range", start=-180, end=180, step=1
144
+ )
145
+ latitude_slider = pn.widgets.RangeSlider(
146
+ name="Latitude Range", start=-90, end=90, step=1
147
+ )
148
 
149
+ depth_range_slider = pn.widgets.IntRangeSlider(
150
+ start=100, end=300, value=(100, 300), step=1, name="Depth Range"
151
+ )
152
+ depth_2_checkbox = pn.widgets.Checkbox(value=False, name="Depth 2 Checkbox")
153
+ depth_3_checkbox = pn.widgets.Checkbox(value=False, name="Depth 3 Checkbox")
154
 
155
+ depth2_range_slider = pn.widgets.IntRangeSlider(
156
+ start=100, end=300, value=(100, 300), step=1, name="Depth 2 Range"
157
+ )
158
+ depth3_range_slider = pn.widgets.IntRangeSlider(
159
+ start=100, end=300, value=(100, 300), step=1, name="Depth 3 Range"
160
+ )
161
 
162
+ num_vectors_slider = pn.widgets.IntSlider(
163
+ start=40, end=800, step=1, value=100, name="Number of Vectors"
 
164
  )
165
+ scale_factor_slider = pn.widgets.FloatSlider(
166
+ start=0.1, end=1, step=0.1, value=0.5, name="Scale Factor"
 
 
167
  )
168
+ bathy_checkbox = pn.widgets.Checkbox(value=False, name="Bathy Checkbox")
169
+
170
+ plot = pn.pane.HoloViews()
171
+ plot_map = pn.pane.Matplotlib(width=800, height=600, sizing_mode="fixed")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
+ data_table = pn.widgets.Tabulator(
174
+ width=400, height=200
175
+ )
176
 
177
+ metadata_table = pn.widgets.Tabulator(
178
+ width=600, height=800
179
+ )
180
+ download_button = pn.widgets.Button(name="Download", button_type="primary")
181
+ # plot = pn.Column()
182
+
183
+ def __init__(self, **params):
184
+ super(SADCP_Viewer, self).__init__(**params)
185
+ self.file_dropdown.objects = self.get_file_list()
186
+ self.file_dropdown.value = (
187
+ self.file_dropdown.objects[0] if self.file_dropdown.objects else None
188
+ )
189
+ self.update_name_options()
190
+
191
+ @param.depends("year_slider.value", "file_dropdown.value", watch=True)
192
+ def update_name_options(self):
193
+ start_year, end_year = self.year_slider.value
194
+ mask = (self.df["year"] >= start_year) & (self.df["year"] <= end_year)
195
+ sorted_df = self.df[mask].sort_values(by="year")
196
+ files = sorted_df["file_name"].unique().tolist()
197
+
198
+ self.file_dropdown.options = files
199
+ if files:
200
+ selected_file = self.file_dropdown.value
201
+ if not selected_file or selected_file not in files:
202
+ selected_file = files[0]
203
+ self.file_dropdown.value = selected_file
204
+ dataframe = sorted_df[sorted_df["file_name"] == selected_file].drop(
205
+ 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"]
206
  )
207
+ dataframe2 = sorted_df[sorted_df["file_name"] == selected_file].drop(
208
+ columns=["file_name","date_start","date_end","ADCP_frequency(kHz)","bin_length(meter)","year"])
209
+
210
+ data_dir = "/Users/lfranc/Documents/octopus_ok/output/"
211
+ file_path = os.path.join(data_dir, selected_file)
212
+ self.ds = (
213
+ xr.open_dataset(
214
+ file_path, decode_cf=True, decode_times=False, engine="scipy"
215
+ )
216
+ .squeeze()
217
+ .set_coords(["LONGITUDE", "LATITUDE", "TIME", "PROFZ"])
218
+ .set_xindex("PROFZ")
219
+ .set_xindex("TIME")
220
  )
 
 
 
 
221
 
222
+ lon_range = (
223
+ int(self.ds["LONGITUDE"].min().round() - 1),
224
+ int(self.ds["LONGITUDE"].max().round() + 1),
225
+ )
226
+ lat_range = (
227
+ int(self.ds["LATITUDE"].min().round() - 1),
228
+ int(self.ds["LATITUDE"].max().round() + 1),
229
+ )
230
+ self.depth1 = abs(self.ds.coords["PROFZ"])
231
+ date = fix_time(self.ds)
232
+ date = xr.DataArray(date, dims="MAXT")
233
+ # self.ds = self.ds.where(
234
+ # (self.ds.VCUR_SEADATANET_QC == 49)
235
+ # & (self.ds.UCUR_SEADATANET_QC == 49)
236
+ # & (self.ds.WCUR_SEADATANET_QC == 49)
237
+ # & (self.ds.ECUR_SEADATANET_QC == 49)
238
+ # & (self.ds.PGOOD_SEADATANET_QC == 49)
239
+ # & (self.ds.ECI_SEADATANET_QC == 49)
240
+ # & (self.ds.BOTTOM_DEPTH_SEADATANET_QC == 49),
241
+ # drop=True,)
242
+ self.ds = self.ds[
243
+ [
244
+ "USHIP",
245
+ "VSHIP",
246
+ "ROLL",
247
+ "PITCH",
248
+ "TR_TEMP",
249
+ "HEADING",
250
+ "U_BOTTOM",
251
+ "V_BOTTOM",
252
+ "UCUR",
253
+ "VCUR",
254
+ "WCUR",
255
+ "ECUR",
256
+ "PGOOD",
257
+ "ECI",
258
+ "BATHY",
259
+ "UTIDE",
260
+ "VTIDE",
261
+ "BOTTOM_DEPTH",
262
+ "TIME",
263
+ ]
264
+ ]
265
+ deph_range = (int(self.depth1.min()), int(self.depth1.max()))
266
 
267
+ # Ku_std_dataarray = xr.DataArray(Ku_std,dims='dim1')
 
268
 
269
+ # date=dataset.assign(TIME=date)
 
 
 
 
 
 
 
 
270
 
271
+ # dataset['TIME']=dataset['TIME'].assign_coords(dim=dataset.dims['MAXT'])
272
+ self.ds = self.ds.assign(TIME=date)
 
 
 
273
 
274
+ self.longitude_slider.start = lon_range[0]
275
+ self.longitude_slider.end = lon_range[1]
276
+ self.longitude_slider.value = lon_range
277
+ self.latitude_slider.start = lat_range[0]
278
+ self.latitude_slider.end = lat_range[1]
279
+ self.latitude_slider.value = lat_range
280
+ self.depth_range_slider.start = deph_range[0]
281
+ self.depth_range_slider.end = deph_range[1]
282
+ self.depth_range_slider.value = deph_range
283
+ self.depth2_range_slider.start = deph_range[0]
284
+ self.depth2_range_slider.end = deph_range[1]
285
+ self.depth2_range_slider.value = deph_range
286
+ self.depth3_range_slider.start = deph_range[0]
287
+ self.depth3_range_slider.end = deph_range[1]
288
+ self.depth3_range_slider.value = deph_range
289
+
290
+
291
+
292
+
293
+ # self.update_plots()
294
+ self.ds.close()
295
+ self.dataframe = dataframe.transpose()
296
+ self.dataframe2 = dataframe2.transpose()
297
+ # self.transposed_dataframe = dataframe.transpose()
298
+ self.data_table.value = self.dataframe
299
+ self.metadata_table.value = self.dataframe2
300
+
301
+ @param.depends(
302
+ "year_slider.value",
303
+ "file_dropdown.value",
304
+ "depth_range_slider.value",
305
+ "depth_2_checkbox.value",
306
+ "depth_3_checkbox.value",
307
+ "depth2_range_slider.value",
308
+ "depth3_range_slider.value",
309
+ "longitude_slider.value",
310
+ "latitude_slider.value",
311
+ "num_vectors_slider.value",
312
+ "scale_factor_slider.value",
313
+ "bathy_checkbox.value",
314
+ watch=True,
315
+ )
316
+ def update_plots(self):
317
+ self.ds_filtered = self.filter_data()
318
+ # vector_plot = self.vectors_plot()
319
+ other_plots = self.plots()
320
+
321
+ # self.plot_map = pn.pane.Matplotlib(vector_plot, width=800, height=600, sizing_mode="fixed")
322
+ self.plot = pn.Column(
323
+ *(pn.pane.HoloViews(plot, width=400, height=200) for plot in other_plots),
324
+ sizing_mode="stretch_width"
325
+ )
326
+ vector_plot = self.vectors_plot() # Update vector plot
327
+ self.plot_map.object = vector_plot
328
+ # other_plots = self.plots() # Update other plots
329
+ # self.plot.objects = [*(pn.pane.HoloViews(p, width=400, height=200) for p in other_plots)]
330
+ # self.plot.object=plot
331
+
332
+ return pn.Row(self.plot_map, self.plot, sizing_mode="stretch_both")
333
+
334
+ def filter_data(self):
335
+ return self.ds.where(
336
+ (self.ds.LONGITUDE >= self.longitude_slider.start)
337
+ & (self.ds.LONGITUDE <= self.longitude_slider.end)
338
+ & (self.ds.LATITUDE >= self.latitude_slider.start)
339
+ & (self.ds.LATITUDE <= self.latitude_slider.end),
340
+ drop=True,
341
+ )
342
+
343
+ def vectors_plot(self):
344
+ import hvplot.xarray
345
+
346
+ self.ds_filtered = self.filter_data()
347
+ # 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))
348
+
349
+ fig, ax = plt.subplots(
350
+ figsize=(8, 7), subplot_kw={"projection": ccrs.Mercator()}
351
+ )
352
+ coords = ["LATITUDE", "LONGITUDE"]
353
+ corsen = max(1, self.ds_filtered.MAXT.size // self.num_vectors_slider.value)
354
+ self.ds_filtered = (
355
+ self.ds_filtered.reset_coords(coords)
356
+ .coarsen({"MAXT": corsen}, boundary="trim")
357
+ .mean()
358
+ .set_coords(coords)
359
+ )
360
+ # self.ds_filtered =self.ds_filtered.coarsen(MAXT = corsen, side = "center", boundary = "trim").mean()[["LONGITUDE", "LONGITUDE", "TIME"]].isel(MAXZ=0)
361
+ depth_filtered = self.ds_filtered.where(
362
+ (self.depth1 > self.depth_range_slider.value[0])
363
+ & (self.depth1 <= self.depth_range_slider.value[1])
364
+ )
365
+
366
+ lon = self.ds_filtered.coords["LONGITUDE"].values
367
+ lat = self.ds_filtered.coords["LATITUDE"].values
368
+ # skip = max(1, int(np.sqrt(lon.size) / self.num_vectors_slider.value))
369
+ # skip = (slice(None, None, skip), slice(None, None, skip))
370
 
371
+ # Moyenne des vecteurs de courant sur la plage de profondeur sélectionnée
372
+ u_mean = depth_filtered.UCUR.mean(dim="MAXZ", skipna=True)
373
+ v_mean = depth_filtered.VCUR.mean(dim="MAXZ", skipna=True)
374
+ ax.quiver(
375
+ lon,
376
+ lat,
377
+ u_mean * self.scale_factor_slider.value,
378
+ v_mean * self.scale_factor_slider.value,
379
+ color="blue",
380
+ scale=2,
381
+ width=0.001,
382
+ headwidth=3,
383
+ transform=ccrs.PlateCarree(),
384
+ )
385
+
386
+ if self.depth_2_checkbox.value:
387
+ depth_filtered = self.ds_filtered.where(
388
+ (self.depth1 > self.depth2_range_slider.value[0])
389
+ & (self.depth1 <= self.depth2_range_slider.value[1])
390
+ )
391
+ u_mean = depth_filtered.UCUR.mean(dim="MAXZ", skipna=True)
392
+ v_mean = depth_filtered.VCUR.mean(dim="MAXZ", skipna=True)
393
+ ax.quiver(
394
+ lon,
395
+ lat,
396
+ u_mean * self.scale_factor_slider.value,
397
+ v_mean * self.scale_factor_slider.value,
398
+ color="green",
399
+ scale=2,
400
+ width=0.001,
401
+ headwidth=3,
402
+ transform=ccrs.PlateCarree(),
403
+ )
404
+
405
+ if self.depth_3_checkbox.value:
406
+ depth_filtered = self.ds_filtered.where(
407
+ (self.depth1 > self.depth3_range_slider.value[0])
408
+ & (self.depth1 <= self.depth3_range_slider.value[1])
409
+ )
410
+ u_mean = depth_filtered.UCUR.mean(dim="MAXZ", skipna=True)
411
+ v_mean = depth_filtered.VCUR.mean(dim="MAXZ", skipna=True)
412
+ ax.quiver(
413
+ lon,
414
+ lat,
415
+ u_mean * self.scale_factor_slider.value,
416
+ v_mean * self.scale_factor_slider.value,
417
+ color="red",
418
+ scale=2,
419
+ width=0.001,
420
+ headwidth=3,
421
+ transform=ccrs.PlateCarree(),
422
+ )
423
+
424
+ ax.add_feature(cfeature.COASTLINE)
425
+ ax.add_feature(cfeature.BORDERS, linestyle=":")
426
+ ax.add_feature(cfeature.LAND, color="lightgray")
427
+
428
+ if self.bathy_checkbox.value:
429
+ contour_levels = [-2000]
430
+ ax.contour(
431
+ bathy.longitude,
432
+ bathy.latitude,
433
+ bathy.z,
434
+ levels=contour_levels,
435
+ colors="black",
436
+ transform=ccrs.PlateCarree(),
437
+ )
438
+
439
+ ax.set_extent(
440
+ [
441
+ self.longitude_slider.value[0],
442
+ self.longitude_slider.value[1],
443
+ self.latitude_slider.value[0],
444
+ self.latitude_slider.value[1],
445
+ ]
446
+ )
447
+ ax.gridlines(draw_labels=True)
448
+ plt.ylabel("Latitude", fontsize=15, labelpad=35)
449
+ plt.xlabel("Longitude", fontsize=15, labelpad=20)
450
+ return fig
451
+
452
+ # pn.pane.Matplotlib(fig,width=800, height=600, sizing_mode="fixed", name="Plot")
453
+
454
+ # @param.depends( 'file_dropdown.value', 'longitude_slider.value', 'latitude_slider.value', watch=True)
455
+ def plots(self):
456
+ return [
457
+ self.ds_filtered["BATHY"].hvplot(x="TIME", width=400, height=200),
458
+ self.ds_filtered["USHIP"].hvplot(x="TIME", width=400, height=200),
459
+ self.ds_filtered["VSHIP"].hvplot(x="TIME", width=400, height=200),
460
+ self.ds_filtered["BOTTOM_DEPTH"].hvplot(x="TIME", width=400, height=200),
461
+ ]
462
+
463
+ def get_file_list(self):
464
+ return self.file_names
465
+
466
+
467
+
468
+
469
+ # Instantiate the SADCP_Viewer class and create a template
470
+ explorer = SADCP_Viewer()
471
+ tabs = pn.Tabs(
472
+ ("Plots", pn.Column(explorer.update_plots)),
473
+ (
474
+ "Metadata",
475
+ pn.Column(
476
+ explorer.metadata_table, explorer.download_button, height=500, margin=10
477
+ ),
478
+ ),
479
  )
480
 
481
+ sidebar = [
482
+ """This application, developed in the frame of Euro Go Shop, helps to interactively visualise and download ship ADCP data.""",
483
+ explorer.year_slider,
484
+ explorer.file_dropdown,
485
+ explorer.longitude_slider,
486
+ explorer.latitude_slider,
487
+ explorer.bathy_checkbox,
488
+ explorer.depth_range_slider,
489
+ explorer.depth_2_checkbox,
490
+ explorer.depth_3_checkbox,
491
+ explorer.depth2_range_slider,
492
+ explorer.depth3_range_slider,
493
+ explorer.num_vectors_slider,
494
+ explorer.scale_factor_slider,
495
+ explorer.data_table,
496
+ ]
497
+ template = pn.template.FastListTemplate(title="SADCP data Viewer", sidebar=sidebar,main=[tabs])
498
+ template.servable()
499
+