pyadps 0.2.0b0__py3-none-any.whl → 0.3.0b0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,575 +0,0 @@
1
- import numpy as np
2
- # import pandas as pd
3
- # import plotly.express as px
4
- import plotly.graph_objects as go
5
- import streamlit as st
6
- from plotly.subplots import make_subplots
7
- from plotly_resampler import FigureResampler
8
- from utils.profile_test import side_lobe_beam_angle, manual_cut_bins
9
- from utils.regrid import regrid2d, regrid3d
10
- from utils.signal_quality import default_mask
11
-
12
- if "flead" not in st.session_state:
13
- st.write(":red[Please Select Data!]")
14
- st.stop()
15
-
16
- # `maskp` holds the temporary changes in the page
17
- # `profile_mask`
18
- if "maskp" not in st.session_state:
19
- if "qc_mask" not in st.session_state:
20
- st.session_state.maskp = np.copy(st.session_state.orig_mask)
21
- else:
22
- st.session_state.maskp = np.copy(st.session_state.qc_mask)
23
-
24
-
25
- if st.session_state.isQCMask:
26
- st.write(":grey[Working on a saved mask file ...]")
27
- if st.session_state.isProfileMask:
28
- st.write(
29
- ":orange[Warning: Profile test already completed. Reset to change settings.]"
30
- )
31
- reset_selectbox = st.selectbox(
32
- "Choose reset option",
33
- ("QC Test", "Default"),
34
- index=None,
35
- placeholder="Reset mask to ...",
36
- )
37
- if reset_selectbox == "Default":
38
- st.write("Default mask file selected")
39
- st.session_state.maskp = st.session_state.orig_mask
40
- elif reset_selectbox == "QC Test":
41
- st.write("QC Test mask file selected")
42
- st.session_state.maskp = st.session_state.qc_mask
43
- else:
44
- st.session_state.maskp = st.session_state.profile_mask
45
- else:
46
- st.session_state.maskp = st.session_state.qc_mask
47
- else:
48
- st.write(":orange[Creating a new mask file ...]")
49
-
50
- mask = st.session_state.maskp
51
-
52
- # Load data
53
- flobj = st.session_state.flead
54
- vlobj = st.session_state.vlead
55
- velocity = st.session_state.velocity
56
- echo = st.session_state.echo
57
- correlation = st.session_state.correlation
58
- pgood = st.session_state.pgood
59
- fdata = flobj.fleader
60
- vdata = vlobj.vleader
61
-
62
-
63
- ensembles = st.session_state.head.ensembles
64
- cells = flobj.field()["Cells"]
65
- x = np.arange(0, ensembles, 1)
66
- y = np.arange(0, cells, 1)
67
-
68
- # Regrided data
69
- if "velocity_regrid" not in st.session_state:
70
- st.session_state.echo_regrid = np.copy(echo)
71
- st.session_state.velocity_regrid = np.copy(velocity)
72
- st.session_state.correlation_regrid = np.copy(correlation)
73
- st.session_state.pgood_regrid = np.copy(pgood)
74
- st.session_state.mask_regrid = np.copy(mask)
75
-
76
-
77
- # @st.cache_data
78
- def fillplot_plotly(
79
- data, title="data", maskdata=None, missing=-32768, colorscale="balance"
80
- ):
81
- fig = FigureResampler(go.Figure())
82
- data = np.int32(data)
83
- data1 = np.where(data == missing, np.nan, data)
84
- fig.add_trace(
85
- go.Heatmap(
86
- z=data1,
87
- x=x,
88
- y=y,
89
- colorscale=colorscale,
90
- hoverongaps=False,
91
- )
92
- )
93
- if mask is not None:
94
- fig.add_trace(
95
- go.Heatmap(
96
- z=maskdata,
97
- x=x,
98
- y=y,
99
- colorscale="gray",
100
- hoverongaps=False,
101
- showscale=False,
102
- opacity=0.7,
103
- )
104
- )
105
- fig.update_layout(
106
- xaxis=dict(showline=True, mirror=True),
107
- yaxis=dict(showline=True, mirror=True),
108
- title_text=title,
109
- )
110
- fig.update_xaxes(title="Ensembles")
111
- fig.update_yaxes(title="Depth Cells")
112
- st.plotly_chart(fig)
113
-
114
-
115
- def fillselect_plotly(data, title="data", colorscale="balance"):
116
- fig = FigureResampler(go.Figure())
117
- data = np.int32(data)
118
- data1 = np.where(data == -32768, None, data)
119
- fig.add_trace(
120
- go.Heatmap(
121
- z=data1,
122
- x=x,
123
- y=y,
124
- colorscale=colorscale,
125
- hoverongaps=False,
126
- )
127
- )
128
- # fig.add_trace(
129
- # go.Scatter(x=X, y=Y, marker=dict(color="black", size=16), mode="lines+markers")
130
- # )
131
- fig.update_layout(
132
- xaxis=dict(showline=True, mirror=True),
133
- yaxis=dict(showline=True, mirror=True),
134
- title_text=title,
135
- )
136
- fig.update_xaxes(title="Ensembles")
137
- fig.update_yaxes(title="Depth Cells")
138
- fig.update_layout(clickmode="event+select")
139
- event = st.plotly_chart(fig, key="1", on_select="rerun", selection_mode="box")
140
-
141
- return event
142
-
143
-
144
- @st.cache_data
145
- def trim_ends(start_ens=0, end_ens=0, ens_range=20):
146
- depth = vdata["Depth of Transducer"] / 10
147
- fig = make_subplots(
148
- rows=1,
149
- cols=2,
150
- subplot_titles=[
151
- "Deployment Ensemble",
152
- "Recovery Ensemble",
153
- ],
154
- )
155
- fig.add_trace(
156
- go.Scatter(
157
- x=x[0:ens_range],
158
- y=depth[0:ens_range],
159
- name="Deployment",
160
- mode="markers",
161
- marker=dict(color="#1f77b4"),
162
- ),
163
- row=1,
164
- col=1,
165
- )
166
-
167
- fig.add_trace(
168
- go.Scatter(
169
- x=x[-1 * ens_range :],
170
- y=depth[-1 * ens_range :],
171
- name="Recovery",
172
- mode="markers",
173
- marker=dict(color="#17becf"),
174
- ),
175
- row=1,
176
- col=2,
177
- )
178
-
179
- if start_ens > x[0]:
180
- fig.add_trace(
181
- go.Scatter(
182
- x=x[0:start_ens],
183
- y=depth[0:start_ens],
184
- name="Selected Points (D)",
185
- mode="markers",
186
- marker=dict(color="red"),
187
- ),
188
- row=1,
189
- col=1,
190
- )
191
-
192
- if end_ens < x[-1] + 1:
193
- fig.add_trace(
194
- go.Scatter(
195
- x=x[end_ens : x[-1] + 1],
196
- y=depth[end_ens : x[-1] + 1],
197
- name="Selected Points (R)",
198
- mode="markers",
199
- marker=dict(color="orange"),
200
- ),
201
- row=1,
202
- col=2,
203
- )
204
-
205
- fig.update_layout(height=600, width=800, title_text="Transducer depth")
206
- fig.update_xaxes(title="Ensembles")
207
- fig.update_yaxes(title="Depth (m)")
208
- st.plotly_chart(fig)
209
-
210
-
211
- st.header("Profile Test")
212
-
213
- ############## TRIM ENDS #################
214
- st.header("Trim Ends", divider="blue")
215
- n = 20
216
- m = 20
217
- if "update_mask" not in st.session_state:
218
- st.session_state.update_mask = False
219
- st.session_state.endpoints = None
220
- st.session_state.isTrimEnds = False
221
- if "update_mask_cutbin" not in st.session_state:
222
- st.session_state.update_mask_cutbin = False
223
- st.session_state.isCutBins = False
224
-
225
- ens_range = st.number_input("Change range", x[0], x[-1], 20)
226
- start_ens = st.slider("Deployment Ensembles", 0, ens_range, 0)
227
- end_ens = st.slider("Recovery Ensembles", x[-1] - ens_range, x[-1] + 1, x[-1] + 1)
228
-
229
- n = int(ens_range)
230
-
231
- if start_ens or end_ens:
232
- trim_ends(start_ens=start_ens, end_ens=end_ens, ens_range=n)
233
- # st.session_state.update_mask = False
234
-
235
- update_mask = st.button("Update mask data")
236
- if update_mask:
237
- if start_ens > 0:
238
- mask[:, :start_ens] = 1
239
-
240
- if end_ens < x[-1]:
241
- mask[:, end_ens:] = 1
242
-
243
- st.session_state.ens_range = ens_range
244
- st.session_state.start_ens = start_ens
245
- st.session_state.end_ens = end_ens
246
- st.session_state.maskp = mask
247
- st.write(":green[mask data updated]")
248
- st.session_state.endpoints = np.array(
249
- [st.session_state.start_ens, st.session_state.end_ens]
250
- )
251
- st.write(st.session_state.endpoints)
252
- st.session_state.update_mask = True
253
- st.session_state.isTrimEnds = True
254
-
255
- if not st.session_state.update_mask:
256
- st.write(":red[mask data not updated]")
257
-
258
-
259
- ############ CUT BINS (SIDE LOBE) ############################
260
- st.header("Cut Bins: Side Lobe Contamination", divider="blue")
261
- st.write(
262
- """
263
- The side lobe echos from hard surface such as sea surface or bottom of the ocean can contaminate
264
- data closer to this region. The data closer to the surface or bottom can be removed using
265
- the relation between beam angle and the thickness of the contaminated layer.
266
- """
267
- )
268
-
269
- # Reset mask
270
- mask = st.session_state.maskp
271
- beam = st.radio("Select beam", (1, 2, 3, 4), horizontal=True)
272
- beam = beam - 1
273
- st.session_state.beam = beam
274
- fillplot_plotly(echo[beam, :, :], title="Echo Intensity")
275
-
276
- orientation = st.session_state.beam_direction
277
- st.write(f"The orientation is `{orientation}`.")
278
- water_column_depth = 0
279
- with st.form(key="cutbin_form"):
280
- extra_cells = st.number_input("Additional Cells to Delete", 0, 10, 0)
281
- if orientation.lower() == 'down':
282
- water_column_depth = st.number_input("Enter water column depth (m): ", 0, 15000, 0)
283
-
284
- cut_bins_mask = st.form_submit_button(label="Cut bins")
285
-
286
- if cut_bins_mask:
287
- st.session_state.extra_cells = extra_cells
288
- mask = side_lobe_beam_angle(flobj, vlobj, mask,
289
- orientation=orientation,
290
- water_column_depth=water_column_depth,
291
- extra_cells=extra_cells)
292
- fillplot_plotly(
293
- echo[beam, :, :],
294
- title="Echo Intensity (Masked)",
295
- maskdata=mask,
296
- )
297
- fillplot_plotly(mask, colorscale="greys", title="Mask Data")
298
-
299
- update_mask_cutbin = st.button("Update mask file after cutbin")
300
- if update_mask_cutbin:
301
- st.session_state.maskp = mask
302
- st.write(":green[mask file updated]")
303
- st.session_state.update_mask_cutbin = True
304
- st.session_state.isCutBins = True
305
-
306
- if not st.session_state.update_mask_cutbin:
307
- st.write(":red[mask file not updated]")
308
-
309
-
310
- ########### CUT BINS: Manual #################
311
- st.header("Cut Bins: Manual", divider="blue")
312
- # Reset mask
313
- # Selection of variable (Velocity, Echo Intensity, etc.)
314
- variable = st.selectbox(
315
- "Select Variable to Display",
316
- ("Velocity", "Echo Intensity", "Correlation", "Percentage Good")
317
- )
318
-
319
- # Map variable selection to corresponding data
320
- data_dict = {
321
- "Velocity": velocity,
322
- "Echo Intensity": echo,
323
- "Correlation": correlation,
324
- "Percentage Good": pgood,
325
- }
326
-
327
- # User selects beam (1-4)
328
- beam = st.radio("Select beam", (1, 2, 3, 4), horizontal=True, key="beam_selection")
329
- beam_index = beam - 1
330
-
331
- # Display the selected variable and beam
332
- selected_data = data_dict[variable][beam_index, :, :]
333
- fillplot_plotly(selected_data, title=f"{variable}")
334
-
335
-
336
- st.subheader("Mask Selected Regions")
337
- with st.form(key="manual_cutbin_form"):
338
- st.write("Select the specific range of cells and ensembles to delete")
339
-
340
- # Input for selecting minimum and maximum cells
341
- min_cell = st.number_input("Min Cell", 0, int(flobj.field()["Cells"]), 0)
342
- max_cell = st.number_input("Max Cell", 0, int(flobj.field()["Cells"]), 10)
343
-
344
- # Input for selecting minimum and maximum ensembles
345
- min_ensemble = st.number_input("Min Ensemble", 0, int(flobj.ensembles), 0)
346
- max_ensemble = st.number_input("Max Ensemble", 0, int(flobj.ensembles), int(flobj.ensembles))
347
-
348
- # Submit button to apply the mask
349
- cut_bins_mask_manual = st.form_submit_button(label="Apply Manual Cut Bins")
350
-
351
- if cut_bins_mask_manual:
352
- mask = manual_cut_bins(mask, min_cell, max_cell, min_ensemble, max_ensemble)
353
- st.session_state.maskp = mask
354
- fillplot_plotly(
355
- echo[beam, :, :],
356
- title="Echo Intensity (Masked Manually)",
357
- maskdata=mask,
358
- )
359
- fillplot_plotly(mask, colorscale="greys", title="Mask Data")
360
-
361
- # Adding the new feature: Delete Single Cell or Ensemble
362
- st.subheader("Delete Specific Cell or Ensemble")
363
-
364
- # Step 1: User chooses between deleting a cell or an ensemble
365
- delete_option = st.radio("Select option to delete", ("Cell", "Ensemble"), horizontal=True)
366
-
367
- # Step 2: Display options based on user's choice
368
- if delete_option == "Cell":
369
- # Option to delete a specific cell across all ensembles
370
- with st.form(key="delete_cell_form"):
371
- st.write("Select a specific cell to delete across all ensembles")
372
-
373
- # Input for selecting a single cell
374
- cell = st.number_input("Cell", 0, int(flobj.field()["Cells"]), 0, key="single_cell")
375
-
376
- # Submit button to apply the mask for cell deletion
377
- delete_cell = st.form_submit_button(label="Delete Cell")
378
-
379
- if delete_cell:
380
- mask[cell, :] = 1 # Mask the entire row for the selected cell
381
- st.session_state.maskp = mask
382
- fillplot_plotly(
383
- echo[beam, :, :],
384
- title=f"Echo Intensity (Cell {cell} Deleted Across Ensembles)",
385
- maskdata=mask,
386
- )
387
- fillplot_plotly(mask, colorscale="greys", title="Mask Data")
388
-
389
- elif delete_option == "Ensemble":
390
- # Option to delete a specific ensemble across all cells
391
- with st.form(key="delete_ensemble_form"):
392
- st.write("Select a specific ensemble to delete across all cells")
393
-
394
- # Input for selecting a specific ensemble
395
- ensemble = st.number_input("Ensemble", 0, int(flobj.ensembles), 0, key="single_ensemble")
396
-
397
- # Submit button to apply the mask for ensemble deletion
398
- delete_ensemble = st.form_submit_button(label="Delete Ensemble")
399
-
400
- if delete_ensemble:
401
- mask[:, ensemble-1] = 1 # Mask the entire column for the selected ensemble
402
- st.session_state.maskp = mask
403
- fillplot_plotly(
404
- echo[beam, :, :],
405
- title=f"Echo Intensity (Ensemble {ensemble} Deleted Across Cells)",
406
- maskdata=mask,
407
- )
408
- fillplot_plotly(mask, colorscale="greys", title="Mask Data")
409
-
410
-
411
- # Layout with two columns
412
- col1, col2 = st.columns([2, 1])
413
-
414
- with col1:
415
-
416
- # Button to save mask data after manual cut bins, with unique key
417
- update_mask_cutbin = st.button("Update mask file after cutbin Manual", key="update_cutbin_button")
418
- if update_mask_cutbin:
419
- st.session_state.maskp = mask
420
- st.write(":green[mask file updated]")
421
- st.session_state.update_mask_cutbin = True
422
- st.session_state.isCutBins = True
423
-
424
- if not st.session_state.update_mask_cutbin:
425
- st.write(":red[mask file not updated]")
426
-
427
- with col2:
428
- # Button to reset the mask data, with unique key
429
- reset_mask_button = st.button("Reset mask data", key="reset_mask_button")
430
- if reset_mask_button:
431
- st.session_state.maskp = np.copy(st.session_state.orig_mask)
432
- st.write(":green[Mask data is reset to default]")
433
- st.session_state.isQCMask = False
434
- st.session_state.isProfileMask = False
435
- st.session_state.isGrid = False
436
- st.session_state.isGridSave = False
437
- st.session_state.isVelocityMask = False
438
-
439
- ############ REGRID ###########################################
440
- st.header("Regrid Depth Cells", divider="blue")
441
-
442
- st.write(
443
- """
444
- When the ADCP buoy has vertical oscillations (greater than depth cell size),
445
- the depth bins has to be regridded based on the pressure sensor data. The data
446
- can be regrided either till the surface or till the last bin.
447
- If the `Cell` option is selected, ensure that the end data are trimmed.
448
- Manual option permits choosing the end cell depth.
449
- """
450
- )
451
-
452
- if st.session_state.beam_direction.lower() == "up":
453
- end_bin_option = st.radio(
454
- "Select the depth of last bin for regridding", ("Cell", "Surface", "Manual"), horizontal=True
455
- )
456
- else:
457
- end_bin_option = st.radio(
458
- "Select the depth of last bin for regridding", ("Cell", "Manual"), horizontal=True
459
- )
460
-
461
- st.session_state.end_bin_option = end_bin_option
462
- st.write(f"You have selected: `{end_bin_option}`")
463
-
464
- if end_bin_option == "Manual":
465
- mean_depth = np.mean(st.session_state.vlead.vleader["Depth of Transducer"]) / 10
466
- mean_depth = round(mean_depth, 2)
467
-
468
- st.write(f"The transducer depth is {mean_depth} m. The value should not exceed the transducer depth")
469
- if st.session_state.beam_direction.lower() == "up":
470
- boundary = st.number_input("Enter the depth (m):", max_value=int(mean_depth), min_value=0)
471
- else:
472
- boundary = st.number_input("Enter the depth (m):", min_value=int(mean_depth))
473
- else:
474
- boundary = 0
475
-
476
- interpolate = st.radio("Choose interpolation method:", ("nearest", "linear", "cubic"))
477
-
478
- regrid_button = st.button(label="Regrid Data")
479
-
480
- if regrid_button:
481
- st.write(st.session_state.endpoints)
482
- z, st.session_state.velocity_regrid = regrid3d(
483
- flobj, vlobj, velocity, -32768,
484
- trimends=st.session_state.endpoints,
485
- end_bin_option=st.session_state.end_bin_option,
486
- orientation=st.session_state.beam_direction,
487
- method=interpolate,
488
- boundary_limit=boundary
489
- )
490
- st.write(":grey[Regrided velocity ...]")
491
- z, st.session_state.echo_regrid = regrid3d(
492
- flobj, vlobj, echo, -32768,
493
- trimends=st.session_state.endpoints,
494
- end_bin_option=st.session_state.end_bin_option,
495
- orientation=st.session_state.beam_direction,
496
- method=interpolate,
497
- boundary_limit=boundary
498
- )
499
- st.write(":grey[Regrided echo intensity ...]")
500
- z, st.session_state.correlation_regrid = regrid3d(
501
- flobj, vlobj, correlation, -32768,
502
- trimends=st.session_state.endpoints,
503
- end_bin_option=st.session_state.end_bin_option,
504
- orientation=st.session_state.beam_direction,
505
- method=interpolate,
506
- boundary_limit=boundary
507
- )
508
- st.write(":grey[Regrided correlation...]")
509
- z, st.session_state.pgood_regrid = regrid3d(
510
- flobj, vlobj, pgood, -32768,
511
- trimends=st.session_state.endpoints,
512
- end_bin_option=st.session_state.end_bin_option,
513
- orientation=st.session_state.beam_direction,
514
- method=interpolate,
515
- boundary_limit=boundary
516
- )
517
- st.write(":grey[Regrided percent good...]")
518
- z, st.session_state.mask_regrid = regrid2d(
519
- flobj, vlobj, mask, 1,
520
- trimends=st.session_state.endpoints,
521
- end_bin_option=st.session_state.end_bin_option,
522
- orientation=st.session_state.beam_direction,
523
- method="nearest",
524
- boundary_limit=boundary
525
- )
526
-
527
- st.session_state.depth = z
528
-
529
- st.write(":grey[Regrided mask...]")
530
- st.write(":green[All data regrided!]")
531
-
532
- st.write("No. of grid depth bins before regridding: ", np.shape(velocity)[1])
533
- st.write(
534
- "No. of grid depth bins after regridding: ",
535
- np.shape(st.session_state.velocity_regrid)[1],
536
- )
537
- fillplot_plotly(
538
- st.session_state.velocity_regrid[0, :, :], title="Regridded Velocity File"
539
- )
540
- fillplot_plotly(velocity[0, :, :], title="Original File")
541
- fillplot_plotly(
542
- st.session_state.mask_regrid, colorscale="greys", title="Regridded Mask File"
543
- )
544
-
545
- st.session_state.isGrid = True
546
- st.session_state.isGridSave = False
547
-
548
-
549
- ########### Save and Reset Mask ##############
550
- st.header("Save & Reset Mask Data", divider="blue")
551
-
552
- col1, col2 = st.columns([1, 1])
553
- with col1:
554
- save_mask_button = st.button(label="Save Mask Data")
555
- if save_mask_button:
556
- if st.session_state.isGrid:
557
- st.session_state.profile_mask = st.session_state.mask_regrid
558
- st.session_state.isGridSave = True
559
- else:
560
- st.session_state.profile_mask = st.session_state.maskp
561
- st.session_state.isProfileMask = True
562
- st.session_state.isVelocityMask = False
563
- st.write(":green[Mask data saved]")
564
- else:
565
- st.write(":red[Mask data not saved]")
566
- with col2:
567
- reset_mask_button = st.button("Reset mask data")
568
- if reset_mask_button:
569
- st.session_state.maskp = np.copy(st.session_state.orig_mask)
570
- st.write(":green[Mask data is reset to default]")
571
- st.session_state.isQCMask = False
572
- st.session_state.isProfileMask = False
573
- st.session_state.isGrid = False
574
- st.session_state.isGridSave = False
575
- st.session_state.isVelocityMask = False