mg-pso-gui 0.1.13__tar.gz → 0.1.16__tar.gz

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.
Files changed (57) hide show
  1. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/PKG-INFO +1 -1
  2. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mg_pso_gui.egg-info/PKG-INFO +1 -1
  3. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mg_pso_gui.egg-info/SOURCES.txt +2 -0
  4. mg-pso-gui-0.1.16/mgpsogui/gui/HomePage.py +632 -0
  5. mg-pso-gui-0.1.16/mgpsogui/gui/images/test.png +0 -0
  6. mg-pso-gui-0.1.16/mgpsogui/trace.json +472 -0
  7. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/pso/csip_access.py +2 -35
  8. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/pso/pso.py +0 -48
  9. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/setup.py +1 -1
  10. mg-pso-gui-0.1.13/mgpsogui/gui/HomePage.py +0 -572
  11. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mg_pso_gui.egg-info/dependency_links.txt +0 -0
  12. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mg_pso_gui.egg-info/entry_points.txt +0 -0
  13. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mg_pso_gui.egg-info/requires.txt +0 -0
  14. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mg_pso_gui.egg-info/top_level.txt +0 -0
  15. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/__init__.py +0 -0
  16. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/OptionManager.py +0 -0
  17. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/PlatformTab/PlatformTab.py +0 -0
  18. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/PlatformTab/__init__.py +0 -0
  19. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/RunTab/RunTab.py +0 -0
  20. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/RunTab/__init__.py +0 -0
  21. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/BoundsEditorWindow.py +0 -0
  22. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/BoundsList.py +0 -0
  23. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/CalibrationParametersView.py +0 -0
  24. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/FunctionsList.py +0 -0
  25. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/ListParametersView.py +0 -0
  26. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/SetupTab.py +0 -0
  27. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/StaticParameterView.py +0 -0
  28. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/StepView.py +0 -0
  29. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/SetupTab/__init__.py +0 -0
  30. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/VisualizeTab/VisualizeTab.py +0 -0
  31. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/VisualizeTab/__init__.py +0 -0
  32. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/__init__.py +0 -0
  33. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/IGOW 4 Logo.png +0 -0
  34. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/collapse.png +0 -0
  35. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/down.png +0 -0
  36. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/expand.png +0 -0
  37. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/play.png +0 -0
  38. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/refresh.png +0 -0
  39. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/refresh_hd.png +0 -0
  40. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/stop.png +0 -0
  41. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/trash.png +0 -0
  42. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/gui/images/up.png +0 -0
  43. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/mgpsogui.py +0 -0
  44. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/start.yaml +0 -0
  45. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/CTkToolTip/__init__.py +0 -0
  46. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/CTkToolTip/ctk_tooltip.py +0 -0
  47. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/GraphGenerator.py +0 -0
  48. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/PSORunner.py +0 -0
  49. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/__init__.py +0 -0
  50. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/__init__.py +0 -0
  51. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/pso/__init__.py +0 -0
  52. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/utils/__init__.py +0 -0
  53. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/utils/plot/__init__.py +0 -0
  54. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/utils/plot/cost_steps.py +0 -0
  55. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/utils/trace_writer.py +0 -0
  56. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/mgpsogui/util/recosu/utils/utils.py +0 -0
  57. {mg-pso-gui-0.1.13 → mg-pso-gui-0.1.16}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mg-pso-gui
3
- Version: 0.1.13
3
+ Version: 0.1.16
4
4
  Summary: GUI for MG-PSO
5
5
  Author: Robert Cordingly
6
6
  Author-email: <rcording@uw.ed>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: mg-pso-gui
3
- Version: 0.1.13
3
+ Version: 0.1.16
4
4
  Summary: GUI for MG-PSO
5
5
  Author: Robert Cordingly
6
6
  Author-email: <rcording@uw.ed>
@@ -8,6 +8,7 @@ mg_pso_gui.egg-info/top_level.txt
8
8
  mgpsogui/__init__.py
9
9
  mgpsogui/mgpsogui.py
10
10
  mgpsogui/start.yaml
11
+ mgpsogui/trace.json
11
12
  mgpsogui/gui/HomePage.py
12
13
  mgpsogui/gui/OptionManager.py
13
14
  mgpsogui/gui/__init__.py
@@ -34,6 +35,7 @@ mgpsogui/gui/images/play.png
34
35
  mgpsogui/gui/images/refresh.png
35
36
  mgpsogui/gui/images/refresh_hd.png
36
37
  mgpsogui/gui/images/stop.png
38
+ mgpsogui/gui/images/test.png
37
39
  mgpsogui/gui/images/trash.png
38
40
  mgpsogui/gui/images/up.png
39
41
  mgpsogui/util/GraphGenerator.py
@@ -0,0 +1,632 @@
1
+ #!/usr/local/bin/python3.9
2
+
3
+ import os
4
+ import time
5
+ dir_path = os.path.dirname(os.path.realpath(__file__))
6
+ os.chdir(dir_path)
7
+ print(dir_path)
8
+
9
+ # minikube kubectl -- create -f ../start.yaml ; sleep 60 ; minikube service pf8087-csu-csip-oms -n csip
10
+
11
+ import requests
12
+
13
+ import tkinter as tk
14
+ import tkinter.messagebox
15
+ import customtkinter
16
+ import json
17
+ import os
18
+ from PIL import Image, ImageTk
19
+ import traceback
20
+ from multiprocessing import Process
21
+ from multiprocessing import Queue
22
+ import re
23
+ import pandas as pd
24
+ import numpy as np
25
+ import ast
26
+ import platform
27
+ import time
28
+
29
+ from queue import Empty
30
+
31
+ from ..util import PSORunner
32
+ from ..util import GraphGenerator
33
+ from ..util.CTkToolTip import CTkToolTip as ctt
34
+
35
+ import subprocess
36
+ import plotly.express as px
37
+ import plotly.graph_objs as go
38
+
39
+ from tkinter.filedialog import askopenfilename
40
+ from tkinter.filedialog import asksaveasfilename
41
+
42
+ from . import OptionManager as om
43
+
44
+ from .SetupTab import SetupTab as st
45
+ from .PlatformTab import PlatformTab as pt
46
+ from .RunTab import RunTab as rt
47
+ from .VisualizeTab import VisualizeTab as vt
48
+
49
+ from ..util.CTkToolTip import CTkToolTip as ctt
50
+
51
+ customtkinter.set_appearance_mode("Dark") # Modes: "System" (standard), "Dark", "Light"
52
+ customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue"
53
+
54
+ results_queue = Queue()
55
+ stdout_queue = Queue()
56
+ stderr_queue = Queue()
57
+ cosu_queue = Queue()
58
+
59
+ class App(customtkinter.CTk):
60
+ def __init__(self):
61
+ super().__init__()
62
+
63
+ self.option_manager = om.OptionManager()
64
+
65
+ self.running_config = None
66
+ self.selected_graph_name = None
67
+
68
+ self.train_process = None
69
+ self.minikube_process = None
70
+ self.data_x = [0]
71
+ self.data_y = [0]
72
+
73
+ self.image_width = 1280
74
+ self.image_height = 720
75
+
76
+ # configure window
77
+ self.title("CSIP PSO")
78
+ self.geometry(f"{1920}x{1080}")
79
+
80
+ # configure grid layout (4x4)
81
+ self.grid_columnconfigure(0, weight=1)
82
+ self.grid_rowconfigure(1, weight=1)
83
+
84
+ header_padding_x = (5, 5)
85
+ header_padding_y = (10, 10)
86
+
87
+ self.sidebar_frame = customtkinter.CTkFrame(self, width=140, corner_radius=0)
88
+ self.sidebar_frame.grid(row=0, column=0, sticky="nsew")
89
+ self.sidebar_frame.grid_columnconfigure(4, weight=1)
90
+ self.logo_label = customtkinter.CTkLabel(self.sidebar_frame, text="CSIP PSO", font=customtkinter.CTkFont(size=20, weight="bold"))
91
+ self.logo_label.grid(row=0, column=0, padx=(20, 10), pady=header_padding_y)
92
+ self.save_button = customtkinter.CTkButton(self.sidebar_frame, text="Save", width=60, command=self.save_project)
93
+ self.save_button.grid(row=0, column=1, padx=header_padding_x, pady=header_padding_y)
94
+ self.load_button = customtkinter.CTkButton(self.sidebar_frame, text="Load", width=60, command=self.load_project)
95
+ self.load_button.grid(row=0, column=2, padx=header_padding_x, pady=header_padding_y)
96
+
97
+ # 4 is service URL
98
+ self.service_label = customtkinter.CTkLabel(self.sidebar_frame, text="Service:", anchor="w")
99
+ self.service_label.grid(row=0, column=3, padx=(80, 5), pady=header_padding_y)
100
+ self.service_url = customtkinter.CTkEntry(self.sidebar_frame, textvariable=self.option_manager.get_arguments()['url'])
101
+ self.service_url.grid(row=0, column=4, columnspan=1, padx=header_padding_x, pady=header_padding_y, sticky="nsew")
102
+ refresh_image = customtkinter.CTkImage(Image.open(os.path.join("./images", "refresh.png")), size=(20, 20))
103
+ self.refresh_button = customtkinter.CTkButton(self.sidebar_frame, text=None, width=30, image=refresh_image, command=self.load)
104
+ ctt(self.refresh_button, delay=0.1, alpha=0.95, message="Connect to Service")
105
+ self.refresh_button.grid(row=0, column=5, padx=(5, 80), pady=header_padding_y)
106
+
107
+ self.scaling_label = customtkinter.CTkLabel(self.sidebar_frame, text="Scale:", anchor="w")
108
+ self.scaling_label.grid(row=0, column=6, padx=header_padding_x, pady=header_padding_y)
109
+ self.scaling_optionemenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["50%", "75%", "100%", "125%", "150%", "175%", "200%"], width=60,
110
+ command=self.change_scaling_event)
111
+ self.scaling_optionemenu.grid(row=0, column=7, padx=header_padding_x, pady=header_padding_y)
112
+ self.scaling_optionemenu.set("100%")
113
+
114
+ expand_image = customtkinter.CTkImage(Image.open(os.path.join("./images", "expand.png")), size=(20, 20))
115
+ self.new_window = customtkinter.CTkButton(self.sidebar_frame, text=None, width=30, image=expand_image, command=self.new_window)
116
+ ctt(self.refresh_button, delay=0.1, alpha=0.95, message="Open New Window")
117
+ self.new_window.grid(row=0, column=8, padx=(5, 20), pady=header_padding_y)
118
+
119
+ self.tabview = customtkinter.CTkTabview(self, bg_color="transparent", fg_color="transparent")
120
+ self.tabview.grid(row=1, column=0, padx=(0, 0), pady=(10, 10), sticky="nsew")
121
+ tab1 = "Platform"
122
+ tab2 = "Setup"
123
+ tab3 = "Logs"
124
+ tab4 = "Results"
125
+ #tab5 = "Results"
126
+
127
+ self.tabview.add(tab1)
128
+ self.tabview.add(tab2)
129
+ self.tabview.add(tab4)
130
+ self.tabview.add(tab3)
131
+ #self.tabview.add(tab5)
132
+
133
+ #self.tabview.configure(state="disabled")
134
+
135
+ pt.create_tab(self, self.tabview.tab(tab1))
136
+ st.create_tab(self, self.tabview.tab(tab2))
137
+ rt.create_tab(self, self.tabview.tab(tab3))
138
+ vt.create_tab(self, self.tabview.tab(tab4))
139
+
140
+ self.footer_frame = customtkinter.CTkFrame(self, corner_radius=0)
141
+ self.footer_frame.grid(row=2, column=0, sticky="nsew")
142
+ self.footer_frame.grid_columnconfigure(4, weight=1)
143
+
144
+ self.footer_progress_label = customtkinter.CTkLabel(self.footer_frame, text="Stopped", width=150, font=customtkinter.CTkFont(size=16, weight="bold"), anchor="w")
145
+ self.footer_progress_label.grid(row=0, column=0, padx=(20, 5), pady=header_padding_y)
146
+
147
+ self.footer_progress_bar = customtkinter.CTkProgressBar(self.footer_frame)
148
+ self.footer_progress_bar.grid(row=0, column=4, padx=(50, 100), pady=header_padding_y, sticky="ew")
149
+ self.footer_progress_bar.set(0)
150
+
151
+ self.algorithm_optionmenu = customtkinter.CTkOptionMenu(self.sidebar_frame, values=["PSO", "Halton"], width=50)
152
+ self.algorithm_optionmenu.grid(row=0, column=6, padx=header_padding_x, pady=header_padding_y)
153
+ self.algorithm_optionmenu.set("PSO")
154
+
155
+ play_image = customtkinter.CTkImage(Image.open(os.path.join("./images", "play.png")), size=(20, 20))
156
+ self.run_button = customtkinter.CTkButton(self.footer_frame, text=None, width=30, image=play_image, command=self.run)
157
+ ctt(self.run_button, delay=0.1, alpha=0.95, message="Start Calibration")
158
+ self.run_button.grid(row=0, column=7, padx=(5, 5), pady=header_padding_y)
159
+
160
+ test_image = customtkinter.CTkImage(Image.open(os.path.join("./images", "test.png")), size=(20, 20))
161
+ self.test_button = customtkinter.CTkButton(self.footer_frame, text=None, width=30, image=test_image, command=self.run)
162
+ ctt(self.test_button, delay=0.1, alpha=0.95, message="Start Testing")
163
+ self.test_button.grid(row=0, column=8, padx=(5, 5), pady=header_padding_y)
164
+
165
+ stop_image = customtkinter.CTkImage(Image.open(os.path.join("./images", "stop.png")), size=(20, 20))
166
+ self.stop_button = customtkinter.CTkButton(self.footer_frame, text=None, width=30, image=stop_image, command=self.stop)
167
+ ctt(self.stop_button, delay=0.1, alpha=0.95, message="Stop")
168
+ self.stop_button.grid(row=0, column=9, padx=(5, 20), pady=header_padding_y)
169
+
170
+ download_image = customtkinter.CTkImage(Image.open(os.path.join("./images", "down.png")), size=(20, 20))
171
+ self.download_button = customtkinter.CTkButton(self.footer_frame, text=None, width=30, image=stop_image, command=self.stop)
172
+ ctt(self.download_button, delay=0.1, alpha=0.95, message="Download Results")
173
+ self.download_button.grid(row=0, column=10, padx=(5, 20), pady=header_padding_y)
174
+
175
+ def _resize_image(self, event):
176
+ self.graph_label.update_idletasks()
177
+ new_width = self.graph_label.winfo_width()
178
+ new_height = self.graph_label.winfo_height()
179
+
180
+ alt_width = new_height * 1.77778
181
+ alt_height = new_width / 1.77778
182
+
183
+ if (new_width < new_height):
184
+ new_height = alt_height
185
+ else:
186
+ new_width = alt_width
187
+
188
+ self.image_width = new_width
189
+ self.image_height = new_height
190
+
191
+ self.graph_image = customtkinter.CTkImage(self.graph_image_obj, size=(new_width, new_height))
192
+ self.graph_label.configure(image=self.graph_image)
193
+ self.graph_label.update_idletasks()
194
+
195
+ def callback_test(self, *args):
196
+ print("callback_test called")
197
+
198
+ def update_graph(self, value):
199
+ selected_graph = self.graph_selector_value.get()
200
+ info = self.option_manager.get_project_data()
201
+ folder = os.path.join(info['path'], info['name'])
202
+
203
+ if not os.path.exists(folder):
204
+ os.makedirs(folder)
205
+
206
+ if (selected_graph == "Best Cost Stacked"):
207
+ self.selected_graph_name = "best_cost_stacked"
208
+ image_path = os.path.join(folder, self.selected_graph_name + ".png")
209
+ if not os.path.exists(image_path):
210
+ image_path = os.path.join("./images", "up.png")
211
+ self.graph_image_obj = Image.open(image_path)
212
+ self.graph_image = customtkinter.CTkImage(self.graph_image_obj, size=(self.image_width, self.image_height))
213
+ self.graph_label.configure(image=self.graph_image)
214
+ elif (selected_graph == "Best Cost by Round"):
215
+ self.selected_graph_name = "best_cost_by_round"
216
+ image_path = os.path.join(folder, self.selected_graph_name + ".png")
217
+ if not os.path.exists(image_path):
218
+ image_path = os.path.join("./images", "up.png")
219
+ self.graph_image_obj = Image.open(image_path)
220
+ self.graph_image = customtkinter.CTkImage(self.graph_image_obj, size=(self.image_width, self.image_height))
221
+ self.graph_label.configure(image=self.graph_image)
222
+ elif (selected_graph == "Iteration Table"):
223
+ self.selected_graph_name = "table"
224
+ image_path = os.path.join(folder, self.selected_graph_name + ".png")
225
+ if not os.path.exists(image_path):
226
+ image_path = os.path.join("./images", "up.png")
227
+ self.graph_image_obj = Image.open(image_path)
228
+ self.graph_image = customtkinter.CTkImage(self.graph_image_obj, size=(self.image_width, self.image_height))
229
+ self.graph_label.configure(image=self.graph_image)
230
+ elif (selected_graph == "Calibrated Parameters"):
231
+ self.selected_graph_name = "calibrated_params_by_round"
232
+ image_path = os.path.join(folder, self.selected_graph_name + ".png")
233
+ if not os.path.exists(image_path):
234
+ image_path = os.path.join("./images", "up.png")
235
+ self.graph_image_obj = Image.open(image_path)
236
+ self.graph_image = customtkinter.CTkImage(self.graph_image_obj, size=(self.image_width, self.image_height))
237
+ self.graph_label.configure(image=self.graph_image)
238
+
239
+ def save_project(self):
240
+ metrics = self.option_manager.get_metrics()
241
+ filename = asksaveasfilename(filetypes=[("JSON", "*.json")], initialfile="config", defaultextension="json", title="Save Project")
242
+
243
+ try:
244
+
245
+ # Convert metrics to json and save to file with proper spacing
246
+ with open(filename, "w") as f:
247
+ f.write(json.dumps(metrics, indent=4))
248
+
249
+ self.save_button.configure(text="Saved!")
250
+ self.after(3000, lambda: self.save_button.configure(text="Save"))
251
+ except Exception as e:
252
+ self.save_button.configure(text="Error!")
253
+ print(e)
254
+ self.after(3000, lambda: self.save_button.configure(text="Save"))
255
+
256
+ def new_window(self):
257
+ # Shell out and run ./main.py
258
+ subprocess.Popen(["python3", "../mgpsogui.py"])
259
+
260
+ def load_project(self):
261
+
262
+ filename = askopenfilename(filetypes=[("JSON", "*.json")], title="Open Project", multiple=False)
263
+ print(filename)
264
+
265
+ try:
266
+
267
+ # Load config.json and convert to metrics
268
+ with open(filename, "r") as f:
269
+ metrics = json.loads(f.read())
270
+
271
+ self.option_manager.set_path(filename)
272
+
273
+ if "arguments" in metrics:
274
+ metrics["arguments"]["calibration_parameters"] = metrics["calibration_parameters"]
275
+
276
+ if "service_parameters" in metrics:
277
+ self.option_manager.set_service_parameters(metrics["service_parameters"])
278
+ self.tabview.configure(state="enabled")
279
+
280
+ print(metrics)
281
+
282
+ self.option_manager.clear()
283
+ self.option_manager.add_arguments(metrics["arguments"])
284
+ self.option_manager.add_steps(metrics["steps"])
285
+
286
+ self.steps_frame.clear()
287
+ self.steps_frame.render()
288
+
289
+ self.static_param_frame.clear()
290
+ self.static_param_frame.render()
291
+
292
+ self.calib_param_frame.clear()
293
+ self.calib_param_frame.render()
294
+
295
+ self.load_button.configure(text="Loaded!")
296
+ self.after(3000, lambda: self.load_button.configure(text="Load"))
297
+
298
+ except Exception as e:
299
+ print(e)
300
+ self.load_button.configure(text="Error!")
301
+ self.after(3000, lambda: self.load_button.configure(text="Load"))
302
+
303
+ def change_appearance_mode_event(self, new_appearance_mode: str):
304
+ customtkinter.set_appearance_mode(new_appearance_mode)
305
+
306
+ def change_scaling_event(self, new_scaling: str):
307
+ new_scaling_float = int(new_scaling.replace("%", "")) / 100
308
+ customtkinter.set_widget_scaling(new_scaling_float)
309
+
310
+ def change_scaling_event(self, new_scaling: str):
311
+ new_scaling_float = int(new_scaling.replace("%", "")) / 100
312
+ customtkinter.set_widget_scaling(new_scaling_float)
313
+
314
+ def make_request(self):
315
+ service_url = self.service_url.get()
316
+ try:
317
+ response = requests.get(service_url)
318
+
319
+ response_json = json.loads(response.text)
320
+ status = response.status_code
321
+
322
+ self.option_manager.set_service_parameters(response_json)
323
+
324
+ self.service_status.delete('0.0', tk.END)
325
+ self.service_status.insert(text=str(status), index='0.0')
326
+ self.service_name.delete('0.0', tk.END)
327
+ self.service_name.insert(text=str(response_json["metainfo"]["name"]), index='0.0')
328
+ self.service_description.delete('0.0', tk.END)
329
+ self.service_description.insert(text=str(response_json["metainfo"]["description"]), index='0.0')
330
+ self.service_details.delete('0.0', tk.END)
331
+ self.service_details.insert(text=json.dumps(response_json, indent=4), index='0.0')
332
+
333
+ self.refresh_button.configure(fg_color="green")
334
+ except Exception as e:
335
+ self.refresh_button.configure(fg_color="red")
336
+
337
+
338
+ def load(self):
339
+ # Make HTTP request to service_url and save the result to bounds.json
340
+
341
+ self.default_button_color = self.refresh_button.cget("fg_color")
342
+
343
+ self.refresh_button.configure(fg_color="gray")
344
+
345
+ self.after(10, self.make_request)
346
+ self.after(3000, lambda: self.refresh_button.configure(fg_color=self.default_button_color))
347
+
348
+ def run(self):
349
+ metrics = self.option_manager.get_metrics()
350
+ self.running_config = metrics
351
+
352
+ #self.progress_bar.configure(mode="indeterminnate")
353
+ #self.progress_bar.start()
354
+ self.footer_progress_bar.configure(mode="indeterminnate")
355
+ self.footer_progress_bar.start()
356
+
357
+ self.data_x = [0]
358
+ self.data_y = [0]
359
+
360
+ self.progress_message_middle.configure(text="Calibration starting...")
361
+ self.footer_progress_label.configure(text="Starting...")
362
+
363
+ self.textbox.insert("0.0", "Starting calibration...\n\n")
364
+ self.textbox.insert("0.0", "Calibration Parameters:\n")
365
+ self.textbox.insert("0.0", json.dumps(metrics, indent=4) + "\n\n")
366
+ try:
367
+ info = self.option_manager.get_project_data()
368
+ folder = os.path.join(info['path'], info['name'])
369
+
370
+ self.train_process = Process(target=PSORunner.run_process, args=(stdout_queue, stderr_queue, results_queue, cosu_queue, metrics, folder))
371
+ self.train_process.daemon = True
372
+ self.train_process.start()
373
+ self.after(1000, self.watch_loop)
374
+ self.string_cache = ""
375
+ self.data_cache = ""
376
+
377
+ except Exception as e:
378
+ self.textbox.insert("0.0", "An exception occurred!\n Exception: " + str(e) + "\n\n")
379
+ self.textbox.insert("0.0", "Stack trace:\n")
380
+ self.textbox.insert("0.0", traceback.format_exc())
381
+ self.textbox.insert("0.0", "\n\n")
382
+ self.textbox.insert("0.0", "Calibration failed!")
383
+ self.progress_message_left.configure(text="")
384
+ self.progress_message_middle.configure(text="Calibration failed! See error log below.")
385
+ self.progress_message_right.configure(text="")
386
+ self.footer_progress_label.configure(text="Failed")
387
+ #self.progress_bar.stop()
388
+ self.footer_progress_bar.stop()
389
+ #self.progress_bar.configure(mode="determinate")
390
+ self.footer_progress_bar.configure(mode="determinate")
391
+ #self.progress_bar.set(0)
392
+ self.footer_progress_bar.set(0)
393
+
394
+ def stop(self):
395
+ print("Stopping...")
396
+ self.train_process.terminate()
397
+
398
+ info = self.option_manager.get_project_data()
399
+ folder = os.path.join(info['path'], info['name'])
400
+
401
+ if not os.path.exists(folder):
402
+ os.makedirs(folder)
403
+
404
+ # Stop the process
405
+ if (os.path.exists(os.path.join(folder, 'output.txt'))):
406
+ os.remove(os.path.join(folder, 'output.txt'))
407
+
408
+ if (os.path.exists(os.path.join(folder, 'error.txt'))):
409
+ os.remove(os.path.join(folder, 'error.txt'))
410
+
411
+ self.textbox.insert("0.0", "\nCalibration terminated!\n")
412
+ #self.progress_bar.stop()
413
+ self.footer_progress_bar.stop()
414
+ #self.progress_bar.configure(mode="determinate")
415
+ self.footer_progress_bar.configure(mode="determinate")
416
+ #self.progress_bar.set(0)
417
+ self.footer_progress_bar.set(0)
418
+ self.progress_message_left.configure(text="")
419
+ self.progress_message_middle.configure(text="Calibration stopped!")
420
+ self.footer_progress_label.configure(text="Stopped")
421
+ self.progress_message_right.configure(text="")
422
+
423
+ def watch_loop(self):
424
+ # Check if file exists:
425
+
426
+ info = self.option_manager.get_project_data()
427
+ folder = os.path.join(info['path'], info['name'])
428
+
429
+ if not os.path.exists(folder):
430
+ os.makedirs(folder)
431
+
432
+ while True:
433
+ try:
434
+ stdout_line = stdout_queue.get_nowait()
435
+
436
+ print("# " + stdout_line, flush=True)
437
+ with open(os.path.join(folder, 'output.txt'), 'a') as f:
438
+ f.write(stdout_line)
439
+
440
+ except Empty:
441
+ break
442
+
443
+ while True:
444
+ try:
445
+ stderr_line = stderr_queue.get_nowait()
446
+
447
+ print("? " + stderr_line, flush=True)
448
+ with open(os.path.join(folder, 'error.txt'), 'a') as f:
449
+ f.write(stderr_line)
450
+
451
+ except Empty:
452
+ break
453
+
454
+ while True:
455
+ try:
456
+ cosu_line = cosu_queue.get_nowait()
457
+
458
+ print("COSU " + cosu_line, flush=True)
459
+ except Empty:
460
+ break
461
+
462
+ if (os.path.exists(os.path.join(folder, 'output.txt'))):
463
+ with open(os.path.join(folder, 'output.txt'), 'r') as f:
464
+ lines = f.readlines()
465
+ lines_string = "".join(lines)
466
+
467
+ new_characters = lines_string.replace(self.string_cache, "")
468
+ # Update the textbox with characters not in self.string_cache
469
+ self.textbox.insert('0.0', new_characters)
470
+ self.string_cache = lines_string
471
+ print(new_characters, end="")
472
+
473
+ try:
474
+ with open(os.path.join(folder, "output.txt"), "r") as f:
475
+ text = f.read()
476
+
477
+ calibrated_params_pattern = r"calibrated params: ({.*?})"
478
+ best_particle_values_pattern = r"best particle values: (\[.*?\])"
479
+ progress_pattern = r"Progress - best_round_cost:(.*?), rel_round_tol:(.*?), rtol:(.*?)\n"
480
+
481
+ calibrated_params = re.findall(calibrated_params_pattern, text)
482
+ best_particle_values = re.findall(best_particle_values_pattern, text)
483
+ progress_values = re.findall(progress_pattern, text)
484
+
485
+ for index, pp in enumerate(best_particle_values):
486
+ pp = pp.strip()
487
+ pp = pp.replace('[ ', '[')
488
+ pp = pp.replace(' ', ',')
489
+ pp = pp.replace(' ', ',')
490
+ best_particle_values[index] = pp
491
+
492
+ calibrated_params = [ast.literal_eval(i) for i in calibrated_params]
493
+ best_particle_values = [ast.literal_eval(i) for i in best_particle_values]
494
+ progress_values = [tuple(map(float, i)) for i in progress_values]
495
+
496
+ print("Current params: " + str(calibrated_params), flush=True)
497
+
498
+ GraphGenerator.calibrated_params_by_round(self.running_config['steps'], calibrated_params, self.option_manager)
499
+ self.update_graph("")
500
+ except Exception as e:
501
+ # Print stack trace
502
+ traceback.print_exc()
503
+
504
+ print(e)
505
+
506
+ if (os.path.exists(os.path.join(folder, 'error.txt'))):
507
+ with open(os.path.join(folder, 'error.txt'), 'r') as f:
508
+ lines = f.readlines()
509
+ lines_string = "".join(lines)
510
+ self.data_cache = lines_string
511
+
512
+ pattern = r'(\d+)%\|.*\|(\d+)/(\d+)(?:,\sbest_cost=(\d+\.\d+))?' # The magic of AI
513
+ matches = re.findall(pattern, self.data_cache)
514
+ filtered_matches = [match for match in matches if match[3] != '']
515
+ matches = filtered_matches
516
+
517
+ if len(matches) > 0:
518
+ df = pd.DataFrame(matches, columns=['percent', 'completed_rounds', 'total_rounds', 'best_cost'], dtype=float)
519
+ df = df[df['best_cost'] != '']
520
+ df = df.dropna()
521
+ df = df.drop_duplicates()
522
+ df['round_step'] = (df['completed_rounds'].diff() < 0).cumsum()
523
+ df = df.drop_duplicates(subset=['completed_rounds', 'round_step'])
524
+
525
+ GraphGenerator.best_cost_stacked(self.running_config['steps'], df, self.option_manager)
526
+ GraphGenerator.best_cost_by_round(self.running_config['steps'], df, self.option_manager)
527
+ GraphGenerator.table(self.running_config['steps'], df, self.option_manager)
528
+ self.update_graph("")
529
+
530
+ match = matches[-1]
531
+ percent = int(match[0])
532
+ completed_rounds = int(match[1])
533
+ total_rounds = int(match[2])
534
+ best_cost = float(match[3]) if match[3] else None
535
+
536
+ if (percent > 0):
537
+ #self.progress_bar.stop()
538
+ self.footer_progress_bar.stop()
539
+ #self.progress_bar.configure(mode="determinate")
540
+ self.footer_progress_bar.configure(mode="determinate")
541
+ #self.progress_bar.set(percent/100)
542
+ self.footer_progress_bar.set(percent/100)
543
+ self.progress_message_left.configure(text="Percent Complete: " + str(percent) + "%")
544
+ self.progress_message_middle.configure(text=str(completed_rounds) + "/" + str(total_rounds))
545
+ self.footer_progress_label.configure(text=str(completed_rounds) + "/" + str(total_rounds))
546
+ self.progress_message_right.configure(text="Best Cost: " + str(best_cost))
547
+ else:
548
+ #self.progress_bar.configure(mode="indeterminate")
549
+ self.footer_progress_bar.configure(mode="indeterminate")
550
+ #self.progress_bar.start()
551
+ self.footer_progress_bar.start()
552
+ self.progress_message_left.configure(text="")
553
+ self.progress_message_middle.configure(text="Starting new round...")
554
+ self.footer_progress_label.configure(text="Next round...")
555
+ self.progress_message_right.configure(text="")
556
+
557
+
558
+
559
+ if self.train_process.is_alive():
560
+ self.after(1000, self.watch_loop)
561
+ else:
562
+ # Check if queue is empty
563
+ """
564
+ if (self.process_queue.empty()):
565
+ print("PROCESS FINISHED BUT WE GOT NO OBJECTS :(")
566
+ self.footer_progress_label.configure(text="Failed")
567
+ else:
568
+ self.final_results = self.process_queue.get()
569
+ print("PROCESS FINISHED WE GOT THINGS")
570
+ print(self.final_results)
571
+ self.footer_progress_label.configure(text="Finished")
572
+ """
573
+
574
+ #self.progress_bar.stop()
575
+ self.footer_progress_bar.stop()
576
+ #self.progress_bar.configure(mode="indeterminate")
577
+ self.footer_progress_bar.configure(mode="indeterminate")
578
+ #self.progress_bar.start()
579
+ self.footer_progress_bar.start()
580
+ self.progress_message_left.configure(text="")
581
+ self.progress_message_middle.configure(text="Calibration finished!")
582
+ self.progress_message_right.configure(text="")
583
+ self.textbox.insert("0.0", "\nCalibration finished!\n")
584
+
585
+ '''
586
+ def get_results(self):
587
+ request: Client = Client()
588
+ for name, value in parameters.items():
589
+ # if parameter name has a / in it assume that is a file based parameter and therefore value needs to be an array
590
+ if "/" in name and type(value) is not list:
591
+ request.add_data(name, [value])
592
+ else:
593
+ request.add_data(name, value)
594
+
595
+ conf = {
596
+ 'service_timeout': 60.0 # (sec)
597
+ }
598
+ files: List[str] = [] #optional list of filenames
599
+
600
+ #Synchronous Call
601
+ result: Client = request.execute(CSIP_ENDPOINT, files=files, sync=True, conf=conf)
602
+
603
+ #Asynchronous Call
604
+ tsamp: float = 0
605
+ def callback(c: Client, progress: str):
606
+ tsamp2: float = time.time()
607
+ print('Halton Update {} - {} - {}'.format(halton_id, c.get_status(), tsamp2 - tsamp))
608
+
609
+
610
+ tsamp = time.time()
611
+ result: Client = request.execute_async(
612
+ CSIP_ENDPOINT,
613
+ files=files,
614
+ callback=callback,
615
+ first_poll=poll_time,
616
+ next_poll=poll_time,
617
+ conf=conf
618
+ )
619
+ # After recieving response
620
+ if result.is_finished():
621
+ print(result)
622
+ else:
623
+ print(result)
624
+ '''
625
+
626
+ def start():
627
+ app = App()
628
+ app.mainloop()
629
+
630
+ if __name__ == "__main__":
631
+ app = App()
632
+ app.mainloop()