teareduce 0.5.9__py3-none-any.whl → 0.6.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.
- teareduce/cleanest/__init__.py +2 -2
- teareduce/cleanest/__main__.py +11 -5
- teareduce/cleanest/askextension.py +85 -0
- teareduce/cleanest/cosmicraycleanerapp.py +294 -71
- teareduce/cleanest/definitions.py +55 -9
- teareduce/cleanest/gausskernel2d_elliptical.py +54 -0
- teareduce/cleanest/imagedisplay.py +1 -0
- teareduce/cleanest/interpolate.py +79 -48
- teareduce/cleanest/interpolation_a.py +1 -0
- teareduce/cleanest/interpolation_x.py +1 -0
- teareduce/cleanest/interpolation_y.py +1 -0
- teareduce/cleanest/interpolationeditor.py +199 -53
- teareduce/cleanest/lacosmicpad.py +95 -2
- teareduce/cleanest/mergemasks.py +11 -1
- teareduce/cleanest/parametereditor.py +279 -51
- teareduce/cleanest/reviewcosmicray.py +245 -30
- teareduce/cleanest/trackedbutton.py +73 -0
- teareduce/version.py +1 -1
- {teareduce-0.5.9.dist-info → teareduce-0.6.1.dist-info}/METADATA +2 -2
- {teareduce-0.5.9.dist-info → teareduce-0.6.1.dist-info}/RECORD +24 -21
- {teareduce-0.5.9.dist-info → teareduce-0.6.1.dist-info}/WHEEL +0 -0
- {teareduce-0.5.9.dist-info → teareduce-0.6.1.dist-info}/entry_points.txt +0 -0
- {teareduce-0.5.9.dist-info → teareduce-0.6.1.dist-info}/licenses/LICENSE.txt +0 -0
- {teareduce-0.5.9.dist-info → teareduce-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -28,15 +28,19 @@ import numpy as np
|
|
|
28
28
|
from rich import print
|
|
29
29
|
|
|
30
30
|
from .centerchildparent import center_on_parent
|
|
31
|
+
from .definitions import DEFAULT_TK_WINDOW_SIZE_X
|
|
32
|
+
from .definitions import DEFAULT_TK_WINDOW_SIZE_Y
|
|
31
33
|
from .definitions import MAX_PIXEL_DISTANCE_TO_CR
|
|
32
34
|
from .imagedisplay import ImageDisplay
|
|
33
35
|
from .interpolation_a import interpolation_a
|
|
34
36
|
from .interpolation_x import interpolation_x
|
|
35
37
|
from .interpolation_y import interpolation_y
|
|
38
|
+
from .trackedbutton import TrackedTkButton
|
|
36
39
|
|
|
37
40
|
from ..imshow import imshow
|
|
38
41
|
from ..sliceregion import SliceRegion2D
|
|
39
42
|
from ..zscale import zscale
|
|
43
|
+
from ..version import VERSION
|
|
40
44
|
|
|
41
45
|
import matplotlib
|
|
42
46
|
|
|
@@ -49,6 +53,8 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
49
53
|
def __init__(
|
|
50
54
|
self,
|
|
51
55
|
root,
|
|
56
|
+
root_width,
|
|
57
|
+
root_height,
|
|
52
58
|
data,
|
|
53
59
|
auxdata,
|
|
54
60
|
cleandata_lacosmic,
|
|
@@ -59,6 +65,10 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
59
65
|
last_dilation=None,
|
|
60
66
|
last_npoints=None,
|
|
61
67
|
last_degree=None,
|
|
68
|
+
last_maskfill_size=None,
|
|
69
|
+
last_maskfill_operator=None,
|
|
70
|
+
last_maskfill_smooth=None,
|
|
71
|
+
last_maskfill_verbose=None,
|
|
62
72
|
):
|
|
63
73
|
"""Initialize the review window.
|
|
64
74
|
|
|
@@ -66,6 +76,10 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
66
76
|
----------
|
|
67
77
|
root : tk.Toplevel
|
|
68
78
|
The parent Tkinter root window.
|
|
79
|
+
root_width : int
|
|
80
|
+
The width of the root window. The review window is scaled accordingly.
|
|
81
|
+
root_height : int
|
|
82
|
+
The height of the root window. The review window is scaled accordingly.
|
|
69
83
|
data : 2D numpy array
|
|
70
84
|
The original image data.
|
|
71
85
|
auxdata : 2D numpy array or None
|
|
@@ -90,6 +104,14 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
90
104
|
The last used number of points parameter for interpolation.
|
|
91
105
|
last_degree : int or None, optional
|
|
92
106
|
The last used degree parameter for interpolation.
|
|
107
|
+
last_maskfill_size : int or None, optional
|
|
108
|
+
The last used maskfill size parameter.
|
|
109
|
+
last_maskfill_operator : str or None, optional
|
|
110
|
+
The last used maskfill operator parameter.
|
|
111
|
+
last_maskfill_smooth : bool or None, optional
|
|
112
|
+
The last used maskfill smooth parameter.
|
|
113
|
+
last_maskfill_verbose : bool or None, optional
|
|
114
|
+
The last used maskfill verbose parameter.
|
|
93
115
|
|
|
94
116
|
Methods
|
|
95
117
|
-------
|
|
@@ -126,6 +148,10 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
126
148
|
----------
|
|
127
149
|
root : tk.Toplevel
|
|
128
150
|
The parent Tkinter root window.
|
|
151
|
+
factor_width : float
|
|
152
|
+
The scaling factor for the width of the review window.
|
|
153
|
+
factor_height : float
|
|
154
|
+
The scaling factor for the height of the review window.
|
|
129
155
|
data : 2D numpy array
|
|
130
156
|
The original image data.
|
|
131
157
|
auxdata : 2D numpy array or None
|
|
@@ -146,19 +172,33 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
146
172
|
Degree parameter for interpolation.
|
|
147
173
|
npoints : int
|
|
148
174
|
Number of points parameter for interpolation.
|
|
175
|
+
maskfill_size : int
|
|
176
|
+
The last used maskfill size parameter.
|
|
177
|
+
maskfill_operator : str
|
|
178
|
+
The last used maskfill operator parameter.
|
|
179
|
+
maskfill_smooth : bool
|
|
180
|
+
The last used maskfill smooth parameter.
|
|
181
|
+
maskfill_verbose : bool
|
|
182
|
+
The last used maskfill verbose parameter.
|
|
149
183
|
last_dilation : int or None
|
|
150
184
|
The last used dilation parameter employed after L.A.Cosmic
|
|
151
185
|
detection.
|
|
152
186
|
"""
|
|
153
187
|
self.root = root
|
|
154
|
-
self.root.title("Review Cosmic Rays")
|
|
188
|
+
self.root.title(f"Review Cosmic Rays (TEA version {VERSION})")
|
|
189
|
+
self.factor_width = root_width / DEFAULT_TK_WINDOW_SIZE_X
|
|
190
|
+
self.factor_height = root_height / DEFAULT_TK_WINDOW_SIZE_Y
|
|
155
191
|
self.auxdata = auxdata
|
|
156
192
|
if self.auxdata is not None:
|
|
157
193
|
# self.root.geometry("1000x700+100+100") # This does not work in Fedora
|
|
158
|
-
self.
|
|
194
|
+
window_width = int(1000 * self.factor_width + 0.5)
|
|
195
|
+
window_height = int(700 * self.factor_height + 0.5)
|
|
196
|
+
self.root.minsize(window_width, window_height)
|
|
159
197
|
else:
|
|
160
|
-
# self.root.geometry("
|
|
161
|
-
self.
|
|
198
|
+
# self.root.geometry("900x700+100+100") # This does not work in Fedora
|
|
199
|
+
window_width = int(900 * self.factor_width + 0.5)
|
|
200
|
+
window_height = int(700 * self.factor_height + 0.5)
|
|
201
|
+
self.root.minsize(window_width, window_height)
|
|
162
202
|
self.root.update_idletasks()
|
|
163
203
|
self.root.geometry("+100+100")
|
|
164
204
|
self.data = data
|
|
@@ -171,6 +211,10 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
171
211
|
self.first_plot = True
|
|
172
212
|
self.degree = last_degree if last_degree is not None else 1
|
|
173
213
|
self.npoints = last_npoints if last_npoints is not None else 2
|
|
214
|
+
self.maskfill_size = last_maskfill_size if last_maskfill_size is not None else 3
|
|
215
|
+
self.maskfill_operator = last_maskfill_operator if last_maskfill_operator is not None else "median"
|
|
216
|
+
self.maskfill_smooth = last_maskfill_smooth if last_maskfill_smooth is not None else True
|
|
217
|
+
self.maskfill_verbose = last_maskfill_verbose if last_maskfill_verbose is not None else False
|
|
174
218
|
self.last_dilation = last_dilation
|
|
175
219
|
# Make a copy of the original labels to allow pixel re-marking
|
|
176
220
|
self.cr_labels_original = self.cr_labels.copy()
|
|
@@ -187,29 +231,74 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
187
231
|
|
|
188
232
|
def create_widgets(self):
|
|
189
233
|
"""Create the GUI widgets for the review window."""
|
|
234
|
+
# Define instance of TrackedTkButton, that facilitates to show help information
|
|
235
|
+
# for each button displayed in the current application window.
|
|
236
|
+
tkbutton = TrackedTkButton(self.root)
|
|
237
|
+
|
|
190
238
|
# Row 1 of buttons
|
|
191
239
|
self.button_frame1 = tk.Frame(self.root)
|
|
192
240
|
self.button_frame1.pack(pady=5)
|
|
193
|
-
self.ndeg_label =
|
|
194
|
-
self.button_frame1,
|
|
241
|
+
self.ndeg_label = tkbutton.new(
|
|
242
|
+
self.button_frame1,
|
|
243
|
+
text=f"Npoints={self.npoints}, Degree={self.degree}",
|
|
244
|
+
command=self.set_ndeg,
|
|
245
|
+
help_text="Set the Npoints and Degree parameters for interpolation.",
|
|
246
|
+
alttext="Npoints=?, Degree=?",
|
|
195
247
|
)
|
|
196
248
|
self.ndeg_label.pack(side=tk.LEFT, padx=5)
|
|
197
|
-
self.
|
|
249
|
+
self.maskfill_button = tkbutton.new(
|
|
250
|
+
self.button_frame1,
|
|
251
|
+
text="Maskfill params.",
|
|
252
|
+
command=self.set_maskfill_params,
|
|
253
|
+
help_text="Set the parameters for the maskfill method.",
|
|
254
|
+
)
|
|
255
|
+
self.maskfill_button.pack(side=tk.LEFT, padx=5)
|
|
256
|
+
self.remove_crosses_button = tkbutton.new(
|
|
257
|
+
self.button_frame1,
|
|
258
|
+
text="remove all x's",
|
|
259
|
+
command=self.remove_crosses,
|
|
260
|
+
help_text="Remove all cross marks from the image.",
|
|
261
|
+
)
|
|
198
262
|
self.remove_crosses_button.pack(side=tk.LEFT, padx=5)
|
|
199
|
-
self.restore_cr_button =
|
|
263
|
+
self.restore_cr_button = tkbutton.new(
|
|
264
|
+
self.button_frame1,
|
|
265
|
+
text="restore CR",
|
|
266
|
+
command=self.restore_cr,
|
|
267
|
+
help_text="Restore current cosmic ray pixels to their original values.",
|
|
268
|
+
)
|
|
200
269
|
self.restore_cr_button.pack(side=tk.LEFT, padx=5)
|
|
201
270
|
self.restore_cr_button.config(state=tk.DISABLED)
|
|
202
|
-
self.next_button =
|
|
271
|
+
self.next_button = tkbutton.new(
|
|
272
|
+
self.button_frame1,
|
|
273
|
+
text="[c]ontinue",
|
|
274
|
+
command=self.continue_cr,
|
|
275
|
+
help_text="Continue to the next cosmic ray.",
|
|
276
|
+
)
|
|
203
277
|
self.next_button.pack(side=tk.LEFT, padx=5)
|
|
204
|
-
self.exit_button =
|
|
278
|
+
self.exit_button = tkbutton.new(
|
|
279
|
+
self.button_frame1,
|
|
280
|
+
text="[e]xit review",
|
|
281
|
+
command=self.exit_review,
|
|
282
|
+
help_text="Exit the cosmic ray review process.",
|
|
283
|
+
)
|
|
205
284
|
self.exit_button.pack(side=tk.LEFT, padx=5)
|
|
206
285
|
|
|
207
286
|
# Row 2 of buttons
|
|
208
287
|
self.button_frame2 = tk.Frame(self.root)
|
|
209
288
|
self.button_frame2.pack(pady=5)
|
|
210
|
-
self.interp_x_button =
|
|
289
|
+
self.interp_x_button = tkbutton.new(
|
|
290
|
+
self.button_frame2,
|
|
291
|
+
text="[x] interp.",
|
|
292
|
+
command=self.interp_x,
|
|
293
|
+
help_text="Perform X-interpolation for the current cosmic ray.",
|
|
294
|
+
)
|
|
211
295
|
self.interp_x_button.pack(side=tk.LEFT, padx=5)
|
|
212
|
-
self.interp_y_button =
|
|
296
|
+
self.interp_y_button = tkbutton.new(
|
|
297
|
+
self.button_frame2,
|
|
298
|
+
text="[y] interp.",
|
|
299
|
+
command=self.interp_y,
|
|
300
|
+
help_text="Perform Y-interpolation for the current cosmic ray.",
|
|
301
|
+
)
|
|
213
302
|
self.interp_y_button.pack(side=tk.LEFT, padx=5)
|
|
214
303
|
# it is important to use lambda here to pass the method argument correctly
|
|
215
304
|
# (avoiding the execution of the function at button creation time, which would happen
|
|
@@ -218,23 +307,51 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
218
307
|
# the function is trying to deactivate the buttons before they are created, which
|
|
219
308
|
# would lead to an error; in addition, since I have two buttons calling the same function
|
|
220
309
|
# with different arguments, using lambda allows to differentiate them)
|
|
221
|
-
self.interp_s_button =
|
|
222
|
-
self.button_frame2,
|
|
310
|
+
self.interp_s_button = tkbutton.new(
|
|
311
|
+
self.button_frame2,
|
|
312
|
+
text="[s]urface interp.",
|
|
313
|
+
command=lambda: self.interp_a("surface"),
|
|
314
|
+
help_text="Perform surface interpolation for the current cosmic ray.",
|
|
223
315
|
)
|
|
224
316
|
self.interp_s_button.pack(side=tk.LEFT, padx=5)
|
|
225
|
-
self.interp_d_button =
|
|
317
|
+
self.interp_d_button = tkbutton.new(
|
|
318
|
+
self.button_frame2,
|
|
319
|
+
text="me[d]ian",
|
|
320
|
+
command=lambda: self.interp_a("median"),
|
|
321
|
+
help_text="Perform median interpolation for the current cosmic ray.",
|
|
322
|
+
)
|
|
226
323
|
self.interp_d_button.pack(side=tk.LEFT, padx=5)
|
|
227
|
-
self.interp_m_button =
|
|
324
|
+
self.interp_m_button = tkbutton.new(
|
|
325
|
+
self.button_frame2,
|
|
326
|
+
text="[m]ean",
|
|
327
|
+
command=lambda: self.interp_a("mean"),
|
|
328
|
+
help_text="Perform mean interpolation for the current cosmic ray.",
|
|
329
|
+
)
|
|
228
330
|
self.interp_m_button.pack(side=tk.LEFT, padx=5)
|
|
229
|
-
self.interp_l_button =
|
|
331
|
+
self.interp_l_button = tkbutton.new(
|
|
332
|
+
self.button_frame2,
|
|
333
|
+
text="[l]acosmic",
|
|
334
|
+
command=self.use_lacosmic,
|
|
335
|
+
help_text="Use L.A.Cosmic interpolation for the current cosmic ray.",
|
|
336
|
+
)
|
|
230
337
|
self.interp_l_button.pack(side=tk.LEFT, padx=5)
|
|
231
338
|
if self.last_dilation is not None and self.last_dilation > 0:
|
|
232
339
|
self.interp_l_button.config(state=tk.DISABLED)
|
|
233
340
|
if self.cleandata_lacosmic is None:
|
|
234
341
|
self.interp_l_button.config(state=tk.DISABLED)
|
|
235
|
-
self.interp_maskfill_button =
|
|
342
|
+
self.interp_maskfill_button = tkbutton.new(
|
|
343
|
+
self.button_frame2,
|
|
344
|
+
text="mask[f]ill",
|
|
345
|
+
command=self.use_maskfill,
|
|
346
|
+
help_text="Perform maskfill interpolation for the current cosmic ray.",
|
|
347
|
+
)
|
|
236
348
|
self.interp_maskfill_button.pack(side=tk.LEFT, padx=5)
|
|
237
|
-
self.interp_aux_button =
|
|
349
|
+
self.interp_aux_button = tkbutton.new(
|
|
350
|
+
self.button_frame2,
|
|
351
|
+
text="[a]ux. data",
|
|
352
|
+
command=self.use_auxdata,
|
|
353
|
+
help_text="Use auxiliary data for interpolation of the current cosmic ray.",
|
|
354
|
+
)
|
|
238
355
|
self.interp_aux_button.pack(side=tk.LEFT, padx=5)
|
|
239
356
|
if self.auxdata is None:
|
|
240
357
|
self.interp_aux_button.config(state=tk.DISABLED)
|
|
@@ -243,20 +360,53 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
243
360
|
self.button_frame3 = tk.Frame(self.root)
|
|
244
361
|
self.button_frame3.pack(pady=5)
|
|
245
362
|
vmin, vmax = zscale(self.data)
|
|
246
|
-
self.vmin_button =
|
|
363
|
+
self.vmin_button = tkbutton.new(
|
|
364
|
+
self.button_frame3,
|
|
365
|
+
text=f"vmin: {vmin:.2f}",
|
|
366
|
+
command=self.set_vmin,
|
|
367
|
+
help_text="Set the minimum value for the display scale.",
|
|
368
|
+
alttext="vmin: ??",
|
|
369
|
+
)
|
|
247
370
|
self.vmin_button.pack(side=tk.LEFT, padx=5)
|
|
248
|
-
self.vmax_button =
|
|
371
|
+
self.vmax_button = tkbutton.new(
|
|
372
|
+
self.button_frame3,
|
|
373
|
+
text=f"vmax: {vmax:.2f}",
|
|
374
|
+
command=self.set_vmax,
|
|
375
|
+
help_text="Set the maximum value for the display scale.",
|
|
376
|
+
alttext="vmax: ??",
|
|
377
|
+
)
|
|
249
378
|
self.vmax_button.pack(side=tk.LEFT, padx=5)
|
|
250
|
-
self.set_minmax_button =
|
|
379
|
+
self.set_minmax_button = tkbutton.new(
|
|
380
|
+
self.button_frame3,
|
|
381
|
+
text="minmax [,]",
|
|
382
|
+
command=self.set_minmax,
|
|
383
|
+
help_text="Set the display scale to the minimum and maximum data values.",
|
|
384
|
+
)
|
|
251
385
|
self.set_minmax_button.pack(side=tk.LEFT, padx=5)
|
|
252
|
-
self.set_zscale_button =
|
|
386
|
+
self.set_zscale_button = tkbutton.new(
|
|
387
|
+
self.button_frame3,
|
|
388
|
+
text="zscale [/]",
|
|
389
|
+
command=self.set_zscale,
|
|
390
|
+
help_text="Set the display scale using zscale.",
|
|
391
|
+
)
|
|
253
392
|
self.set_zscale_button.pack(side=tk.LEFT, padx=5)
|
|
393
|
+
self.help_button = tkbutton.new(
|
|
394
|
+
self.button_frame3,
|
|
395
|
+
text="Help",
|
|
396
|
+
command=tkbutton.show_help,
|
|
397
|
+
help_text="Show help information for all buttons.",
|
|
398
|
+
)
|
|
399
|
+
self.help_button.pack(side=tk.LEFT, padx=5)
|
|
254
400
|
|
|
255
401
|
# Figure
|
|
256
402
|
if self.auxdata is not None:
|
|
257
|
-
self.fig, (self.
|
|
403
|
+
self.fig, (self.ax, self.ax_aux) = plt.subplots(
|
|
404
|
+
ncols=2, figsize=(11 * self.factor_width, 5.5 * self.factor_height), constrained_layout=True
|
|
405
|
+
)
|
|
258
406
|
else:
|
|
259
|
-
self.fig, self.ax = plt.subplots(
|
|
407
|
+
self.fig, self.ax = plt.subplots(
|
|
408
|
+
figsize=(9 * self.factor_width, 5.5 * self.factor_height), constrained_layout=True
|
|
409
|
+
)
|
|
260
410
|
self.canvas = FigureCanvasTkAgg(self.fig, master=self.root)
|
|
261
411
|
self.canvas.get_tk_widget().pack(padx=5, pady=5)
|
|
262
412
|
# The next two instructions prevent a segmentation fault when pressing "q"
|
|
@@ -376,6 +526,61 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
376
526
|
self.npoints = new_npoints
|
|
377
527
|
self.ndeg_label.config(text=f"Npoints={self.npoints}, Degree={self.degree}")
|
|
378
528
|
|
|
529
|
+
def set_maskfill_params(self):
|
|
530
|
+
"""Set the maskfill parameters."""
|
|
531
|
+
new_size = simpledialog.askinteger(
|
|
532
|
+
"Set Maskfill Size", "Enter Maskfill Size (odd integer >=1):", initialvalue=self.maskfill_size, minvalue=1
|
|
533
|
+
)
|
|
534
|
+
if new_size is None:
|
|
535
|
+
return
|
|
536
|
+
if new_size % 2 == 0:
|
|
537
|
+
messagebox.showerror("Input Error", "Maskfill size must be an odd integer.")
|
|
538
|
+
return
|
|
539
|
+
new_operator = simpledialog.askstring(
|
|
540
|
+
"Set Maskfill Operator",
|
|
541
|
+
"Enter Maskfill Operator ('median' or 'mean'):",
|
|
542
|
+
initialvalue=self.maskfill_operator,
|
|
543
|
+
)
|
|
544
|
+
if new_operator is None:
|
|
545
|
+
return
|
|
546
|
+
if new_operator not in ["median", "mean"]:
|
|
547
|
+
messagebox.showerror("Input Error", "Maskfill operator must be 'median' or 'mean'.")
|
|
548
|
+
return
|
|
549
|
+
smooth_str = simpledialog.askstring(
|
|
550
|
+
"Set Maskfill Smooth",
|
|
551
|
+
"Enter Maskfill Smooth ('True' or 'False'):",
|
|
552
|
+
initialvalue=str(self.maskfill_smooth),
|
|
553
|
+
)
|
|
554
|
+
if smooth_str is None:
|
|
555
|
+
return
|
|
556
|
+
smooth_str = smooth_str.strip().lower()
|
|
557
|
+
if smooth_str == "true":
|
|
558
|
+
new_smooth = True
|
|
559
|
+
elif smooth_str == "false":
|
|
560
|
+
new_smooth = False
|
|
561
|
+
else:
|
|
562
|
+
messagebox.showerror("Input Error", "Maskfill Smooth must be 'True' or 'False'.")
|
|
563
|
+
return
|
|
564
|
+
verbose_str = simpledialog.askstring(
|
|
565
|
+
"Set Maskfill Verbose",
|
|
566
|
+
"Enter Maskfill Verbose ('True' or 'False'):",
|
|
567
|
+
initialvalue=str(self.maskfill_verbose),
|
|
568
|
+
)
|
|
569
|
+
if verbose_str is None:
|
|
570
|
+
return
|
|
571
|
+
verbose_str = verbose_str.strip().lower()
|
|
572
|
+
if verbose_str == "true":
|
|
573
|
+
new_verbose = True
|
|
574
|
+
elif verbose_str == "false":
|
|
575
|
+
new_verbose = False
|
|
576
|
+
else:
|
|
577
|
+
messagebox.showerror("Input Error", "Maskfill Verbose must be 'True' or 'False'.")
|
|
578
|
+
return
|
|
579
|
+
self.maskfill_size = new_size
|
|
580
|
+
self.maskfill_operator = new_operator
|
|
581
|
+
self.maskfill_smooth = new_smooth
|
|
582
|
+
self.maskfill_verbose = new_verbose
|
|
583
|
+
|
|
379
584
|
def set_buttons_after_cleaning_cr(self):
|
|
380
585
|
"""Set the state of buttons after cleaning a cosmic ray."""
|
|
381
586
|
self.disable_interpolation_buttons()
|
|
@@ -388,6 +593,7 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
388
593
|
messagebox.showerror("Input Error", "2*Npoints must be greater than Degree for x interpolation.")
|
|
389
594
|
return
|
|
390
595
|
print(f"X-interpolation of cosmic ray {self.cr_index}")
|
|
596
|
+
print(f"Interpolation parameters: Npoints={self.npoints}, Degree={self.degree}")
|
|
391
597
|
interpolation_performed, xfit_all, yfit_all = interpolation_x(
|
|
392
598
|
data=self.data,
|
|
393
599
|
mask_fixed=self.mask_fixed,
|
|
@@ -410,6 +616,7 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
410
616
|
messagebox.showerror("Input Error", "2*Npoints must be greater than Degree for y interpolation.")
|
|
411
617
|
return
|
|
412
618
|
print(f"Y-interpolation of cosmic ray {self.cr_index}")
|
|
619
|
+
print(f"Interpolation parameters: Npoints={self.npoints}, Degree={self.degree}")
|
|
413
620
|
interpolation_performed, xfit_all, yfit_all = interpolation_y(
|
|
414
621
|
data=self.data,
|
|
415
622
|
mask_fixed=self.mask_fixed,
|
|
@@ -435,6 +642,7 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
435
642
|
The interpolation method to use ('surface', 'median' or 'mean').
|
|
436
643
|
"""
|
|
437
644
|
print(f"{method} interpolation of cosmic ray {self.cr_index}")
|
|
645
|
+
print(f'Interpolation parameters: Npoints={self.npoints}, method="{method}"')
|
|
438
646
|
interpolation_performed, xfit_all, yfit_all = interpolation_a(
|
|
439
647
|
data=self.data,
|
|
440
648
|
mask_fixed=self.mask_fixed,
|
|
@@ -468,6 +676,12 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
468
676
|
def use_maskfill(self):
|
|
469
677
|
"""Use maskfill cleaned data to clean a cosmic ray."""
|
|
470
678
|
print(f"Maskfill interpolation of cosmic ray {self.cr_index}")
|
|
679
|
+
print(
|
|
680
|
+
f"Maskfill parameters: size={self.maskfill_size}, "
|
|
681
|
+
f"operator={self.maskfill_operator}, "
|
|
682
|
+
f"smooth={self.maskfill_smooth}, "
|
|
683
|
+
f"verbose={self.maskfill_verbose}"
|
|
684
|
+
)
|
|
471
685
|
ycr_list, xcr_list = np.where(self.cr_labels == self.cr_index)
|
|
472
686
|
mask = np.zeros(self.data.shape, dtype=bool)
|
|
473
687
|
for iy, ix in zip(ycr_list, xcr_list):
|
|
@@ -475,9 +689,10 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
475
689
|
smoothed_output, _ = maskfill(
|
|
476
690
|
input_image=self.data,
|
|
477
691
|
mask=mask,
|
|
478
|
-
size=
|
|
479
|
-
operator=
|
|
480
|
-
smooth=
|
|
692
|
+
size=self.maskfill_size,
|
|
693
|
+
operator=self.maskfill_operator,
|
|
694
|
+
smooth=self.maskfill_smooth,
|
|
695
|
+
verbose=self.maskfill_verbose,
|
|
481
696
|
)
|
|
482
697
|
for iy, ix in zip(ycr_list, xcr_list):
|
|
483
698
|
self.data[iy, ix] = smoothed_output[iy, ix]
|
|
@@ -628,8 +843,8 @@ class ReviewCosmicRay(ImageDisplay):
|
|
|
628
843
|
self.interp_d_button.config(state=tk.NORMAL)
|
|
629
844
|
self.interp_m_button.config(state=tk.NORMAL)
|
|
630
845
|
if self.cleandata_lacosmic is not None:
|
|
631
|
-
|
|
632
|
-
|
|
846
|
+
if self.last_dilation is None or self.last_dilation == 0:
|
|
847
|
+
self.interp_l_button.config(state=tk.NORMAL)
|
|
633
848
|
self.interp_maskfill_button.config(state=tk.NORMAL)
|
|
634
849
|
if self.auxdata is not None:
|
|
635
850
|
self.interp_aux_button.config(state=tk.NORMAL)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright 2025 Universidad Complutense de Madrid
|
|
3
|
+
#
|
|
4
|
+
# This file is part of teareduce
|
|
5
|
+
#
|
|
6
|
+
# SPDX-License-Identifier: GPL-3.0+
|
|
7
|
+
# License-Filename: LICENSE.txt
|
|
8
|
+
#
|
|
9
|
+
|
|
10
|
+
"""Tracked button widget for the cleanest module."""
|
|
11
|
+
|
|
12
|
+
import tkinter as tk
|
|
13
|
+
from rich.console import Console
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class TrackedTkButton:
|
|
19
|
+
"""Class to create tracked Tkinter buttons with help text."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, root):
|
|
22
|
+
"""Initialize the TrackedTkButton instance.
|
|
23
|
+
|
|
24
|
+
Initializes an empty list to store button information.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
root : tk.Tk or tk.Frame
|
|
29
|
+
The parent widget where the help information about
|
|
30
|
+
the actions associated to each button will be displayed.
|
|
31
|
+
"""
|
|
32
|
+
self.root = root
|
|
33
|
+
self.buttons_info = []
|
|
34
|
+
|
|
35
|
+
def new(self, parent, text, command, help_text, alttext=None, **kwargs):
|
|
36
|
+
"""Create a Tkinter button with tracking information.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
parent : tk.Widget
|
|
41
|
+
The parent widget where the button will be placed.
|
|
42
|
+
text : str
|
|
43
|
+
The text to display on the button.
|
|
44
|
+
command : callable
|
|
45
|
+
The function to call when the button is pressed.
|
|
46
|
+
help_text : str
|
|
47
|
+
The help text associated with the button.
|
|
48
|
+
alttext : str, optional
|
|
49
|
+
Alternative text for the button.
|
|
50
|
+
**kwargs : dict
|
|
51
|
+
Additional keyword arguments to pass to the Tkinter Button constructor.
|
|
52
|
+
|
|
53
|
+
Returns
|
|
54
|
+
-------
|
|
55
|
+
button : tk.Button
|
|
56
|
+
The created Tkinter button.
|
|
57
|
+
"""
|
|
58
|
+
button = tk.Button(parent, text=text, command=command, **kwargs)
|
|
59
|
+
self.buttons_info.append({"button": button, "text": text, "help_text": help_text, "alttext": alttext})
|
|
60
|
+
return button
|
|
61
|
+
|
|
62
|
+
def show_help(self):
|
|
63
|
+
"""Display help information for all tracked buttons."""
|
|
64
|
+
console.rule("[bold red]Button Help Information[/bold red]")
|
|
65
|
+
for info in self.buttons_info:
|
|
66
|
+
if info["alttext"] is not None:
|
|
67
|
+
text = info["alttext"]
|
|
68
|
+
else:
|
|
69
|
+
text = info["text"]
|
|
70
|
+
# replace '[' by '\[' to avoid formatting issues
|
|
71
|
+
text = text.replace("[", "\\[")
|
|
72
|
+
console.print(f"[bold blue]{text}[/bold blue]: {info['help_text']}")
|
|
73
|
+
console.rule()
|
teareduce/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: teareduce
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: Utilities for astronomical data reduction
|
|
5
5
|
Author-email: Nicolás Cardiel <cardiel@ucm.es>
|
|
6
6
|
License: GPL-3.0-or-later
|
|
@@ -51,7 +51,7 @@ practical for use in Master’s level classes.
|
|
|
51
51
|
## Documentation
|
|
52
52
|
|
|
53
53
|
The documentation for this package is available at [this
|
|
54
|
-
link](https://
|
|
54
|
+
link](https://nicocardiel.github.io/teareduce-cookbook/intro.html).
|
|
55
55
|
It includes Juypter notebooks that can be easily downloaded and demonstrate the
|
|
56
56
|
practical use of the defined functionality.
|
|
57
57
|
|
|
@@ -15,37 +15,40 @@ teareduce/sdistortion.py,sha256=5ZsZn4vD5Sw2aoqO8-NIOH7H89Zmh7ZDkow6YbAotHU,5916
|
|
|
15
15
|
teareduce/simulateccdexposure.py,sha256=cdbpca6GVuM3d7R1LGzlIZZvjTq_jzrlkk_Cli7aouQ,24636
|
|
16
16
|
teareduce/sliceregion.py,sha256=Jdf8XvmGaY_vaY1cneTaRtSOYPxpUsJm9cXJDDMa0YM,18626
|
|
17
17
|
teareduce/statsummary.py,sha256=VTNAnBV8z6suqiyB2Lhw3YjUUOjlmwUPX3enkOKRF54,5422
|
|
18
|
-
teareduce/version.py,sha256=
|
|
18
|
+
teareduce/version.py,sha256=RJWCscyH4cJAAqke3NP_StsgFVOL0CjPEjXdsqc_8KI,419
|
|
19
19
|
teareduce/wavecal.py,sha256=2MewWz5Y3ms41c305UtWOM_LaLNdk1mugDXCtzf-fSw,68586
|
|
20
20
|
teareduce/write_array_to_fits.py,sha256=kWDrEH9coJ1yIu56oQJpWtDqJL4c8HGmssE9jle4e94,617
|
|
21
21
|
teareduce/zscale.py,sha256=SDgmcDD2N5GvDn46JADCgTQJPBF_N_jSKMHoeTz9Nsw,1152
|
|
22
|
-
teareduce/cleanest/__init__.py,sha256=
|
|
23
|
-
teareduce/cleanest/__main__.py,sha256=
|
|
22
|
+
teareduce/cleanest/__init__.py,sha256=1rcfu97uqj3R-OZbU9HHLYaTzWkS-poRFBBy8nuH7p4,547
|
|
23
|
+
teareduce/cleanest/__main__.py,sha256=KhFJSekko0mz_pVz3gxNnEmqvv4nuRBdhaXB2Nt4aL0,6145
|
|
24
|
+
teareduce/cleanest/askextension.py,sha256=Q6mGLA6ajUcDU4gsVA4P78GsPei0c7iZK1f7SfK9iVo,3014
|
|
24
25
|
teareduce/cleanest/centerchildparent.py,sha256=wHxOvNrrQ-KBLZAbtQ9bJAxYhGOzqYBF4LgdIQk7UF8,1285
|
|
25
|
-
teareduce/cleanest/cosmicraycleanerapp.py,sha256=
|
|
26
|
-
teareduce/cleanest/definitions.py,sha256=
|
|
26
|
+
teareduce/cleanest/cosmicraycleanerapp.py,sha256=OpBBhgvvGiC8rO_C26Zwc0gIlQ6phDVjSarQNMEfpTY,61327
|
|
27
|
+
teareduce/cleanest/definitions.py,sha256=Ryreer1ztkk4W3muWGI_SSfm3ZAhyAOQJbZLtdfTJsc,4692
|
|
27
28
|
teareduce/cleanest/dilatemask.py,sha256=I5tHAv5VEO6V0Wed8Ar20uLt4F9P-tgjmLL5BAaFvgM,1276
|
|
28
29
|
teareduce/cleanest/find_closest_true.py,sha256=mWdIvhipzAXDRKfePDrP7f0lP4U48cckpHiKwiB4jHI,1320
|
|
29
|
-
teareduce/cleanest/
|
|
30
|
-
teareduce/cleanest/
|
|
31
|
-
teareduce/cleanest/
|
|
32
|
-
teareduce/cleanest/
|
|
33
|
-
teareduce/cleanest/
|
|
34
|
-
teareduce/cleanest/
|
|
35
|
-
teareduce/cleanest/
|
|
36
|
-
teareduce/cleanest/
|
|
30
|
+
teareduce/cleanest/gausskernel2d_elliptical.py,sha256=f6AT0ZHmLCd83NAIyyJ8ODlihMeeTkmvNnUSK3vjP9I,1606
|
|
31
|
+
teareduce/cleanest/imagedisplay.py,sha256=m8wmQ7CSDywABxkra2G4dFD06CVP1KvIYIdnZqoVdrI,5871
|
|
32
|
+
teareduce/cleanest/interpolate.py,sha256=EZGxiRDh8i5jL5_fK_iTLDt96TaK1ILsiFXV5m6g2J4,7068
|
|
33
|
+
teareduce/cleanest/interpolation_a.py,sha256=iyAEbh0Bf74OfAVhZjSvP3cO7pDC8eVDrVnDUd18FZQ,4030
|
|
34
|
+
teareduce/cleanest/interpolation_x.py,sha256=MZhtlZZuMLvLnOK0EsLkJM3_dpyNHsxQL_BU1vLt9Lw,3767
|
|
35
|
+
teareduce/cleanest/interpolation_y.py,sha256=ZX1Uv3FOxoLHtuR_yspcSA5B81CK_J0oNJ1ztzp0l5g,3782
|
|
36
|
+
teareduce/cleanest/interpolationeditor.py,sha256=mIy-25dylQnqC91tLny4iZWS4d_bJ4sDDs-kNOWM-yE,19933
|
|
37
|
+
teareduce/cleanest/lacosmicpad.py,sha256=IXwHAHeh4rQlQjMw2lfKSzjzmoo3HdSt0Qj0nhK_nHU,6921
|
|
38
|
+
teareduce/cleanest/mergemasks.py,sha256=TdbfQl5ETxtyFfod0WCD7Czzmgt-WxYOk3hpLqGNOTQ,2620
|
|
37
39
|
teareduce/cleanest/modalprogressbar.py,sha256=uwd-p92PvOVJnbXd-B8DRcBZ--keKpr4ZN9PLeqm1Ws,6449
|
|
38
|
-
teareduce/cleanest/parametereditor.py,sha256=
|
|
39
|
-
teareduce/cleanest/reviewcosmicray.py,sha256=
|
|
40
|
+
teareduce/cleanest/parametereditor.py,sha256=V8twAQzR0vjd68PB92PfdQBmTRDR04xx2mb4SLSV68Y,24530
|
|
41
|
+
teareduce/cleanest/reviewcosmicray.py,sha256=8jUaJCHVvZqlQ57A9eCDNIfBCKQ0IqFADq8C1H7T7ko,36518
|
|
42
|
+
teareduce/cleanest/trackedbutton.py,sha256=r6Mzhb24c3HaJdvGGGFLn7cF9n4TgsKYc_yfcYIyB4g,2348
|
|
40
43
|
teareduce/cookbook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
44
|
teareduce/cookbook/get_cookbook_file.py,sha256=vde-iNii2lm1QII8GmLRsFsKNxkdsd7njCBE-8Z7io0,1088
|
|
42
45
|
teareduce/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
46
|
teareduce/tests/test_cleanest.py,sha256=6dRqkw1RQMKsFrC8cEweMvTD6wXhiDv3P4PS57-HEqI,5598
|
|
44
47
|
teareduce/tests/test_sliceregion.py,sha256=S7Zoh2eEBFIEbfsXgWBEMCf7pottjw2oLhqlZJQkAwg,3785
|
|
45
48
|
teareduce/tests/test_version.py,sha256=mKLnbXyvVNc1pATq5PxR8qeoFMPAFL_GilFV6IHLOi0,172
|
|
46
|
-
teareduce-0.
|
|
47
|
-
teareduce-0.
|
|
48
|
-
teareduce-0.
|
|
49
|
-
teareduce-0.
|
|
50
|
-
teareduce-0.
|
|
51
|
-
teareduce-0.
|
|
49
|
+
teareduce-0.6.1.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
50
|
+
teareduce-0.6.1.dist-info/METADATA,sha256=tYpScu331TcUdNsSurzVythnm0_NHdEQe9CijpaOiCw,3628
|
|
51
|
+
teareduce-0.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
52
|
+
teareduce-0.6.1.dist-info/entry_points.txt,sha256=6yBvig5jTL2ugqz5SF767AiszzrHKGRASsX1II84kqA,66
|
|
53
|
+
teareduce-0.6.1.dist-info/top_level.txt,sha256=7OkwtX9zNRkGJ7ACgjk4ESgC74qUYcS5O2qcO0v-Si4,10
|
|
54
|
+
teareduce-0.6.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|