pyadps 0.1.0b0__py3-none-any.whl → 0.1.1__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 (50) hide show
  1. pyadps/Home_Page.py +11 -5
  2. pyadps/pages/01_Read_File.py +191 -16
  3. pyadps/pages/02_View_Raw_Data.py +69 -33
  4. pyadps/pages/03_Download_Raw_File.py +161 -60
  5. pyadps/pages/04_Sensor_Health.py +905 -0
  6. pyadps/pages/05_QC_Test.py +476 -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 +587 -0
  10. pyadps/pages/09_Auto_process.py +64 -0
  11. pyadps/pages/__pycache__/__init__.cpython-312.pyc +0 -0
  12. pyadps/utils/__init__.py +3 -3
  13. pyadps/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  14. pyadps/utils/__pycache__/autoprocess.cpython-312.pyc +0 -0
  15. pyadps/utils/__pycache__/cutbin.cpython-312.pyc +0 -0
  16. pyadps/utils/__pycache__/plotgen.cpython-312.pyc +0 -0
  17. pyadps/utils/__pycache__/profile_test.cpython-312.pyc +0 -0
  18. pyadps/utils/__pycache__/pyreadrdi.cpython-312.pyc +0 -0
  19. pyadps/utils/__pycache__/readrdi.cpython-312.pyc +0 -0
  20. pyadps/utils/__pycache__/regrid.cpython-312.pyc +0 -0
  21. pyadps/utils/__pycache__/script.cpython-312.pyc +0 -0
  22. pyadps/utils/__pycache__/sensor_health.cpython-312.pyc +0 -0
  23. pyadps/utils/__pycache__/signal_quality.cpython-312.pyc +0 -0
  24. pyadps/utils/__pycache__/velocity_test.cpython-312.pyc +0 -0
  25. pyadps/utils/__pycache__/writenc.cpython-312.pyc +0 -0
  26. pyadps/utils/autoprocess.py +548 -0
  27. pyadps/utils/metadata/config.ini +99 -0
  28. pyadps/utils/metadata/demo.000 +0 -0
  29. pyadps/utils/plotgen.py +505 -3
  30. pyadps/utils/profile_test.py +526 -145
  31. pyadps/utils/pyreadrdi.py +27 -17
  32. pyadps/utils/readrdi.py +167 -20
  33. pyadps/utils/script.py +197 -147
  34. pyadps/utils/sensor_health.py +120 -0
  35. pyadps/utils/signal_quality.py +344 -24
  36. pyadps/utils/velocity_test.py +103 -20
  37. pyadps/utils/writenc.py +223 -27
  38. {pyadps-0.1.0b0.dist-info → pyadps-0.1.1.dist-info}/METADATA +56 -24
  39. pyadps-0.1.1.dist-info/RECORD +47 -0
  40. {pyadps-0.1.0b0.dist-info → pyadps-0.1.1.dist-info}/WHEEL +1 -1
  41. pyadps-0.1.1.dist-info/entry_points.txt +5 -0
  42. pyadps/pages/04_QC_Test.py +0 -283
  43. pyadps/pages/05_Profile_Test.py +0 -389
  44. pyadps/pages/06_Velocity_Test.py +0 -293
  45. pyadps/pages/07_Write_File.py +0 -367
  46. pyadps/utils/cutbin.py +0 -413
  47. pyadps/utils/regrid.py +0 -122
  48. pyadps-0.1.0b0.dist-info/RECORD +0 -29
  49. pyadps-0.1.0b0.dist-info/entry_points.txt +0 -3
  50. {pyadps-0.1.0b0.dist-info → pyadps-0.1.1.dist-info}/LICENSE +0 -0
pyadps/Home_Page.py CHANGED
@@ -8,16 +8,22 @@ def main():
8
8
  layout="wide",
9
9
  initial_sidebar_state="auto",
10
10
  menu_items={
11
- "Get Help": "http://github.com/p-amol/adps",
12
- "Report a bug": "http://github.com/adps/issues",
11
+ "Get Help": "https://github.com/p-amol/pyadps",
12
+ "Report a bug": "https://github.com/p-amol/pyadps/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
- `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.
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.
20
21
 
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
21
27
  ## Features
22
28
 
23
29
  * Access RDI ADCP binary files using Python 3
@@ -25,8 +31,8 @@ def main():
25
31
  * Process ADCP data
26
32
 
27
33
  ## Contribute
28
- Issue Tracker: http://github.com/adps/issues
29
- Source Code: http://github.com/p-amol/adps
34
+ Issue Tracker: https://github.com/p-amol/pyadps/issues
35
+ Source Code: https://github.com/p-amol/pyadps
30
36
 
31
37
  ## Support
32
38
  If you are having issues, please let us know.
@@ -1,12 +1,15 @@
1
1
  import os
2
2
  import tempfile
3
3
 
4
+ import numpy as np
4
5
  import pandas as pd
5
6
  import streamlit as st
6
7
  import utils.readrdi as rd
7
- import utils.writenc as wr
8
- from streamlit.runtime.state import session_state
9
8
  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")
10
13
 
11
14
  """
12
15
  Streamlit page to load ADCP binary file and display File Header
@@ -110,6 +113,7 @@ if uploaded_file is not None:
110
113
  correlation = ds.correlation.data
111
114
  echo = ds.echo.data
112
115
  pgood = ds.percentgood.data
116
+ beamdir = ds.fixedleader.system_configuration()["Beam Direction"]
113
117
 
114
118
  st.session_state.fname = uploaded_file.name
115
119
  st.session_state.head = ds.fileheader
@@ -119,6 +123,15 @@ if uploaded_file is not None:
119
123
  st.session_state.echo = ds.echo.data
120
124
  st.session_state.correlation = ds.correlation.data
121
125
  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
+ )
122
135
 
123
136
  # st.session_state.flead = flead
124
137
  # st.session_state.vlead = vlead
@@ -132,6 +145,9 @@ if uploaded_file is not None:
132
145
  elif "flead" in st.session_state:
133
146
  st.write("You selected `%s`" % st.session_state.fname)
134
147
  else:
148
+ # reset the cache and resources if the user press reload button.
149
+ st.cache_data.clear()
150
+ st.cache_resource.clear()
135
151
  st.stop()
136
152
 
137
153
  ########## TIME AXIS ##############
@@ -164,8 +180,159 @@ date_df = pd.DataFrame(
164
180
  )
165
181
 
166
182
  st.session_state.date = pd.to_datetime(date_df)
167
-
168
- ######### MASK DATA ##############
183
+ st.session_state.date1 = pd.to_datetime(date_df)
184
+ st.session_state.date2 = pd.to_datetime(date_df)
185
+ st.session_state.date3 = pd.to_datetime(date_df)
186
+ st.session_state.ensemble_axis = np.arange(0, st.session_state.head.ensembles, 1)
187
+ st.session_state.axis_option = "time"
188
+
189
+
190
+ # ---------- Initialize all options -------------
191
+ # ------------------------
192
+ # Page: Download Raw File
193
+ # ------------------------
194
+ # Widgets
195
+ st.session_state.add_attributes_DRW = "No"
196
+ st.session_state.axis_option_DRW = "time"
197
+ st.session_state.rawnc_download_DRW = False
198
+ st.session_state.vleadnc_download_DRW = False
199
+ st.session_state.rawcsv_option_DRW = "Velocity"
200
+ st.session_state.rawcsv_beam_DRW = 1
201
+ st.session_state.rawcsv_download_DRW = False
202
+
203
+ # ------------------
204
+ # Page: Sensor Test
205
+ # ------------------
206
+ st.session_state.isSensorTest = False
207
+ st.session_state.isFirstSensorVisit = True
208
+
209
+ # -- Tab 1: Depth Correction
210
+ st.session_state.isDepthModified_ST = False
211
+ # Widgets
212
+ # Options: "Fixed Value", "File Upload"
213
+ st.session_state.depthoption_ST = "Fixed Value"
214
+ st.session_state.isFixedDepth_ST = False
215
+ st.session_state.fixeddepth_ST = 0
216
+ st.session_state.isUploadDepth_ST = False
217
+
218
+ # -- Tab 2: Salinity Correction
219
+ st.session_state.isSalinityModified_ST = False
220
+ # Widgets
221
+ st.session_state.salinityoption_ST = "Fixed Value"
222
+ st.session_state.isFixedSalinity_ST = False
223
+ st.session_state.fixedsalinity_ST = 35
224
+ st.session_state.isUploadSalinity_ST = False
225
+
226
+ # -- Tab 3: Temperature Correction
227
+ st.session_state.isTemperatureModified_ST = False
228
+ # Widgets
229
+ st.session_state.temperatureoption_ST = "Fixed Value"
230
+ st.session_state.isFixedTemperature_ST = False
231
+ st.session_state.fixedtemperature_ST = 0
232
+ st.session_state.isUploadTemperature_ST = False
233
+
234
+ # -- Tab 7: Pitch, Roll, Velocity Correction
235
+ st.session_state.isRollCheck_ST = False
236
+ st.session_state.isPitchCheck_ST = False
237
+ st.session_state.isVelocityModifiedSound_ST = False
238
+ # Widgets
239
+ st.session_state.roll_cutoff_ST = 359
240
+ st.session_state.pitch_cutoff_ST = 359
241
+
242
+ # ------------------
243
+ # Page: QC Test
244
+ # ------------------
245
+ # Global Test
246
+ st.session_state.isQCTest = False
247
+ st.session_state.isFirstQCVisit = True
248
+
249
+ # Tab 2: Apply QC
250
+ st.session_state.isQCCheck_QCT = False
251
+ # Widgets
252
+ st.session_state.ct_QCT = 64
253
+ st.session_state.et_QCT = 0
254
+ st.session_state.evt_QCT = 2000
255
+ st.session_state.ft_QCT = 50
256
+ st.session_state.is3beam_QCT = True
257
+ st.session_state.pgt_QCT = 0
258
+
259
+ # Data Modifications
260
+ st.session_state.isBeamModified_QCT = False
261
+ # Widgets
262
+ st.session_state.beam_direction_QCT = st.session_state.beam_direction
263
+
264
+ # ------------------
265
+ # Page: Profile Test
266
+ # ------------------
267
+ st.session_state.isProfileTest = False
268
+ st.session_state.isFirstProfileVisit = True
269
+
270
+ # Tab1: Trim Ends
271
+ st.session_state.isTrimEndsCheck_PT = False
272
+ # Widgets
273
+ st.session_state.start_ens_PT = 0
274
+ st.session_state.end_ens_PT = st.session_state.head.ensembles
275
+
276
+ # Tab2: Cutbins - Sidelobe
277
+ st.session_state.isCutBinSideLobeCheck_PT = False
278
+ st.session_state.extra_cells_PT = 0
279
+ st.session_state.water_depth_PT = 0
280
+
281
+ # Tab3: Cutbins - Manual
282
+ st.session_state.isCutBinManualCheck_PT = False
283
+
284
+ # Tab4: Regrid
285
+ st.session_state.isRegridCheck_PT = False
286
+ st.session_state.end_cell_option_PT = "Cell"
287
+ st.session_state.interpolate_PT = "nearest"
288
+ st.session_state.manualdepth_PT = 0
289
+
290
+ # ------------------
291
+ # Page: Velocity Test
292
+ # ------------------
293
+ # Global Test
294
+ st.session_state.isVelocityTest = False
295
+ # Check if visiting the page first time
296
+ st.session_state.isFirstVelocityVisit = True
297
+ # Local Tests:
298
+ # Tab1: Magnetic Declination
299
+ st.session_state.isMagnetCheck_VT = False
300
+ # OPTIONS: pygeomag, API, Manual
301
+ st.session_state.magnet_method_VT = "pygeomag"
302
+ st.session_state.magnet_lat_VT = 0
303
+ st.session_state.magnet_lon_VT = 0
304
+ st.session_state.magnet_year_VT = 2025
305
+ st.session_state.magnet_depth_VT = 0
306
+ st.session_state.magnet_user_input_VT = 0
307
+
308
+ # Tab2: Velocity Cutoff
309
+ st.session_state.isCutoffCheck_VT = False
310
+ st.session_state.maxuvel_VT = 250
311
+ st.session_state.maxvvel_VT = 250
312
+ st.session_state.maxwvel_VT = 15
313
+
314
+ # Tab3: Despike
315
+ st.session_state.isDespikeCheck_VT = False
316
+ st.session_state.despike_kernel_VT = 5
317
+ st.session_state.despike_cutoff_VT = 3
318
+
319
+ # Tab4: Flatline
320
+ st.session_state.isFlatlineCheck_VT = False
321
+ st.session_state.flatline_kernel_VT = 5
322
+ st.session_state.flatline_cutoff_VT = 3
323
+
324
+ # ------------------
325
+ # Page: Write File
326
+ # ------------------
327
+ st.session_state.isWriteFile = True
328
+ st.session_state.isAttributes = False
329
+ st.session_state.mask_data_WF = "Yes"
330
+ # FileTypes: NetCDF, CSV
331
+ st.session_state.file_type_WF = "NetCDF"
332
+ st.session_state.isProcessedNetcdfDownload_WF = True
333
+ st.session_state.isProcessedCSVDownload_WF = False
334
+
335
+ # MASK DATA
169
336
  # The velocity data has missing values due to the cutoff
170
337
  # criteria used before deployment. The `default_mask` uses
171
338
  # the velocity to create a mask. This mask file is stored
@@ -174,16 +341,17 @@ st.session_state.date = pd.to_datetime(date_df)
174
341
  # WARNING: Never Change `st.session_state.orig_mask` in the code!
175
342
  #
176
343
  if "orig_mask" not in st.session_state:
177
- st.session_state.orig_mask = default_mask(
178
- st.session_state.flead, st.session_state.velocity
179
- )
344
+ ds = st.session_state.ds
345
+ st.session_state.orig_mask = default_mask(ds)
180
346
 
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
347
+ # ----------------------
348
+ # Page returning options
349
+ # ----------------------
350
+ # This checks if we have returned back to the page after saving the data
351
+ st.session_state.isSensorPageReturn = False
352
+ st.session_state.isQCPageReturn = False
353
+ st.session_state.isProfilePageReturn = False
354
+ st.session_state.isVelocityPageReturn = False
187
355
 
188
356
  ########## FILE HEADER ###############
189
357
  st.header("File Header", divider="blue")
@@ -260,10 +428,18 @@ if flead_check_button:
260
428
 
261
429
  flead_button = st.button("Fixed Leader")
262
430
  if flead_button:
431
+ # Pandas array should have all elements with same data type.
432
+ # Except Sl. no., which is np.uint64, rest are np.int64.
433
+ # Convert all datatype to uint64
434
+ fl_dict = st.session_state.flead.field().items()
435
+ new_dict = {}
436
+ for key, value in fl_dict:
437
+ new_dict[key] = value.astype(np.uint64)
438
+
263
439
  df = pd.DataFrame(
264
440
  {
265
- "Fields": st.session_state.flead.field().keys(),
266
- "Values": st.session_state.flead.field().values(),
441
+ "Fields": new_dict.keys(),
442
+ "Values": new_dict.values(),
267
443
  }
268
444
  )
269
445
  st.dataframe(df, use_container_width=True)
@@ -281,4 +457,3 @@ with right:
281
457
  df = df.astype("str")
282
458
  st.write((df.style.map(color_bool2)))
283
459
  # st.dataframe(df)
284
-
@@ -84,45 +84,81 @@ 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:
87
90
  # Fixed Leader Plots
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))
91
+ st.header("Fixed Leader", divider="blue")
92
+ fbutton = st.radio("Select a dynamic variable to plot:", fdata.keys(), horizontal=True)
93
+ lineplot(fdata[fbutton], fbutton, xaxis=str(xbutton))
91
94
 
95
+ with tab2:
92
96
  # Variable Leader Plots
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))
96
-
97
- basic_options = [
98
- "Pressure",
99
- "Temperature",
100
- "Salinity",
101
- "Depth of Transducer",
102
- "Heading",
103
- "Pitch",
104
- "Roll",
105
- ]
106
-
97
+ st.header("Variable Leader", divider="blue")
98
+ vbutton = st.radio("Select a dynamic variable to plot:", vdata.keys(), horizontal=True)
99
+ lineplot(vdata[vbutton], vbutton, xaxis=str(xbutton))
107
100
 
108
- st.header("Velocity, Echo Intensity, Correlation & Percent Good", divider="blue")
101
+ with tab1:
102
+ st.header("Velocity, Echo Intensity, Correlation & Percent Good", divider="blue")
109
103
 
110
104
 
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)
105
+ def call_plot(varname, beam, xaxis="time"):
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)
120
114
 
121
115
 
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
-
116
+ var_option = st.selectbox(
117
+ "Select a data type", ("Velocity", "Echo", "Correlation", "Percent Good")
118
+ )
119
+ beam = st.radio("Select beam", (1, 2, 3, 4), horizontal=True)
120
+ call_plot(var_option, beam, xaxis=str(xbutton))
121
+
122
+
123
+ with tab4:
124
+ st.header("Advanced Data", divider="blue")
125
+ adv_option = st.selectbox(
126
+ "Select a data type", ("Bit Result",
127
+ "ADC Channel",
128
+ "Error Status Word 1",
129
+ "Error Status Word 2",
130
+ "Error Status Word 3",
131
+ "Error Status Word 4"))
132
+ if adv_option == "Bit Result":
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))
128
164