pyadps 0.1.0__py3-none-any.whl → 0.1.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/Home_Page.py +5 -11
- pyadps/pages/01_Read_File.py +16 -190
- pyadps/pages/02_View_Raw_Data.py +33 -69
- pyadps/pages/03_Download_Raw_File.py +60 -124
- pyadps/pages/04_QC_Test.py +283 -0
- pyadps/pages/05_Profile_Test.py +389 -0
- pyadps/pages/06_Velocity_Test.py +293 -0
- pyadps/pages/07_Write_File.py +367 -0
- pyadps/utils/__init__.py +3 -3
- pyadps/utils/cutbin.py +413 -0
- pyadps/utils/plotgen.py +3 -505
- pyadps/utils/profile_test.py +145 -526
- pyadps/utils/pyreadrdi.py +6 -13
- pyadps/utils/readrdi.py +20 -167
- pyadps/utils/regrid.py +122 -0
- pyadps/utils/script.py +147 -197
- pyadps/utils/signal_quality.py +24 -344
- pyadps/utils/velocity_test.py +16 -99
- pyadps/utils/writenc.py +27 -104
- {pyadps-0.1.0.dist-info → pyadps-0.1.0b0.dist-info}/METADATA +22 -54
- pyadps-0.1.0b0.dist-info/RECORD +29 -0
- {pyadps-0.1.0.dist-info → pyadps-0.1.0b0.dist-info}/WHEEL +1 -1
- pyadps-0.1.0b0.dist-info/entry_points.txt +3 -0
- pyadps/pages/04_Sensor_Health.py +0 -905
- pyadps/pages/05_QC_Test.py +0 -476
- pyadps/pages/06_Profile_Test.py +0 -971
- pyadps/pages/07_Velocity_Test.py +0 -600
- pyadps/pages/08_Write_File.py +0 -574
- pyadps/pages/09_Auto_process.py +0 -62
- pyadps/utils/autoprocess.py +0 -530
- pyadps/utils/metadata/config.ini +0 -99
- pyadps/utils/metadata/demo.000 +0 -0
- pyadps/utils/sensor_health.py +0 -120
- pyadps-0.1.0.dist-info/RECORD +0 -33
- pyadps-0.1.0.dist-info/entry_points.txt +0 -5
- {pyadps-0.1.0.dist-info → pyadps-0.1.0b0.dist-info}/LICENSE +0 -0
pyadps/Home_Page.py
CHANGED
@@ -8,22 +8,16 @@ def main():
|
|
8
8
|
layout="wide",
|
9
9
|
initial_sidebar_state="auto",
|
10
10
|
menu_items={
|
11
|
-
"Get Help": "
|
12
|
-
"Report a bug": "
|
11
|
+
"Get Help": "http://github.com/p-amol/adps",
|
12
|
+
"Report a bug": "http://github.com/adps/issues",
|
13
13
|
"About": "# Python ADCP Data Processing Software (PyADPS)",
|
14
14
|
},
|
15
15
|
)
|
16
16
|
|
17
17
|
"""
|
18
18
|
# **Python ADCP Data Processing Software (pyadps)**
|
19
|
-
|
20
|
-
`pyadps` is a Python package for processing moored Acoustic Doppler Current Profiler (ADCP) data. It provides various functionalities such as data reading, quality control tests, NetCDF file creation, and visualization.
|
19
|
+
`pyadps` is a software for processing Teledyne RDI Acoustic Doppler Current Profiler (ADCP) PD0 files. Currently the software can process the data from Workhorse ADCPs.
|
21
20
|
|
22
|
-
This software offers both a graphical interface (Streamlit) for those new to Python and direct Python package access for experienced users. Please note that pyadps is primarily designed for Teledyne RDI workhorse ADCPs. Other company's ADCP files are not compatible, and while some other RDI models may work, they might require additional considerations.
|
23
|
-
|
24
|
-
* Documentation: https://pyadps.readthedocs.io
|
25
|
-
* Source code: https://github.com/p-amol/pyadps
|
26
|
-
* Bug reports: https://github.com/p-amol/pyadps/issues
|
27
21
|
## Features
|
28
22
|
|
29
23
|
* Access RDI ADCP binary files using Python 3
|
@@ -31,8 +25,8 @@ def main():
|
|
31
25
|
* Process ADCP data
|
32
26
|
|
33
27
|
## Contribute
|
34
|
-
Issue Tracker:
|
35
|
-
Source Code:
|
28
|
+
Issue Tracker: http://github.com/adps/issues
|
29
|
+
Source Code: http://github.com/p-amol/adps
|
36
30
|
|
37
31
|
## Support
|
38
32
|
If you are having issues, please let us know.
|
pyadps/pages/01_Read_File.py
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
import os
|
2
2
|
import tempfile
|
3
3
|
|
4
|
-
import numpy as np
|
5
4
|
import pandas as pd
|
6
5
|
import streamlit as st
|
7
6
|
import utils.readrdi as rd
|
7
|
+
import utils.writenc as wr
|
8
|
+
from streamlit.runtime.state import session_state
|
8
9
|
from utils.signal_quality import default_mask
|
9
|
-
from utils.readrdi import ReadFile
|
10
|
-
|
11
|
-
# To make the page wider if the user presses the reload button.
|
12
|
-
st.set_page_config(layout="wide")
|
13
10
|
|
14
11
|
"""
|
15
12
|
Streamlit page to load ADCP binary file and display File Header
|
@@ -113,7 +110,6 @@ if uploaded_file is not None:
|
|
113
110
|
correlation = ds.correlation.data
|
114
111
|
echo = ds.echo.data
|
115
112
|
pgood = ds.percentgood.data
|
116
|
-
beamdir = ds.fixedleader.system_configuration()["Beam Direction"]
|
117
113
|
|
118
114
|
st.session_state.fname = uploaded_file.name
|
119
115
|
st.session_state.head = ds.fileheader
|
@@ -123,15 +119,6 @@ if uploaded_file is not None:
|
|
123
119
|
st.session_state.echo = ds.echo.data
|
124
120
|
st.session_state.correlation = ds.correlation.data
|
125
121
|
st.session_state.pgood = ds.percentgood.data
|
126
|
-
st.session_state.beam_direction = beamdir
|
127
|
-
st.session_state.sound_speed = ds.variableleader.speed_of_sound.data
|
128
|
-
st.session_state.depth = ds.variableleader.depth_of_transducer.data
|
129
|
-
st.session_state.temperature = (
|
130
|
-
ds.variableleader.temperature.data * ds.variableleader.temperature.scale
|
131
|
-
)
|
132
|
-
st.session_state.salinity = (
|
133
|
-
ds.variableleader.salinity.data * ds.variableleader.salinity.scale
|
134
|
-
)
|
135
122
|
|
136
123
|
# st.session_state.flead = flead
|
137
124
|
# st.session_state.vlead = vlead
|
@@ -145,9 +132,6 @@ if uploaded_file is not None:
|
|
145
132
|
elif "flead" in st.session_state:
|
146
133
|
st.write("You selected `%s`" % st.session_state.fname)
|
147
134
|
else:
|
148
|
-
# reset the cache and resources if the user press reload button.
|
149
|
-
st.cache_data.clear()
|
150
|
-
st.cache_resource.clear()
|
151
135
|
st.stop()
|
152
136
|
|
153
137
|
########## TIME AXIS ##############
|
@@ -180,158 +164,8 @@ date_df = pd.DataFrame(
|
|
180
164
|
)
|
181
165
|
|
182
166
|
st.session_state.date = pd.to_datetime(date_df)
|
183
|
-
|
184
|
-
|
185
|
-
st.session_state.ensemble_axis = np.arange(0, st.session_state.head.ensembles, 1)
|
186
|
-
st.session_state.axis_option = "time"
|
187
|
-
|
188
|
-
|
189
|
-
# ---------- Initialize all options -------------
|
190
|
-
# ------------------------
|
191
|
-
# Page: Download Raw File
|
192
|
-
# ------------------------
|
193
|
-
# Widgets
|
194
|
-
st.session_state.add_attributes_DRW = "No"
|
195
|
-
st.session_state.axis_option_DRW = "time"
|
196
|
-
st.session_state.rawnc_download_DRW = False
|
197
|
-
st.session_state.vleadnc_download_DRW = False
|
198
|
-
st.session_state.rawcsv_option_DRW = "Velocity"
|
199
|
-
st.session_state.rawcsv_beam_DRW = 1
|
200
|
-
st.session_state.rawcsv_download_DRW = False
|
201
|
-
|
202
|
-
# ------------------
|
203
|
-
# Page: Sensor Test
|
204
|
-
# ------------------
|
205
|
-
st.session_state.isSensorTest = False
|
206
|
-
st.session_state.isFirstSensorVisit = True
|
207
|
-
|
208
|
-
# -- Tab 1: Depth Correction
|
209
|
-
st.session_state.isDepthModified_ST = False
|
210
|
-
# Widgets
|
211
|
-
# Options: "Fixed Value", "File Upload"
|
212
|
-
st.session_state.depthoption_ST = "Fixed Value"
|
213
|
-
st.session_state.isFixedDepth_ST = False
|
214
|
-
st.session_state.fixeddepth_ST = 0
|
215
|
-
st.session_state.isUploadDepth_ST = False
|
216
|
-
|
217
|
-
# -- Tab 2: Salinity Correction
|
218
|
-
st.session_state.isSalinityModified_ST = False
|
219
|
-
# Widgets
|
220
|
-
st.session_state.salinityoption_ST = "Fixed Value"
|
221
|
-
st.session_state.isFixedSalinity_ST = False
|
222
|
-
st.session_state.fixedsalinity_ST = 35
|
223
|
-
st.session_state.isUploadSalinity_ST = False
|
224
|
-
|
225
|
-
# -- Tab 3: Temperature Correction
|
226
|
-
st.session_state.isTemperatureModified_ST = False
|
227
|
-
# Widgets
|
228
|
-
st.session_state.temperatureoption_ST = "Fixed Value"
|
229
|
-
st.session_state.isFixedTemperature_ST = False
|
230
|
-
st.session_state.fixedtemperature_ST = 0
|
231
|
-
st.session_state.isUploadTemperature_ST = False
|
232
|
-
|
233
|
-
# -- Tab 7: Pitch, Roll, Velocity Correction
|
234
|
-
st.session_state.isRollCheck_ST = False
|
235
|
-
st.session_state.isPitchCheck_ST = False
|
236
|
-
st.session_state.isVelocityModifiedSound_ST = False
|
237
|
-
# Widgets
|
238
|
-
st.session_state.roll_cutoff_ST = 359
|
239
|
-
st.session_state.pitch_cutoff_ST = 359
|
240
|
-
|
241
|
-
# ------------------
|
242
|
-
# Page: QC Test
|
243
|
-
# ------------------
|
244
|
-
# Global Test
|
245
|
-
st.session_state.isQCTest = False
|
246
|
-
st.session_state.isFirstQCVisit = True
|
247
|
-
|
248
|
-
# Tab 2: Apply QC
|
249
|
-
st.session_state.isQCCheck_QCT = False
|
250
|
-
# Widgets
|
251
|
-
st.session_state.ct_QCT = 64
|
252
|
-
st.session_state.et_QCT = 0
|
253
|
-
st.session_state.evt_QCT = 2000
|
254
|
-
st.session_state.ft_QCT = 50
|
255
|
-
st.session_state.is3beam_QCT = True
|
256
|
-
st.session_state.pgt_QCT = 0
|
257
|
-
|
258
|
-
# Data Modifications
|
259
|
-
st.session_state.isBeamModified_QCT = False
|
260
|
-
# Widgets
|
261
|
-
st.session_state.beam_direction_QCT = st.session_state.beam_direction
|
262
|
-
|
263
|
-
# ------------------
|
264
|
-
# Page: Profile Test
|
265
|
-
# ------------------
|
266
|
-
st.session_state.isProfileTest = False
|
267
|
-
st.session_state.isFirstProfileVisit = True
|
268
|
-
|
269
|
-
# Tab1: Trim Ends
|
270
|
-
st.session_state.isTrimEndsCheck_PT = False
|
271
|
-
# Widgets
|
272
|
-
st.session_state.start_ens_PT = 0
|
273
|
-
st.session_state.end_ens_PT = st.session_state.head.ensembles
|
274
|
-
|
275
|
-
# Tab2: Cutbins - Sidelobe
|
276
|
-
st.session_state.isCutBinSideLobeCheck_PT = False
|
277
|
-
st.session_state.extra_cells_PT = 0
|
278
|
-
st.session_state.water_depth_PT = 0
|
279
|
-
|
280
|
-
# Tab3: Cutbins - Manual
|
281
|
-
st.session_state.isCutBinManualCheck_PT = False
|
282
|
-
|
283
|
-
# Tab4: Regrid
|
284
|
-
st.session_state.isRegridCheck_PT = False
|
285
|
-
st.session_state.end_cell_option_PT = "Cell"
|
286
|
-
st.session_state.interpolate_PT = "nearest"
|
287
|
-
st.session_state.manualdepth_PT = 0
|
288
|
-
|
289
|
-
# ------------------
|
290
|
-
# Page: Velocity Test
|
291
|
-
# ------------------
|
292
|
-
# Global Test
|
293
|
-
st.session_state.isVelocityTest = False
|
294
|
-
# Check if visiting the page first time
|
295
|
-
st.session_state.isFirstVelocityVisit = True
|
296
|
-
# Local Tests:
|
297
|
-
# Tab1: Magnetic Declination
|
298
|
-
st.session_state.isMagnetCheck_VT = False
|
299
|
-
# OPTIONS: pygeomag, API, Manual
|
300
|
-
st.session_state.magnet_method_VT = "pygeomag"
|
301
|
-
st.session_state.magnet_lat_VT = 0
|
302
|
-
st.session_state.magnet_lon_VT = 0
|
303
|
-
st.session_state.magnet_year_VT = 2025
|
304
|
-
st.session_state.magnet_depth_VT = 0
|
305
|
-
st.session_state.magnet_user_input_VT = 0
|
306
|
-
|
307
|
-
# Tab2: Velocity Cutoff
|
308
|
-
st.session_state.isCutoffCheck_VT = False
|
309
|
-
st.session_state.maxuvel_VT = 250
|
310
|
-
st.session_state.maxvvel_VT = 250
|
311
|
-
st.session_state.maxwvel_VT = 15
|
312
|
-
|
313
|
-
# Tab3: Despike
|
314
|
-
st.session_state.isDespikeCheck_VT = False
|
315
|
-
st.session_state.despike_kernal_VT = 5
|
316
|
-
st.session_state.despike_cutoff_VT = 3
|
317
|
-
|
318
|
-
# Tab4: Flatline
|
319
|
-
st.session_state.isFlatlineCheck_VT = False
|
320
|
-
st.session_state.flatline_kernal_VT = 5
|
321
|
-
st.session_state.flatline_cutoff_VT = 3
|
322
|
-
|
323
|
-
# ------------------
|
324
|
-
# Page: Write File
|
325
|
-
# ------------------
|
326
|
-
st.session_state.isWriteFile = True
|
327
|
-
st.session_state.isAttributes = False
|
328
|
-
st.session_state.mask_data_WF = "Yes"
|
329
|
-
# FileTypes: NetCDF, CSV
|
330
|
-
st.session_state.file_type_WF = "NetCDF"
|
331
|
-
st.session_state.isProcessedNetcdfDownload_WF = True
|
332
|
-
st.session_state.isProcessedCSVDownload_WF = False
|
333
|
-
|
334
|
-
# MASK DATA
|
167
|
+
|
168
|
+
######### MASK DATA ##############
|
335
169
|
# The velocity data has missing values due to the cutoff
|
336
170
|
# criteria used before deployment. The `default_mask` uses
|
337
171
|
# the velocity to create a mask. This mask file is stored
|
@@ -340,17 +174,16 @@ st.session_state.isProcessedCSVDownload_WF = False
|
|
340
174
|
# WARNING: Never Change `st.session_state.orig_mask` in the code!
|
341
175
|
#
|
342
176
|
if "orig_mask" not in st.session_state:
|
343
|
-
|
344
|
-
|
177
|
+
st.session_state.orig_mask = default_mask(
|
178
|
+
st.session_state.flead, st.session_state.velocity
|
179
|
+
)
|
345
180
|
|
346
|
-
#
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
st.session_state.
|
351
|
-
st.session_state.
|
352
|
-
st.session_state.isProfilePageReturn = False
|
353
|
-
st.session_state.isVelocityPageReturn = False
|
181
|
+
# Checks if the following quality checks are carried out
|
182
|
+
st.session_state.isQCMask = False
|
183
|
+
st.session_state.isProfileMask = False
|
184
|
+
st.session_state.isGrid = False
|
185
|
+
st.session_state.isGridSave = False
|
186
|
+
st.session_state.isVelocityMask = False
|
354
187
|
|
355
188
|
########## FILE HEADER ###############
|
356
189
|
st.header("File Header", divider="blue")
|
@@ -427,18 +260,10 @@ if flead_check_button:
|
|
427
260
|
|
428
261
|
flead_button = st.button("Fixed Leader")
|
429
262
|
if flead_button:
|
430
|
-
# Pandas array should have all elements with same data type.
|
431
|
-
# Except Sl. no., which is np.uint64, rest are np.int64.
|
432
|
-
# Convert all datatype to uint64
|
433
|
-
fl_dict = st.session_state.flead.field().items()
|
434
|
-
new_dict = {}
|
435
|
-
for key, value in fl_dict:
|
436
|
-
new_dict[key] = value.astype(np.uint64)
|
437
|
-
|
438
263
|
df = pd.DataFrame(
|
439
264
|
{
|
440
|
-
"Fields":
|
441
|
-
"Values":
|
265
|
+
"Fields": st.session_state.flead.field().keys(),
|
266
|
+
"Values": st.session_state.flead.field().values(),
|
442
267
|
}
|
443
268
|
)
|
444
269
|
st.dataframe(df, use_container_width=True)
|
@@ -456,3 +281,4 @@ with right:
|
|
456
281
|
df = df.astype("str")
|
457
282
|
st.write((df.style.map(color_bool2)))
|
458
283
|
# st.dataframe(df)
|
284
|
+
|
pyadps/pages/02_View_Raw_Data.py
CHANGED
@@ -84,81 +84,45 @@ The ordinate (y-axis) for the heatmap is `bins` as the depth correction is not a
|
|
84
84
|
xbutton = st.radio("Select an x-axis to plot", ["time", "ensemble"], horizontal=True)
|
85
85
|
|
86
86
|
|
87
|
-
tab1, tab2, tab3, tab4 = st.tabs(["Primary Data", "Variable Leader", "Fixed Leader", "Advanced"])
|
88
|
-
|
89
|
-
with tab3:
|
90
87
|
# Fixed Leader Plots
|
91
|
-
|
92
|
-
|
93
|
-
|
88
|
+
st.header("Fixed Leader", divider="blue")
|
89
|
+
fbutton = st.radio("Select a dynamic variable to plot:", fdata.keys(), horizontal=True)
|
90
|
+
lineplot(fdata[fbutton], fbutton, xaxis=str(xbutton))
|
94
91
|
|
95
|
-
with tab2:
|
96
92
|
# Variable Leader Plots
|
97
|
-
|
98
|
-
|
99
|
-
|
93
|
+
st.header("Variable Leader", divider="blue")
|
94
|
+
vbutton = st.radio("Select a dynamic variable to plot:", vdata.keys(), horizontal=True)
|
95
|
+
lineplot(vdata[vbutton], vbutton, xaxis=str(xbutton))
|
100
96
|
|
101
|
-
|
102
|
-
|
97
|
+
basic_options = [
|
98
|
+
"Pressure",
|
99
|
+
"Temperature",
|
100
|
+
"Salinity",
|
101
|
+
"Depth of Transducer",
|
102
|
+
"Heading",
|
103
|
+
"Pitch",
|
104
|
+
"Roll",
|
105
|
+
]
|
103
106
|
|
104
107
|
|
105
|
-
|
106
|
-
if varname == "Velocity":
|
107
|
-
fillplot_plotly(velocity[beam - 1, :, :], title=varname, xaxis=xaxis)
|
108
|
-
elif varname == "Echo":
|
109
|
-
fillplot_plotly(echo[beam - 1, :, :], title=varname, xaxis=xaxis)
|
110
|
-
elif varname == "Correlation":
|
111
|
-
fillplot_plotly(correlation[beam - 1, :, :], title=varname, xaxis=xaxis)
|
112
|
-
elif varname == "Percent Good":
|
113
|
-
fillplot_plotly(pgood[beam - 1, :, :], title=varname, xaxis=xaxis)
|
108
|
+
st.header("Velocity, Echo Intensity, Correlation & Percent Good", divider="blue")
|
114
109
|
|
115
110
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
bitdata = st.session_state.vlead.bitresult()
|
134
|
-
st.subheader("BIT Result", divider="orange")
|
135
|
-
st.write("""
|
136
|
-
This field contains the results of Workhorse ADCPs builtin test functions.
|
137
|
-
A zero indicates a successful BIT result.
|
138
|
-
""")
|
139
|
-
bitbutton = st.radio("Select a dynamic variable to plot:", bitdata.keys(), horizontal=True)
|
140
|
-
lineplot(bitdata[bitbutton], bitbutton, xaxis=str(xbutton))
|
141
|
-
|
142
|
-
elif adv_option == "ADC Channel":
|
143
|
-
adcdata = st.session_state.vlead.adc_channel()
|
144
|
-
st.subheader("ADC Channel", divider="orange")
|
145
|
-
adcbutton = st.radio("Select a dynamic variable to plot:", adcdata.keys(), horizontal=True)
|
146
|
-
lineplot(adcdata[adcbutton], adcbutton, xaxis=str(xbutton))
|
147
|
-
elif adv_option == "Error Status Word 1":
|
148
|
-
errordata1 = st.session_state.vlead.error_status_word(esw=1)
|
149
|
-
st.subheader("Error Status Word", divider="orange")
|
150
|
-
errorbutton = st.radio("Select a dynamic variable to plot:", errordata1.keys(), horizontal=True)
|
151
|
-
lineplot(errordata1[errorbutton], errorbutton, xaxis=str(xbutton))
|
152
|
-
elif adv_option == "Error Status Word 2":
|
153
|
-
errordata2 = st.session_state.vlead.error_status_word(esw=2)
|
154
|
-
errorbutton = st.radio("Select a dynamic variable to plot:", errordata2.keys(), horizontal=True)
|
155
|
-
lineplot(errordata2[errorbutton], errorbutton, xaxis=str(xbutton))
|
156
|
-
elif adv_option == "Error Status Word 3":
|
157
|
-
errordata3 = st.session_state.vlead.error_status_word(esw=3)
|
158
|
-
errorbutton = st.radio("Select a dynamic variable to plot:", errordata3.keys(), horizontal=True)
|
159
|
-
lineplot(errordata3[errorbutton], errorbutton, xaxis=str(xbutton))
|
160
|
-
elif adv_option == "Error Status Word 4":
|
161
|
-
errordata4 = st.session_state.vlead.error_status_word(esw=4)
|
162
|
-
errorbutton = st.radio("Select a dynamic variable to plot:", errordata4.keys(), horizontal=True)
|
163
|
-
lineplot(errordata4[errorbutton], errorbutton, xaxis=str(xbutton))
|
111
|
+
def call_plot(varname, beam, xaxis="time"):
|
112
|
+
if varname == "Velocity":
|
113
|
+
fillplot_plotly(velocity[beam - 1, :, :], title=varname, xaxis=xaxis)
|
114
|
+
elif varname == "Echo":
|
115
|
+
fillplot_plotly(echo[beam - 1, :, :], title=varname, xaxis=xaxis)
|
116
|
+
elif varname == "Correlation":
|
117
|
+
fillplot_plotly(correlation[beam - 1, :, :], title=varname, xaxis=xaxis)
|
118
|
+
elif varname == "Percent Good":
|
119
|
+
fillplot_plotly(pgood[beam - 1, :, :], title=varname, xaxis=xaxis)
|
120
|
+
|
121
|
+
|
122
|
+
var_option = st.selectbox(
|
123
|
+
"Select a data type", ("Velocity", "Echo", "Correlation", "Percent Good")
|
124
|
+
)
|
125
|
+
beam = st.radio("Select beam", (1, 2, 3, 4), horizontal=True)
|
126
|
+
call_plot(var_option, beam, xaxis=str(xbutton))
|
127
|
+
|
164
128
|
|