pyadps 0.1.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.
@@ -0,0 +1,731 @@
1
+ import numpy as np
2
+ import matplotlib as mpl
3
+ import matplotlib.pyplot as plt
4
+ from matplotlib.widgets import Button, RadioButtons, Slider, TextBox
5
+ from matplotlib.widgets import RectangleSelector
6
+
7
+ mpl.use("TkAgg")
8
+
9
+
10
+ class CutBins:
11
+ def __init__(
12
+ self, data, mask, newmask=False, t1=0, t2=200, tinc=500, z1=0, z2=-1, zinc=0
13
+ ):
14
+ # DATA SETUP
15
+ self.orig_data = np.uint16(data)
16
+ self.orig_shape = np.shape(self.orig_data)
17
+ self.fill = 999
18
+ self.maskarray = mask
19
+ if not newmask:
20
+ self.orig_data[self.maskarray == 1] = self.fill
21
+
22
+ self.t1, self.t2, self.tinc = t1, t2, tinc
23
+ self.z1, self.z2, self.zinc = z1, z2, zinc
24
+ if z2 == -1:
25
+ self.z2 = self.orig_shape[0]
26
+
27
+ self.data = self.orig_data[self.z1 : self.z2, self.t1 : self.t2]
28
+ self.orig_subset = self.orig_data[self.z1 : self.z2, self.t1 : self.t2]
29
+ self.datacopy = np.copy(self.orig_data)
30
+ self.datamin = np.min(self.orig_data)
31
+ self.datamax = np.max(self.orig_data)
32
+ self.shape = np.shape(self.data)
33
+
34
+ # PLOT SETUP
35
+ self.t = np.arange(self.t1, self.t2)
36
+ self.z = np.arange(self.z1, self.z2)
37
+ self.tickinterval = int((self.t2 - self.t1) / 5)
38
+ self.xticks = np.arange(self.t1, self.t2, self.tickinterval)
39
+ self.X, self.Y = np.meshgrid(self.t, self.z)
40
+ self.fig, self.axs = plt.subplot_mosaic(
41
+ [["a", "b"], ["c", "b"]],
42
+ figsize=(12, 10),
43
+ width_ratios=[2, 1],
44
+ height_ratios=[1.75, 1],
45
+ )
46
+ self.fig.set_facecolor("darkgrey")
47
+ plt.subplots_adjust(top=0.82, right=0.95)
48
+
49
+ # ADDING WIDGET AXES
50
+ self.ax_clear_button = self.fig.add_axes(rect=(0.125, 0.90, 0.08, 0.025))
51
+ self.ax_delete_button = self.fig.add_axes(rect=(0.225, 0.90, 0.08, 0.025))
52
+ self.ax_refill_button = self.fig.add_axes(rect=(0.325, 0.90, 0.08, 0.025))
53
+ self.ax_next_button = self.fig.add_axes(rect=(0.630, 0.65, 0.02, 0.050))
54
+ self.ax_previous_button = self.fig.add_axes(rect=(0.075, 0.65, 0.02, 0.050))
55
+ self.ax_radio_button = self.fig.add_axes(rect=(0.725, 0.87, 0.10, 0.10))
56
+ self.ax_exit_button = self.fig.add_axes(rect=(0.825, 0.025, 0.08, 0.035))
57
+ self.ax_hslider = self.fig.add_axes(rect=(0.125, 0.85, 0.50, 0.03))
58
+ self.ax_vslider = self.fig.add_axes(rect=(0.04, 0.25, 0.03, 0.50))
59
+
60
+ self.ax_delete_button.set_visible(False)
61
+ self.ax_refill_button.set_visible(False)
62
+
63
+ # --- Slider settings ---
64
+ # Initial slider settings
65
+ self.hevent = 0
66
+ self.vevent = 0
67
+
68
+ # Slider options
69
+ self.hslider = Slider(
70
+ ax=self.ax_hslider,
71
+ label="Ensemble",
72
+ valmin=self.t1,
73
+ valmax=self.t2,
74
+ valinit=self.hevent,
75
+ valfmt="%i",
76
+ valstep=1,
77
+ )
78
+
79
+ self.vslider = Slider(
80
+ ax=self.ax_vslider,
81
+ label="Bins",
82
+ valmin=self.z1,
83
+ valmax=self.z2,
84
+ valinit=self.vevent,
85
+ valfmt="%i",
86
+ valstep=1,
87
+ orientation="vertical",
88
+ )
89
+
90
+ # Button Labels
91
+ self.clear_button = Button(self.ax_clear_button, "Clear")
92
+ self.delete_button = Button(self.ax_delete_button, "Delete")
93
+ self.refill_button = Button(self.ax_refill_button, "Refill")
94
+ self.previous_button = Button(self.ax_previous_button, "<")
95
+ self.next_button = Button(self.ax_next_button, ">")
96
+ self.exit_button = Button(self.ax_exit_button, "Save & Exit")
97
+ # self.cell_button = Button(self.ax_cell_button, "Cell")
98
+ # self.ensemble_button = Button(self.ax_ensemble_button, "Ensemble")
99
+ self.radio_button = RadioButtons(
100
+ self.ax_radio_button, ("Bin", "Ensemble", "Cell", "Region")
101
+ )
102
+
103
+ # --------------PLOTS---------------------
104
+
105
+ # Settings colorbar extreme to black
106
+ cmap = mpl.cm.turbo.with_extremes(over="k")
107
+ # FILL PLOT
108
+ self.mesh = self.axs["a"].pcolormesh(
109
+ self.X, self.Y, self.data, cmap=cmap, picker=True, vmin=0, vmax=255
110
+ )
111
+ plt.colorbar(self.mesh, orientation="horizontal")
112
+ self.axs["a"].set_xlim([self.t1, self.t2])
113
+ self.axs["a"].set_ylim([self.z1, self.z2])
114
+ # Draw vertical and horizontal lines
115
+ (self.vline,) = self.axs["a"].plot(
116
+ [self.t1, self.t1], [self.z1, self.z2], color="r", linewidth=2.5
117
+ )
118
+ (self.hline,) = self.axs["a"].plot(
119
+ [self.t1, self.t2], [self.z1, self.z1], color="r", linewidth=2.5
120
+ )
121
+
122
+ # PROFILE
123
+ (self.profile,) = self.axs["b"].plot(
124
+ self.data[self.z1 : self.z2, self.t1 + self.hevent], range(self.z1, self.z2)
125
+ )
126
+
127
+ self.axs["b"].set_xlim([self.datamin, self.datamax])
128
+ self.profile_text = self.axs["b"].text(
129
+ 0.95,
130
+ 0.95,
131
+ f"Ensemble No.: {self.t1 + self.hevent}",
132
+ verticalalignment="bottom",
133
+ horizontalalignment="right",
134
+ transform=self.axs["b"].transAxes,
135
+ color="k",
136
+ fontsize=12,
137
+ )
138
+
139
+ # TIME SERIES
140
+ (self.tseries,) = self.axs["c"].plot(
141
+ range(self.t1, self.t2), self.data[self.z1 + self.vevent, self.t1 : self.t2]
142
+ )
143
+ self.axs["c"].set_ylim([self.datamin, self.datamax])
144
+ self.tseries_text = self.axs["c"].text(
145
+ 0.90,
146
+ 0.90,
147
+ f"Bin No.: {self.z1 + self.vevent}",
148
+ verticalalignment="bottom",
149
+ horizontalalignment="right",
150
+ transform=self.axs["c"].transAxes,
151
+ color="k",
152
+ fontsize=12,
153
+ )
154
+ # --------------END PLOTS---------------------
155
+
156
+ # EVENTS
157
+ self.onclick = self.onclick_bin
158
+ self.hslider.on_changed(self.hupdate)
159
+ self.vslider.on_changed(self.vupdate)
160
+ self.clear_button.on_clicked(self.clear)
161
+ self.radio_button.on_clicked(self.radio)
162
+ self.cid = self.fig.canvas.mpl_connect("pick_event", self.onclick)
163
+
164
+ self.delete_button.on_clicked(self.boxdelete)
165
+ self.refill_button.on_clicked(self.boxrefill)
166
+ self.next_button.on_clicked(self.next)
167
+ self.previous_button.on_clicked(self.previous)
168
+ self.exit_button.on_clicked(self.exit)
169
+
170
+ def next(self, event):
171
+ if self.t2 <= self.orig_shape[1]:
172
+ # Next works till the last subset. The if statement checks for last subset.
173
+ self.t1 = self.t1 + self.tinc
174
+ self.t2 = self.t2 + self.tinc
175
+ if self.t2 > (self.orig_shape[1]):
176
+ # If in last subset create a dummy data set with missing value.
177
+ self.data = self.datacopy[
178
+ self.z1 : self.z2, self.t1 : self.orig_shape[1]
179
+ ]
180
+ self.orig_subset = self.orig_data[
181
+ self.z1 : self.z2, self.t1 : self.orig_shape[1]
182
+ ]
183
+ self.missing = (
184
+ np.ones((self.z2 - self.z1, self.t2 - self.orig_shape[1]))
185
+ * self.fill
186
+ )
187
+ # self.data consist of data along with flagged value
188
+ self.data = np.append(self.data, self.missing, axis=1)
189
+ # self.orig_subset contains only the subset of the original data
190
+ # Useful for plotting time series and profiles
191
+ self.orig_subset = np.append(self.orig_subset, self.missing, axis=1)
192
+ else:
193
+ self.data = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
194
+ self.orig_subset = self.orig_data[self.z1 : self.z2, self.t1 : self.t2]
195
+
196
+ self.mesh.set_array(self.data)
197
+ self.tick = np.arange(self.t1, self.t2, self.tickinterval)
198
+ self.axs["a"].set_xticks(self.xticks, self.tick)
199
+
200
+ self.profile.set_xdata(self.orig_subset[:, self.hevent])
201
+ self.profile_text.set_text(f"Ensemble No.: {self.t1 + self.hevent}")
202
+ self.vline.set_xdata([self.hevent, self.hevent])
203
+
204
+ self.tseries.set_ydata(self.orig_subset[self.vevent, :])
205
+ self.tseries_text.set_text(f"Bin No.: {self.z1 + self.vevent}")
206
+ self.hline.set_ydata([self.vevent, self.vevent])
207
+
208
+ self.fig.canvas.draw()
209
+
210
+ def previous(self, event):
211
+ if self.t1 >= self.tinc:
212
+ self.t1 = self.t1 - self.tinc
213
+ self.t2 = self.t2 - self.tinc
214
+ self.tick = np.arange(self.t1, self.t2, self.tickinterval)
215
+ self.data = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
216
+ self.axs["a"].set_xticks(self.xticks, self.tick)
217
+ self.mesh.set_array(self.data)
218
+
219
+ # Reset sliders
220
+ self.profile.set_xdata(self.orig_data[self.z1 : self.z2, self.hevent])
221
+ self.profile_text.set_text(f"Ensemble No.: {self.hevent}")
222
+ self.vline.set_xdata([self.hevent, self.hevent])
223
+
224
+ self.tseries.set_ydata(self.orig_data[self.vevent, self.t1 : self.t2])
225
+ self.tseries_text.set_text(f"Bin No.: {self.z1 + self.vevent}")
226
+ self.hline.set_ydata([self.vevent, self.vevent])
227
+
228
+ self.fig.canvas.draw()
229
+
230
+ def radio(self, event):
231
+ self.fig.canvas.mpl_disconnect(self.cid)
232
+ if event == "Bin":
233
+ self.cid = self.fig.canvas.mpl_connect("pick_event", self.onclick_bin)
234
+ elif event == "Ensemble":
235
+ self.cid = self.fig.canvas.mpl_connect("pick_event", self.onclick_ens)
236
+ elif event == "Cell":
237
+ self.cid = self.fig.canvas.mpl_connect("pick_event", self.onclick_cell)
238
+ else:
239
+ self.rid = RectangleSelector(
240
+ self.axs["a"],
241
+ self.onclick_box,
242
+ useblit=True,
243
+ minspanx=2,
244
+ minspany=2,
245
+ interactive=True,
246
+ )
247
+
248
+ def clear(self, event):
249
+ if event.button == 1:
250
+ self.datacopy = np.copy(self.orig_data)
251
+ if self.t2 >= (self.orig_shape[1]):
252
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
253
+ test = np.append(test, self.missing, axis=1)
254
+ else:
255
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
256
+
257
+ # self.mesh.set_array(self.datacopy[self.z1 : self.z2, self.t1 : self.t2])
258
+ self.mesh.set_array(test)
259
+ self.fig.canvas.draw()
260
+
261
+ def hupdate(self, event):
262
+ self.hevent = event
263
+ self.profile.set_xdata(self.orig_subset[:, self.hevent])
264
+ self.profile_text.set_text(f"Ensemble No.: {self.t1 + self.hevent}")
265
+ self.vline.set_xdata([self.hevent, self.hevent])
266
+
267
+ def vupdate(self, event):
268
+ self.vevent = event
269
+ self.tseries.set_ydata(self.orig_subset[self.vevent, :])
270
+ self.tseries_text.set_text(f"Bin No.: {self.z1 + self.vevent}")
271
+ self.hline.set_ydata([self.vevent, self.vevent])
272
+
273
+ def onclick_bin(self, event):
274
+ ind = event.ind
275
+ x = ind // (self.t[-1] + 1)
276
+ # y = ind % (self.t[-1] + 1)
277
+ xx = self.z1 + x
278
+ # yy = self.t1 + y
279
+ if np.all(self.datacopy[xx, :] == self.fill):
280
+ self.datacopy[xx, :] = np.copy(self.orig_data[xx, :])
281
+
282
+ else:
283
+ self.datacopy[xx, :] = self.fill
284
+
285
+ if self.t2 >= (self.orig_shape[1]):
286
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
287
+ test = np.append(test, self.missing, axis=1)
288
+ else:
289
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
290
+
291
+ # self.mesh.set_array(self.datacopy[self.z1 : self.z2, self.t1 : self.t2])
292
+ self.mesh.set_array(test)
293
+ self.hline.set_ydata([x, x])
294
+ self.vslider.set_val(x[0])
295
+ self.fig.canvas.draw()
296
+
297
+ def onclick_ens(self, event):
298
+ ind = event.ind
299
+ if np.size(ind) != 1:
300
+ return
301
+ # x = ind // (self.t[-1] + 1)
302
+ y = ind % (self.t[-1] + 1)
303
+ yy = self.t1 + y
304
+
305
+ if yy < self.orig_shape[1]:
306
+ if np.all(self.datacopy[:, yy] == self.fill):
307
+ self.datacopy[:, yy] = np.copy(self.orig_data[:, yy])
308
+ else:
309
+ self.datacopy[:, yy] = self.fill
310
+
311
+ if self.t2 >= (self.orig_shape[1]):
312
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
313
+ test = np.append(test, self.missing, axis=1)
314
+ else:
315
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
316
+ # self.mesh.set_array(self.datacopy[self.z1 : self.z2, self.t1 : self.t2])
317
+ self.mesh.set_array(test)
318
+ self.hline.set_xdata([y, y])
319
+ self.hslider.set_val(y[0])
320
+ self.fig.canvas.draw()
321
+
322
+ def onclick_cell(self, event):
323
+ ind = event.ind
324
+ if np.size(ind) != 1:
325
+ return
326
+ x = ind // (self.t[-1] + 1)
327
+ y = ind % (self.t[-1] + 1)
328
+ xx = self.z1 + x
329
+ yy = self.t1 + y
330
+
331
+ if yy < self.orig_shape[1]:
332
+ if self.datacopy[xx, yy] == self.fill:
333
+ self.datacopy[xx, yy] = np.copy(self.orig_data[x, y])
334
+ else:
335
+ self.datacopy[xx, yy] = self.fill
336
+
337
+ if self.t2 > (self.orig_shape[1]):
338
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
339
+ test = np.append(test, self.missing, axis=1)
340
+ else:
341
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
342
+
343
+ # self.mesh.set_array(self.datacopy[self.z1 : self.z2, self.t1 : self.t2])
344
+ self.mesh.set_array(test)
345
+ self.vline.set_xdata([y, y])
346
+ self.hline.set_ydata([x, x])
347
+ self.hslider.set_val(y[0])
348
+ self.vslider.set_val(x[0])
349
+ self.fig.canvas.draw()
350
+
351
+ def onclick_box(self, eclick, erelease):
352
+ self.ax_delete_button.set_visible(True)
353
+ self.ax_refill_button.set_visible(True)
354
+ plt.gcf().canvas.draw()
355
+ self.x11, self.y11 = int(eclick.xdata), int(eclick.ydata)
356
+ self.x22, self.y22 = int(erelease.xdata) + 1, int(erelease.ydata) + 1
357
+
358
+ print(
359
+ f"({self.x11:3.2f}, {self.y11:3.2f}) --> ({self.x22:3.2f}, {self.y22:3.2f})"
360
+ )
361
+ print(f" The buttons you used were: {eclick.button} {erelease.button}")
362
+
363
+ def boxdelete(self, event):
364
+ z1 = self.z1 + self.y11 + 1
365
+ z2 = self.z1 + self.y22
366
+ t1 = self.t1 + self.x11 + 1
367
+ t2 = self.t1 + self.x22
368
+ self.datacopy[z1:z2, t1:t2] = self.fill
369
+
370
+ if self.t2 > (self.orig_shape[1]):
371
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
372
+ test = np.append(test, self.missing, axis=1)
373
+ else:
374
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
375
+
376
+ # self.mesh.set_array(self.datacopy[self.z1 : self.z2, self.t1 : self.t2])
377
+ self.mesh.set_array(test)
378
+ self.fig.canvas.draw()
379
+
380
+ def boxrefill(self, event):
381
+ z1 = self.z1 + self.y11 + 1
382
+ z2 = self.z1 + self.y22
383
+ t1 = self.t1 + self.x11 + 1
384
+ t2 = self.t1 + self.x22
385
+ self.datacopy[z1:z2, t1:t2] = self.orig_data[z1:z2, t1:t2]
386
+
387
+ if self.t2 > (self.orig_shape[1]):
388
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
389
+ test = np.append(test, self.missing, axis=1)
390
+ else:
391
+ test = self.datacopy[self.z1 : self.z2, self.t1 : self.t2]
392
+ # self.mesh.set_array(self.datacopy[self.z1 : self.z2, self.t1 : self.t2])
393
+ self.mesh.set_array(test)
394
+ self.fig.canvas.draw()
395
+
396
+ def exit(self, event):
397
+ plt.close()
398
+
399
+ def mask(self):
400
+ self.maskarray[self.datacopy == self.fill] = 1
401
+ return self.maskarray
402
+
403
+
404
+ class PlotEnds:
405
+ def __init__(self, pressure, delta=10):
406
+ self.dep = pressure / 980
407
+
408
+ self.n = np.size(self.dep)
409
+ self.delta = delta
410
+ self.nmin = 0
411
+ self.nmax = self.nmin + self.delta
412
+ self.mmax = 0
413
+ self.mmin = self.mmax - self.delta
414
+
415
+ self.x = np.arange(0, self.n)
416
+
417
+ self.start_ens = 0
418
+ self.end_ens = 0
419
+
420
+ self.fig, self.axs = plt.subplots(1, 2, figsize=(12, 8))
421
+ self.fig.set_facecolor("darkgrey")
422
+ plt.subplots_adjust(bottom=0.28, right=0.72)
423
+
424
+ self.ax_end = self.fig.add_axes(rect=(0.25, 0.08, 0.47, 0.03))
425
+ self.ax_start = self.fig.add_axes(rect=(0.25, 0.15, 0.47, 0.03))
426
+ self.ax_button = self.fig.add_axes(rect=(0.81, 0.05, 0.15, 0.075))
427
+ # self.ax_depmaxbutton = self.fig.add_axes(rect=(0.68, 0.13, 0.04, 0.02))
428
+ # self.ax_depminbutton = self.fig.add_axes(rect=(0.25, 0.13, 0.04, 0.02))
429
+ # self.ax_recmaxbutton = self.fig.add_axes(rect=(0.68, 0.06, 0.04, 0.02))
430
+ # self.ax_recminbutton = self.fig.add_axes(rect=(0.25, 0.06, 0.04, 0.02))
431
+
432
+ # Plot
433
+ self.axs[0].scatter(self.x, self.dep, color="k")
434
+ self.axs[1].scatter(self.x, self.dep, color="k")
435
+
436
+ # Figure Labels
437
+ for i in range(2):
438
+ self.axs[i].set_xlabel("Ensemble")
439
+ self.axs[0].set_xlim([self.nmin - 1, self.nmax])
440
+ self.axs[1].set_xlim([self.n - self.delta, self.n])
441
+ self.axs[0].set_ylabel("Depth (m)")
442
+ self.fig.suptitle("Trim Ends")
443
+
444
+ # Display statistics
445
+ self.axs[0].text(0.82, 0.60, "Statistics", transform=plt.gcf().transFigure)
446
+ self.max = np.round(np.max(self.dep), decimals=2)
447
+ self.min = np.round(np.min(self.dep), decimals=2)
448
+ self.median = np.round(np.median(self.dep), decimals=2)
449
+ self.mean = np.round(np.mean(self.dep), decimals=2)
450
+ self.t1 = self.axs[0].text(
451
+ 0.75,
452
+ 0.50,
453
+ f"Dep. Max = {self.max} \nDep. Min = {self.min} \nDep. Median = {self.median}",
454
+ transform=plt.gcf().transFigure,
455
+ )
456
+
457
+ self.sl_start = Slider(
458
+ ax=self.ax_start,
459
+ label="Dep. Ensemble",
460
+ valmin=self.nmin,
461
+ valmax=self.nmax,
462
+ valinit=0,
463
+ valfmt="%i",
464
+ valstep=1,
465
+ )
466
+
467
+ self.sl_end = Slider(
468
+ ax=self.ax_end,
469
+ label="Rec. Ensemble",
470
+ valmin=self.mmin,
471
+ valmax=self.mmax,
472
+ valinit=0,
473
+ valfmt="%i",
474
+ valstep=1,
475
+ )
476
+
477
+ self.sl_start.on_changed(self.update1)
478
+ self.sl_end.on_changed(self.update2)
479
+ self.button = Button(self.ax_button, "Save & Exit")
480
+ # self.depminbutton = Button(self.ax_depminbutton, "<<")
481
+ # self.depmaxbutton = Button(self.ax_depmaxbutton, ">>")
482
+ # self.recminbutton = Button(self.ax_recminbutton, "<<")
483
+ # self.recmaxbutton = Button(self.ax_recmaxbutton, ">>")
484
+
485
+ self.button.on_clicked(self.exitwin)
486
+
487
+ def update1(self, value):
488
+ self.axs[0].scatter(self.x, self.dep, color="k")
489
+ self.axs[0].scatter(self.x[0:value], self.dep[0:value], color="r")
490
+ self.start_ens = value
491
+
492
+ def update2(self, value):
493
+ self.axs[1].scatter(self.x, self.dep, color="k")
494
+ if value < 0:
495
+ self.axs[1].scatter(
496
+ self.x[self.n + value : self.n],
497
+ self.dep[self.n + value : self.n],
498
+ color="r",
499
+ )
500
+ self.end_ens = value
501
+
502
+ def show(self):
503
+ plt.show()
504
+
505
+ def exitwin(self, event):
506
+ plt.close()
507
+
508
+
509
+ class PlotNoise:
510
+ def __init__(self, echo):
511
+ self.cutoff = 0
512
+ self.echo = echo
513
+
514
+ # Assign axes for plots and widgets
515
+ self.fig, self.axs = plt.subplots(1, 2)
516
+ self.fig.set_facecolor("darkgrey")
517
+
518
+ plt.subplots_adjust(bottom=0.28, right=0.72)
519
+ self.ax_tbox = self.fig.add_axes(rect=(0.85, 0.8, 0.1, 0.05))
520
+ self.ax_end = self.fig.add_axes(rect=(0.25, 0.1, 0.47, 0.03))
521
+ self.ax_start = self.fig.add_axes(rect=(0.25, 0.15, 0.47, 0.03))
522
+ self.ax_button = self.fig.add_axes(rect=(0.81, 0.65, 0.15, 0.075))
523
+
524
+ # Displays cutoff value
525
+ self.textvar = self.axs[0].text(
526
+ 0.78,
527
+ 0.75,
528
+ f"Default Cutoff: {self.cutoff}",
529
+ color="blue",
530
+ transform=plt.gcf().transFigure,
531
+ )
532
+
533
+ # Plot echo for first and last ensemble
534
+ shape = np.shape(echo)
535
+ self.x = np.arange(0, shape[1], 1)
536
+
537
+ self.l1 = [
538
+ self.axs[0].plot(echo[i, :, 0], self.x, label=f"Beam {i+1}")
539
+ for i in range(4)
540
+ ]
541
+
542
+ self.l2 = [
543
+ self.axs[1].plot(echo[i, :, -1], self.x, label=f"Beam {i+1}")
544
+ for i in range(4)
545
+ ]
546
+
547
+ # Figure Labels
548
+ for i in range(2):
549
+ self.axs[i].legend()
550
+ self.axs[i].set_xlabel("Echo")
551
+ self.axs[i].set_xlim([20, 200])
552
+ self.axs[0].set_ylabel("Cell")
553
+ self.fig.suptitle("Noise Floor Identification")
554
+
555
+ # Display statistics
556
+ self.axs[0].text(0.82, 0.60, "Statistics", transform=plt.gcf().transFigure)
557
+ l1max = np.max(echo[0, :, :])
558
+ l1min = np.min(echo[0, :, :])
559
+ l1med = np.median(echo[0, :, :])
560
+ self.t1 = self.axs[0].text(
561
+ 0.75,
562
+ 0.50,
563
+ f"Dep. Max = {l1max} \nDep. Min = {l1min} \nDep. Median = {l1med}",
564
+ transform=plt.gcf().transFigure,
565
+ )
566
+
567
+ l2max = np.max(echo[:, :, -1])
568
+ l2min = np.min(echo[:, :, -1])
569
+ l2med = np.median(echo[:, :, -1])
570
+ self.t2 = self.axs[0].text(
571
+ 0.75,
572
+ 0.35,
573
+ f"Rec. Max = {l2max} \nRec. Min = {l2min}\nRec. Median = {l2med}",
574
+ transform=plt.gcf().transFigure,
575
+ )
576
+
577
+ # Define Widgets
578
+ self.tbox = TextBox(
579
+ ax=self.ax_tbox,
580
+ label="Enter Cutoff",
581
+ color="lightgrey",
582
+ hovercolor="yellow",
583
+ initial="0",
584
+ )
585
+
586
+ self.sl_start = Slider(
587
+ ax=self.ax_start,
588
+ label="Deployment Ensemble",
589
+ valmin=0,
590
+ valmax=10,
591
+ valinit=0,
592
+ valfmt="%i",
593
+ valstep=1,
594
+ )
595
+ self.sl_end = Slider(
596
+ ax=self.ax_end,
597
+ label="Recovery Ensemble",
598
+ valmin=-11,
599
+ valmax=-1,
600
+ valinit=0,
601
+ valfmt="%i",
602
+ valstep=1,
603
+ )
604
+
605
+ self.button = Button(self.ax_button, "Save & Exit")
606
+
607
+ # Activate widgets
608
+ self.sl_start.on_changed(self.update1)
609
+ self.sl_end.on_changed(self.update2)
610
+ self.tbox.on_submit(self.submit)
611
+ self.button.on_clicked(self.exitwin)
612
+
613
+ def update1(self, value):
614
+ for i, line in enumerate(self.l1):
615
+ line[0].set_xdata(self.echo[i, :, value])
616
+
617
+ self.t1.remove()
618
+ l1max = np.max(self.echo[:, :, value])
619
+ l1min = np.min(self.echo[:, :, value])
620
+ l1med = np.median(self.echo[:, :, value])
621
+ self.t1 = self.axs[0].text(
622
+ 0.75,
623
+ 0.50,
624
+ f"Dep. Max = {l1max} \nRec. Min = {l1min}\nRec. Median = {l1med}",
625
+ transform=plt.gcf().transFigure,
626
+ )
627
+ self.fig.canvas.draw_idle()
628
+ self.fig.canvas.flush_events()
629
+
630
+ def update2(self, value):
631
+ for i, line in enumerate(self.l2):
632
+ line[0].set_xdata(self.echo[i, :, value])
633
+ self.t2.remove()
634
+ l2max = np.max(self.echo[:, :, value])
635
+ l2min = np.min(self.echo[:, :, value])
636
+ l2med = np.median(self.echo[:, :, value])
637
+ self.t2 = self.axs[0].text(
638
+ 0.75,
639
+ 0.35,
640
+ f"Rec. Max = {l2max} \nRec. Min = {l2min}\nRec. Median = {l2med}",
641
+ transform=plt.gcf().transFigure,
642
+ )
643
+ self.fig.canvas.draw_idle()
644
+ self.fig.canvas.flush_events()
645
+
646
+ def submit(self, exp):
647
+ try:
648
+ self.cutoff = int(exp)
649
+ self.textvar.remove()
650
+ self.textvar = self.axs[0].text(
651
+ 0.78,
652
+ 0.75,
653
+ f"Cutoff:{self.cutoff}",
654
+ color="black",
655
+ transform=plt.gcf().transFigure,
656
+ )
657
+ except ValueError:
658
+ self.cutoff = 0
659
+ self.textvar.remove()
660
+ self.textvar = self.axs[0].text(
661
+ 0.78,
662
+ 0.75,
663
+ "Error: Enter an integer",
664
+ color="red",
665
+ transform=plt.gcf().transFigure,
666
+ )
667
+
668
+ def show(self):
669
+ plt.show()
670
+
671
+ def exitwin(self, event):
672
+ plt.close()
673
+
674
+
675
+ def plotmask(mask1, mask2):
676
+ cpal = "binary"
677
+ fig, axs = plt.subplots(2, 1, sharex=True, sharey=True)
678
+ shape = np.shape(mask1)
679
+ x = np.arange(0, shape[1])
680
+ y = np.arange(0, shape[0])
681
+ X, Y = np.meshgrid(x, y)
682
+ axs[0].pcolor(X, Y, mask1, cmap=cpal, label="Original Mask")
683
+ axs[1].pcolor(X, Y, mask2, cmap=cpal, label="New Mask")
684
+ axs[0].set_title("Original Mask")
685
+ axs[1].set_title("New Mask")
686
+ plt.xlabel("Ensembles")
687
+ plt.ylabel("Cells")
688
+ fig.tight_layout()
689
+ plt.show()
690
+
691
+
692
+ def plotvar(var, name, mask=None, alpha=True):
693
+ shape = np.shape(var)
694
+ cpal = "turbo"
695
+ fig, axs = plt.subplots(2, 2, figsize=(12, 8), sharex=True, sharey=True)
696
+ x = np.arange(0, shape[-1])
697
+ y = np.arange(0, shape[1])
698
+ X, Y = np.meshgrid(x, y)
699
+ i = 0
700
+ for j in range(2):
701
+ for k in range(2):
702
+ if mask is not None:
703
+ if alpha:
704
+ nanmask = np.copy(mask)
705
+ nanmask[mask == 0] = np.nan
706
+ axs[j, k].pcolor(X, Y, var[i, :, :], cmap=cpal)
707
+ axs[j, k].pcolor(X, Y, nanmask, cmap="binary", alpha=0.05)
708
+ else:
709
+ maskdata = np.ma.masked_array(var[i, :, :], mask)
710
+ axs[j, k].pcolor(X, Y, maskdata, cmap=cpal)
711
+ else:
712
+ axs[j, k].pcolor(X, Y, var[i, :, :], cmap=cpal)
713
+
714
+ axs[j, k].set_title(f"Beam {i+1}")
715
+ axs[j, k].set_xlabel("Ensembles")
716
+ axs[j, k].set_ylabel("Cells")
717
+ i = i + 1
718
+ fig.suptitle(name)
719
+ fig.tight_layout()
720
+ plt.show()
721
+
722
+
723
+ def plot1d(data):
724
+ fig = plt.figure(figsize=(2, 2), facecolor="lightskyblue", layout="constrained")
725
+ fig.suptitle("Fixed Leader Data")
726
+ ax = fig.add_subplot()
727
+ ax.set_title("Fleader", loc="center", fontstyle="oblique", fontsize="medium")
728
+ ax.set_xlabel("Ensemble")
729
+ ax.set_ylabel("Fleader")
730
+ (l,) = ax.plot(data)
731
+ l.set_color("C0")