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