pyadps 0.2.1b0__py3-none-any.whl → 0.3.0__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.
Files changed (39) hide show
  1. pyadps/Home_Page.py +11 -5
  2. pyadps/pages/01_Read_File.py +623 -215
  3. pyadps/pages/02_View_Raw_Data.py +97 -41
  4. pyadps/pages/03_Download_Raw_File.py +200 -67
  5. pyadps/pages/04_Sensor_Health.py +905 -0
  6. pyadps/pages/05_QC_Test.py +493 -0
  7. pyadps/pages/06_Profile_Test.py +971 -0
  8. pyadps/pages/07_Velocity_Test.py +600 -0
  9. pyadps/pages/08_Write_File.py +623 -0
  10. pyadps/pages/09_Add-Ons.py +168 -0
  11. pyadps/utils/__init__.py +5 -3
  12. pyadps/utils/autoprocess.py +371 -80
  13. pyadps/utils/logging_utils.py +269 -0
  14. pyadps/utils/metadata/config.ini +22 -4
  15. pyadps/utils/metadata/demo.000 +0 -0
  16. pyadps/utils/metadata/flmeta.json +420 -420
  17. pyadps/utils/metadata/vlmeta.json +611 -565
  18. pyadps/utils/multifile.py +292 -0
  19. pyadps/utils/plotgen.py +505 -3
  20. pyadps/utils/profile_test.py +720 -125
  21. pyadps/utils/pyreadrdi.py +164 -92
  22. pyadps/utils/readrdi.py +436 -186
  23. pyadps/utils/script.py +197 -147
  24. pyadps/utils/sensor_health.py +120 -0
  25. pyadps/utils/signal_quality.py +472 -68
  26. pyadps/utils/velocity_test.py +79 -31
  27. pyadps/utils/writenc.py +222 -39
  28. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/METADATA +13 -14
  29. pyadps-0.3.0.dist-info/RECORD +35 -0
  30. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/WHEEL +1 -1
  31. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/entry_points.txt +1 -0
  32. pyadps/pages/04_QC_Test.py +0 -334
  33. pyadps/pages/05_Profile_Test.py +0 -575
  34. pyadps/pages/06_Velocity_Test.py +0 -341
  35. pyadps/pages/07_Write_File.py +0 -452
  36. pyadps/utils/cutbin.py +0 -413
  37. pyadps/utils/regrid.py +0 -279
  38. pyadps-0.2.1b0.dist-info/RECORD +0 -31
  39. {pyadps-0.2.1b0.dist-info → pyadps-0.3.0.dist-info}/LICENSE +0 -0
@@ -0,0 +1,600 @@
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 streamlit.runtime.state import session_state
9
+ from utils.profile_test import side_lobe_beam_angle
10
+ from utils.signal_quality import default_mask
11
+ from utils.velocity_test import (
12
+ despike,
13
+ flatline, # magnetic_declination,
14
+ magdec,
15
+ velocity_cutoff,
16
+ wmm2020api,
17
+ velocity_modifier,
18
+ )
19
+
20
+ if "flead" not in st.session_state:
21
+ st.write(":red[Please Select Data!]")
22
+ st.stop()
23
+
24
+ flobj = st.session_state.flead
25
+ vlobj = st.session_state.vlead
26
+ fdata = flobj.fleader
27
+ vdata = vlobj.vleader
28
+
29
+
30
+ def reset_velocitytest():
31
+ # Reset Global Test
32
+ st.session_state.isVelocityTest = False
33
+
34
+ # Reset Local Tests
35
+ st.session_state.isMagnetCheck_VT = False
36
+ st.session_state.isDespikeCheck_VT = False
37
+ st.session_state.isFlatlineCheck = False
38
+ st.session_state.isCutoffCheck_VT = False
39
+
40
+ st.session_state.isVelocityModifiedMagnet = False
41
+
42
+ # Page return
43
+ st.session_state.isProfilePageReturn = False
44
+ if not st.session_state.isProfileTest:
45
+ st.session_state.isQCPageReturn = False
46
+ if not st.session_state.isQCTest:
47
+ st.session_state.isSensorPageReturn = False
48
+
49
+ # Data Reset
50
+ if st.session_state.isRegridCheck_PT:
51
+ st.session_state.velocity_magnet = st.session_state.velocity_regrid
52
+ elif st.session_state.isVelocityModifiedSound_ST:
53
+ st.session_state.velocity_magnet = st.session_state.velocity_sensor
54
+ else:
55
+ st.session_state.velocity_magnet = st.session_state.velocity
56
+
57
+ # Reset Mask
58
+ if st.session_state.isProfileTest:
59
+ if st.session_state.isRegridCheck_PT:
60
+ st.session_state.velocity_mask_default = np.copy(
61
+ st.session_state.profile_mask_regrid
62
+ )
63
+ else:
64
+ st.session_state.velocity_mask_default = np.copy(
65
+ st.session_state.profile_mask
66
+ )
67
+ elif st.session_state.isQCTest:
68
+ st.session_state.velocity_mask_default = np.copy(st.session_state.qc_mask)
69
+ elif st.session_state.isSensorTest:
70
+ st.session_state.velocity_mask_default = np.copy(st.session_state.sensor_mask)
71
+ else:
72
+ st.session_state.velocity_mask_default = np.copy(st.session_state.orig_mask)
73
+
74
+ mask = st.session_state.velocity_mask_default
75
+ st.session_state.velocity_mask_temp = np.copy(mask)
76
+ st.session_state.velocity_mask = np.copy(mask)
77
+ st.session_state.velocity_mask_cutoff = np.copy(mask)
78
+ st.session_state.velocity_mask_spike = np.copy(mask)
79
+ st.session_state.velocity_mask_flatline = np.copy(mask)
80
+
81
+
82
+ def hard_reset(option):
83
+ # Reset Global Test
84
+ st.session_state.isVelocityTest = False
85
+
86
+ # Reset Local Tests
87
+ st.session_state.isMagnetCheck_VT = False
88
+ st.session_state.isDespikeCheck_VT = False
89
+ st.session_state.isFlatlineCheck = False
90
+ st.session_state.isCutoffCheck_VT = False
91
+
92
+ # Page return
93
+ st.session_state.isProfilePageReturn = False
94
+ if not st.session_state.isProfileTest:
95
+ st.session_state.isQCPageReturn = False
96
+ if not st.session_state.isQCTest:
97
+ st.session_state.isSensorPageReturn = False
98
+
99
+ # Velocity data reset
100
+ st.session_state.velocity_magnet = st.session_state.velocity
101
+
102
+ if option == "Sensor Test":
103
+ st.session_state.velocity_mask_default = np.copy(st.session_state.sensor_mask)
104
+ if st.session_state.isVelocityModifiedSound_ST:
105
+ st.session_state.velocity_magnet = st.session_state.velocity_sensor
106
+ elif option == "QC Test":
107
+ st.session_state.velocity_mask_default = np.copy(st.session_state.qc_mask)
108
+ elif option == "Profile Test":
109
+ st.session_state.velocity_mask_default = np.copy(st.session_state.profile_mask)
110
+ if st.session_state.isRegridCheck_PT:
111
+ st.session_state.velocity_magnet = st.session_state.velocity_regrid
112
+ else:
113
+ st.session_state.velocity_mask_default = np.copy(st.session_state.orig_mask)
114
+
115
+ st.session_state.velocity_mask = np.copy(st.session_state.velocity_mask_default)
116
+ st.session_state.velocity_mask_temp = np.copy(
117
+ st.session_state.velocity_mask_default
118
+ )
119
+ st.session_state.velocity_mask_cutoff = np.copy(
120
+ st.session_state.velocity_mask_default
121
+ )
122
+ st.session_state.velocity_mask_spike = np.copy(
123
+ st.session_state.velocity_mask_default
124
+ )
125
+ st.session_state.velocity_mask_flatline = np.copy(
126
+ st.session_state.velocity_mask_default
127
+ )
128
+
129
+
130
+ ####### Initialize Mask File ##############
131
+ if (
132
+ st.session_state.isProfileTest
133
+ or st.session_state.isQCTest
134
+ or st.session_state.isSensorTest
135
+ ):
136
+ st.write(":grey[Working on a saved mask file ...]")
137
+ if st.session_state.isVelocityPageReturn:
138
+ st.write(
139
+ ":orange[Warning: Velocity test already completed. Reset to change settings.]"
140
+ )
141
+ reset_selectbox = st.selectbox(
142
+ "Choose reset option",
143
+ ("Profile Test", "QC Test", "Sensor Test", "Default"),
144
+ index=None,
145
+ placeholder="Reset mask to ...",
146
+ )
147
+ if reset_selectbox == "Default":
148
+ st.write("Default mask file selected")
149
+ elif reset_selectbox == "Sensor Test":
150
+ st.write("Sensor Test mask file selected")
151
+ elif reset_selectbox == "QC Test":
152
+ st.write("QC Test mask file selected")
153
+ elif reset_selectbox == "Profile Test":
154
+ st.write("Profile Test mask file selected")
155
+
156
+ if reset_selectbox is not None:
157
+ hard_reset(reset_selectbox)
158
+
159
+ elif st.session_state.isFirstVelocityVisit:
160
+ reset_velocitytest()
161
+ st.session_state.isFirstVelocityVisit = False
162
+ else:
163
+ if st.session_state.isFirstVelocityVisit:
164
+ reset_velocitytest()
165
+ st.session_state.isFirstVelocityVisit = False
166
+ st.write(":grey[Creating a new mask file ...]")
167
+
168
+
169
+ # If data are not regrided use the default one
170
+ # if st.session_state.isGridSave:
171
+ # st.session_state.velocity_magnet = np.copy(st.session_state.velocity_regrid)
172
+ # else:
173
+ # st.session_state.velocity_magnet = np.copy(st.session_state.velocity)
174
+
175
+ velocity = st.session_state.velocity_magnet
176
+
177
+ ensembles = st.session_state.head.ensembles
178
+ cells = flobj.field()["Cells"]
179
+ x = np.arange(0, ensembles, 1)
180
+ y = np.arange(0, cells, 1)
181
+
182
+
183
+ ########### Introduction ##########
184
+ st.header("Velocity Test", divider="orange")
185
+
186
+ st.write(
187
+ """
188
+ The processing in this page apply only to the velocity data.
189
+ """
190
+ )
191
+ tab1, tab2, tab3, tab4, tab5 = st.tabs(
192
+ [
193
+ "Magnetic Declination",
194
+ "Velocity Cutoffs",
195
+ "Despike Data",
196
+ "Remove Flatline",
197
+ "Save & Reset Data",
198
+ ]
199
+ )
200
+
201
+ ############ Magnetic Declination ##############
202
+ # Commenting the wmm2020 c based model if needed can be implemented.
203
+
204
+ # * The magnetic declination is obtained from World Magnetic Model 2020 (WMM2020).
205
+ # The python wrapper module `wmm2020` is available from this [Link](https://github.com/space-physics/wmm2020).
206
+
207
+ with tab1:
208
+ st.header("Magnetic Declination", divider="blue")
209
+ st.write(
210
+ """
211
+ * The pygeomag method uses a python library [pygeomag](https://github.com/boxpet/pygeomag.git) for calculating the magnetic declination.
212
+ * It can work from 2010 till date.
213
+ * The API method utilizes the online magnetic declination service provided by the National Geophysical Data Center (NGDC)
214
+ of the National Oceanic and Atmospheric Administration (NOAA) to calculate the magnetic declination. The service is available at this [link](https://www.ngdc.noaa.gov/geomag/calculators/magcalc.shtml#declination).
215
+ Internet connection is necessary for this method to work.
216
+ * According to the year, different models are used for calculating magnetic declination.
217
+ * From 2025 till date, WMM2025 (World Magnetic Model)
218
+ * From 2019 to 2024 IGRF (International Geomagnetic Reference Field)
219
+ * From 2000 to 2018 EMM (Enhanced Magnetic Model)
220
+ * Before 1999 IGRF
221
+ * In the manual method, the user can directly enter the magnetic declination.
222
+ If the magnetic declination is reset, re-run the remaining tests again.
223
+ """
224
+ )
225
+
226
+ # Selecting the method to calculate magnetic declination.
227
+ # method = st.radio("Select a method", ("WMM2020", "API", "Manual"), horizontal=True)
228
+ method = st.radio("Select a method", ("pygeomag", "API", "Manual"), horizontal=True)
229
+ # method = method - 1
230
+ st.session_state.method = method
231
+
232
+ if "isMagnetButton" not in st.session_state:
233
+ st.session_state.isMagnetButton = False
234
+
235
+ # Track button clicks
236
+ if "isButtonClicked" not in st.session_state:
237
+ st.session_state.isButtonClicked = False
238
+
239
+ def toggle_btns():
240
+ st.session_state.isMagnetButton = not st.session_state.isMagnetButton
241
+ st.session_state.isButtonClicked = not st.session_state.isButtonClicked
242
+
243
+ with st.form(key="magnet_form"):
244
+ if st.session_state.method == "pygeomag":
245
+ # st.session_state.isMagnet = False
246
+ lat = st.number_input("Latitude", -90.0, 90.0, 0.0, step=1.0)
247
+ lon = st.number_input("Longitude", 0.0, 360.0, 0.1, step=1.0, format="%.4f")
248
+ depth = st.number_input("Depth", 0, 1000, 0, step=1)
249
+ year = st.number_input("Year", 2010, 2030, 2025, 1)
250
+
251
+ elif st.session_state.method == "API":
252
+ # st.session_state.isMagnet = False
253
+ lat = st.number_input("Latitude", -90.0, 90.0, 0.0, step=1.0)
254
+ lon = st.number_input("Longitude", 0.0, 360.0, 0.1, step=1.0, format="%.4f")
255
+ year = st.number_input("Year", 1950, 2030, 2025, 1)
256
+ else:
257
+ # st.session_state.isMagnet = False
258
+ mag = [[st.number_input("Declination", -180.0, 180.0, 0.0, 0.1)]]
259
+ st.session_state.magnet_user_input_VT = mag
260
+
261
+ if st.session_state.method == "Manual":
262
+ button_name = "Accept"
263
+ else:
264
+ button_name = "Compute"
265
+
266
+ if st.form_submit_button(
267
+ button_name, on_click=toggle_btns, disabled=st.session_state.isMagnetButton
268
+ ):
269
+ if st.session_state.method == "pygeomag":
270
+ mag = magdec(lat, lon, depth, year)
271
+ st.session_state.velocity_magnet = velocity_modifier(velocity, mag)
272
+ st.session_state.magnet_lat_VT = lat
273
+ st.session_state.magnet_lon_VT = lon
274
+ st.session_state.magnet_year_VT = year
275
+ st.session_state.magnet_depth_VT = depth
276
+ st.session_state.angle = np.round(mag[0][0], decimals=3)
277
+ st.session_state.isMagnetCheck_VT = True
278
+ st.session_state.isButtonClicked = True
279
+
280
+ if st.session_state.method == "API":
281
+ try:
282
+ mag = wmm2020api(lat, lon, year)
283
+ st.session_state.velocity_magnet = velocity_modifier(velocity, mag)
284
+ st.session_state.magnet_lat_VT = lat
285
+ st.session_state.magnet_lon_VT = lon
286
+ st.session_state.magnet_year_VT = year
287
+ # st.session_state.angle = np.trunc(mag[0][0])
288
+ st.session_state.angle = np.round(mag[0][0], decimals=3)
289
+ st.session_state.isMagnetCheck_VT = True
290
+ st.session_state.isButtonClicked = True
291
+ except:
292
+ st.write(
293
+ ":red[Connection error! please check the internet or use manual method]"
294
+ )
295
+ else:
296
+ st.session_state.velocity_magnet = velocity_modifier(velocity, mag)
297
+ st.session_state.angle = np.round(mag[0][0], decimals=3)
298
+ st.session_state.isMagnetCheck_VT = True
299
+ st.session_state.isButtonClicked = True
300
+
301
+ if st.session_state.isMagnetCheck_VT:
302
+ st.write(f"Magnetic declination: {st.session_state.angle}\u00b0")
303
+ st.write(":green[Magnetic declination correction applied to velocities]")
304
+
305
+ magnet_button_reset = st.button(
306
+ "Reset Magnetic Declination",
307
+ on_click=toggle_btns,
308
+ disabled=not st.session_state.isMagnetButton,
309
+ )
310
+ if magnet_button_reset:
311
+ st.session_state.velocity_magnet = np.copy(velocity)
312
+ st.session_state.isMagnetCheck_VT = False
313
+ st.session_state.isButtonClicked = False
314
+
315
+ with tab2:
316
+ ############# Velocity Cutoffs #################
317
+ st.header("Velocity Cutoffs", divider="blue")
318
+ st.write(
319
+ """
320
+ Drop velocities whose magnitude is larger than the threshold.
321
+ """
322
+ )
323
+ with st.form(key="cutbin_form"):
324
+ maxuvel = st.number_input(
325
+ "Maximum Zonal Velocity Cutoff (cm/s)", 0, 2000, 250, 1
326
+ )
327
+ maxvvel = st.number_input(
328
+ "Maximum Meridional Velocity Cutoff (cm/s)", 0, 2000, 250, 1
329
+ )
330
+ maxwvel = st.number_input(
331
+ "Maximum Vertical Velocity Cutoff (cm/s)", 0, 2000, 15, 1
332
+ )
333
+ submit_cutoff = st.form_submit_button(label="Submit")
334
+
335
+ if submit_cutoff:
336
+ velocity = st.session_state.velocity_magnet
337
+ st.session_state.maxuvel_VT = maxuvel
338
+ st.session_state.maxvvel_VT = maxvvel
339
+ st.session_state.maxwvel_VT = maxwvel
340
+
341
+ st.session_state.velocity_mask_cutoff = velocity_cutoff(
342
+ velocity[0, :, :], st.session_state.velocity_mask_temp, cutoff=maxuvel
343
+ )
344
+ st.session_state.velocity_mask_cutoff = velocity_cutoff(
345
+ velocity[1, :, :], st.session_state.velocity_mask_temp, cutoff=maxvvel
346
+ )
347
+ st.session_state.velocity_mask_cutoff = velocity_cutoff(
348
+ velocity[2, :, :], st.session_state.velocity_mask_temp, cutoff=maxwvel
349
+ )
350
+ st.session_state.velocity_mask_temp = np.copy(
351
+ st.session_state.velocity_mask_cutoff
352
+ )
353
+ st.session_state.isCutoffCheck_VT = True
354
+
355
+ if st.session_state.isCutoffCheck_VT:
356
+ st.success("Cutoff Applied")
357
+ a = {
358
+ "Max. Zonal Velocity": maxuvel,
359
+ "Max. Meridional Velocity": maxvvel,
360
+ "Max. Vertical Velocity": maxwvel,
361
+ }
362
+ st.write(a)
363
+
364
+ def reset_button_cutoff():
365
+ st.session_state.isCutoffCheck_VT = False
366
+ st.session_state.velocity_mask_temp = np.copy(
367
+ st.session_state.velocity_mask_default
368
+ )
369
+ st.session_state.velocity_mask_cutoff = np.copy(
370
+ st.session_state.velocity_mask_default
371
+ )
372
+
373
+ reset_cutoff = st.button("Reset Cutoff to default", on_click=reset_button_cutoff)
374
+ if reset_cutoff:
375
+ st.info("Cutoff Test is reset")
376
+
377
+
378
+ with tab3:
379
+ ############## DESPIKE DATA #################
380
+ st.header("Despike Data", divider="blue")
381
+ st.write("""A rolling median filter is applied to remove spikes from the data.
382
+ The kernel size determines the number of ensembles (time interval) for the filter window.
383
+ The standard deviation specifies the maximum allowable deviation to remove the spike.""")
384
+
385
+ # time_interval = pd.Timedelta(st.session_state.date[-1] - st.session_state.date[0]).seconds/(3600*st.session_state.head.ensembles)
386
+
387
+ st.write("Time interval: ", st.session_state.date[1] - st.session_state.date[0])
388
+
389
+ despike_kernel = st.number_input(
390
+ "Enter Despike kernel Size for Median Filter",
391
+ 0,
392
+ st.session_state.head.ensembles,
393
+ 5,
394
+ 1,
395
+ )
396
+
397
+ despike_cutoff = st.number_input(
398
+ "Standard Deviation Cutoff for Spike Removal", 0.1, 10.0, 3.0, 0.1
399
+ )
400
+ despike_button = st.button("Despike")
401
+ if despike_button:
402
+ st.session_state.despike_kernel_VT = despike_kernel
403
+ st.session_state.despike_cutoff_VT = despike_cutoff
404
+
405
+ st.session_state.velocity_mask_despike = despike(
406
+ velocity[0, :, :],
407
+ st.session_state.velocity_mask_temp,
408
+ kernel_size=despike_kernel,
409
+ cutoff=despike_cutoff,
410
+ )
411
+ st.session_state.velocity_mask_despike = despike(
412
+ velocity[1, :, :],
413
+ st.session_state.velocity_mask_temp,
414
+ kernel_size=despike_kernel,
415
+ cutoff=despike_cutoff,
416
+ )
417
+
418
+ # Reset the temporary mask
419
+ st.session_state.velocity_mask_temp = np.copy(
420
+ st.session_state.velocity_mask_despike
421
+ )
422
+ st.session_state.isDespikeCheck_VT = True
423
+
424
+ if st.session_state.isDespikeCheck_VT:
425
+ st.success("Data Despiked")
426
+ b = {
427
+ "kernel Size": despike_kernel,
428
+ "Despike Cutoff": despike_cutoff,
429
+ }
430
+ st.write(b)
431
+
432
+ def reset_button_despike():
433
+ st.session_state.isDespikeCheck_VT = False
434
+ if st.session_state.isCutoffCheck_VT:
435
+ st.session_state.velocity_mask_temp = np.copy(
436
+ st.session_state.velocity_mask_cutoff
437
+ )
438
+ st.session_state.velocity_mask_despike = np.copy(
439
+ st.session_state.velocity_mask_cutoff
440
+ )
441
+ else:
442
+ st.session_state.velocity_mask_temp = np.copy(
443
+ st.session_state.velocity_mask_default
444
+ )
445
+ st.session_state.velocity_mask_despike = np.copy(
446
+ st.session_state.velocity_mask_default
447
+ )
448
+
449
+ reset_despike = st.button("Reset Despike to default", on_click=reset_button_despike)
450
+ if reset_despike:
451
+ st.info("Despike Test is reset")
452
+
453
+ with tab4:
454
+ st.header("Remove Flatline", divider="blue")
455
+
456
+ st.write("""
457
+ Flatline removal detects segments of data where values remain constant over
458
+ a specified interval. The kernel size defines the number of consecutive
459
+ ensembles (time intervals) considered in the check, while the threshold sets
460
+ the maximum allowable variation.
461
+ """)
462
+
463
+ st.write("Time interval: ", st.session_state.date[1] - st.session_state.date[0])
464
+
465
+ flatline_kernel = st.number_input("Enter Flatline kernel Size", 0, 100, 13, 1)
466
+ flatline_cutoff = st.number_input("Enter Flatline deviation (mm/s)", 0, 100, 1, 1)
467
+
468
+ flatline_button = st.button("Remove Flatline")
469
+
470
+ if flatline_button:
471
+ st.session_state.flatline_kernel_VT = flatline_kernel
472
+ st.session_state.flatline_cutoff_VT = flatline_cutoff
473
+
474
+ st.session_state.velocity_mask_flatline = flatline(
475
+ velocity[0, :, :],
476
+ st.session_state.velocity_mask_temp,
477
+ kernel_size=flatline_kernel,
478
+ cutoff=flatline_cutoff,
479
+ )
480
+ st.session_state.velocity_mask_flatline = flatline(
481
+ velocity[1, :, :],
482
+ st.session_state.velocity_mask_temp,
483
+ kernel_size=flatline_kernel,
484
+ cutoff=flatline_cutoff,
485
+ )
486
+ st.session_state.velocity_mask_flatline = flatline(
487
+ velocity[2, :, :],
488
+ st.session_state.velocity_mask_temp,
489
+ kernel_size=flatline_kernel,
490
+ cutoff=flatline_cutoff,
491
+ )
492
+ # Modify the temporary mask file
493
+ st.session_state.velocity_mask_temp = np.copy(
494
+ st.session_state.velocity_mask_flatline
495
+ )
496
+ st.session_state.isFlatlineCheck = True
497
+
498
+ if st.session_state.isFlatlineCheck:
499
+ st.success("Flatline Removed")
500
+ b = {
501
+ "kernel Size": flatline_kernel,
502
+ "Flatline Cutoff": flatline_cutoff,
503
+ }
504
+ st.write(b)
505
+
506
+ def reset_button_flatline():
507
+ st.session_state.isFlatlineCheck = False
508
+ if st.session_state.isDespikeCheck_VT:
509
+ st.session_state.velocity_mask_temp = np.copy(
510
+ st.session_state.velocity_mask_despike
511
+ )
512
+ st.session_state.velocity_mask_flatline = np.copy(
513
+ st.session_state.velocity_mask_despike
514
+ )
515
+ elif st.session_state.isCutoffCheck_VT:
516
+ st.session_state.velocity_mask_temp = np.copy(
517
+ st.session_state.velocity_mask_cutoff
518
+ )
519
+ st.session_state.velocity_mask_flatline = np.copy(
520
+ st.session_state.velocity_mask_cutoff
521
+ )
522
+ else:
523
+ st.session_state.velocity_mask_temp = np.copy(
524
+ st.session_state.velocity_mask_default
525
+ )
526
+ st.session_state.velocity_mask_flatline = np.copy(
527
+ st.session_state.velocity_mask_default
528
+ )
529
+
530
+ reset_despike = st.button(
531
+ "Reset Flatline to default", on_click=reset_button_flatline
532
+ )
533
+ if reset_despike:
534
+ st.info("Flatline Test is reset")
535
+
536
+
537
+ ##################### SAVE DATA ###################
538
+ with tab5:
539
+ st.header("Save & Reset Data", divider="blue")
540
+
541
+ def save_velocitytest():
542
+ st.session_state.isVelocityTest = True
543
+ st.session_state.isFirstVelocityVisit = False
544
+ st.session_state.velocity_mask = st.session_state.velocity_mask_temp
545
+
546
+ st.session_state.isSensorPageReturn = True
547
+ st.session_state.isQCPageReturn = True
548
+ st.session_state.isProfilePageReturn = True
549
+
550
+ col1, col2 = st.columns([1, 1])
551
+ with col1:
552
+ save_button = st.button(label="Save Data", on_click=save_velocitytest)
553
+ if save_button:
554
+ st.write(":green[Mask data saved]")
555
+ # Status Summary Table
556
+ status_summary = pd.DataFrame(
557
+ [
558
+ [
559
+ "Magnetic Declination",
560
+ "True" if st.session_state.isButtonClicked else "False",
561
+ ],
562
+ [
563
+ "Velocity Cutoffs",
564
+ "True" if st.session_state.isCutoffCheck_VT else "False",
565
+ ],
566
+ [
567
+ "Despike Data",
568
+ "True" if st.session_state.isDespikeCheck_VT else "False",
569
+ ],
570
+ [
571
+ "Remove Flatline",
572
+ "True" if st.session_state.isFlatlineCheck else "False",
573
+ ],
574
+ ],
575
+ columns=["Test", "Status"],
576
+ )
577
+
578
+ # Define a mapping function for styling
579
+ def status_color_map(value):
580
+ if value == "True":
581
+ return "background-color: green; color: white"
582
+ elif value == "False":
583
+ return "background-color: red; color: white"
584
+ else:
585
+ return ""
586
+
587
+ # Apply styles using Styler.apply
588
+ styled_table = status_summary.style.set_properties(
589
+ **{"text-align": "center"}
590
+ )
591
+ styled_table = styled_table.map(status_color_map, subset=["Status"])
592
+
593
+ # Display the styled table
594
+ st.write(styled_table.to_html(), unsafe_allow_html=True)
595
+ else:
596
+ st.write(":red[Data not saved]")
597
+
598
+ with col2:
599
+ st.button(label="Reset Data", on_click=reset_velocitytest)
600
+ st.info("Velocity test reset to default")