teareduce 0.5.9__py3-none-any.whl → 0.6.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.
- teareduce/cleanest/__init__.py +2 -2
- teareduce/cleanest/__main__.py +11 -5
- teareduce/cleanest/askextension.py +85 -0
- teareduce/cleanest/cosmicraycleanerapp.py +289 -64
- teareduce/cleanest/definitions.py +55 -9
- teareduce/cleanest/gausskernel2d_elliptical.py +54 -0
- teareduce/cleanest/interpolate.py +65 -48
- teareduce/cleanest/interpolationeditor.py +196 -52
- teareduce/cleanest/lacosmicpad.py +92 -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.0.dist-info}/METADATA +1 -1
- {teareduce-0.5.9.dist-info → teareduce-0.6.0.dist-info}/RECORD +19 -16
- {teareduce-0.5.9.dist-info → teareduce-0.6.0.dist-info}/WHEEL +0 -0
- {teareduce-0.5.9.dist-info → teareduce-0.6.0.dist-info}/entry_points.txt +0 -0
- {teareduce-0.5.9.dist-info → teareduce-0.6.0.dist-info}/licenses/LICENSE.txt +0 -0
- {teareduce-0.5.9.dist-info → teareduce-0.6.0.dist-info}/top_level.txt +0 -0
|
@@ -15,12 +15,30 @@ from tkinter import ttk
|
|
|
15
15
|
|
|
16
16
|
from .centerchildparent import center_on_parent
|
|
17
17
|
from .definitions import VALID_CLEANING_METHODS
|
|
18
|
+
from .definitions import MASKFILL_OPERATOR_VALUES
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class InterpolationEditor:
|
|
21
22
|
"""Dialog to select interpolation cleaning parameters."""
|
|
22
23
|
|
|
23
|
-
def __init__(
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
root,
|
|
27
|
+
last_dilation,
|
|
28
|
+
last_npoints,
|
|
29
|
+
last_degree,
|
|
30
|
+
last_maskfill_size,
|
|
31
|
+
last_maskfill_operator,
|
|
32
|
+
last_maskfill_smooth,
|
|
33
|
+
last_maskfill_verbose,
|
|
34
|
+
auxdata,
|
|
35
|
+
cleandata_lacosmic,
|
|
36
|
+
xmin,
|
|
37
|
+
xmax,
|
|
38
|
+
ymin,
|
|
39
|
+
ymax,
|
|
40
|
+
imgshape,
|
|
41
|
+
):
|
|
24
42
|
"""Initialize the interpolation editor dialog.
|
|
25
43
|
|
|
26
44
|
Parameters
|
|
@@ -33,8 +51,18 @@ class InterpolationEditor:
|
|
|
33
51
|
The last used number of points for interpolation.
|
|
34
52
|
last_degree : int
|
|
35
53
|
The last used degree for interpolation.
|
|
54
|
+
last_maskfill_size : int
|
|
55
|
+
The last used maskfill size parameter.
|
|
56
|
+
last_maskfill_operator : str
|
|
57
|
+
The last used maskfill operator parameter.
|
|
58
|
+
last_maskfill_smooth : bool
|
|
59
|
+
The last used maskfill smooth parameter.
|
|
60
|
+
last_maskfill_verbose : bool
|
|
61
|
+
The last used maskfill verbose parameter.
|
|
36
62
|
auxdata : array-like or None
|
|
37
63
|
Auxiliary data for cleaning, if available.
|
|
64
|
+
cleandata_lacosmic : array-like or None
|
|
65
|
+
Cleaned data from L.A.Cosmic, if available.
|
|
38
66
|
xmin : float
|
|
39
67
|
Minimum x value of the data. From 1 to NAXIS1.
|
|
40
68
|
xmax : float
|
|
@@ -56,8 +84,6 @@ class InterpolationEditor:
|
|
|
56
84
|
Handle the Cancel button click event.
|
|
57
85
|
action_on_method_change()
|
|
58
86
|
Handle changes in the selected cleaning method.
|
|
59
|
-
check_interp_methods()
|
|
60
|
-
Check that all interpolation methods are valid.
|
|
61
87
|
|
|
62
88
|
Attributes
|
|
63
89
|
----------
|
|
@@ -67,6 +93,8 @@ class InterpolationEditor:
|
|
|
67
93
|
The last used dilation parameter.
|
|
68
94
|
auxdata : array-like or None
|
|
69
95
|
Auxiliary data for cleaning, if available.
|
|
96
|
+
cleandata_lacosmic : array-like or None
|
|
97
|
+
Cleaned data from L.A.Cosmic, if available.
|
|
70
98
|
dict_interp_methods : dict
|
|
71
99
|
Mapping of interpolation method names to their codes.
|
|
72
100
|
cleaning_method : str or None
|
|
@@ -75,6 +103,12 @@ class InterpolationEditor:
|
|
|
75
103
|
The number of points for interpolation.
|
|
76
104
|
degree : int
|
|
77
105
|
The degree for interpolation.
|
|
106
|
+
maskfill_size : int
|
|
107
|
+
The size parameter for maskfill.
|
|
108
|
+
maskfill_operator : str
|
|
109
|
+
The operator parameter for maskfill.
|
|
110
|
+
maskfill_smooth : bool
|
|
111
|
+
The smooth parameter for maskfill.
|
|
78
112
|
xmin : float
|
|
79
113
|
Minimum x value of the data. From 1 to NAXIS1.
|
|
80
114
|
xmax : float
|
|
@@ -90,21 +124,15 @@ class InterpolationEditor:
|
|
|
90
124
|
self.root.title("Cleaning Parameters")
|
|
91
125
|
self.last_dilation = last_dilation
|
|
92
126
|
self.auxdata = auxdata
|
|
93
|
-
self.
|
|
94
|
-
"x interp.": "x",
|
|
95
|
-
"y interp.": "y",
|
|
96
|
-
"surface interp.": "a-plane",
|
|
97
|
-
"median": "a-median",
|
|
98
|
-
"mean": "a-mean",
|
|
99
|
-
"lacosmic": "lacosmic",
|
|
100
|
-
"maskfill": "maskfill",
|
|
101
|
-
"auxdata": "auxdata",
|
|
102
|
-
}
|
|
103
|
-
self.check_interp_methods()
|
|
127
|
+
self.cleandata_lacosmic = cleandata_lacosmic
|
|
104
128
|
# Initialize parameters
|
|
105
129
|
self.cleaning_method = None
|
|
106
130
|
self.npoints = last_npoints
|
|
107
131
|
self.degree = last_degree
|
|
132
|
+
self.maskfill_size = last_maskfill_size
|
|
133
|
+
self.maskfill_operator = last_maskfill_operator
|
|
134
|
+
self.maskfill_smooth = last_maskfill_smooth
|
|
135
|
+
self.maskfill_verbose = last_maskfill_verbose
|
|
108
136
|
self.xmin = xmin
|
|
109
137
|
self.xmax = xmax
|
|
110
138
|
self.ymin = ymin
|
|
@@ -129,38 +157,48 @@ class InterpolationEditor:
|
|
|
129
157
|
bold_font = default_font.copy()
|
|
130
158
|
bold_font.configure(weight="bold", size=default_font.cget("size") + 2)
|
|
131
159
|
subtitle_label = tk.Label(main_frame, text="Select Cleaning Method", font=bold_font)
|
|
132
|
-
subtitle_label.grid(row=row, column=0, columnspan=
|
|
160
|
+
subtitle_label.grid(row=row, column=0, columnspan=7, pady=(0, 15))
|
|
133
161
|
row += 1
|
|
134
162
|
|
|
135
163
|
# Create labels and entry fields for each cleaning method
|
|
136
164
|
row = 1
|
|
165
|
+
column = 0
|
|
137
166
|
self.cleaning_method_var = tk.StringVar(value="surface interp.")
|
|
138
|
-
for interp_method in
|
|
139
|
-
|
|
167
|
+
for interp_method in VALID_CLEANING_METHODS.keys():
|
|
168
|
+
state = "normal"
|
|
140
169
|
# Skip replace by L.A.Cosmic values if last dilation is not zero
|
|
141
|
-
if interp_method == "lacosmic"
|
|
142
|
-
|
|
170
|
+
if interp_method == "lacosmic":
|
|
171
|
+
if self.last_dilation != 0:
|
|
172
|
+
state = "disabled"
|
|
173
|
+
if self.cleandata_lacosmic is None:
|
|
174
|
+
state = "disabled"
|
|
143
175
|
# Skip auxdata method if auxdata is not available
|
|
144
176
|
if interp_method == "auxdata" and self.auxdata is None:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
177
|
+
state = "disabled"
|
|
178
|
+
tk.Radiobutton(
|
|
179
|
+
main_frame,
|
|
180
|
+
text=interp_method,
|
|
181
|
+
variable=self.cleaning_method_var,
|
|
182
|
+
value=interp_method,
|
|
183
|
+
command=self.action_on_method_change,
|
|
184
|
+
state=state,
|
|
185
|
+
).grid(row=row, column=column, sticky="w", padx=5, pady=5)
|
|
186
|
+
column += 1
|
|
187
|
+
if column > 6:
|
|
188
|
+
column = 0
|
|
154
189
|
row += 1
|
|
190
|
+
row += 1
|
|
155
191
|
|
|
156
192
|
# Separator
|
|
157
193
|
separator1 = ttk.Separator(main_frame, orient="horizontal")
|
|
158
|
-
separator1.grid(row=row, column=0, columnspan=
|
|
194
|
+
separator1.grid(row=row, column=0, columnspan=7, sticky="ew", pady=(10, 10))
|
|
159
195
|
row += 1
|
|
160
196
|
|
|
161
197
|
# Subtitle for additional parameters
|
|
162
|
-
|
|
163
|
-
|
|
198
|
+
subtitle_label1 = tk.Label(main_frame, text="Fitting Parameters", font=bold_font)
|
|
199
|
+
subtitle_label1.grid(row=row, column=0, columnspan=3, pady=(0, 15))
|
|
200
|
+
subtitle_label2 = tk.Label(main_frame, text="Maskfill Parameters", font=bold_font)
|
|
201
|
+
subtitle_label2.grid(row=row, column=3, columnspan=3, pady=(0, 15))
|
|
164
202
|
row += 1
|
|
165
203
|
|
|
166
204
|
# Create labels and entry fields for each additional parameter
|
|
@@ -175,27 +213,61 @@ class InterpolationEditor:
|
|
|
175
213
|
self.entry_degree = tk.Entry(main_frame, width=10)
|
|
176
214
|
self.entry_degree.insert(0, self.degree)
|
|
177
215
|
self.entry_degree.grid(row=row, column=1, sticky="w")
|
|
216
|
+
row -= 1
|
|
217
|
+
label = tk.Label(main_frame, text="Size:")
|
|
218
|
+
label.grid(row=row, column=3, sticky="e", padx=(0, 10))
|
|
219
|
+
self.entry_maskfill_size = tk.Entry(main_frame, width=10)
|
|
220
|
+
self.entry_maskfill_size.insert(0, self.maskfill_size)
|
|
221
|
+
self.entry_maskfill_size.grid(row=row, column=4, sticky="w")
|
|
222
|
+
label = tk.Label(main_frame, text="Operator:")
|
|
223
|
+
label.grid(row=row, column=5, sticky="e", padx=(0, 10))
|
|
224
|
+
self.entry_maskfill_operator = ttk.Combobox(
|
|
225
|
+
main_frame, width=10, values=MASKFILL_OPERATOR_VALUES, state="readonly"
|
|
226
|
+
)
|
|
227
|
+
self.entry_maskfill_operator.set(self.maskfill_operator)
|
|
228
|
+
# self.entry_maskfill_operator = tk.Entry(main_frame, width=10)
|
|
229
|
+
# self.entry_maskfill_operator.insert(0, self.maskfill_operator)
|
|
230
|
+
self.entry_maskfill_operator.grid(row=row, column=6, sticky="w")
|
|
231
|
+
row += 1
|
|
232
|
+
label = tk.Label(main_frame, text="Smooth:")
|
|
233
|
+
label.grid(row=row, column=3, sticky="e", padx=(0, 10))
|
|
234
|
+
self.entry_maskfill_smooth = tk.Entry(main_frame, width=10)
|
|
235
|
+
self.entry_maskfill_smooth.insert(0, str(self.maskfill_smooth))
|
|
236
|
+
self.entry_maskfill_smooth.grid(row=row, column=4, sticky="w")
|
|
237
|
+
label = tk.Label(main_frame, text="Verbose:")
|
|
238
|
+
label.grid(row=row, column=5, sticky="e", padx=(0, 10))
|
|
239
|
+
self.entry_maskfill_verbose = tk.Entry(main_frame, width=10)
|
|
240
|
+
self.entry_maskfill_verbose.insert(0, str(self.maskfill_verbose))
|
|
241
|
+
self.entry_maskfill_verbose.grid(row=row, column=6, sticky="w")
|
|
178
242
|
row += 1
|
|
179
243
|
|
|
244
|
+
# Vertical separator
|
|
245
|
+
separatorv1 = ttk.Separator(main_frame, orient="vertical")
|
|
246
|
+
separatorv1.grid(row=row - 3, column=2, rowspan=3, sticky="ns", padx=5)
|
|
247
|
+
|
|
180
248
|
# Separator
|
|
181
249
|
separator2 = ttk.Separator(main_frame, orient="horizontal")
|
|
182
|
-
separator2.grid(row=row, column=0, columnspan=
|
|
250
|
+
separator2.grid(row=row, column=0, columnspan=7, sticky="ew", pady=(10, 10))
|
|
183
251
|
row += 1
|
|
184
252
|
|
|
185
253
|
# Subtitle for region to be examined
|
|
186
254
|
subtitle_label = tk.Label(main_frame, text="Region to be Examined", font=bold_font)
|
|
187
|
-
subtitle_label.grid(row=row, column=0, columnspan=
|
|
255
|
+
subtitle_label.grid(row=row, column=0, columnspan=7, pady=(0, 15))
|
|
188
256
|
row += 1
|
|
189
257
|
|
|
190
258
|
# Region to be examined label and entries
|
|
191
259
|
for key in ["xmin", "xmax", "ymin", "ymax"]:
|
|
192
260
|
# Parameter name label
|
|
193
|
-
label = tk.Label(main_frame, text=f"{key}:", anchor="e"
|
|
194
|
-
|
|
261
|
+
label = tk.Label(main_frame, text=f"{key}:", anchor="e")
|
|
262
|
+
if key in ["xmin", "xmax"]:
|
|
263
|
+
coloff = 0
|
|
264
|
+
else:
|
|
265
|
+
coloff = 4
|
|
266
|
+
label.grid(row=row, column=coloff, sticky="e", pady=5)
|
|
195
267
|
# Entry field
|
|
196
268
|
entry = tk.Entry(main_frame, width=10)
|
|
197
269
|
entry.insert(0, str(self.__dict__[key]))
|
|
198
|
-
entry.grid(row=row, column=1, padx=10, pady=5)
|
|
270
|
+
entry.grid(row=row, column=coloff + 1, padx=10, pady=5)
|
|
199
271
|
self.entries[key] = entry # dictionary to hold entry widgets
|
|
200
272
|
# Type label
|
|
201
273
|
dumtext = "(int)"
|
|
@@ -204,32 +276,42 @@ class InterpolationEditor:
|
|
|
204
276
|
else:
|
|
205
277
|
dumtext += f" --> [1, {self.imgshape[0]}]"
|
|
206
278
|
type_label = tk.Label(main_frame, text=dumtext, fg="gray", anchor="w", width=15)
|
|
207
|
-
type_label.grid(row=row, column=2, sticky="w", pady=5)
|
|
208
|
-
|
|
279
|
+
type_label.grid(row=row, column=coloff + 2, sticky="w", pady=5)
|
|
280
|
+
if key == "xmax":
|
|
281
|
+
row -= 1
|
|
282
|
+
else:
|
|
283
|
+
row += 1
|
|
284
|
+
|
|
285
|
+
# Vertical separator
|
|
286
|
+
separatorv2 = ttk.Separator(main_frame, orient="vertical")
|
|
287
|
+
separatorv2.grid(row=row - 2, column=3, rowspan=2, sticky="ns", padx=5)
|
|
209
288
|
|
|
210
289
|
# Separator
|
|
211
290
|
separator3 = ttk.Separator(main_frame, orient="horizontal")
|
|
212
|
-
separator3.grid(row=row, column=0, columnspan=
|
|
291
|
+
separator3.grid(row=row, column=0, columnspan=7, sticky="ew", pady=(10, 10))
|
|
213
292
|
row += 1
|
|
214
293
|
|
|
215
294
|
# Button frame
|
|
216
295
|
self.button_frame = tk.Frame(main_frame)
|
|
217
|
-
self.button_frame.grid(row=row, column=0, columnspan=
|
|
296
|
+
self.button_frame.grid(row=row, column=0, columnspan=7, pady=(5, 0))
|
|
218
297
|
|
|
219
298
|
# OK button
|
|
220
|
-
self.ok_button =
|
|
299
|
+
self.ok_button = ttk.Button(self.button_frame, text="OK", command=self.on_ok)
|
|
221
300
|
self.ok_button.pack(side="left", padx=5)
|
|
222
301
|
|
|
223
302
|
# Cancel button
|
|
224
|
-
self.cancel_button =
|
|
303
|
+
self.cancel_button = ttk.Button(self.button_frame, text="Cancel", command=self.on_cancel)
|
|
225
304
|
self.cancel_button.pack(side="left", padx=5)
|
|
226
305
|
|
|
306
|
+
# Initial focus on OK button
|
|
307
|
+
self.ok_button.focus_set()
|
|
308
|
+
|
|
227
309
|
# Initial action depending on the default method
|
|
228
310
|
self.action_on_method_change()
|
|
229
311
|
|
|
230
312
|
def on_ok(self):
|
|
231
313
|
"""Handle the OK button click event."""
|
|
232
|
-
self.cleaning_method =
|
|
314
|
+
self.cleaning_method = VALID_CLEANING_METHODS[self.cleaning_method_var.get()]
|
|
233
315
|
try:
|
|
234
316
|
self.npoints = int(self.entry_npoints.get())
|
|
235
317
|
except ValueError:
|
|
@@ -252,6 +334,44 @@ class InterpolationEditor:
|
|
|
252
334
|
messagebox.showerror("Input Error", "2*Npoints must be greater than Degree for x and y interpolation.")
|
|
253
335
|
return
|
|
254
336
|
|
|
337
|
+
try:
|
|
338
|
+
self.maskfill_size = int(self.entry_maskfill_size.get())
|
|
339
|
+
except ValueError:
|
|
340
|
+
messagebox.showerror("Input Error", "Maskfill size must be an integer.")
|
|
341
|
+
return
|
|
342
|
+
if self.maskfill_size < 1:
|
|
343
|
+
messagebox.showerror("Input Error", "Maskfill size must be at least 1.")
|
|
344
|
+
return
|
|
345
|
+
if self.maskfill_size % 2 == 0:
|
|
346
|
+
messagebox.showerror("Input Error", "Maskfill size must be an odd integer.")
|
|
347
|
+
return
|
|
348
|
+
|
|
349
|
+
self.maskfill_operator = self.entry_maskfill_operator.get().strip()
|
|
350
|
+
if not self.maskfill_operator:
|
|
351
|
+
messagebox.showerror("Input Error", "Maskfill operator cannot be empty.")
|
|
352
|
+
return
|
|
353
|
+
if self.maskfill_operator not in ["median", "mean"]:
|
|
354
|
+
messagebox.showerror("Input Error", "Maskfill operator must be 'median' or 'mean'.")
|
|
355
|
+
return
|
|
356
|
+
|
|
357
|
+
smooth_str = self.entry_maskfill_smooth.get().strip().lower()
|
|
358
|
+
if smooth_str == "true":
|
|
359
|
+
self.maskfill_smooth = True
|
|
360
|
+
elif smooth_str == "false":
|
|
361
|
+
self.maskfill_smooth = False
|
|
362
|
+
else:
|
|
363
|
+
messagebox.showerror("Input Error", "Maskfill smooth must be True or False.")
|
|
364
|
+
return
|
|
365
|
+
|
|
366
|
+
verbose_str = self.entry_maskfill_verbose.get().strip().lower()
|
|
367
|
+
if verbose_str == "true":
|
|
368
|
+
self.maskfill_verbose = True
|
|
369
|
+
elif verbose_str == "false":
|
|
370
|
+
self.maskfill_verbose = False
|
|
371
|
+
else:
|
|
372
|
+
messagebox.showerror("Input Error", "Maskfill verbose must be True or False.")
|
|
373
|
+
return
|
|
374
|
+
|
|
255
375
|
# Retrieve and validate region parameters
|
|
256
376
|
try:
|
|
257
377
|
xmin = int(self.entries["xmin"].get())
|
|
@@ -307,27 +427,51 @@ class InterpolationEditor:
|
|
|
307
427
|
if selected_method in ["x interp.", "y interp."]:
|
|
308
428
|
self.entry_npoints.config(state="normal")
|
|
309
429
|
self.entry_degree.config(state="normal")
|
|
430
|
+
self.entry_maskfill_size.config(state="disabled")
|
|
431
|
+
self.entry_maskfill_operator.config(state="disabled")
|
|
432
|
+
self.entry_maskfill_smooth.config(state="disabled")
|
|
433
|
+
self.entry_maskfill_verbose.config(state="disabled")
|
|
310
434
|
elif selected_method == "surface interp.":
|
|
311
435
|
self.entry_npoints.config(state="normal")
|
|
312
436
|
self.entry_degree.config(state="disabled")
|
|
437
|
+
self.entry_maskfill_size.config(state="disabled")
|
|
438
|
+
self.entry_maskfill_operator.config(state="disabled")
|
|
439
|
+
self.entry_maskfill_smooth.config(state="disabled")
|
|
440
|
+
self.entry_maskfill_verbose.config(state="disabled")
|
|
313
441
|
elif selected_method == "median":
|
|
314
442
|
self.entry_npoints.config(state="normal")
|
|
315
443
|
self.entry_degree.config(state="disabled")
|
|
444
|
+
self.entry_maskfill_size.config(state="disabled")
|
|
445
|
+
self.entry_maskfill_operator.config(state="disabled")
|
|
446
|
+
self.entry_maskfill_smooth.config(state="disabled")
|
|
447
|
+
self.entry_maskfill_verbose.config(state="disabled")
|
|
316
448
|
elif selected_method == "mean":
|
|
317
449
|
self.entry_npoints.config(state="normal")
|
|
318
450
|
self.entry_degree.config(state="disabled")
|
|
451
|
+
self.entry_maskfill_size.config(state="disabled")
|
|
452
|
+
self.entry_maskfill_operator.config(state="disabled")
|
|
453
|
+
self.entry_maskfill_smooth.config(state="disabled")
|
|
454
|
+
self.entry_maskfill_verbose.config(state="disabled")
|
|
319
455
|
elif selected_method == "lacosmic":
|
|
320
456
|
self.entry_npoints.config(state="disabled")
|
|
321
457
|
self.entry_degree.config(state="disabled")
|
|
458
|
+
self.entry_maskfill_size.config(state="disabled")
|
|
459
|
+
self.entry_maskfill_operator.config(state="disabled")
|
|
460
|
+
self.entry_maskfill_smooth.config(state="disabled")
|
|
461
|
+
self.entry_maskfill_verbose.config(state="disabled")
|
|
322
462
|
elif selected_method == "auxdata":
|
|
323
463
|
self.entry_npoints.config(state="disabled")
|
|
324
464
|
self.entry_degree.config(state="disabled")
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
465
|
+
self.entry_maskfill_size.config(state="disabled")
|
|
466
|
+
self.entry_maskfill_operator.config(state="disabled")
|
|
467
|
+
self.entry_maskfill_smooth.config(state="disabled")
|
|
468
|
+
self.entry_maskfill_verbose.config(state="disabled")
|
|
469
|
+
elif selected_method == "maskfill":
|
|
470
|
+
self.entry_npoints.config(state="disabled")
|
|
471
|
+
self.entry_degree.config(state="disabled")
|
|
472
|
+
self.entry_maskfill_size.config(state="normal")
|
|
473
|
+
self.entry_maskfill_operator.config(state="normal")
|
|
474
|
+
self.entry_maskfill_smooth.config(state="normal")
|
|
475
|
+
self.entry_maskfill_verbose.config(state="normal")
|
|
476
|
+
else:
|
|
477
|
+
messagebox.showerror("Error", f"Unknown cleaning method selected: {selected_method}")
|
|
@@ -19,8 +19,11 @@ except ModuleNotFoundError as e:
|
|
|
19
19
|
) from e
|
|
20
20
|
import numpy as np
|
|
21
21
|
|
|
22
|
+
from .definitions import VALID_LACOSMIC_PSFMODEL_VALUES
|
|
23
|
+
from .gausskernel2d_elliptical import gausskernel2d_elliptical
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
|
|
26
|
+
def lacosmicpad(pad_width, show_arguments=False, **kwargs):
|
|
24
27
|
"""Execute LACosmic algorithm on a padded array.
|
|
25
28
|
|
|
26
29
|
This function pads the input image array before applying the LACosmic
|
|
@@ -39,6 +42,8 @@ def lacosmicpad(pad_width, **kwargs):
|
|
|
39
42
|
pad_width : int
|
|
40
43
|
Width of the padding to be applied to the image before executing
|
|
41
44
|
the LACosmic algorithm.
|
|
45
|
+
show_arguments : bool
|
|
46
|
+
If True, display LACosmic arguments being employed.
|
|
42
47
|
**kwargs : dict
|
|
43
48
|
Keyword arguments to be passed to the `cosmicray_lacosmic` function.
|
|
44
49
|
|
|
@@ -49,6 +54,7 @@ def lacosmicpad(pad_width, **kwargs):
|
|
|
49
54
|
mask_array : 2D numpy.ndarray of bool
|
|
50
55
|
The mask array indicating detected cosmic rays.
|
|
51
56
|
"""
|
|
57
|
+
# Check for required 'ccd' argument
|
|
52
58
|
if "ccd" not in kwargs:
|
|
53
59
|
raise ValueError("The 'ccd' keyword argument must be provided.")
|
|
54
60
|
array = kwargs.pop("ccd")
|
|
@@ -56,6 +62,91 @@ def lacosmicpad(pad_width, **kwargs):
|
|
|
56
62
|
raise TypeError("The 'ccd' keyword argument must be a numpy ndarray.")
|
|
57
63
|
# Pad the array
|
|
58
64
|
padded_array = np.pad(array, pad_width, mode="reflect")
|
|
65
|
+
|
|
66
|
+
# Pad inbkg if provided
|
|
67
|
+
if "inbkg" in kwargs:
|
|
68
|
+
if kwargs["inbkg"] is not None:
|
|
69
|
+
inbkg = kwargs["inbkg"]
|
|
70
|
+
if not isinstance(inbkg, np.ndarray):
|
|
71
|
+
raise TypeError("The 'inbkg' keyword argument must be a numpy ndarray.")
|
|
72
|
+
kwargs["inbkg"] = np.pad(inbkg, pad_width, mode="reflect")
|
|
73
|
+
else:
|
|
74
|
+
kwargs["inbkg"] = None
|
|
75
|
+
|
|
76
|
+
# Pad invar if provided
|
|
77
|
+
if "invar" in kwargs:
|
|
78
|
+
if kwargs["invar"] is not None:
|
|
79
|
+
invar = kwargs["invar"]
|
|
80
|
+
if not isinstance(invar, np.ndarray):
|
|
81
|
+
raise TypeError("The 'invar' keyword argument must be a numpy ndarray.")
|
|
82
|
+
kwargs["invar"] = np.pad(invar, pad_width, mode="reflect")
|
|
83
|
+
else:
|
|
84
|
+
kwargs["invar"] = None
|
|
85
|
+
|
|
86
|
+
# check for fsmode
|
|
87
|
+
if "fsmode" not in kwargs:
|
|
88
|
+
raise ValueError("The 'fsmode' keyword argument must be provided.")
|
|
89
|
+
else:
|
|
90
|
+
fsmode = kwargs["fsmode"]
|
|
91
|
+
if fsmode == "convolve":
|
|
92
|
+
if "psfmodel" not in kwargs:
|
|
93
|
+
raise ValueError("The 'psfmodel' keyword argument must be provided when fsmode is 'convolve'.")
|
|
94
|
+
psfmodel = kwargs["psfmodel"]
|
|
95
|
+
if psfmodel not in VALID_LACOSMIC_PSFMODEL_VALUES:
|
|
96
|
+
raise ValueError(f"The 'psfmodel' keyword argument must be one of {VALID_LACOSMIC_PSFMODEL_VALUES}.")
|
|
97
|
+
if "psffwhm" in kwargs:
|
|
98
|
+
raise ValueError(
|
|
99
|
+
"When 'fsmode' is 'convolve', 'psffwhm' should not be provided; use 'psffwhm_x' and 'psffwhm_y' instead."
|
|
100
|
+
)
|
|
101
|
+
if "psffwhm_x" not in kwargs or "psffwhm_y" not in kwargs:
|
|
102
|
+
raise ValueError("When 'fsmode' is 'convolve', both 'psffwhm_x' and 'psffwhm_y' must be provided.")
|
|
103
|
+
fwhm_x = kwargs["psffwhm_x"]
|
|
104
|
+
fwhm_y = kwargs["psffwhm_y"]
|
|
105
|
+
if "psfsize" not in kwargs:
|
|
106
|
+
raise ValueError("When 'fsmode' is 'convolve', 'psfsize' must be provided.")
|
|
107
|
+
psfsize = kwargs["psfsize"]
|
|
108
|
+
if kwargs["psfmodel"] == "gaussxy":
|
|
109
|
+
if "psfk" in kwargs:
|
|
110
|
+
raise ValueError(
|
|
111
|
+
"When 'fsmode' is 'convolve' and 'psfmodel' is 'gaussxy', 'psfk' should not be provided; it will be generated from 'psffwhm_x' and 'psffwhm_y'."
|
|
112
|
+
)
|
|
113
|
+
kwargs["psfk"] = gausskernel2d_elliptical(fwhm_x, fwhm_y, psfsize)
|
|
114
|
+
if show_arguments:
|
|
115
|
+
print(
|
|
116
|
+
f"Generated elliptical Gaussian kernel with fwhm_x={fwhm_x}, fwhm_y={fwhm_y}, size={psfsize}."
|
|
117
|
+
)
|
|
118
|
+
elif kwargs["psfmodel"] in ["gauss", "moffat"]:
|
|
119
|
+
kwargs["psffwhm"] = (fwhm_x + fwhm_y) / 2.0 # average for circular psf
|
|
120
|
+
if show_arguments:
|
|
121
|
+
print(f"Set psffwhm to average of fwhm_x and fwhm_y: {kwargs['psffwhm']}.")
|
|
122
|
+
elif kwargs["psfmodel"] == "gaussx":
|
|
123
|
+
kwargs["psffwhm"] = fwhm_x
|
|
124
|
+
if show_arguments:
|
|
125
|
+
print(f"Set psffwhm to fwhm_x: {fwhm_x}.")
|
|
126
|
+
elif kwargs["psfmodel"] == "gaussy":
|
|
127
|
+
kwargs["psffwhm"] = fwhm_y
|
|
128
|
+
if show_arguments:
|
|
129
|
+
print(f"Set psffwhm to fwhm_y: {fwhm_y}.")
|
|
130
|
+
else:
|
|
131
|
+
raise ValueError(f"Unsupported psfmodel: {kwargs['psfmodel']}")
|
|
132
|
+
if show_arguments:
|
|
133
|
+
print("Deleting 'psffwhm_x' and 'psffwhm_y' from kwargs.")
|
|
134
|
+
del kwargs["psffwhm_x"]
|
|
135
|
+
del kwargs["psffwhm_y"]
|
|
136
|
+
elif fsmode == "median":
|
|
137
|
+
# Remove unnecessary parameters for median fsmode
|
|
138
|
+
for param in ["psfmodel", "psfsize", "psffwhm", "psffwhm_x", "psffwhm_y"]:
|
|
139
|
+
if param in kwargs:
|
|
140
|
+
if show_arguments:
|
|
141
|
+
print(f"Removing '{param}' argument since fsmode is 'median'.")
|
|
142
|
+
del kwargs[param]
|
|
143
|
+
else:
|
|
144
|
+
raise ValueError("The 'fsmode' keyword argument must be either 'convolve' or 'median'.")
|
|
145
|
+
|
|
146
|
+
# Show LACosmic arguments if requested
|
|
147
|
+
if show_arguments:
|
|
148
|
+
for key, value in kwargs.items():
|
|
149
|
+
print(f"LACosmic parameter: {key} = {value}")
|
|
59
150
|
# Apply LACosmic algorithm to the padded array
|
|
60
151
|
cleaned_padded_array, mask_padded_array = cosmicray_lacosmic(ccd=padded_array, **kwargs)
|
|
61
152
|
# Remove padding
|