tinaok commited on
Commit
e58cf31
1 Parent(s): 4d1a958

Delete app.py

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