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
|
@@ -9,10 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
"""Parameter editor dialog for L.A.Cosmic parameters."""
|
|
11
11
|
|
|
12
|
+
from astropy.io import fits
|
|
13
|
+
from pathlib import Path
|
|
12
14
|
import tkinter as tk
|
|
13
15
|
from tkinter import ttk
|
|
16
|
+
from tkinter import filedialog
|
|
14
17
|
from tkinter import messagebox
|
|
15
18
|
|
|
19
|
+
from .askextension import ask_extension_input_image
|
|
16
20
|
from .centerchildparent import center_on_parent
|
|
17
21
|
from .definitions import lacosmic_default_dict
|
|
18
22
|
|
|
@@ -20,7 +24,21 @@ from .definitions import lacosmic_default_dict
|
|
|
20
24
|
class ParameterEditor:
|
|
21
25
|
"""A dialog to edit L.A.Cosmic parameters."""
|
|
22
26
|
|
|
23
|
-
def __init__(
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
root,
|
|
30
|
+
param_dict,
|
|
31
|
+
window_title,
|
|
32
|
+
xmin,
|
|
33
|
+
xmax,
|
|
34
|
+
ymin,
|
|
35
|
+
ymax,
|
|
36
|
+
imgshape,
|
|
37
|
+
inbkg=None,
|
|
38
|
+
extnum_inbkg=None,
|
|
39
|
+
invar=None,
|
|
40
|
+
extnum_invar=None,
|
|
41
|
+
):
|
|
24
42
|
"""Initialize the parameter editor dialog.
|
|
25
43
|
|
|
26
44
|
Parameters
|
|
@@ -45,6 +63,14 @@ class ParameterEditor:
|
|
|
45
63
|
From 1 to NAXIS2.
|
|
46
64
|
imgshape : tuple
|
|
47
65
|
Shape of the image (height, width).
|
|
66
|
+
inbkg : str or None
|
|
67
|
+
Path to the input background image FITS file.
|
|
68
|
+
extnum_inbkg : int or None
|
|
69
|
+
FITS extension number for the input background image.
|
|
70
|
+
invar : str or None
|
|
71
|
+
Path to the input variance image FITS file.
|
|
72
|
+
extnum_invar : int or None
|
|
73
|
+
FITS extension number for the input variance image.
|
|
48
74
|
|
|
49
75
|
Methods
|
|
50
76
|
-------
|
|
@@ -82,7 +108,11 @@ class ParameterEditor:
|
|
|
82
108
|
self.param_dict["ymax"]["value"] = ymax
|
|
83
109
|
self.imgshape = imgshape
|
|
84
110
|
self.entries = {"run1": {}, "run2": {}} # dictionary to hold entry widgets
|
|
85
|
-
self.
|
|
111
|
+
self.inbkg = inbkg
|
|
112
|
+
self.extnum_inbkg = extnum_inbkg
|
|
113
|
+
self.invar = invar
|
|
114
|
+
self.extnum_invar = extnum_invar
|
|
115
|
+
self.result_dict = {}
|
|
86
116
|
|
|
87
117
|
# Create the form
|
|
88
118
|
self.create_widgets()
|
|
@@ -90,6 +120,11 @@ class ParameterEditor:
|
|
|
90
120
|
|
|
91
121
|
def create_widgets(self):
|
|
92
122
|
"""Create the widgets for the dialog."""
|
|
123
|
+
# Define different styles for different conditions
|
|
124
|
+
style = ttk.Style()
|
|
125
|
+
style.configure("Normal.TCombobox", foreground="black", background="white")
|
|
126
|
+
style.configure("Changed.TCombobox", foreground="red", background="white")
|
|
127
|
+
|
|
93
128
|
# Main frame
|
|
94
129
|
main_frame = tk.Frame(self.root, padx=10, pady=10)
|
|
95
130
|
main_frame.pack()
|
|
@@ -101,59 +136,147 @@ class ParameterEditor:
|
|
|
101
136
|
bold_font = default_font.copy()
|
|
102
137
|
bold_font.configure(weight="bold", size=default_font.cget("size") + 2)
|
|
103
138
|
subtitle_label = tk.Label(main_frame, text="L.A.Cosmic Parameters", font=bold_font)
|
|
104
|
-
subtitle_label.grid(row=row, column=0, columnspan=
|
|
139
|
+
subtitle_label.grid(row=row, column=0, columnspan=9, pady=(0, 10))
|
|
105
140
|
row += 1
|
|
106
141
|
|
|
142
|
+
# Count number of parameters for run1 and run2
|
|
143
|
+
nparams_run1 = sum(1 for key in self.param_dict.keys() if key.startswith("run1_"))
|
|
144
|
+
nparams_run2 = sum(1 for key in self.param_dict.keys() if key.startswith("run2_"))
|
|
145
|
+
if nparams_run1 != nparams_run2:
|
|
146
|
+
raise ValueError("Number of parameters for run1 and run2 do not match.")
|
|
147
|
+
nparams_input_images = len(["inbkg", "invar"])
|
|
148
|
+
nparams_total = nparams_input_images + nparams_run1
|
|
149
|
+
max_num_params_in_columns = nparams_total // 2 + nparams_total % 2
|
|
150
|
+
|
|
107
151
|
# Create labels and entry fields for each parameter.
|
|
108
152
|
bold_font_subheader = default_font.copy()
|
|
109
153
|
bold_font_subheader.configure(weight="bold", size=default_font.cget("size") + 1)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
154
|
+
for subtable in range(2):
|
|
155
|
+
if subtable == 0:
|
|
156
|
+
coloff = 0
|
|
157
|
+
else:
|
|
158
|
+
coloff = 5
|
|
159
|
+
label = tk.Label(main_frame, text="Parameter", font=bold_font_subheader, anchor="w", fg="gray")
|
|
160
|
+
label.grid(row=row, column=0 + coloff, sticky="e", pady=0)
|
|
161
|
+
label = tk.Label(main_frame, text="Run 1", font=bold_font_subheader, anchor="w", fg="gray", width=10)
|
|
162
|
+
label.grid(row=row, column=1 + coloff, sticky="w", padx=10, pady=0)
|
|
163
|
+
label = tk.Label(main_frame, text="Run 2", font=bold_font_subheader, anchor="w", fg="gray", width=10)
|
|
164
|
+
label.grid(row=row, column=2 + coloff, sticky="w", padx=10, pady=0)
|
|
165
|
+
label = tk.Label(main_frame, text="Type", font=bold_font_subheader, anchor="w", fg="gray", width=10)
|
|
166
|
+
label.grid(row=row, column=3 + coloff, sticky="w", pady=0)
|
|
118
167
|
row += 1
|
|
168
|
+
|
|
119
169
|
# Note: here we are using entry_vars to trace changes in the entries
|
|
120
170
|
# so that we can update the color of run2 entries if they differ from run1.
|
|
121
171
|
self.entry_vars = {}
|
|
172
|
+
row_subtable = 0
|
|
173
|
+
coloff = 0
|
|
122
174
|
for key, info in self.param_dict.items():
|
|
123
175
|
if not key.startswith("run1_"):
|
|
124
176
|
continue
|
|
125
177
|
# Parameter name label
|
|
126
178
|
label = tk.Label(main_frame, text=f"{key[5:]}:", anchor="e", width=15)
|
|
127
|
-
label.grid(row=row, column=
|
|
179
|
+
label.grid(row=row, column=coloff, sticky="w", pady=5)
|
|
128
180
|
# Entry field for run1
|
|
129
181
|
self.entry_vars[key] = tk.StringVar()
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
182
|
+
if key[5:] in ["cleantype", "fsmode", "psfmodel"]:
|
|
183
|
+
entry = ttk.Combobox(
|
|
184
|
+
main_frame,
|
|
185
|
+
textvariable=self.entry_vars[key],
|
|
186
|
+
width=8,
|
|
187
|
+
state="readonly",
|
|
188
|
+
values=info["valid_values"],
|
|
189
|
+
style="Normal.TCombobox",
|
|
190
|
+
)
|
|
191
|
+
self.entry_vars[key].set(str(info["value"]))
|
|
192
|
+
entry.bind("<<ComboboxSelected>>", lambda e: self.update_colour_param_run1_run2())
|
|
193
|
+
else:
|
|
194
|
+
self.entry_vars[key].trace_add("write", lambda *args: self.update_colour_param_run1_run2())
|
|
195
|
+
entry = tk.Entry(main_frame, textvariable=self.entry_vars[key], width=10)
|
|
196
|
+
entry.insert(0, str(info["value"]))
|
|
197
|
+
entry.grid(row=row, column=1 + coloff, padx=10, pady=5)
|
|
134
198
|
self.entries[key] = entry # dictionary to hold entry widgets
|
|
135
199
|
# Entry field for run2
|
|
136
200
|
key2 = "run2_" + key[5:]
|
|
137
201
|
self.entry_vars[key2] = tk.StringVar()
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
202
|
+
if key[5:] in ["cleantype", "fsmode", "psfmodel"]:
|
|
203
|
+
entry = ttk.Combobox(
|
|
204
|
+
main_frame,
|
|
205
|
+
textvariable=self.entry_vars[key2],
|
|
206
|
+
width=8,
|
|
207
|
+
state="readonly",
|
|
208
|
+
values=info["valid_values"],
|
|
209
|
+
style="Normal.TCombobox",
|
|
210
|
+
)
|
|
211
|
+
self.entry_vars[key2].set(str(self.param_dict[key2]["value"]))
|
|
212
|
+
entry.bind("<<ComboboxSelected>>", lambda e: self.update_colour_param_run1_run2())
|
|
213
|
+
else:
|
|
214
|
+
self.entry_vars[key2].trace_add("write", lambda *args: self.update_colour_param_run1_run2())
|
|
215
|
+
entry = tk.Entry(main_frame, textvariable=self.entry_vars[key2], width=10)
|
|
216
|
+
entry.insert(0, str(self.param_dict[key2]["value"]))
|
|
217
|
+
entry.grid(row=row, column=2 + coloff, padx=10, pady=5)
|
|
142
218
|
self.entries["run2_" + key[5:]] = entry # dictionary to hold entry widgets
|
|
143
219
|
# Type label
|
|
144
|
-
|
|
145
|
-
|
|
220
|
+
infotext = info["type"].__name__
|
|
221
|
+
if infotext == "int":
|
|
222
|
+
if "intmode" in info:
|
|
223
|
+
if info["intmode"] == "odd":
|
|
224
|
+
infotext += ", odd"
|
|
225
|
+
elif info["intmode"] == "even":
|
|
226
|
+
infotext += ", even"
|
|
227
|
+
type_label = tk.Label(main_frame, text=f"({infotext})", fg="gray", anchor="w", width=10)
|
|
228
|
+
type_label.grid(row=row, column=3 + coloff, sticky="w", pady=5)
|
|
229
|
+
row_subtable += 1
|
|
230
|
+
if row_subtable == max_num_params_in_columns:
|
|
231
|
+
coloff = 5
|
|
232
|
+
row -= max_num_params_in_columns
|
|
146
233
|
row += 1
|
|
147
|
-
|
|
234
|
+
|
|
235
|
+
# Auxiliary images
|
|
236
|
+
label = tk.Label(main_frame, text="inbkg:", anchor="e", width=15)
|
|
237
|
+
label.grid(row=row, column=coloff, sticky="w", pady=5)
|
|
238
|
+
if self.inbkg is None:
|
|
239
|
+
self.filename_inbkg = tk.StringVar(value="None")
|
|
240
|
+
else:
|
|
241
|
+
self.filename_inbkg = tk.StringVar(value=str(Path(self.inbkg).name + f"[{self.extnum_inbkg}]"))
|
|
242
|
+
file_inbkg_label = tk.Label(
|
|
243
|
+
main_frame, textvariable=self.filename_inbkg, fg="blue", bg="white", cursor="hand2", anchor="w", width=40
|
|
244
|
+
)
|
|
245
|
+
file_inbkg_label.grid(row=row, column=coloff + 1, columnspan=4, sticky="w", padx=10, pady=5)
|
|
246
|
+
file_inbkg_label.bind("<Button-1>", lambda e: self.define_inbkg())
|
|
247
|
+
row += 1
|
|
248
|
+
|
|
249
|
+
label = tk.Label(main_frame, text="invar:", anchor="e", width=15)
|
|
250
|
+
label.grid(row=row, column=coloff, sticky="w", pady=5)
|
|
251
|
+
if self.invar is None:
|
|
252
|
+
self.filename_invar = tk.StringVar(value="None")
|
|
253
|
+
else:
|
|
254
|
+
self.filename_invar = tk.StringVar(value=str(Path(self.invar).name + f"[{self.extnum_invar}]"))
|
|
255
|
+
file_invar_label = tk.Label(
|
|
256
|
+
main_frame, textvariable=self.filename_invar, fg="blue", bg="white", cursor="hand2", anchor="w", width=40
|
|
257
|
+
)
|
|
258
|
+
file_invar_label.grid(row=row, column=coloff + 1, columnspan=4, sticky="w", padx=10, pady=5)
|
|
259
|
+
file_invar_label.bind("<Button-1>", lambda e: self.define_invar())
|
|
260
|
+
row += 1
|
|
261
|
+
|
|
262
|
+
# Adjust row if odd number of parameters
|
|
263
|
+
if nparams_total % 2 != 0:
|
|
264
|
+
row += nparams_total % 2
|
|
265
|
+
|
|
266
|
+
# Vertical separator between splitted table
|
|
267
|
+
separatorv1 = ttk.Separator(main_frame, orient="vertical")
|
|
268
|
+
separatorv1.grid(
|
|
269
|
+
row=row - max_num_params_in_columns, column=4, rowspan=max_num_params_in_columns, sticky="ns", padx=10
|
|
270
|
+
)
|
|
148
271
|
|
|
149
272
|
# Separator
|
|
150
273
|
separator1 = ttk.Separator(main_frame, orient="horizontal")
|
|
151
|
-
separator1.grid(row=row, column=0, columnspan=
|
|
274
|
+
separator1.grid(row=row, column=0, columnspan=9, sticky="ew", pady=(10, 10))
|
|
152
275
|
row += 1
|
|
153
276
|
|
|
154
277
|
# Subtitle for additional parameters
|
|
155
278
|
subtitle_label = tk.Label(main_frame, text="Additional Parameters", font=bold_font)
|
|
156
|
-
subtitle_label.grid(row=row, column=0, columnspan=
|
|
279
|
+
subtitle_label.grid(row=row, column=0, columnspan=9, pady=(0, 10))
|
|
157
280
|
row += 1
|
|
158
281
|
|
|
159
282
|
# Dilation label and entry
|
|
@@ -167,28 +290,31 @@ class ParameterEditor:
|
|
|
167
290
|
main_frame, text=f"({self.param_dict['dilation']['type'].__name__})", fg="gray", anchor="w", width=10
|
|
168
291
|
)
|
|
169
292
|
type_label.grid(row=row, column=2, sticky="w", pady=5)
|
|
170
|
-
row += 1
|
|
171
293
|
|
|
172
294
|
label = tk.Label(main_frame, text="Border Padding:", anchor="e", width=15)
|
|
173
|
-
label.grid(row=row, column=
|
|
295
|
+
label.grid(row=row, column=5, sticky="w", pady=5)
|
|
174
296
|
entry = tk.Entry(main_frame, width=10)
|
|
175
297
|
entry.insert(0, str(self.param_dict["borderpadd"]["value"]))
|
|
176
|
-
entry.grid(row=row, column=
|
|
298
|
+
entry.grid(row=row, column=6, padx=10, pady=5)
|
|
177
299
|
self.entries["borderpadd"] = entry
|
|
178
300
|
type_label = tk.Label(
|
|
179
301
|
main_frame, text=f"({self.param_dict['borderpadd']['type'].__name__})", fg="gray", anchor="w", width=10
|
|
180
302
|
)
|
|
181
|
-
type_label.grid(row=row, column=
|
|
303
|
+
type_label.grid(row=row, column=7, sticky="w", pady=5)
|
|
182
304
|
row += 1
|
|
183
305
|
|
|
306
|
+
# Vertical separator
|
|
307
|
+
separatorv2 = ttk.Separator(main_frame, orient="vertical")
|
|
308
|
+
separatorv2.grid(row=row - 1, column=4, rowspan=1, sticky="ns", padx=10)
|
|
309
|
+
|
|
184
310
|
# Separator
|
|
185
311
|
separator2 = ttk.Separator(main_frame, orient="horizontal")
|
|
186
|
-
separator2.grid(row=row, column=0, columnspan=
|
|
312
|
+
separator2.grid(row=row, column=0, columnspan=9, sticky="ew", pady=(10, 10))
|
|
187
313
|
row += 1
|
|
188
314
|
|
|
189
315
|
# Subtitle for region to be examined
|
|
190
316
|
subtitle_label = tk.Label(main_frame, text="Region to be Examined", font=bold_font)
|
|
191
|
-
subtitle_label.grid(row=row, column=0, columnspan=
|
|
317
|
+
subtitle_label.grid(row=row, column=0, columnspan=9, pady=(0, 10))
|
|
192
318
|
row += 1
|
|
193
319
|
|
|
194
320
|
# Region to be examined label and entries
|
|
@@ -196,11 +322,15 @@ class ParameterEditor:
|
|
|
196
322
|
if key.lower() in ["xmin", "xmax", "ymin", "ymax"]:
|
|
197
323
|
# Parameter name label
|
|
198
324
|
label = tk.Label(main_frame, text=f"{key}:", anchor="e", width=15)
|
|
199
|
-
|
|
325
|
+
if key.lower() in ["xmin", "xmax"]:
|
|
326
|
+
coloff = 0
|
|
327
|
+
else:
|
|
328
|
+
coloff = 5
|
|
329
|
+
label.grid(row=row, column=coloff, sticky="w", pady=5)
|
|
200
330
|
# Entry field
|
|
201
331
|
entry = tk.Entry(main_frame, width=10)
|
|
202
332
|
entry.insert(0, str(info["value"]))
|
|
203
|
-
entry.grid(row=row, column=1, padx=10, pady=5)
|
|
333
|
+
entry.grid(row=row, column=coloff + 1, padx=10, pady=5)
|
|
204
334
|
self.entries[key] = entry # dictionary to hold entry widgets
|
|
205
335
|
# Type label
|
|
206
336
|
dumtext = f"({info['type'].__name__})"
|
|
@@ -209,37 +339,100 @@ class ParameterEditor:
|
|
|
209
339
|
else:
|
|
210
340
|
dumtext += f" --> [1, {self.imgshape[0]}]"
|
|
211
341
|
type_label = tk.Label(main_frame, text=dumtext, fg="gray", anchor="w", width=15)
|
|
212
|
-
type_label.grid(row=row, column=2, sticky="w", pady=5)
|
|
213
|
-
|
|
342
|
+
type_label.grid(row=row, column=coloff + 2, sticky="w", pady=5)
|
|
343
|
+
if key.lower() == "xmax":
|
|
344
|
+
row -= 1
|
|
345
|
+
else:
|
|
346
|
+
row += 1
|
|
347
|
+
|
|
348
|
+
# Vertical separator
|
|
349
|
+
separatorv3 = ttk.Separator(main_frame, orient="vertical")
|
|
350
|
+
separatorv3.grid(row=row - 2, column=4, rowspan=2, sticky="ns", padx=10)
|
|
214
351
|
|
|
215
352
|
# Separator
|
|
216
353
|
separator3 = ttk.Separator(main_frame, orient="horizontal")
|
|
217
|
-
separator3.grid(row=row, column=0, columnspan=
|
|
354
|
+
separator3.grid(row=row, column=0, columnspan=9, sticky="ew", pady=(10, 10))
|
|
218
355
|
row += 1
|
|
219
356
|
|
|
220
357
|
# Button frame
|
|
221
358
|
button_frame = tk.Frame(main_frame)
|
|
222
|
-
button_frame.grid(row=row, column=0, columnspan=
|
|
359
|
+
button_frame.grid(row=row, column=0, columnspan=9, pady=(5, 0))
|
|
223
360
|
|
|
224
361
|
# OK button
|
|
225
|
-
ok_button =
|
|
226
|
-
ok_button.pack(side="left", padx=5)
|
|
362
|
+
self.ok_button = ttk.Button(button_frame, text="OK", takefocus=True, command=self.on_ok)
|
|
363
|
+
self.ok_button.pack(side="left", padx=5)
|
|
227
364
|
|
|
228
365
|
# Cancel button
|
|
229
|
-
cancel_button =
|
|
230
|
-
cancel_button.pack(side="left", padx=5)
|
|
366
|
+
self.cancel_button = ttk.Button(button_frame, text="Cancel", command=self.on_cancel)
|
|
367
|
+
self.cancel_button.pack(side="left", padx=5)
|
|
231
368
|
|
|
232
369
|
# Reset button
|
|
233
|
-
reset_button =
|
|
234
|
-
reset_button.pack(side="left", padx=5)
|
|
370
|
+
self.reset_button = ttk.Button(button_frame, text="Reset", command=self.on_reset)
|
|
371
|
+
self.reset_button.pack(side="left", padx=5)
|
|
372
|
+
|
|
373
|
+
# Set focus to OK button
|
|
374
|
+
self.ok_button.focus_set()
|
|
375
|
+
|
|
376
|
+
def define_inbkg(self):
|
|
377
|
+
"""Define the input background image."""
|
|
378
|
+
self.inbkg = filedialog.askopenfilename(
|
|
379
|
+
parent=self.root,
|
|
380
|
+
title="Select FITS file to be used as input background image",
|
|
381
|
+
filetypes=[("FITS files", "*.fits *.fit *.fts"), ("All files", "*.*")],
|
|
382
|
+
)
|
|
383
|
+
if not self.inbkg:
|
|
384
|
+
self.inbkg = None
|
|
385
|
+
if isinstance(self.inbkg, str):
|
|
386
|
+
self.inbkg = self.inbkg.strip()
|
|
387
|
+
|
|
388
|
+
if self.inbkg in ["", None]:
|
|
389
|
+
self.inbkg = None
|
|
390
|
+
self.filename_inbkg.set("None")
|
|
391
|
+
self.extnum_inbkg = None
|
|
392
|
+
return
|
|
393
|
+
else:
|
|
394
|
+
self.extnum_inbkg = ask_extension_input_image(self.inbkg, self.imgshape)
|
|
395
|
+
if self.extnum_inbkg is None:
|
|
396
|
+
self.inbkg = None
|
|
397
|
+
else:
|
|
398
|
+
self.filename_inbkg.set(str(Path(self.inbkg).name + f"[{self.extnum_inbkg}]"))
|
|
399
|
+
|
|
400
|
+
def define_invar(self):
|
|
401
|
+
"""Define the input variance image."""
|
|
402
|
+
self.invar = filedialog.askopenfilename(
|
|
403
|
+
parent=self.root,
|
|
404
|
+
title="Select FITS file to be used as input variance image",
|
|
405
|
+
filetypes=[("FITS files", "*.fits *.fit *.fts"), ("All files", "*.*")],
|
|
406
|
+
)
|
|
407
|
+
if not self.invar:
|
|
408
|
+
self.invar = None
|
|
409
|
+
if isinstance(self.invar, str):
|
|
410
|
+
self.invar = self.invar.strip()
|
|
411
|
+
|
|
412
|
+
if self.invar in ["", None]:
|
|
413
|
+
self.invar = None
|
|
414
|
+
self.filename_invar.set("None")
|
|
415
|
+
self.extnum_invar = None
|
|
416
|
+
return
|
|
417
|
+
else:
|
|
418
|
+
self.extnum_invar = ask_extension_input_image(self.invar, self.imgshape)
|
|
419
|
+
if self.extnum_invar is None:
|
|
420
|
+
self.invar = None
|
|
421
|
+
else:
|
|
422
|
+
self.filename_invar.set(str(Path(self.invar).name + f"[{self.extnum_invar}]"))
|
|
235
423
|
|
|
236
424
|
def on_ok(self):
|
|
237
425
|
"""Validate and save the updated values"""
|
|
238
426
|
try:
|
|
239
|
-
updated_dict = {
|
|
427
|
+
updated_dict = {
|
|
428
|
+
"inbkg": {"value": self.inbkg, "type": str},
|
|
429
|
+
"extnum_inbkg": {"value": self.extnum_inbkg, "type": int},
|
|
430
|
+
"invar": {"value": self.invar, "type": str},
|
|
431
|
+
"extnum_invar": {"value": self.extnum_invar, "type": int},
|
|
432
|
+
}
|
|
240
433
|
|
|
241
434
|
for key, info in self.param_dict.items():
|
|
242
|
-
if key
|
|
435
|
+
if key in ["nruns", "inbkg", "extnum_inbkg", "invar", "extnum_invar"]:
|
|
243
436
|
continue
|
|
244
437
|
entry_value = self.entries[key].get()
|
|
245
438
|
value_type = info["type"]
|
|
@@ -253,12 +446,24 @@ class ParameterEditor:
|
|
|
253
446
|
converted_value = False
|
|
254
447
|
else:
|
|
255
448
|
raise ValueError(f"Invalid boolean value for {key}")
|
|
449
|
+
elif value_type == str:
|
|
450
|
+
converted_value = entry_value
|
|
451
|
+
if "valid_values" in info and entry_value not in info["valid_values"]:
|
|
452
|
+
raise ValueError(f"Invalid value for {key}. Valid values are: {info['valid_values']}")
|
|
256
453
|
else:
|
|
257
454
|
converted_value = value_type(entry_value)
|
|
258
455
|
if "positive" in info and info["positive"] and converted_value < 0:
|
|
259
456
|
raise ValueError(f"Value for {key} must be positive")
|
|
457
|
+
if "intmode" in info:
|
|
458
|
+
if info["intmode"] == "odd" and converted_value % 2 == 0:
|
|
459
|
+
raise ValueError(f"Value for {key} must be an odd integer")
|
|
460
|
+
elif info["intmode"] == "even" and converted_value % 2 != 0:
|
|
461
|
+
raise ValueError(f"Value for {key} must be an even integer")
|
|
260
462
|
|
|
261
|
-
|
|
463
|
+
# Duplicate the parameter info and update only the value
|
|
464
|
+
# (preserving other metadata)
|
|
465
|
+
updated_dict[key] = self.param_dict[key].copy()
|
|
466
|
+
updated_dict[key]["value"] = converted_value
|
|
262
467
|
|
|
263
468
|
# Check whether any run1 and run2 parameters differ
|
|
264
469
|
nruns = 1
|
|
@@ -306,11 +511,21 @@ class ParameterEditor:
|
|
|
306
511
|
self.param_dict["xmax"]["value"] = self.imgshape[1]
|
|
307
512
|
self.param_dict["ymin"]["value"] = 1
|
|
308
513
|
self.param_dict["ymax"]["value"] = self.imgshape[0]
|
|
514
|
+
self.inbkg = None
|
|
515
|
+
self.extnum_inbkg = None
|
|
516
|
+
self.filename_inbkg.set("None")
|
|
517
|
+
self.invar = None
|
|
518
|
+
self.extnum_invar = None
|
|
519
|
+
self.filename_invar.set("None")
|
|
309
520
|
for key, info in self.param_dict.items():
|
|
310
|
-
if key
|
|
521
|
+
if key in ["nruns", "inbkg", "extnum_inbkg", "invar", "extnum_invar"]:
|
|
311
522
|
continue
|
|
312
|
-
|
|
313
|
-
|
|
523
|
+
parname = key[5:]
|
|
524
|
+
if parname in ["cleantype", "fsmode", "psfmodel"]:
|
|
525
|
+
self.entries[key].set(str(info["value"]))
|
|
526
|
+
else:
|
|
527
|
+
self.entries[key].delete(0, tk.END)
|
|
528
|
+
self.entries[key].insert(0, str(info["value"]))
|
|
314
529
|
|
|
315
530
|
def get_result(self):
|
|
316
531
|
"""Return the updated dictionary"""
|
|
@@ -324,6 +539,19 @@ class ParameterEditor:
|
|
|
324
539
|
parname = key[5:]
|
|
325
540
|
if key in self.entries and "run2_" + parname in self.entries:
|
|
326
541
|
if self.entries[key].get() != self.entries["run2_" + parname].get():
|
|
327
|
-
|
|
542
|
+
if parname in ["cleantype", "fsmode", "psfmodel"]:
|
|
543
|
+
self.entries["run2_" + parname].configure(style="Changed.TCombobox")
|
|
544
|
+
else:
|
|
545
|
+
self.entries["run2_" + parname].config(fg="red")
|
|
328
546
|
else:
|
|
329
|
-
|
|
547
|
+
if parname in ["cleantype", "fsmode", "psfmodel"]:
|
|
548
|
+
self.entries["run2_" + parname].configure(style="Normal.TCombobox")
|
|
549
|
+
else:
|
|
550
|
+
self.entries["run2_" + parname].config(fg="black")
|
|
551
|
+
# Remove the highlight after choosing an option from the dropdown
|
|
552
|
+
# (to see the color change immediately)
|
|
553
|
+
if parname in ["cleantype", "fsmode", "psfmodel"]:
|
|
554
|
+
if "run_1_" + parname in self.entries:
|
|
555
|
+
self.entries["run1_" + parname].selection_clear()
|
|
556
|
+
if "run2_" + parname in self.entries:
|
|
557
|
+
self.entries["run2_" + parname].selection_clear()
|