pyadps 0.2.1b0__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.
- pyadps/pages/01_Read_File.py +92 -17
- pyadps/pages/02_View_Raw_Data.py +69 -33
- pyadps/pages/04_Sensor_Health.py +892 -0
- pyadps/pages/05_QC_Test.py +478 -0
- pyadps/pages/06_Profile_Test.py +959 -0
- pyadps/pages/07_Velocity_Test.py +599 -0
- pyadps/pages/{07_Write_File.py → 08_Write_File.py} +127 -52
- pyadps/pages/09_Auto_process.py +62 -0
- pyadps/utils/__init__.py +2 -3
- pyadps/utils/autoprocess.py +129 -46
- pyadps/utils/metadata/config.ini +22 -4
- pyadps/utils/metadata/demo.000 +0 -0
- pyadps/utils/plotgen.py +499 -0
- pyadps/utils/profile_test.py +491 -126
- pyadps/utils/pyreadrdi.py +13 -6
- pyadps/utils/readrdi.py +78 -6
- pyadps/utils/script.py +21 -23
- pyadps/utils/sensor_health.py +120 -0
- pyadps/utils/signal_quality.py +343 -23
- pyadps/utils/velocity_test.py +75 -27
- pyadps/utils/writenc.py +8 -1
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0b0.dist-info}/METADATA +3 -3
- pyadps-0.3.0b0.dist-info/RECORD +33 -0
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0b0.dist-info}/WHEEL +1 -1
- pyadps/pages/04_QC_Test.py +0 -334
- pyadps/pages/05_Profile_Test.py +0 -575
- pyadps/pages/06_Velocity_Test.py +0 -341
- pyadps/utils/cutbin.py +0 -413
- pyadps/utils/regrid.py +0 -279
- pyadps-0.2.1b0.dist-info/RECORD +0 -31
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0b0.dist-info}/LICENSE +0 -0
- {pyadps-0.2.1b0.dist-info → pyadps-0.3.0b0.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,478 @@
|
|
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.signal_quality import (
|
10
|
+
ev_check,
|
11
|
+
false_target,
|
12
|
+
pg_check,
|
13
|
+
echo_check,
|
14
|
+
correlation_check,
|
15
|
+
)
|
16
|
+
|
17
|
+
if "flead" not in st.session_state:
|
18
|
+
st.write(":red[Please Select Data!]")
|
19
|
+
st.stop()
|
20
|
+
|
21
|
+
|
22
|
+
def reset_qctest():
|
23
|
+
# Reset Global Test
|
24
|
+
st.session_state.isQCTest = False
|
25
|
+
# Reset Local Tests
|
26
|
+
st.session_state.isQCCheck = False
|
27
|
+
|
28
|
+
# Reset Data
|
29
|
+
st.session_state.isBeamModified = False
|
30
|
+
beamdir = st.session_state.ds.fixedleader.system_configuration()["Beam Direction"]
|
31
|
+
st.session_state.beam_direction = beamdir
|
32
|
+
|
33
|
+
# As QC test is not saved the Sensor Page Returns is set to False
|
34
|
+
st.session_state.isSensorPageReturn = False
|
35
|
+
|
36
|
+
# Reset Mask Data
|
37
|
+
# Copy the sensor mask if sensor mask completed.
|
38
|
+
# Else copy the default mask.
|
39
|
+
if st.session_state.isSensorTest:
|
40
|
+
st.session_state.qc_mask = np.copy(st.session_state.sensor_mask)
|
41
|
+
st.session_state.qc_mask_temp = np.copy(st.session_state.sensor_mask)
|
42
|
+
else:
|
43
|
+
st.session_state.qc_mask = np.copy(st.session_state.orig_mask)
|
44
|
+
st.session_state.qc_mask_temp = np.copy(st.session_state.orig_mask)
|
45
|
+
|
46
|
+
|
47
|
+
def hard_reset(option):
|
48
|
+
# Reset Global Test
|
49
|
+
st.session_state.isQCTest = False
|
50
|
+
# Reset Local Tests
|
51
|
+
st.session_state.isQCCheck = False
|
52
|
+
st.session_state.isBeamModified = False
|
53
|
+
# Reset Data
|
54
|
+
beamdir = st.session_state.ds.fixedleader.system_configuration()["Beam Direction"]
|
55
|
+
st.session_state.beam_direction = beamdir
|
56
|
+
|
57
|
+
st.session_state.isSensorPageReturn = False
|
58
|
+
|
59
|
+
# Reset Mask Data based on user options
|
60
|
+
if option == "Sensor Test":
|
61
|
+
st.session_state.qc_mask = np.copy(st.session_state.sensor_mask)
|
62
|
+
st.session_state.qc_mask_temp = np.copy(st.session_state.sensor_mask)
|
63
|
+
|
64
|
+
elif option == "Default":
|
65
|
+
st.session_state.qc_mask = np.copy(st.session_state.orig_mask)
|
66
|
+
st.session_state.qc_mask_temp = np.copy(st.session_state.orig_mask)
|
67
|
+
|
68
|
+
|
69
|
+
def save_qctest():
|
70
|
+
st.session_state.qc_mask = np.copy(st.session_state.qc_mask_temp)
|
71
|
+
st.session_state.isQCTest = True
|
72
|
+
st.session_state.isProfileMask = False
|
73
|
+
st.session_state.isGridSave = False
|
74
|
+
st.session_state.isVelocityMask = False
|
75
|
+
# Indicate previous pages that Test has been carried out
|
76
|
+
st.session_state.isSensorPageReturn = True
|
77
|
+
|
78
|
+
|
79
|
+
def qc_submit():
|
80
|
+
# st.write(st.session_state.newthresh)
|
81
|
+
st.session_state.isQCCheck = True
|
82
|
+
|
83
|
+
# First Quality check of the page
|
84
|
+
mask = np.copy(st.session_state.qc_mask_temp)
|
85
|
+
# if st.session_state.isSensorTest:
|
86
|
+
# mask = np.copy(st.session_state.sensor_mask)
|
87
|
+
# else:
|
88
|
+
# mask = np.copy(st.session_state.default_mask)
|
89
|
+
|
90
|
+
ds = st.session_state.ds
|
91
|
+
pgt = st.session_state.pgt
|
92
|
+
ct = st.session_state.ct
|
93
|
+
et = st.session_state.et
|
94
|
+
evt = st.session_state.evt
|
95
|
+
ft = st.session_state.ft
|
96
|
+
option = st.session_state.option
|
97
|
+
mask = pg_check(ds, mask, pgt, threebeam=option)
|
98
|
+
mask = correlation_check(ds, mask, ct)
|
99
|
+
mask = echo_check(ds, mask, et)
|
100
|
+
mask = ev_check(ds, mask, evt)
|
101
|
+
mask = false_target(ds, mask, ft, threebeam=True)
|
102
|
+
# Store the processed mask in a temporary mask
|
103
|
+
st.session_state.qc_mask_temp = mask
|
104
|
+
|
105
|
+
|
106
|
+
if st.session_state.isSensorTest:
|
107
|
+
st.write(":grey[Working on a saved mask file ...]")
|
108
|
+
if st.session_state.isQCPageReturn:
|
109
|
+
st.write(
|
110
|
+
":orange[Warning: QC test already completed. Reset the mask file to change settings.]"
|
111
|
+
)
|
112
|
+
reset_selectbox = st.selectbox(
|
113
|
+
"Choose reset option",
|
114
|
+
("Sensor Test", "Default"),
|
115
|
+
index=None,
|
116
|
+
placeholder="Reset mask to ...",
|
117
|
+
)
|
118
|
+
if reset_selectbox is not None:
|
119
|
+
hard_reset(reset_selectbox)
|
120
|
+
elif st.session_state.isFirstQCVisit:
|
121
|
+
reset_qctest()
|
122
|
+
st.session_state.isFirstQCVisit = False
|
123
|
+
else:
|
124
|
+
if st.session_state.isFirstQCVisit:
|
125
|
+
# This will rest to the default mask file
|
126
|
+
reset_qctest()
|
127
|
+
st.session_state.isFirstQCVisit = False
|
128
|
+
st.write(":orange[Creating a new mask file ...]")
|
129
|
+
|
130
|
+
|
131
|
+
# Load data
|
132
|
+
ds = st.session_state.ds
|
133
|
+
flobj = st.session_state.flead
|
134
|
+
vlobj = st.session_state.vlead
|
135
|
+
velocity = st.session_state.velocity
|
136
|
+
echo = st.session_state.echo
|
137
|
+
correlation = st.session_state.correlation
|
138
|
+
pgood = st.session_state.pgood
|
139
|
+
ensembles = st.session_state.head.ensembles
|
140
|
+
cells = flobj.field()["Cells"]
|
141
|
+
fdata = flobj.fleader
|
142
|
+
vdata = vlobj.vleader
|
143
|
+
x = np.arange(0, ensembles, 1)
|
144
|
+
y = np.arange(0, cells, 1)
|
145
|
+
|
146
|
+
|
147
|
+
@st.cache_data
|
148
|
+
def fillplot_plotly(data, colorscale="balance"):
|
149
|
+
fig = FigureResampler(go.Figure())
|
150
|
+
data1 = np.where(data == -32768, np.nan, data)
|
151
|
+
fig.add_trace(
|
152
|
+
go.Heatmap(z=data1[:, 0:-1], x=x, y=y, colorscale=colorscale, hoverongaps=False)
|
153
|
+
)
|
154
|
+
st.plotly_chart(fig)
|
155
|
+
|
156
|
+
|
157
|
+
@st.cache_data
|
158
|
+
def lineplot(data, title, slope=None, xaxis="time"):
|
159
|
+
if xaxis == "time":
|
160
|
+
xdata = st.session_state.date
|
161
|
+
else:
|
162
|
+
xdata = st.session_state.ensemble_axis
|
163
|
+
scatter_trace = go.Scatter(
|
164
|
+
x=xdata,
|
165
|
+
y=data,
|
166
|
+
mode="markers",
|
167
|
+
name=title,
|
168
|
+
marker=dict(color="blue", size=10), # Customize marker color and size
|
169
|
+
)
|
170
|
+
# Create the slope line trace
|
171
|
+
if slope is not None:
|
172
|
+
line_trace = go.Scatter(
|
173
|
+
x=xdata,
|
174
|
+
y=slope,
|
175
|
+
mode="lines",
|
176
|
+
name="Slope Line",
|
177
|
+
line=dict(color="red", width=2, dash="dash"), # Dashed red line
|
178
|
+
)
|
179
|
+
fig = go.Figure(data=[scatter_trace, line_trace])
|
180
|
+
else:
|
181
|
+
fig = go.Figure(data=[scatter_trace])
|
182
|
+
|
183
|
+
st.plotly_chart(fig)
|
184
|
+
|
185
|
+
|
186
|
+
@st.cache_data
|
187
|
+
def plot_noise(dep=0, rec=-1):
|
188
|
+
n = dep
|
189
|
+
m = rec
|
190
|
+
colorleft = [
|
191
|
+
"rgb(240, 255, 255)",
|
192
|
+
"rgb(115, 147, 179)",
|
193
|
+
"rgb(100, 149, 237)",
|
194
|
+
"rgb(15, 82, 186)",
|
195
|
+
]
|
196
|
+
colorright = [
|
197
|
+
"rgb(250, 200, 152)",
|
198
|
+
"rgb(255, 165, 0)",
|
199
|
+
"rgb(255, 95, 31)",
|
200
|
+
"rgb(139, 64, 0)",
|
201
|
+
]
|
202
|
+
fig = make_subplots(
|
203
|
+
rows=1,
|
204
|
+
cols=2,
|
205
|
+
subplot_titles=[
|
206
|
+
f"Deployment Ensemble ({x[n]+1})",
|
207
|
+
f"Recovery Ensemble ({x[m]+1})",
|
208
|
+
],
|
209
|
+
)
|
210
|
+
for i in range(4):
|
211
|
+
fig.add_trace(
|
212
|
+
go.Scatter(
|
213
|
+
x=echo[i, :, n],
|
214
|
+
y=y,
|
215
|
+
name=f"Beam (D) {i+1}",
|
216
|
+
line=dict(color=colorleft[i]),
|
217
|
+
),
|
218
|
+
row=1,
|
219
|
+
col=1,
|
220
|
+
)
|
221
|
+
for i in range(4):
|
222
|
+
fig.add_trace(
|
223
|
+
go.Scatter(
|
224
|
+
x=echo[i, :, m],
|
225
|
+
y=y,
|
226
|
+
name=f"Beam (R) {i+1}",
|
227
|
+
line=dict(color=colorright[i]),
|
228
|
+
),
|
229
|
+
row=1,
|
230
|
+
col=2,
|
231
|
+
)
|
232
|
+
|
233
|
+
fig.update_layout(height=600, width=800, title_text="Echo Intensity")
|
234
|
+
fig.update_xaxes(title="Echo (count)")
|
235
|
+
fig.update_yaxes(title="Cells")
|
236
|
+
st.plotly_chart(fig)
|
237
|
+
|
238
|
+
|
239
|
+
tab1, tab2, tab3, tab4, tab5 = st.tabs(
|
240
|
+
[
|
241
|
+
"Noise Floor Identification",
|
242
|
+
"QC Tests",
|
243
|
+
"Display Mask",
|
244
|
+
"Fix Orientation",
|
245
|
+
"Save Data",
|
246
|
+
]
|
247
|
+
)
|
248
|
+
######### NOISE FLOOR IDENTIFICATION ##############
|
249
|
+
with tab1:
|
250
|
+
dn = rn = 1
|
251
|
+
st.header("Noise Floor Identification", divider="blue")
|
252
|
+
st.write(
|
253
|
+
"""
|
254
|
+
If the ADCP has collected data from the air either
|
255
|
+
before deployment or after recovery, this data can
|
256
|
+
be used to estimate the echo intensity threshold.
|
257
|
+
The plots below show the echo intensity from the first
|
258
|
+
and last ensembles. The noise level is typically around
|
259
|
+
30-40 counts throughout the entire profile.
|
260
|
+
"""
|
261
|
+
)
|
262
|
+
dn = st.number_input("Deployment Ensemble", x[0] + 1, x[-1] + 1, x[0] + 1)
|
263
|
+
# r = st.number_input("Recovery Ensemble", -1 * (x[-1] + 1), -1 * (x[0] + 1), -1)
|
264
|
+
rn = st.number_input("Recovery Ensemble", x[0] + 1, x[-1] + 1, x[-1] + 1)
|
265
|
+
dn = dn - 1
|
266
|
+
rn = rn - 1
|
267
|
+
|
268
|
+
plot_noise(dep=dn, rec=rn)
|
269
|
+
|
270
|
+
|
271
|
+
################## QC Test ###################
|
272
|
+
with tab2:
|
273
|
+
st.header("Quality Control Tests", divider="blue")
|
274
|
+
st.write("")
|
275
|
+
|
276
|
+
left, right = st.columns([1, 1])
|
277
|
+
with left:
|
278
|
+
st.write(""" Teledyne RDI recommends these quality control tests,
|
279
|
+
some of which can be configured before deployment.
|
280
|
+
The pre-deployment values configured for the ADCP are listed
|
281
|
+
in the table below. The noise-floor identification graph above
|
282
|
+
can assist in determining the echo intensity threshold.
|
283
|
+
For more information about these tests,
|
284
|
+
refer to *Acoustic Doppler Current Profiler Principles of
|
285
|
+
Operation: A Practical Primer* by Teledyne RDI.""")
|
286
|
+
fdata = st.session_state.flead.field()
|
287
|
+
st.divider()
|
288
|
+
st.write(":blue-background[Additional Information:]")
|
289
|
+
st.write(f"Number of Pings per Ensemble: `{fdata["Pings"]}`")
|
290
|
+
st.write(f"Number of Beams: `{fdata["Beams"]}`")
|
291
|
+
st.divider()
|
292
|
+
st.write(":red-background[Thresholds used during deployment:]")
|
293
|
+
thresh = pd.DataFrame(
|
294
|
+
[
|
295
|
+
["Correlation", fdata["Correlation Thresh"]],
|
296
|
+
["Error Velocity", fdata["Error Velocity Thresh"]],
|
297
|
+
["Echo Intensity", 0],
|
298
|
+
["False Target", fdata["False Target Thresh"]],
|
299
|
+
["Percentage Good", fdata["Percent Good Min"]],
|
300
|
+
],
|
301
|
+
columns=["Threshold", "Values"],
|
302
|
+
)
|
303
|
+
|
304
|
+
st.write(thresh)
|
305
|
+
|
306
|
+
with right:
|
307
|
+
with st.form(key="my_form"):
|
308
|
+
st.write("Would you like to apply new threshold?")
|
309
|
+
|
310
|
+
st.session_state.ct = st.number_input(
|
311
|
+
"Select Correlation Threshold",
|
312
|
+
0,
|
313
|
+
255,
|
314
|
+
fdata["Correlation Thresh"],
|
315
|
+
)
|
316
|
+
|
317
|
+
st.session_state.evt = st.number_input(
|
318
|
+
"Select Error Velocity Threshold",
|
319
|
+
0,
|
320
|
+
9999,
|
321
|
+
fdata["Error Velocity Thresh"],
|
322
|
+
)
|
323
|
+
|
324
|
+
st.session_state.et = st.number_input(
|
325
|
+
"Select Echo Intensity Threshold",
|
326
|
+
0,
|
327
|
+
255,
|
328
|
+
0,
|
329
|
+
)
|
330
|
+
|
331
|
+
st.session_state.ft = st.number_input(
|
332
|
+
"Select False Target Threshold",
|
333
|
+
0,
|
334
|
+
255,
|
335
|
+
fdata["False Target Thresh"],
|
336
|
+
)
|
337
|
+
|
338
|
+
st.session_state.option = st.selectbox(
|
339
|
+
"Would you like to use a three-beam solution?", (True, False)
|
340
|
+
)
|
341
|
+
|
342
|
+
st.session_state.pgt = st.number_input(
|
343
|
+
"Select Percent Good Threshold",
|
344
|
+
0,
|
345
|
+
100,
|
346
|
+
fdata["Percent Good Min"],
|
347
|
+
)
|
348
|
+
submit_button = st.form_submit_button(label="Submit", on_click=qc_submit)
|
349
|
+
|
350
|
+
# mask = st.session_state.qc_mask_temp
|
351
|
+
with left:
|
352
|
+
if submit_button:
|
353
|
+
st.session_state.isQCCheck = True
|
354
|
+
st.session_state.newthresh = pd.DataFrame(
|
355
|
+
[
|
356
|
+
["Correlation", str(st.session_state.ct)],
|
357
|
+
["Error Velocity", str(st.session_state.evt)],
|
358
|
+
["Echo Intensity", str(st.session_state.et)],
|
359
|
+
["False Target", str(st.session_state.ft)],
|
360
|
+
["Three Beam", str(st.session_state.option)],
|
361
|
+
["Percentage Good", str(st.session_state.pgt)],
|
362
|
+
],
|
363
|
+
columns=["Threshold", "Values"],
|
364
|
+
)
|
365
|
+
|
366
|
+
if st.session_state.isQCCheck:
|
367
|
+
st.write(":green-background[Current Thresholds]")
|
368
|
+
st.write(st.session_state.newthresh)
|
369
|
+
|
370
|
+
|
371
|
+
with tab3:
|
372
|
+
st.header("Mask File", divider="blue")
|
373
|
+
st.write(
|
374
|
+
"""
|
375
|
+
Display the mask file.
|
376
|
+
Ensure to save any necessary changes or apply additional thresholds if needed.
|
377
|
+
"""
|
378
|
+
)
|
379
|
+
|
380
|
+
leftplot, rightplot = st.columns([1, 1])
|
381
|
+
if st.button("Display mask file"):
|
382
|
+
with leftplot:
|
383
|
+
st.subheader("Default Mask File")
|
384
|
+
st.write(
|
385
|
+
"""
|
386
|
+
CAPTION:
|
387
|
+
ADCP assigns missing values based on thresholds
|
388
|
+
set before deployment. These values cannot be
|
389
|
+
recovered and are part of default mask file.
|
390
|
+
"""
|
391
|
+
)
|
392
|
+
fillplot_plotly(st.session_state.orig_mask, colorscale="greys")
|
393
|
+
with rightplot:
|
394
|
+
st.subheader("Updated Mask File")
|
395
|
+
# values, counts = np.unique(mask, return_counts=True)
|
396
|
+
st.write(
|
397
|
+
"""
|
398
|
+
CAPTION:
|
399
|
+
Updated mask displayed after applying threshold.
|
400
|
+
If thresholds are not saved, default mask
|
401
|
+
is displayed.
|
402
|
+
"""
|
403
|
+
)
|
404
|
+
fillplot_plotly(st.session_state.qc_mask_temp, colorscale="greys")
|
405
|
+
|
406
|
+
with tab4:
|
407
|
+
################## Fix Orientation ###################
|
408
|
+
st.subheader("Fix Orientation", divider="orange")
|
409
|
+
|
410
|
+
if st.session_state.beam_direction == "Up":
|
411
|
+
beamalt = "Down"
|
412
|
+
else:
|
413
|
+
beamalt = "Up"
|
414
|
+
st.write(
|
415
|
+
f"The current orientation of ADCP is `{st.session_state.beam_direction}`. Use the below option to correct the orientation."
|
416
|
+
)
|
417
|
+
|
418
|
+
beamdir_select = st.radio(f"Change orientation to {beamalt}", ["No", "Yes"])
|
419
|
+
if beamdir_select == "Yes":
|
420
|
+
st.session_state.beam_direction = beamalt
|
421
|
+
st.session_state.isBeamModified = True
|
422
|
+
st.write(f"The orientation changed to `{st.session_state.beam_direction}`")
|
423
|
+
|
424
|
+
with tab5:
|
425
|
+
################## Save Button #############
|
426
|
+
st.header("Save Data", divider="blue")
|
427
|
+
col1, col2 = st.columns([1, 1])
|
428
|
+
with col1:
|
429
|
+
save_mask_button = st.button(label="Save Mask Data", on_click=save_qctest)
|
430
|
+
|
431
|
+
if save_mask_button:
|
432
|
+
# st.session_state.qc_mask_temp = mask
|
433
|
+
st.success("Mask file saved")
|
434
|
+
# Table summarizing changes
|
435
|
+
changes_summary = pd.DataFrame(
|
436
|
+
[
|
437
|
+
[
|
438
|
+
"Quality Control Tests",
|
439
|
+
"True" if st.session_state.isQCCheck else "False",
|
440
|
+
],
|
441
|
+
["Fix Orientation", st.session_state.beam_direction],
|
442
|
+
],
|
443
|
+
columns=["Test", "Status"],
|
444
|
+
)
|
445
|
+
|
446
|
+
# Define a mapping function for styling
|
447
|
+
def status_color_map(value):
|
448
|
+
if value == "True":
|
449
|
+
return "background-color: green; color: white"
|
450
|
+
elif value == "False":
|
451
|
+
return "background-color: red; color: white"
|
452
|
+
elif value == "Up":
|
453
|
+
return "background-color: blue; color: white"
|
454
|
+
elif value == "Down":
|
455
|
+
return "background-color: orange; color: white"
|
456
|
+
else:
|
457
|
+
return ""
|
458
|
+
|
459
|
+
# Apply styles using Styler.apply
|
460
|
+
styled_table = changes_summary.style.set_properties(
|
461
|
+
**{"text-align": "center"}
|
462
|
+
)
|
463
|
+
styled_table = styled_table.map(status_color_map, subset=["Status"])
|
464
|
+
|
465
|
+
# Display the styled table
|
466
|
+
st.write(styled_table.to_html(), unsafe_allow_html=True)
|
467
|
+
else:
|
468
|
+
st.warning("Mask data not saved")
|
469
|
+
with col2:
|
470
|
+
reset_mask_button = st.button("Reset mask Data", on_click=reset_qctest)
|
471
|
+
if reset_mask_button:
|
472
|
+
# st.session_state.qc_mask_temp = np.copy(st.session_state.orig_mask)
|
473
|
+
# st.session_state.isQCCheck = False
|
474
|
+
# st.session_state.isQCTest = False
|
475
|
+
# st.session_state.isGrid = False
|
476
|
+
# st.session_state.isProfileMask = False
|
477
|
+
# st.session_state.isVelocityMask = False
|
478
|
+
st.success("Mask data is reset to default")
|