teareduce 0.4.9__py3-none-any.whl → 0.5.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/__main__.py +18 -6
- teareduce/cleanest/cosmicraycleanerapp.py +586 -85
- teareduce/cleanest/definitions.py +51 -0
- teareduce/cleanest/find_closest_true.py +44 -0
- teareduce/cleanest/imagedisplay.py +155 -0
- teareduce/cleanest/interpolation_a.py +83 -0
- teareduce/cleanest/interpolation_x.py +80 -0
- teareduce/cleanest/interpolation_y.py +81 -0
- teareduce/cleanest/interpolationeditor.py +207 -0
- teareduce/cleanest/parametereditor.py +251 -0
- teareduce/cleanest/reviewcosmicray.py +351 -267
- teareduce/cookbook/get_cookbook_file.py +5 -0
- teareduce/version.py +1 -1
- {teareduce-0.4.9.dist-info → teareduce-0.5.1.dist-info}/METADATA +4 -1
- {teareduce-0.4.9.dist-info → teareduce-0.5.1.dist-info}/RECORD +19 -11
- {teareduce-0.4.9.dist-info → teareduce-0.5.1.dist-info}/WHEEL +0 -0
- {teareduce-0.4.9.dist-info → teareduce-0.5.1.dist-info}/entry_points.txt +0 -0
- {teareduce-0.4.9.dist-info → teareduce-0.5.1.dist-info}/licenses/LICENSE.txt +0 -0
- {teareduce-0.4.9.dist-info → teareduce-0.5.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,207 @@
|
|
|
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
|
+
"""Interpolation editor dialog for interpolation parameters."""
|
|
11
|
+
|
|
12
|
+
import tkinter as tk
|
|
13
|
+
from tkinter import messagebox
|
|
14
|
+
|
|
15
|
+
from .definitions import VALID_CLEANING_METHODS
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class InterpolationEditor:
|
|
19
|
+
"""Dialog to select interpolation cleaning parameters."""
|
|
20
|
+
def __init__(self, root, last_dilation, last_npoints, last_degree, auxdata):
|
|
21
|
+
"""Initialize the interpolation editor dialog.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
root : tk.Tk
|
|
26
|
+
The root Tkinter window.
|
|
27
|
+
last_dilation : int
|
|
28
|
+
The last used dilation parameter.
|
|
29
|
+
last_npoints : int
|
|
30
|
+
The last used number of points for interpolation.
|
|
31
|
+
last_degree : int
|
|
32
|
+
The last used degree for interpolation.
|
|
33
|
+
auxdata : array-like or None
|
|
34
|
+
Auxiliary data for cleaning, if available.
|
|
35
|
+
|
|
36
|
+
Methods
|
|
37
|
+
-------
|
|
38
|
+
create_widgets()
|
|
39
|
+
Create the widgets for the dialog.
|
|
40
|
+
on_ok()
|
|
41
|
+
Handle the OK button click event.
|
|
42
|
+
on_cancel()
|
|
43
|
+
Handle the Cancel button click event.
|
|
44
|
+
action_on_method_change()
|
|
45
|
+
Handle changes in the selected cleaning method.
|
|
46
|
+
check_interp_methods()
|
|
47
|
+
Check that all interpolation methods are valid.
|
|
48
|
+
|
|
49
|
+
Attributes
|
|
50
|
+
----------
|
|
51
|
+
root : tk.Tk
|
|
52
|
+
The root Tkinter window.
|
|
53
|
+
last_dilation : int
|
|
54
|
+
The last used dilation parameter.
|
|
55
|
+
auxdata : array-like or None
|
|
56
|
+
Auxiliary data for cleaning, if available.
|
|
57
|
+
dict_interp_methods : dict
|
|
58
|
+
Mapping of interpolation method names to their codes.
|
|
59
|
+
cleaning_method : str or None
|
|
60
|
+
The selected cleaning method code.
|
|
61
|
+
npoints : int
|
|
62
|
+
The number of points for interpolation.
|
|
63
|
+
degree : int
|
|
64
|
+
The degree for interpolation.
|
|
65
|
+
"""
|
|
66
|
+
self.root = root
|
|
67
|
+
self.root.title("Cleaning Parameters")
|
|
68
|
+
self.last_dilation = last_dilation
|
|
69
|
+
self.auxdata = auxdata
|
|
70
|
+
self.dict_interp_methods = {
|
|
71
|
+
"x interp.": "x",
|
|
72
|
+
"y interp.": "y",
|
|
73
|
+
"surface interp.": "a-plane",
|
|
74
|
+
"median": "a-median",
|
|
75
|
+
"lacosmic": "lacosmic",
|
|
76
|
+
"auxdata": "auxdata"
|
|
77
|
+
}
|
|
78
|
+
self.check_interp_methods()
|
|
79
|
+
# Initialize parameters
|
|
80
|
+
self.cleaning_method = None
|
|
81
|
+
self.npoints = last_npoints
|
|
82
|
+
self.degree = last_degree
|
|
83
|
+
# Create the form
|
|
84
|
+
self.create_widgets()
|
|
85
|
+
|
|
86
|
+
def create_widgets(self):
|
|
87
|
+
"""Create the widgets for the dialog."""
|
|
88
|
+
# Main frame
|
|
89
|
+
main_frame = tk.Frame(self.root, padx=10, pady=10)
|
|
90
|
+
main_frame.pack()
|
|
91
|
+
|
|
92
|
+
# Title
|
|
93
|
+
title_label = tk.Label(main_frame, text="Select Cleaning Method", font=("Arial", 14, "bold"))
|
|
94
|
+
title_label.grid(row=0, column=0, columnspan=2, pady=(0, 15))
|
|
95
|
+
|
|
96
|
+
# Create labels and entry fields for each cleaning method
|
|
97
|
+
row = 1
|
|
98
|
+
self.cleaning_method_var = tk.StringVar(value="surface interp.")
|
|
99
|
+
for interp_method in self.dict_interp_methods.keys():
|
|
100
|
+
valid_method = True
|
|
101
|
+
# Skip replace by L.A.Cosmic values if last dilation is not zero
|
|
102
|
+
if interp_method == "lacosmic" and self.last_dilation != 0:
|
|
103
|
+
valid_method = False
|
|
104
|
+
# Skip auxdata method if auxdata is not available
|
|
105
|
+
if interp_method == "auxdata" and self.auxdata is None:
|
|
106
|
+
valid_method = False
|
|
107
|
+
if valid_method:
|
|
108
|
+
tk.Radiobutton(
|
|
109
|
+
main_frame,
|
|
110
|
+
text=interp_method,
|
|
111
|
+
variable=self.cleaning_method_var,
|
|
112
|
+
value=interp_method,
|
|
113
|
+
command=self.action_on_method_change
|
|
114
|
+
).grid(row=row, column=0, sticky='w')
|
|
115
|
+
row += 1
|
|
116
|
+
|
|
117
|
+
# Create labels and entry fields for each additional parameter
|
|
118
|
+
label = tk.Label(main_frame, text='Npoints:')
|
|
119
|
+
label.grid(row=row, column=0, sticky='e', padx=(0, 10))
|
|
120
|
+
self.entry_npoints = tk.Entry(main_frame, width=10)
|
|
121
|
+
self.entry_npoints.insert(0, self.npoints)
|
|
122
|
+
self.entry_npoints.grid(row=row, column=1, sticky='w')
|
|
123
|
+
row += 1
|
|
124
|
+
label = tk.Label(main_frame, text='Degree:')
|
|
125
|
+
label.grid(row=row, column=0, sticky='e', padx=(0, 10))
|
|
126
|
+
self.entry_degree = tk.Entry(main_frame, width=10)
|
|
127
|
+
self.entry_degree.insert(0, self.degree)
|
|
128
|
+
self.entry_degree.grid(row=row, column=1, sticky='w')
|
|
129
|
+
row += 1
|
|
130
|
+
|
|
131
|
+
# Button frame
|
|
132
|
+
self.button_frame = tk.Frame(main_frame)
|
|
133
|
+
self.button_frame.grid(row=row, column=0, columnspan=2, pady=(15, 0))
|
|
134
|
+
|
|
135
|
+
# OK button
|
|
136
|
+
self.ok_button = tk.Button(self.button_frame, text="OK", width=5, command=self.on_ok)
|
|
137
|
+
self.ok_button.pack(side='left', padx=5)
|
|
138
|
+
|
|
139
|
+
# Cancel button
|
|
140
|
+
self.cancel_button = tk.Button(self.button_frame, text="Cancel", width=5, command=self.on_cancel)
|
|
141
|
+
self.cancel_button.pack(side='left', padx=5)
|
|
142
|
+
|
|
143
|
+
# Initial action depending on the default method
|
|
144
|
+
self.action_on_method_change()
|
|
145
|
+
|
|
146
|
+
def on_ok(self):
|
|
147
|
+
"""Handle the OK button click event."""
|
|
148
|
+
self.cleaning_method = self.dict_interp_methods[self.cleaning_method_var.get()]
|
|
149
|
+
try:
|
|
150
|
+
self.npoints = int(self.entry_npoints.get())
|
|
151
|
+
except ValueError:
|
|
152
|
+
messagebox.showerror("Input Error", "Npoints must be a positive integer.")
|
|
153
|
+
return
|
|
154
|
+
if self.npoints < 1:
|
|
155
|
+
messagebox.showerror("Input Error", "Npoints must be at least 1.")
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
self.degree = int(self.entry_degree.get())
|
|
160
|
+
except ValueError:
|
|
161
|
+
messagebox.showerror("Input Error", "Degree must be an integer.")
|
|
162
|
+
return
|
|
163
|
+
if self.degree < 0:
|
|
164
|
+
messagebox.showerror("Input Error", "Degree must be non-negative.")
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
if self.cleaning_method in ['x', 'y'] and 2 * self.npoints <= self.degree:
|
|
168
|
+
messagebox.showerror("Input Error", "2*Npoints must be greater than Degree for x and y interpolation.")
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
self.root.destroy()
|
|
172
|
+
|
|
173
|
+
def on_cancel(self):
|
|
174
|
+
"""Close the dialog without saving selected parameters."""
|
|
175
|
+
self.cleaning_method = None
|
|
176
|
+
self.npoints = None
|
|
177
|
+
self.degree = None
|
|
178
|
+
self.root.destroy()
|
|
179
|
+
|
|
180
|
+
def action_on_method_change(self):
|
|
181
|
+
"""Handle changes in the selected cleaning method."""
|
|
182
|
+
selected_method = self.cleaning_method_var.get()
|
|
183
|
+
print(f"Selected cleaning method: {selected_method}")
|
|
184
|
+
if selected_method in ['x interp.', 'y interp.']:
|
|
185
|
+
self.entry_npoints.config(state='normal')
|
|
186
|
+
self.entry_degree.config(state='normal')
|
|
187
|
+
elif selected_method == 'surface interp.':
|
|
188
|
+
self.entry_npoints.config(state='normal')
|
|
189
|
+
self.entry_degree.config(state='disabled')
|
|
190
|
+
elif selected_method == 'median':
|
|
191
|
+
self.entry_npoints.config(state='normal')
|
|
192
|
+
self.entry_degree.config(state='disabled')
|
|
193
|
+
elif selected_method == 'lacosmic':
|
|
194
|
+
self.entry_npoints.config(state='disabled')
|
|
195
|
+
self.entry_degree.config(state='disabled')
|
|
196
|
+
elif selected_method == 'auxdata':
|
|
197
|
+
self.entry_npoints.config(state='disabled')
|
|
198
|
+
self.entry_degree.config(state='disabled')
|
|
199
|
+
|
|
200
|
+
def check_interp_methods(self):
|
|
201
|
+
"""Check that all interpolation methods are valid."""
|
|
202
|
+
for method in self.dict_interp_methods.keys():
|
|
203
|
+
if method not in VALID_CLEANING_METHODS:
|
|
204
|
+
raise ValueError(f"Invalid interpolation method: {method}")
|
|
205
|
+
for method in VALID_CLEANING_METHODS:
|
|
206
|
+
if method not in self.dict_interp_methods.keys():
|
|
207
|
+
raise ValueError(f"Interpolation method not mapped: {method}")
|
|
@@ -0,0 +1,251 @@
|
|
|
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
|
+
"""Parameter editor dialog for L.A.Cosmic parameters."""
|
|
11
|
+
|
|
12
|
+
import tkinter as tk
|
|
13
|
+
from tkinter import ttk
|
|
14
|
+
from tkinter import messagebox
|
|
15
|
+
|
|
16
|
+
from .definitions import lacosmic_default_dict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ParameterEditor:
|
|
20
|
+
"""A dialog to edit L.A.Cosmic parameters."""
|
|
21
|
+
def __init__(self, root, param_dict, window_title, xmin, xmax, ymin, ymax, imgshape):
|
|
22
|
+
"""Initialize the parameter editor dialog.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
root : tk.Tk
|
|
27
|
+
The root Tkinter window.
|
|
28
|
+
param_dict : dict
|
|
29
|
+
Dictionary with L.A.Cosmic parameters.
|
|
30
|
+
window_title : str
|
|
31
|
+
Title of the dialog window.
|
|
32
|
+
xmin : int
|
|
33
|
+
Minimum x-coordinate of the region to be examined.
|
|
34
|
+
xmax : int
|
|
35
|
+
Maximum x-coordinate of the region to be examined.
|
|
36
|
+
ymin : int
|
|
37
|
+
Minimum y-coordinate of the region to be examined.
|
|
38
|
+
ymax : int
|
|
39
|
+
Maximum y-coordinate of the region to be examined.
|
|
40
|
+
imgshape : tuple
|
|
41
|
+
Shape of the image (height, width).
|
|
42
|
+
|
|
43
|
+
Methods
|
|
44
|
+
-------
|
|
45
|
+
create_widgets()
|
|
46
|
+
Create the widgets for the dialog.
|
|
47
|
+
on_ok()
|
|
48
|
+
Validate and save the updated values.
|
|
49
|
+
on_cancel()
|
|
50
|
+
Close the dialog without saving.
|
|
51
|
+
on_reset()
|
|
52
|
+
Reset all fields to original values.
|
|
53
|
+
get_result()
|
|
54
|
+
Return the updated dictionary.
|
|
55
|
+
|
|
56
|
+
Attributes
|
|
57
|
+
----------
|
|
58
|
+
root : tk.Tk
|
|
59
|
+
The root Tkinter window.
|
|
60
|
+
param_dict : dict
|
|
61
|
+
Dictionary with L.A.Cosmic parameters.
|
|
62
|
+
imgshape : tuple
|
|
63
|
+
Shape of the image (height, width).
|
|
64
|
+
entries : dict
|
|
65
|
+
Dictionary to hold entry widgets.
|
|
66
|
+
result_dict : dict or None
|
|
67
|
+
The updated dictionary of parameters or None if cancelled.
|
|
68
|
+
"""
|
|
69
|
+
self.root = root
|
|
70
|
+
self.root.title(window_title)
|
|
71
|
+
self.param_dict = param_dict
|
|
72
|
+
# Set default region values
|
|
73
|
+
self.param_dict['xmin']['value'] = xmin
|
|
74
|
+
self.param_dict['xmax']['value'] = xmax
|
|
75
|
+
self.param_dict['ymin']['value'] = ymin
|
|
76
|
+
self.param_dict['ymax']['value'] = ymax
|
|
77
|
+
self.imgshape = imgshape
|
|
78
|
+
self.entries = {} # dictionary to hold entry widgets
|
|
79
|
+
self.result_dict = None
|
|
80
|
+
|
|
81
|
+
# Create the form
|
|
82
|
+
self.create_widgets()
|
|
83
|
+
|
|
84
|
+
def create_widgets(self):
|
|
85
|
+
"""Create the widgets for the dialog."""
|
|
86
|
+
# Main frame
|
|
87
|
+
main_frame = tk.Frame(self.root, padx=10, pady=10)
|
|
88
|
+
main_frame.pack()
|
|
89
|
+
|
|
90
|
+
row = 0
|
|
91
|
+
|
|
92
|
+
# Subtitle for L.A.Cosmic parameters
|
|
93
|
+
subtitle_label = tk.Label(main_frame, text="L.A.Cosmic Parameters", font=("Arial", 14, "bold"))
|
|
94
|
+
subtitle_label.grid(row=row, column=0, columnspan=3, pady=(0, 15))
|
|
95
|
+
row += 1
|
|
96
|
+
|
|
97
|
+
# Create labels and entry fields for each parameter
|
|
98
|
+
for key, info in self.param_dict.items():
|
|
99
|
+
if key.lower() not in ['dilation', 'xmin', 'xmax', 'ymin', 'ymax']:
|
|
100
|
+
# Parameter name label
|
|
101
|
+
label = tk.Label(main_frame, text=f"{key}:", anchor='e', width=15)
|
|
102
|
+
label.grid(row=row, column=0, sticky='w', pady=5)
|
|
103
|
+
# Entry field
|
|
104
|
+
entry = tk.Entry(main_frame, width=10)
|
|
105
|
+
entry.insert(0, str(info['value']))
|
|
106
|
+
entry.grid(row=row, column=1, padx=10, pady=5)
|
|
107
|
+
self.entries[key] = entry # dictionary to hold entry widgets
|
|
108
|
+
# Type label
|
|
109
|
+
type_label = tk.Label(main_frame, text=f"({info['type'].__name__})", fg='gray', anchor='w', width=10)
|
|
110
|
+
type_label.grid(row=row, column=2, sticky='w', pady=5)
|
|
111
|
+
row += 1
|
|
112
|
+
|
|
113
|
+
# Separator
|
|
114
|
+
separator1 = ttk.Separator(main_frame, orient='horizontal')
|
|
115
|
+
separator1.grid(row=row, column=0, columnspan=3, sticky='ew', pady=(10, 10))
|
|
116
|
+
row += 1
|
|
117
|
+
|
|
118
|
+
# Subtitle for additional parameters
|
|
119
|
+
subtitle_label = tk.Label(main_frame, text="Additional Parameters", font=("Arial", 14, "bold"))
|
|
120
|
+
subtitle_label.grid(row=row, column=0, columnspan=3, pady=(0, 15))
|
|
121
|
+
row += 1
|
|
122
|
+
|
|
123
|
+
# Dilation label and entry
|
|
124
|
+
label = tk.Label(main_frame, text="Dilation:", anchor='e', width=15)
|
|
125
|
+
label.grid(row=row, column=0, sticky='w', pady=5)
|
|
126
|
+
entry = tk.Entry(main_frame, width=10)
|
|
127
|
+
entry.insert(0, str(self.param_dict['dilation']['value']))
|
|
128
|
+
entry.grid(row=row, column=1, padx=10, pady=5)
|
|
129
|
+
self.entries['dilation'] = entry
|
|
130
|
+
type_label = tk.Label(main_frame, text=f"({self.param_dict['dilation']['type'].__name__})",
|
|
131
|
+
fg='gray', anchor='w', width=10)
|
|
132
|
+
type_label.grid(row=row, column=2, sticky='w', pady=5)
|
|
133
|
+
row += 1
|
|
134
|
+
|
|
135
|
+
# Separator
|
|
136
|
+
separator2 = ttk.Separator(main_frame, orient='horizontal')
|
|
137
|
+
separator2.grid(row=row, column=0, columnspan=3, sticky='ew', pady=(10, 10))
|
|
138
|
+
row += 1
|
|
139
|
+
|
|
140
|
+
# Subtitle for region to be examined
|
|
141
|
+
subtitle_label = tk.Label(main_frame, text="Region to be Examined", font=("Arial", 14, "bold"))
|
|
142
|
+
subtitle_label.grid(row=row, column=0, columnspan=3, pady=(0, 15))
|
|
143
|
+
row += 1
|
|
144
|
+
|
|
145
|
+
# Region to be examined label and entries
|
|
146
|
+
for key, info in self.param_dict.items():
|
|
147
|
+
if key.lower() in ['xmin', 'xmax', 'ymin', 'ymax']:
|
|
148
|
+
# Parameter name label
|
|
149
|
+
label = tk.Label(main_frame, text=f"{key}:", anchor='e', width=15)
|
|
150
|
+
label.grid(row=row, column=0, sticky='w', pady=5)
|
|
151
|
+
# Entry field
|
|
152
|
+
entry = tk.Entry(main_frame, width=10)
|
|
153
|
+
entry.insert(0, str(info['value']))
|
|
154
|
+
entry.grid(row=row, column=1, padx=10, pady=5)
|
|
155
|
+
self.entries[key] = entry # dictionary to hold entry widgets
|
|
156
|
+
# Type label
|
|
157
|
+
dumtext = f"({info['type'].__name__})"
|
|
158
|
+
if key.lower() in ['xmax', 'ymax']:
|
|
159
|
+
dumtext += f" --> [1, {self.imgshape[1]}]"
|
|
160
|
+
else:
|
|
161
|
+
dumtext += f" --> [1, {self.imgshape[0]}]"
|
|
162
|
+
type_label = tk.Label(main_frame, text=dumtext, fg='gray', anchor='w', width=15)
|
|
163
|
+
type_label.grid(row=row, column=2, sticky='w', pady=5)
|
|
164
|
+
row += 1
|
|
165
|
+
|
|
166
|
+
# Separator
|
|
167
|
+
separator3 = ttk.Separator(main_frame, orient='horizontal')
|
|
168
|
+
separator3.grid(row=row, column=0, columnspan=3, sticky='ew', pady=(10, 10))
|
|
169
|
+
row += 1
|
|
170
|
+
|
|
171
|
+
# Button frame
|
|
172
|
+
button_frame = tk.Frame(main_frame)
|
|
173
|
+
button_frame.grid(row=row, column=0, columnspan=3, pady=(5, 0))
|
|
174
|
+
|
|
175
|
+
# OK button
|
|
176
|
+
ok_button = tk.Button(button_frame, text="OK", width=5, command=self.on_ok)
|
|
177
|
+
ok_button.pack(side='left', padx=5)
|
|
178
|
+
|
|
179
|
+
# Cancel button
|
|
180
|
+
cancel_button = tk.Button(button_frame, text="Cancel", width=5, command=self.on_cancel)
|
|
181
|
+
cancel_button.pack(side='left', padx=5)
|
|
182
|
+
|
|
183
|
+
# Reset button
|
|
184
|
+
reset_button = tk.Button(button_frame, text="Reset", width=5, command=self.on_reset)
|
|
185
|
+
reset_button.pack(side='left', padx=5)
|
|
186
|
+
|
|
187
|
+
def on_ok(self):
|
|
188
|
+
"""Validate and save the updated values"""
|
|
189
|
+
try:
|
|
190
|
+
updated_dict = {}
|
|
191
|
+
|
|
192
|
+
for key, info in self.param_dict.items():
|
|
193
|
+
entry_value = self.entries[key].get()
|
|
194
|
+
value_type = info['type']
|
|
195
|
+
|
|
196
|
+
# Convert string to appropriate type
|
|
197
|
+
if value_type == bool:
|
|
198
|
+
# Handle boolean conversion
|
|
199
|
+
if entry_value.lower() in ['true', '1', 'yes']:
|
|
200
|
+
converted_value = True
|
|
201
|
+
elif entry_value.lower() in ['false', '0', 'no']:
|
|
202
|
+
converted_value = False
|
|
203
|
+
else:
|
|
204
|
+
raise ValueError(f"Invalid boolean value for {key}")
|
|
205
|
+
else:
|
|
206
|
+
converted_value = value_type(entry_value)
|
|
207
|
+
if 'positive' in info and info['positive'] and converted_value < 0:
|
|
208
|
+
raise ValueError(f"Value for {key} must be positive")
|
|
209
|
+
|
|
210
|
+
updated_dict[key] = {
|
|
211
|
+
'value': converted_value,
|
|
212
|
+
'type': value_type
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
# Additional validation for region limits
|
|
216
|
+
try:
|
|
217
|
+
if updated_dict['xmax']['value'] <= updated_dict['xmin']['value']:
|
|
218
|
+
raise ValueError("xmax must be greater than xmin")
|
|
219
|
+
if updated_dict['ymax']['value'] <= updated_dict['ymin']['value']:
|
|
220
|
+
raise ValueError("ymax must be greater than ymin")
|
|
221
|
+
self.result_dict = updated_dict
|
|
222
|
+
self.root.destroy()
|
|
223
|
+
except ValueError as e:
|
|
224
|
+
messagebox.showerror("Invalid Inputs",
|
|
225
|
+
"Error in region limits:\n"
|
|
226
|
+
f"{str(e)}\n\nPlease check your inputs.")
|
|
227
|
+
|
|
228
|
+
except ValueError as e:
|
|
229
|
+
messagebox.showerror("Invalid Inputs",
|
|
230
|
+
f"Error converting value for {key}:\n{str(e)}\n\n"
|
|
231
|
+
"Please check your inputs.")
|
|
232
|
+
|
|
233
|
+
def on_cancel(self):
|
|
234
|
+
"""Close without saving"""
|
|
235
|
+
self.result_dict = None
|
|
236
|
+
self.root.destroy()
|
|
237
|
+
|
|
238
|
+
def on_reset(self):
|
|
239
|
+
"""Reset all fields to original values"""
|
|
240
|
+
self.param_dict = lacosmic_default_dict.copy()
|
|
241
|
+
self.param_dict['xmin']['value'] = 1
|
|
242
|
+
self.param_dict['xmax']['value'] = self.imgshape[1]
|
|
243
|
+
self.param_dict['ymin']['value'] = 1
|
|
244
|
+
self.param_dict['ymax']['value'] = self.imgshape[0]
|
|
245
|
+
for key, info in self.param_dict.items():
|
|
246
|
+
self.entries[key].delete(0, tk.END)
|
|
247
|
+
self.entries[key].insert(0, str(info['value']))
|
|
248
|
+
|
|
249
|
+
def get_result(self):
|
|
250
|
+
"""Return the updated dictionary"""
|
|
251
|
+
return self.result_dict
|