mg-pso-gui 0.1.13__py3-none-any.whl → 0.2.75__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. {mg_pso_gui-0.1.13.dist-info → mg_pso_gui-0.2.75.dist-info}/METADATA +10 -11
  2. mg_pso_gui-0.2.75.dist-info/RECORD +76 -0
  3. {mg_pso_gui-0.1.13.dist-info → mg_pso_gui-0.2.75.dist-info}/WHEEL +1 -1
  4. mgpsogui/gui/General/ParameterView.py +110 -0
  5. mgpsogui/gui/General/__init__.py +0 -0
  6. mgpsogui/gui/HomePage.py +565 -513
  7. mgpsogui/gui/OptionManager.py +333 -145
  8. mgpsogui/gui/OptionManager_backup.py +443 -0
  9. mgpsogui/gui/PlatformTab/PlatformTab.py +15 -6
  10. mgpsogui/gui/RunTab/OptimalParameterView.py +47 -0
  11. mgpsogui/gui/RunTab/RunTab.py +89 -35
  12. mgpsogui/gui/SetupTab/BoundsEditorWindow.py +1 -1
  13. mgpsogui/gui/SetupTab/BoundsList.py +97 -34
  14. mgpsogui/gui/SetupTab/CustomFunctionEditorWindow.py +74 -0
  15. mgpsogui/gui/SetupTab/CustomFunctionMetrics.py +156 -0
  16. mgpsogui/gui/SetupTab/FunctionsList.py +60 -6
  17. mgpsogui/gui/SetupTab/{StaticParameterView.py → ListEditor.py} +27 -16
  18. mgpsogui/gui/SetupTab/ListParametersView.py +7 -6
  19. mgpsogui/gui/SetupTab/{CalibrationParametersView.py → OverrideParameterMetrics.py} +35 -9
  20. mgpsogui/gui/SetupTab/OverrideParameterWindow.py +40 -0
  21. mgpsogui/gui/SetupTab/SetupTab.py +31 -11
  22. mgpsogui/gui/SetupTab/StepView.py +93 -22
  23. mgpsogui/gui/VisualizeTab/MatrixEditor.py +68 -0
  24. mgpsogui/gui/VisualizeTab/SideBar.py +399 -0
  25. mgpsogui/gui/VisualizeTab/VisualizeTab.py +76 -11
  26. mgpsogui/gui/defaults/__init__.py +0 -0
  27. mgpsogui/gui/defaults/optimization.json +176 -0
  28. mgpsogui/gui/defaults/sampling.json +111 -0
  29. mgpsogui/gui/defaults/sensitivity.json +20 -0
  30. mgpsogui/gui/images/plus.png +0 -0
  31. mgpsogui/gui/images/test.png +0 -0
  32. mgpsogui/util/GraphGenerator.py +747 -42
  33. mgpsogui/util/PSORunner.py +608 -116
  34. mgpsogui/util/debug.py +559 -0
  35. mgpsogui/util/helpers.py +95 -0
  36. mgpsogui/util/recosu/__init__.py +2 -1
  37. mgpsogui/util/recosu/pso/csip_access.py +2 -35
  38. mgpsogui/util/recosu/pso/pso.py +55 -59
  39. mgpsogui/util/recosu/sampling/__init__.py +16 -0
  40. mgpsogui/util/recosu/sampling/halton/__init__.py +0 -0
  41. mgpsogui/util/recosu/sampling/halton/halton.py +45 -0
  42. mgpsogui/util/recosu/sampling/halton/prime.py +82 -0
  43. mgpsogui/util/recosu/sampling/random/__init__.py +0 -0
  44. mgpsogui/util/recosu/sampling/random/random_sampler.py +34 -0
  45. mgpsogui/util/recosu/sampling/sample_trace_writer.py +47 -0
  46. mgpsogui/util/recosu/sampling/sampler_task.py +75 -0
  47. mgpsogui/util/recosu/sampling/sampling.py +99 -0
  48. mgpsogui/util/sampler_test_driver.py +129 -0
  49. mg_pso_gui-0.1.13.dist-info/RECORD +0 -50
  50. mgpsogui/gui/images/IGOW 4 Logo.png +0 -0
  51. {mg_pso_gui-0.1.13.dist-info → mg_pso_gui-0.2.75.dist-info}/entry_points.txt +0 -0
  52. {mg_pso_gui-0.1.13.dist-info → mg_pso_gui-0.2.75.dist-info}/top_level.txt +0 -0
@@ -8,54 +8,108 @@ import re
8
8
  import ast
9
9
  import pandas as pd
10
10
  import numpy as np
11
+ import os
12
+ import platform
13
+ import subprocess
11
14
 
12
15
  from ...util import PSORunner
13
16
  from ...util import GraphGenerator
14
17
  from ...util.CTkToolTip import CTkToolTip as ctt
18
+ import customtkinter
19
+
20
+ from . import OptimalParameterView as opv
15
21
 
16
22
  def create_tab(self, tab):
17
23
 
18
24
  # URL
19
25
  tab.grid_columnconfigure(0, weight=1)
20
- tab.grid_rowconfigure(0, weight=1)
21
- tab.grid_rowconfigure(1, weight=200)
22
-
23
- """
24
- self.url = customtkinter.CTkEntry(tab, textvariable=self.option_manager.get_arguments()['url'])
25
- self.url.grid(row=0, column=0, columnspan=1, padx=(20, 20), pady=(20, 20), sticky="nsew")
26
+ tab.grid_columnconfigure(1, weight=5)
27
+ tab.grid_columnconfigure(2, weight=1)
28
+ tab.grid_rowconfigure(0, weight=200)
26
29
 
27
- self.run_button = customtkinter.CTkButton(tab, text="Run", command=self.run)
28
- self.run_button.grid(row=0, column=1, padx=(20, 20), pady=(20, 20), sticky="nsew")
29
- ctt(self.run_button, delay=0.5, message="Start calibration...")
30
-
31
- self.stop_button = customtkinter.CTkButton(tab, text="Stop", command=self.stop)
32
- self.stop_button.grid(row=0, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew")
33
- ctt(self.stop_button, delay=0.5, message="Stop calibration...")
34
-
35
- """
36
-
37
- self.progress_container = customtkinter.CTkFrame(tab)
38
- self.progress_container.grid_columnconfigure(0, weight=1)
39
- self.progress_container.grid_columnconfigure(1, weight=1)
40
- self.progress_container.grid_columnconfigure(2, weight=1)
41
- self.progress_container.grid(row=0, column=0, padx=(20, 20), pady=(20, 20), sticky="nsew")
30
+ #self.progress_container = customtkinter.CTkFrame(tab)
31
+ #self.progress_container.grid_columnconfigure(0, weight=1)
32
+ #self.progress_container.grid_columnconfigure(1, weight=1)
33
+ #self.progress_container.grid_columnconfigure(2, weight=1)
34
+ #self.progress_container.grid(row=0, column=0, padx=(20, 20), pady=(20, 20), sticky="nsew")
42
35
 
43
36
  # Add progress bar to progress container
44
- self.progress_message_left = customtkinter.CTkLabel(self.progress_container, text="")
45
- self.progress_message_left.grid(row=0, column=0, padx=(10, 10), pady=(10, 10), sticky="w")
46
-
47
- self.progress_message_middle = customtkinter.CTkLabel(self.progress_container, text="Calibration not running...")
48
- self.progress_message_middle.grid(row=0, column=1, padx=(10, 10), pady=(10, 10), sticky="ew")
37
+ #self.progress_message_left = customtkinter.CTkLabel(self.progress_container, text="")
38
+ #self.progress_message_left.grid(row=0, column=0, padx=(10, 10), pady=(10, 10), sticky="w")
49
39
 
50
- self.progress_message_right = customtkinter.CTkLabel(self.progress_container, text="")
51
- self.progress_message_right.grid(row=0, column=2, padx=(10, 10), pady=(10, 10), sticky="e")
40
+ #self.progress_message_middle = customtkinter.CTkLabel(self.progress_container, text="Calibration not running...")
41
+ #self.progress_message_middle.grid(row=0, column=1, padx=(10, 10), pady=(10, 10), sticky="ew")
52
42
 
53
- #self.progress_bar = customtkinter.CTkProgressBar(self.progress_container)
54
- #self.progress_bar.grid(row=1, column=0, columnspan=3, padx=(10, 10), pady=(10, 10), sticky="ew")
55
- #self.progress_bar.set(0)
56
- #ctt(self.progress_bar, delay=0.5, message="Current calibration progress")
43
+ #self.progress_message_right = customtkinter.CTkLabel(self.progress_container, text="")
44
+ #self.progress_message_right.grid(row=0, column=2, padx=(10, 10), pady=(10, 10), sticky="e")
57
45
 
46
+ self.optimal_param_frame = opv.OptimalParameterView(tab, option_manager=self.option_manager, label_text="Optimal Parameters")
47
+ self.optimal_param_frame.grid(row=0, column=0, padx=(20, 20), pady=(20, 20), sticky="nsew")
48
+ self.optimal_param_frame.grid_columnconfigure(0, weight=1)
49
+ self.optimal_param_frame.grid_rowconfigure(0, weight=1)
50
+
58
51
  self.textbox = customtkinter.CTkTextbox(tab)
59
- self.textbox.grid(row=1, column=0, padx=(20, 20), pady=(20, 20), sticky="nsew")
60
- self.textbox.insert("0.0", "Welcome to the CSIP PSO Calibration Tool!\n\nUse the Calibration tab to define steps and calibration parameters. Use this tab to run and observe calibration progress. Once finished, use the Visualization tab to generate figures and graphs.")
61
-
52
+ self.textbox.grid(row=0, column=1, padx=(20, 20), pady=(20, 20), sticky="nsew")
53
+ self.textbox.insert("0.0", "Welcome to the CSIP PSO Calibration Tool!\n\nUse the Setup tab to define steps and calibration parameters. Use this tab to view logs and manage your Project. Once finished, use the Results tab to generate figures and graphs.")
54
+
55
+ self.project_editor = customtkinter.CTkScrollableFrame(tab, label_text="Project Editor")
56
+ self.project_editor.grid(row=0, column=2, padx=(20, 20), pady=(20, 20), sticky="nsew")
57
+ self.project_editor.grid_columnconfigure(0, weight=1)
58
+ self.project_editor.grid_rowconfigure(0, weight=1)
59
+
60
+ customtkinter.CTkLabel(self.project_editor, text="Copy Data to Current Mode:").grid(row=0, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
61
+
62
+ def copy_sense():
63
+ self.option_manager.copy_list("Sensitivity Analysis")
64
+ self.refresh_step_view(0)
65
+
66
+ def copy_halton():
67
+ self.option_manager.copy_list("Sampling: Halton")
68
+ self.refresh_step_view(0)
69
+
70
+ def copy_random():
71
+ self.option_manager.copy_list("Sampling: Random")
72
+ self.refresh_step_view(0)
73
+
74
+ def copy_optim():
75
+ self.option_manager.copy_list("Optimization")
76
+ self.refresh_step_view(0)
77
+
78
+ def open_project_folder():
79
+ # Open the file in the default program
80
+ folder = self.option_manager.get_project_folder()
81
+
82
+ if not os.path.exists(folder):
83
+ os.makedirs(folder)
84
+
85
+ if platform.system() == "Windows":
86
+ os.startfile(folder)
87
+ elif platform.system() == "Darwin":
88
+ subprocess.Popen(["open", folder])
89
+ else:
90
+ subprocess.Popen(["xdg-open", folder])
91
+
92
+ self.halton_copy = customtkinter.CTkButton(self.project_editor, text="From Sampling: Halton", command=copy_halton)
93
+ self.halton_copy.grid(row=1, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
94
+
95
+ self.random_copy = customtkinter.CTkButton(self.project_editor, text="From Sampling: Random", command=copy_random)
96
+ self.random_copy.grid(row=2, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
97
+
98
+ self.analysis_copy = customtkinter.CTkButton(self.project_editor, text="From Sensitivity Analysis", command=copy_sense)
99
+ self.analysis_copy.grid(row=3, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
100
+
101
+ self.optimization_copy = customtkinter.CTkButton(self.project_editor, text="From Optimization", command=copy_optim)
102
+ self.optimization_copy.grid(row=4, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
103
+
104
+ customtkinter.CTkLabel(self.project_editor, text="Project Management:").grid(row=5, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
105
+
106
+ self.open_folder = customtkinter.CTkButton(self.project_editor, text="Open Project Folder", command=open_project_folder)
107
+ self.open_folder.grid(row=6, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
108
+
109
+ customtkinter.CTkLabel(self.project_editor, text="Project Name:").grid(row=7, column=0, padx=(20, 20), pady=(10, 5), sticky="ew")
110
+ self.project_name_label = customtkinter.CTkLabel(self.project_editor, text=self.option_manager.get_project_data()["name"])
111
+ self.project_name_label.grid(row=8, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
112
+
113
+ customtkinter.CTkLabel(self.project_editor, text="Project Path:").grid(row=9, column=0, padx=(20, 20), pady=(10, 5), sticky="ew")
114
+ self.project_path_label = customtkinter.CTkLabel(self.project_editor, text=self.option_manager.get_project_data()["path"])
115
+ self.project_path_label.grid(row=10, column=0, padx=(20, 20), pady=(5, 10), sticky="ew")
@@ -54,7 +54,7 @@ class BoundsEditorWindow(CTkInputDialog):
54
54
  hover_color=self._button_hover_color,
55
55
  text_color=self._button_text_color,
56
56
  text='Cancel',
57
- command=self._ok_event)
57
+ command=self._cancel_event)
58
58
  self._cancel_button.grid(row=2, column=1, columnspan=1, padx=(10, 20), pady=(0, 20), sticky="ew")
59
59
 
60
60
  def _ok_event(self, event=None):
@@ -13,6 +13,8 @@ import json
13
13
  import PIL
14
14
  from PIL import Image
15
15
  import os
16
+ import pandas as pd
17
+ from tkinter.filedialog import askopenfilename
16
18
 
17
19
  class BoundsList(CTkFrame):
18
20
  def __init__(self, *args,
@@ -21,20 +23,8 @@ class BoundsList(CTkFrame):
21
23
  **kwargs):
22
24
  super().__init__(*args, **kwargs)
23
25
 
24
- self.optParams = []
25
26
  self.option_manager = option_manager
26
27
 
27
- details = self.option_manager.get_service_parameters()
28
- self.paramMap = {}
29
- if "parameter" in details:
30
- for param in details["parameter"]:
31
- self.paramMap[param["name"]] = param
32
- if "min" in param:
33
- self.optParams.append(param["name"])
34
-
35
- self.optParams.sort()
36
-
37
-
38
28
  self.edit_mode = False
39
29
  self.tooltip_list = []
40
30
 
@@ -62,6 +52,34 @@ class BoundsList(CTkFrame):
62
52
  index = 0
63
53
 
64
54
  self.tooltip_list = []
55
+
56
+ mode = self.option_manager.get_mode()
57
+
58
+ # Load bound parameters depending on the mode
59
+ self.optParams = []
60
+ if mode == "Optimization" or mode == "Sampling: Halton" or mode == "Sampling: Random":
61
+ details = self.option_manager.serialize_data(self.option_manager.get("service_request_data"))
62
+ self.paramMap = {}
63
+ if "parameter" in details:
64
+ for param in details["parameter"]:
65
+ self.paramMap[param["name"]] = param
66
+ if "min" in param:
67
+ self.optParams.append(param["name"])
68
+
69
+ self.optParams.sort()
70
+ elif mode == "Sensitivity Analysis":
71
+ file_path = self.option_manager.get("sensitivity_analysis_path").get()
72
+ folder = self.option_manager.get_project_folder()
73
+ file_path = os.path.join(folder, "results", file_path)
74
+ if os.path.exists(file_path):
75
+ try:
76
+ df = pd.read_csv(file_path)
77
+ self.optParams = df.columns.tolist()
78
+ except Exception as e:
79
+ print(f"Error loading CSV file: {e}")
80
+ else:
81
+ print(f"File does not exist: {file_path}")
82
+
65
83
 
66
84
  self.containerFrame = CTkFrame(self, fg_color="transparent")
67
85
  self.containerFrame.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew")
@@ -71,12 +89,16 @@ class BoundsList(CTkFrame):
71
89
 
72
90
  CTkLabel(self.containerFrame, text="Type:").grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew")
73
91
  CTkLabel(self.containerFrame, text="Name:").grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="nsew")
74
- CTkLabel(self.containerFrame, text="Bounds:").grid(row=row, column=2, columnspan=2, padx=(5, 5), pady=(5, 5), sticky="nsew")
75
- CTkLabel(self.containerFrame, text="Default:").grid(row=row, column=4, padx=(5, 5), pady=(5, 5), sticky="nsew")
76
- CTkLabel(self.containerFrame, text="Strategy:").grid(row=row, column=5, padx=(5, 5), pady=(5, 5), sticky="nsew")
92
+
93
+ if mode != "Sensitivity Analysis":
94
+ CTkLabel(self.containerFrame, text="Bounds:").grid(row=row, column=2, columnspan=2, padx=(5, 5), pady=(5, 5), sticky="nsew")
95
+
96
+ if mode == "Optimization":
97
+ CTkLabel(self.containerFrame, text="Default:").grid(row=row, column=4, padx=(5, 5), pady=(5, 5), sticky="nsew")
98
+ CTkLabel(self.containerFrame, text="Strategy:").grid(row=row, column=5, padx=(5, 5), pady=(5, 5), sticky="nsew")
77
99
  row += 1
78
100
 
79
- bounds = self.option_manager.get_steps()[self.step_index]["param"]
101
+ bounds = self.option_manager.get_steps()[self.step_index]["parameter_objects"]
80
102
 
81
103
  for bound in bounds:
82
104
  tt1 = None
@@ -112,34 +134,53 @@ class BoundsList(CTkFrame):
112
134
  bb.grid(row=row, column=2, padx=(5, 5), pady=(5, 5), sticky="new")
113
135
  ctt(bb, delay=0.1, alpha=0.95, message="Delete this bound...")
114
136
  else:
137
+
138
+ if mode == "Sensitivity Analysis":
139
+ row += 1
140
+ index += 1
141
+ continue
142
+
115
143
  bounds_min = CTkEntry(self.containerFrame)
116
144
  vcmd = (self.register(self.validate_number), '%P', cc, bounds_min)
117
145
  bounds_min.grid(row=row, column=2, padx=(5, 5), pady=(5, 5), sticky="new")
118
- bounds_min.configure(textvariable=bound["bounds"][0], validate='all', validatecommand=vcmd)
146
+ bounds_min.configure(textvariable=bound["min_bound"], validate='all', validatecommand=vcmd)
119
147
  self.validate_number(bounds_min.get(), cc, bounds_min)
120
148
 
121
149
  bounds_max = CTkEntry(self.containerFrame)
122
150
  vcmd = (self.register(self.validate_number), '%P', cc, bounds_max)
123
151
  bounds_max.grid(row=row, column=3, padx=(5, 5), pady=(5, 5), sticky="new")
124
- bounds_max.configure(textvariable=bound["bounds"][1], validate='all', validatecommand=vcmd)
152
+ bounds_max.configure(textvariable=bound["max_bound"], validate='all', validatecommand=vcmd)
125
153
  self.validate_number(bounds_max.get(), cc, bounds_max)
126
154
  tt2 = ctt(bounds_max, delay=0.1, alpha=0.95, message="...")
127
155
 
128
- default_value = CTkEntry(self.containerFrame)
129
- default_value.grid(row=row, column=4, padx=(5, 5), pady=(5, 5), sticky="new")
130
- default_value.configure(textvariable=bound["default_value"])
131
-
132
-
133
156
  if (bound_type == "list"):
134
157
  def button_click_event(bound_index):
135
- dialog = BEW(title="Edit List Bound", step_index=self.step_index, bound_index=bound_index, option_manager=self.option_manager)
136
- print("Number:", dialog.get_input())
158
+ BEW(title="Edit List Bound", step_index=self.step_index, bound_index=bound_index, option_manager=self.option_manager)
137
159
 
138
160
  open_window = lambda event=None, bound_index=index: (button_click_event(bound_index))
139
161
  expand_image = CTkImage(Image.open(os.path.join("./images", "expand.png")), size=(20, 20))
140
162
  button = CTkButton(self.containerFrame, width=30, text=None, image=expand_image, command=open_window)
141
163
  button.grid(row=row, column=6, padx=(5, 5), pady=(5, 5), sticky="new")
142
164
 
165
+ if mode == "Sampling: Random" or mode == "Sampling: Halton":
166
+
167
+ tt1 = ctt(bounds_min, delay=0.1, alpha=0.95, message="...")
168
+ tt2 = ctt(bounds_max, delay=0.1, alpha=0.95, message="...")
169
+ if cc is not None:
170
+ tt3 = ctt(cc, delay=0.1, alpha=0.95, message="...")
171
+
172
+ self.tooltip_list.append([tt3, tt1, tt2])
173
+
174
+ self.update_tooltips(index)
175
+
176
+ row += 1
177
+ index += 1
178
+ continue
179
+
180
+ default_value = CTkEntry(self.containerFrame)
181
+ default_value.grid(row=row, column=4, padx=(5, 5), pady=(5, 5), sticky="new")
182
+ default_value.configure(textvariable=bound["default_value"])
183
+
143
184
  calibration_strat = CTkOptionMenu(self.containerFrame, dynamic_resizing=False, values=['none', 'mean', 'single'], variable=bound["calibration_strategy"])
144
185
  calibration_strat.grid(row=row, column=5, padx=(5, 5), pady=(5, 5), sticky="new")
145
186
 
@@ -161,26 +202,48 @@ class BoundsList(CTkFrame):
161
202
  CTkButton(self.containerFrame, text="Exit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="new")
162
203
  else:
163
204
  CTkButton(self.containerFrame, text="Edit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="new")
164
- CTkButton(self.containerFrame, text="Add Bound", command=add_func).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="new")
165
- else:
166
- CTkButton(self.containerFrame, text="Add Bound", command=add_func).grid(row=row, column=0, columnspan=2, padx=(5, 5), pady=(5, 5), sticky="new")
205
+
206
+ CTkButton(self.containerFrame, text="Add Bound", command=add_func).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="new")
207
+
208
+ def import_csv():
209
+ filename = askopenfilename(filetypes=[("CSV", "*.csv")], title="Open Bound CSV", multiple=False)
210
+ print(filename)
211
+
212
+ # Open CSV file
213
+ if filename is not None and filename != "":
214
+ df = pd.read_csv(filename)
215
+ for _, row in df.iterrows():
216
+ if "name" not in row:
217
+ continue
218
+ name = row["name"] if "name" in row else "name"
219
+ type_ = row["type"] if "type" in row else "custom"
220
+ min_bound = row["min_bound"] if "min_bound" in row else 0
221
+ max_bound = row["max_bound"] if "max_bound" in row else 1
222
+ default_value = row["default_value"] if "default_value" in row else 1
223
+ calibration_strategy = row["calibration_strategy"] if "calibration_strategy" in row else "none"
224
+ self.option_manager.add_bound(step_index=self.step_index, name=name, min=min_bound, max=max_bound, type=type_, default_value=default_value, calibration_strategy=calibration_strategy)
225
+
226
+ self.clear()
227
+ self.render()
228
+
229
+ CTkButton(self.containerFrame, text="Import CSV", command=import_csv).grid(row=row, column=2, padx=(5, 5), pady=(5, 5), sticky="new")
167
230
 
168
231
  def update_type(self, index, option):
169
232
  value = option.get()
170
- self.option_manager.get_steps()[self.step_index]["param"][index]["type"].set(value)
233
+ self.option_manager.get_steps()[self.step_index]["parameter_objects"][index]["type"].set(value)
171
234
  self.refresh()
172
235
 
173
236
  def update_values(self, index):
174
- name = self.option_manager.get_steps()[self.step_index]["param"][index]["name"].get()
237
+ name = self.option_manager.get_steps()[self.step_index]["parameter_objects"][index]["name"].get()
175
238
  if name in self.paramMap:
176
239
  obj = self.paramMap[name]
177
- self.option_manager.get_steps()[self.step_index]["param"][index]["bounds"][0].set(obj["softmin"])
178
- self.option_manager.get_steps()[self.step_index]["param"][index]["bounds"][1].set(obj["softmax"])
240
+ self.option_manager.get_steps()[self.step_index]["parameter_objects"][index]["min_bound"].set(obj["softmin"])
241
+ self.option_manager.get_steps()[self.step_index]["parameter_objects"][index]["max_bound"].set(obj["softmax"])
179
242
 
180
243
  def update_tooltips(self, index):
181
244
  try:
182
- name = self.option_manager.get_steps()[self.step_index]["param"][index]["name"].get()
183
- bound_type = self.option_manager.get_steps()[self.step_index]["param"][index]["type"].get()
245
+ name = self.option_manager.get_steps()[self.step_index]["parameter_objects"][index]["name"].get()
246
+ bound_type = self.option_manager.get_steps()[self.step_index]["parameter_objects"][index]["type"].get()
184
247
 
185
248
  tooltips = self.tooltip_list[index]
186
249
  t3 = tooltips[0]
@@ -0,0 +1,74 @@
1
+ from typing import Union, Tuple, Optional
2
+
3
+ from customtkinter import CTkLabel
4
+ from customtkinter import CTkButton
5
+ from customtkinter import CTkEntry
6
+ from customtkinter import CTkInputDialog
7
+ from .CustomFunctionMetrics import CustomFunctionsMetricsView as ListView
8
+
9
+ class CustomFunctionEditorWindow(CTkInputDialog):
10
+ """
11
+ Dialog with extra window, message, entry widget, cancel and ok button.
12
+ For detailed information check out the documentation.
13
+ """
14
+
15
+ def __init__(self, *args,
16
+ step_index: 0,
17
+ function_index: 0,
18
+ option_manager: None,
19
+ **kwargs):
20
+ super().__init__(*args, **kwargs)
21
+
22
+ self.geometry("400x800")
23
+
24
+ self.step_index = step_index
25
+ self.function_index = function_index
26
+ self.option_manager = option_manager
27
+ self.bounds = None
28
+
29
+ def _create_widgets(self):
30
+
31
+ self.grid_columnconfigure((0, 1), weight=1)
32
+ self.rowconfigure(0, weight=1)
33
+
34
+ self.bounds = ListView(
35
+ self, step_index=self.step_index, function_index=self.function_index, option_manager=self.option_manager)
36
+ self.bounds.grid(row=0, column=0, columnspan=2, padx=(10, 10),
37
+ pady=(10, 10), sticky="nsew")
38
+ self.bounds.grid_columnconfigure(0, weight=1)
39
+
40
+ self._ok_button = CTkButton(master=self,
41
+ width=100,
42
+ border_width=0,
43
+ fg_color=self._button_fg_color,
44
+ hover_color=self._button_hover_color,
45
+ text_color=self._button_text_color,
46
+ text='Save',
47
+ command=self._ok_event)
48
+ self._ok_button.grid(row=2, column=0, columnspan=1, padx=(20, 10), pady=(0, 20), sticky="ew")
49
+
50
+ self._cancel_button = CTkButton(master=self,
51
+ width=100,
52
+ border_width=0,
53
+ fg_color=self._button_fg_color,
54
+ hover_color=self._button_hover_color,
55
+ text_color=self._button_text_color,
56
+ text='Cancel',
57
+ command=self._cancel_event)
58
+ self._cancel_button.grid(row=2, column=1, columnspan=1, padx=(10, 20), pady=(0, 20), sticky="ew")
59
+
60
+ def _ok_event(self, event=None):
61
+ # Save values in bounds editor...
62
+
63
+ self.bounds.push_to_option_manager()
64
+
65
+ self.grab_release()
66
+ self.destroy()
67
+
68
+ def _on_closing(self):
69
+ self.grab_release()
70
+ self.destroy()
71
+
72
+ def _cancel_event(self):
73
+ self.grab_release()
74
+ self.destroy()
@@ -0,0 +1,156 @@
1
+ from customtkinter import CTkScrollableFrame
2
+ from customtkinter import CTkFrame
3
+ from customtkinter import CTkLabel
4
+ from customtkinter import CTkButton
5
+ from customtkinter import CTkEntry
6
+ from customtkinter import CTkOptionMenu
7
+ import tkinter as tk
8
+ import subprocess
9
+ import platform
10
+ import os
11
+
12
+ global option_manager
13
+
14
+ class CustomFunctionsMetricsView(CTkScrollableFrame):
15
+ def __init__(self, *args,
16
+ option_manager: None,
17
+ step_index: 0,
18
+ function_index: 0,
19
+ **kwargs):
20
+ super().__init__(*args, **kwargs)
21
+
22
+ self.option_manager = option_manager
23
+ self.step_index = step_index
24
+ self.functions_index = function_index
25
+ self.key_values = []
26
+
27
+ self.edit_mode = False
28
+
29
+ self.columns = ["absdiff",
30
+ "absdifflog",
31
+ "ave",
32
+ "bias",
33
+ "fhf",
34
+ "ioa",
35
+ "ioa2",
36
+ "kge",
37
+ "kge09",
38
+ "mns",
39
+ "mse",
40
+ "ns",
41
+ "ns2log",
42
+ "nslog1p",
43
+ "nslog2",
44
+ "pbias",
45
+ "pmcc",
46
+ "rmse",
47
+ "trmse"]
48
+
49
+ self.positive_best = {"absdiff": True,
50
+ "absdifflog": True,
51
+ "ave": True,
52
+ "bias": True,
53
+ "fhf": True,
54
+ "ioa": True,
55
+ "ioa2": True,
56
+ "kge": True,
57
+ "kge09": True,
58
+ "mns": True,
59
+ "mse": True,
60
+ "ns": False,
61
+ "ns2log": True,
62
+ "nslog1p": True,
63
+ "nslog2": True,
64
+ "pbias": True,
65
+ "pmcc": True,
66
+ "rmse": True,
67
+ "trmse": True}
68
+
69
+ equation = self.option_manager.get_steps()[self.step_index]["objective_functions"][self.functions_index]["custom_function"].get()
70
+
71
+ # Example equation (0 * (1 - ns)) + (bias * 0) + (pbias * 0) + (absdiff * 0)
72
+ try:
73
+ if equation != "":
74
+ equation = equation.replace("1 - ", "")
75
+ equation = equation.replace("(", "")
76
+ equation = equation.replace(")", "")
77
+ equation = equation.replace(" ", "")
78
+ pairs = equation.split("+")
79
+ for pair in pairs:
80
+ key, value = pair.split("*")
81
+ self.add_key(key, value)
82
+ except Exception as e:
83
+ self.key_values = []
84
+
85
+ self.render()
86
+
87
+ def clear(self):
88
+ self.containerFrame.destroy()
89
+
90
+ def toggle_edit_mode(self):
91
+ self.clear()
92
+ self.edit_mode = not self.edit_mode
93
+ self.render()
94
+
95
+ def add_key(self, key="ns", value="0"):
96
+ obj = {"name": tk.StringVar(), "value": tk.StringVar()}
97
+ obj['name'].set(key)
98
+ obj['value'].set(value)
99
+ self.key_values.append(obj)
100
+
101
+ def remove_key(self, index):
102
+ self.key_values.pop(index)
103
+
104
+ def render(self):
105
+ row = 0
106
+ index = 0
107
+
108
+ self.containerFrame = CTkFrame(self)
109
+ self.containerFrame.grid(row=0, column=0, padx=(5, 5), pady=(5, 5), sticky="nsew")
110
+ self.containerFrame.grid_columnconfigure((0, 1), weight=1)
111
+
112
+ CTkLabel(self.containerFrame, text="Objective:").grid(row=row, column=0, columnspan=1, padx=5, pady=5, sticky="")
113
+ CTkLabel(self.containerFrame, text="Weight:").grid(row=row, column=1, columnspan=1, padx=5, pady=5, sticky="")
114
+ row += 1
115
+
116
+ for key_value_pair in self.key_values:
117
+ CTkOptionMenu(self.containerFrame, values=self.columns, variable=self.key_values[index]["name"]).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="ew")
118
+
119
+
120
+ if self.edit_mode:
121
+ return_func = lambda index=index: (self.clear(), self.remove_key(index), self.render())
122
+ CTkButton(self.containerFrame, text="Remove", command=return_func).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")
123
+ else:
124
+ bb = CTkEntry(self.containerFrame)
125
+ bb.grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")
126
+ bb.configure(textvariable=self.key_values[index]["value"])
127
+ row += 1
128
+ index += 1
129
+
130
+ if self.edit_mode:
131
+ CTkButton(self.containerFrame, text="Exit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="ew")
132
+ else:
133
+ CTkButton(self.containerFrame, text="Edit", command=self.toggle_edit_mode).grid(row=row, column=0, padx=(5, 5), pady=(5, 5), sticky="ew")
134
+
135
+ add_key_func = lambda: (self.clear(), self.add_key(), self.render())
136
+ CTkButton(self.containerFrame, text="Add", command=add_key_func).grid(row=row, column=1, padx=(5, 5), pady=(5, 5), sticky="ew")
137
+
138
+ row += 1
139
+
140
+ def push_to_option_manager(self):
141
+ equation = ""
142
+
143
+ for key_value in self.key_values:
144
+ name = key_value["name"].get()
145
+ weight = key_value["value"].get()
146
+
147
+ positiveBest = self.positive_best[name]
148
+
149
+ if positiveBest:
150
+ equation += f"({name} * {weight}) + "
151
+ else:
152
+ equation += f"((1 - {name}) * {weight}) + "
153
+
154
+ equation = equation[:-3] # Remove the last " + "
155
+
156
+ self.option_manager.get_steps()[self.step_index]["objective_functions"][self.functions_index]["custom_function"].set(equation)