pyadps 0.2.1b0__tar.gz → 0.3.1b0__tar.gz

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 (40) hide show
  1. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/PKG-INFO +3 -3
  2. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/pyproject.toml +9 -10
  3. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/pages/01_Read_File.py +92 -17
  4. pyadps-0.3.1b0/src/pyadps/pages/02_View_Raw_Data.py +164 -0
  5. pyadps-0.3.1b0/src/pyadps/pages/04_Sensor_Health.py +892 -0
  6. pyadps-0.3.1b0/src/pyadps/pages/05_QC_Test.py +478 -0
  7. pyadps-0.3.1b0/src/pyadps/pages/06_Profile_Test.py +958 -0
  8. pyadps-0.3.1b0/src/pyadps/pages/07_Velocity_Test.py +599 -0
  9. pyadps-0.2.1b0/src/pyadps/pages/07_Write_File.py → pyadps-0.3.1b0/src/pyadps/pages/08_Write_File.py +130 -52
  10. pyadps-0.3.1b0/src/pyadps/pages/09_Auto_process.py +62 -0
  11. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/__init__.py +2 -3
  12. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/autoprocess.py +228 -46
  13. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/metadata/config.ini +22 -4
  14. pyadps-0.3.1b0/src/pyadps/utils/metadata/demo.000 +0 -0
  15. pyadps-0.2.1b0/src/pyadps/utils/cutbin.py → pyadps-0.3.1b0/src/pyadps/utils/plotgen.py +330 -15
  16. pyadps-0.3.1b0/src/pyadps/utils/profile_test.py +552 -0
  17. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/pyreadrdi.py +13 -6
  18. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/readrdi.py +78 -6
  19. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/script.py +21 -23
  20. pyadps-0.3.1b0/src/pyadps/utils/sensor_health.py +120 -0
  21. pyadps-0.3.1b0/src/pyadps/utils/signal_quality.py +455 -0
  22. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/velocity_test.py +75 -27
  23. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/writenc.py +8 -1
  24. pyadps-0.2.1b0/src/pyadps/pages/02_View_Raw_Data.py +0 -128
  25. pyadps-0.2.1b0/src/pyadps/pages/04_QC_Test.py +0 -334
  26. pyadps-0.2.1b0/src/pyadps/pages/05_Profile_Test.py +0 -575
  27. pyadps-0.2.1b0/src/pyadps/pages/06_Velocity_Test.py +0 -341
  28. pyadps-0.2.1b0/src/pyadps/utils/plotgen.py +0 -229
  29. pyadps-0.2.1b0/src/pyadps/utils/profile_test.py +0 -187
  30. pyadps-0.2.1b0/src/pyadps/utils/regrid.py +0 -279
  31. pyadps-0.2.1b0/src/pyadps/utils/signal_quality.py +0 -135
  32. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/LICENSE +0 -0
  33. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/README.md +0 -0
  34. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/Home_Page.py +0 -0
  35. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/__init__.py +0 -0
  36. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/__main__.py +0 -0
  37. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/pages/03_Download_Raw_File.py +0 -0
  38. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/pages/__init__.py +0 -0
  39. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/metadata/flmeta.json +0 -0
  40. {pyadps-0.2.1b0 → pyadps-0.3.1b0}/src/pyadps/utils/metadata/vlmeta.json +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: pyadps
3
- Version: 0.2.1b0
3
+ Version: 0.3.1b0
4
4
  Summary: A Python package for ADCP data processing
5
5
  Home-page: https://example.com
6
6
  License: MIT
@@ -22,9 +22,9 @@ Requires-Dist: numpy (>=1.26.4)
22
22
  Requires-Dist: pandas (>=2.2.2)
23
23
  Requires-Dist: plotly (>=5.22.0)
24
24
  Requires-Dist: plotly-resampler (>=0.10.0)
25
+ Requires-Dist: pygeomag (>=1.1.0,<2.0.0)
25
26
  Requires-Dist: scipy (>=1.14.0)
26
27
  Requires-Dist: streamlit (>=1.36.0)
27
- Requires-Dist: wmm2020 (>=1.1.1)
28
28
  Project-URL: Documentation, https://example.com/docs
29
29
  Project-URL: Repository, https://github.com/p-amol/pyadps
30
30
  Description-Content-Type: text/markdown
@@ -1,19 +1,19 @@
1
1
  [tool.poetry]
2
2
  name = "pyadps"
3
- version = "0.2.1-beta"
3
+ version = "0.3.1-beta"
4
4
  description = "A Python package for ADCP data processing"
5
5
  authors = ["P. Amol <prakashamol@gmail.com>"]
6
6
  readme = "README.md"
7
7
  license = "MIT"
8
- homepage = "https://example.com" # You can add your homepage URL or GitHub URL here
9
- repository = "https://github.com/p-amol/pyadps" # Replace with your repository link
10
- documentation = "https://example.com/docs" # Optional documentation link
8
+ homepage = "https://example.com" # You can add your homepage URL or GitHub URL here
9
+ repository = "https://github.com/p-amol/pyadps" # Replace with your repository link
10
+ documentation = "https://example.com/docs" # Optional documentation link
11
11
  keywords = ["adcp", "data-processing", "oceanography"]
12
12
  include = ["utils/metadata/*.json"]
13
13
  classifiers = [
14
- "Programming Language :: Python :: 3",
15
- "License :: OSI Approved :: MIT License",
16
- "Operating System :: OS Independent"
14
+ "Programming Language :: Python :: 3",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Operating System :: OS Independent",
17
17
  ]
18
18
 
19
19
 
@@ -23,13 +23,14 @@ streamlit = ">=1.36.0"
23
23
  numpy = ">=1.26.4"
24
24
  matplotlib = ">=3.8.4"
25
25
  scipy = ">=1.14.0"
26
- wmm2020 = ">=1.1.1"
27
26
  cmake = ">=3.30.2"
28
27
  pandas = ">=2.2.2"
29
28
  netCDF4 = ">=1.7.1"
30
29
  plotly = ">=5.22.0"
31
30
  plotly-resampler = ">=0.10.0"
32
31
  meson = ">=1.4.1"
32
+ pygeomag = "^1.1.0"
33
+
33
34
 
34
35
  [tool.poetry.extras]
35
36
  tests = ["pytest"]
@@ -41,5 +42,3 @@ run-auto = "pyadps.utils.autoprocess:main"
41
42
  [build-system]
42
43
  requires = ["poetry-core>=1.0.0"]
43
44
  build-backend = "poetry.core.masonry.api"
44
-
45
-
@@ -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,7 +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
113
- beamdir = ds.fixedleader.system_configuration()['Beam Direction']
116
+ beamdir = ds.fixedleader.system_configuration()["Beam Direction"]
114
117
 
115
118
  st.session_state.fname = uploaded_file.name
116
119
  st.session_state.head = ds.fileheader
@@ -121,6 +124,14 @@ if uploaded_file is not None:
121
124
  st.session_state.correlation = ds.correlation.data
122
125
  st.session_state.pgood = ds.percentgood.data
123
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
+ )
124
135
 
125
136
  # st.session_state.flead = flead
126
137
  # st.session_state.vlead = vlead
@@ -134,6 +145,9 @@ if uploaded_file is not None:
134
145
  elif "flead" in st.session_state:
135
146
  st.write("You selected `%s`" % st.session_state.fname)
136
147
  else:
148
+ # reset the cache and resources if the user press reload button.
149
+ st.cache_data.clear()
150
+ st.cache_resource.clear()
137
151
  st.stop()
138
152
 
139
153
  ########## TIME AXIS ##############
@@ -168,10 +182,63 @@ date_df = pd.DataFrame(
168
182
  st.session_state.date = pd.to_datetime(date_df)
169
183
  st.session_state.date1 = pd.to_datetime(date_df)
170
184
  st.session_state.date2 = pd.to_datetime(date_df)
185
+ st.session_state.ensemble_axis = np.arange(0, st.session_state.head.ensembles, 1)
171
186
 
172
187
 
173
-
174
- ######### MASK DATA ##############
188
+ # ---------- Initialize all options -------------
189
+ # ------------------
190
+ # Global Tests
191
+ # ------------------
192
+ # Checks if the following tests are carried out
193
+ st.session_state.isSensorTest = False
194
+ st.session_state.isQCTest = False
195
+ st.session_state.isProfileTest = False
196
+ st.session_state.isGrid = False
197
+ st.session_state.isGridSave = False
198
+ st.session_state.isVelocityTest = False
199
+
200
+ # Check if visiting the page first time
201
+ st.session_state.isFirstSensorVisit = True
202
+ st.session_state.isFirstQCVisit = True
203
+ st.session_state.isFirstProfileVisit = True
204
+ st.session_state.isFirstVelocityVisit = True
205
+ # ------------------
206
+ # Local Tests:
207
+ # ------------------
208
+ st.session_state.isRollCheck = False
209
+ st.session_state.isPitchCheck = False
210
+
211
+ st.session_state.isQCCheck = False
212
+ st.session_state.isBeamModified = False
213
+
214
+ st.session_state.isTrimEndsCheck = False
215
+ st.session_state.isCutBinSideLobeCheck = False
216
+ st.session_state.isCutBinManualCheck = False
217
+ st.session_state.isRegridCheck = False
218
+
219
+ st.session_state.isMagnetCheck = False
220
+ st.session_state.isDespikeCheck = False
221
+ st.session_state.isFlatlineCheck = False
222
+ st.session_state.isCutoffCheck = False
223
+
224
+
225
+ # ------------------
226
+ # Data Modifications
227
+ # ------------------
228
+ # SENSOR TEST
229
+ # Velocity Modified Based on Sound
230
+ st.session_state.isVelocityModifiedSound = False
231
+ # Transducer depth modified based on Pressure sensor
232
+ st.session_state.isDepthModified = False
233
+ st.session_state.isTemperatureModified = False
234
+ st.session_state.isSalinityModified = False
235
+ # QC TEST
236
+ st.session_state.isBeamModified = False
237
+ # VELOCITY TEST
238
+ # Velocity Modified based on magnetic declination
239
+ st.session_state.isVelocityModifiedMagnet = False
240
+
241
+ # MASK DATA
175
242
  # The velocity data has missing values due to the cutoff
176
243
  # criteria used before deployment. The `default_mask` uses
177
244
  # the velocity to create a mask. This mask file is stored
@@ -180,16 +247,17 @@ st.session_state.date2 = pd.to_datetime(date_df)
180
247
  # WARNING: Never Change `st.session_state.orig_mask` in the code!
181
248
  #
182
249
  if "orig_mask" not in st.session_state:
183
- st.session_state.orig_mask = default_mask(
184
- st.session_state.flead, st.session_state.velocity
185
- )
250
+ ds = st.session_state.ds
251
+ st.session_state.orig_mask = default_mask(ds)
186
252
 
187
- # Checks if the following quality checks are carried out
188
- st.session_state.isQCMask = False
189
- st.session_state.isProfileMask = False
190
- st.session_state.isGrid = False
191
- st.session_state.isGridSave = False
192
- st.session_state.isVelocityMask = False
253
+ # ----------------------
254
+ # Page returning options
255
+ # ----------------------
256
+ # This checks if we have returned back to the page after saving the data
257
+ st.session_state.isSensorPageReturn = False
258
+ st.session_state.isQCPageReturn = False
259
+ st.session_state.isProfilePageReturn = False
260
+ st.session_state.isVelocityPageReturn = False
193
261
 
194
262
  ########## FILE HEADER ###############
195
263
  st.header("File Header", divider="blue")
@@ -266,10 +334,18 @@ if flead_check_button:
266
334
 
267
335
  flead_button = st.button("Fixed Leader")
268
336
  if flead_button:
337
+ # Pandas array should have all elements with same data type.
338
+ # Except Sl. no., which is np.uint64, rest are np.int64.
339
+ # Convert all datatype to uint64
340
+ fl_dict = st.session_state.flead.field().items()
341
+ new_dict = {}
342
+ for key, value in fl_dict:
343
+ new_dict[key] = value.astype(np.uint64)
344
+
269
345
  df = pd.DataFrame(
270
346
  {
271
- "Fields": st.session_state.flead.field().keys(),
272
- "Values": st.session_state.flead.field().values(),
347
+ "Fields": new_dict.keys(),
348
+ "Values": new_dict.values(),
273
349
  }
274
350
  )
275
351
  st.dataframe(df, use_container_width=True)
@@ -287,4 +363,3 @@ with right:
287
363
  df = df.astype("str")
288
364
  st.write((df.style.map(color_bool2)))
289
365
  # st.dataframe(df)
290
-
@@ -0,0 +1,164 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ import pandas as pd
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ import streamlit as st
7
+ from plotly_resampler import FigureResampler
8
+
9
+ if "flead" not in st.session_state:
10
+ st.write(":red[Please Select Data!]")
11
+ st.stop()
12
+
13
+ # Load data
14
+ fdata = st.session_state.flead.fleader
15
+ vdata = st.session_state.vlead.vleader
16
+ velocity = st.session_state.velocity
17
+ echo = st.session_state.echo
18
+ correlation = st.session_state.correlation
19
+ pgood = st.session_state.pgood
20
+
21
+ x = np.arange(0, st.session_state.head.ensembles, 1)
22
+ y = np.arange(0, fdata["Cells"][0], 1)
23
+
24
+ X, Y = np.meshgrid(x, y)
25
+
26
+
27
+ @st.cache_data
28
+ def fillplot_matplotlib(data):
29
+ fig, ax = plt.subplots()
30
+ cs = ax.contourf(X, Y, data)
31
+ fig.colorbar(cs)
32
+ st.pyplot(fig)
33
+
34
+
35
+ @st.cache_data
36
+ def fillplot_plotly(data, colorscale="balance", title="Data", xaxis="time"):
37
+ if xaxis == "time":
38
+ xdata = st.session_state.date
39
+ elif xaxis == "ensemble":
40
+ xdata = x
41
+ else:
42
+ xdata = x
43
+ fig = FigureResampler(go.Figure())
44
+ data1 = np.where(data == -32768, np.nan, data)
45
+ fig.add_trace(
46
+ go.Heatmap(
47
+ z=data1[:, 0:-1],
48
+ x=xdata,
49
+ y=y,
50
+ colorscale=colorscale,
51
+ hoverongaps=False,
52
+ )
53
+ )
54
+ fig.update_layout(
55
+ xaxis=dict(showline=True, mirror=True),
56
+ yaxis=dict(showline=True, mirror=True),
57
+ title_text=title,
58
+ )
59
+ st.plotly_chart(fig)
60
+
61
+
62
+ @st.cache_data
63
+ def lineplot(data, title, xaxis="time"):
64
+ if xaxis == "time":
65
+ df = pd.DataFrame({"date": st.session_state.date, title: data})
66
+ fig = px.line(df, x="date", y=title)
67
+ else:
68
+ df = pd.DataFrame({"ensemble": x, title: data})
69
+ fig = px.line(df, x="ensemble", y=title)
70
+
71
+ st.plotly_chart(fig)
72
+
73
+
74
+ # Introduction
75
+ st.header("View Raw Data", divider="orange")
76
+ st.write(
77
+ """
78
+ Displays all variables available in the raw file. No processing has been carried out.
79
+ Data might be missing because of the quality-check criteria used before deployment.\n
80
+ Either `time` or `ensemble` axis can be chosen as the abscissa (x-axis).
81
+ The ordinate (y-axis) for the heatmap is `bins` as the depth correction is not applied.
82
+ """
83
+ )
84
+ xbutton = st.radio("Select an x-axis to plot", ["time", "ensemble"], horizontal=True)
85
+
86
+
87
+ tab1, tab2, tab3, tab4 = st.tabs(["Primary Data", "Variable Leader", "Fixed Leader", "Advanced"])
88
+
89
+ with tab3:
90
+ # Fixed Leader Plots
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))
94
+
95
+ with tab2:
96
+ # Variable Leader Plots
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))
100
+
101
+ with tab1:
102
+ st.header("Velocity, Echo Intensity, Correlation & Percent Good", divider="blue")
103
+
104
+
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)
114
+
115
+
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))
164
+