alchemist-nrel 0.2.1__py3-none-any.whl → 0.3.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.
Files changed (37) hide show
  1. alchemist_core/__init__.py +14 -7
  2. alchemist_core/acquisition/botorch_acquisition.py +14 -6
  3. alchemist_core/audit_log.py +594 -0
  4. alchemist_core/data/experiment_manager.py +69 -5
  5. alchemist_core/models/botorch_model.py +6 -4
  6. alchemist_core/models/sklearn_model.py +44 -6
  7. alchemist_core/session.py +600 -8
  8. alchemist_core/utils/doe.py +200 -0
  9. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/METADATA +57 -40
  10. alchemist_nrel-0.3.0.dist-info/RECORD +66 -0
  11. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/entry_points.txt +1 -0
  12. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/top_level.txt +1 -0
  13. api/main.py +19 -3
  14. api/models/requests.py +71 -0
  15. api/models/responses.py +144 -0
  16. api/routers/experiments.py +117 -5
  17. api/routers/sessions.py +329 -10
  18. api/routers/visualizations.py +10 -5
  19. api/services/session_store.py +210 -54
  20. api/static/NEW_ICON.ico +0 -0
  21. api/static/NEW_ICON.png +0 -0
  22. api/static/NEW_LOGO_DARK.png +0 -0
  23. api/static/NEW_LOGO_LIGHT.png +0 -0
  24. api/static/assets/api-vcoXEqyq.js +1 -0
  25. api/static/assets/index-C0_glioA.js +4084 -0
  26. api/static/assets/index-CB4V1LI5.css +1 -0
  27. api/static/index.html +14 -0
  28. api/static/vite.svg +1 -0
  29. run_api.py +55 -0
  30. ui/gpr_panel.py +7 -2
  31. ui/notifications.py +197 -10
  32. ui/ui.py +1117 -68
  33. ui/variables_setup.py +47 -2
  34. ui/visualizations.py +60 -3
  35. alchemist_nrel-0.2.1.dist-info/RECORD +0 -54
  36. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/WHEEL +0 -0
  37. {alchemist_nrel-0.2.1.dist-info → alchemist_nrel-0.3.0.dist-info}/licenses/LICENSE +0 -0
ui/variables_setup.py CHANGED
@@ -2,6 +2,7 @@ import customtkinter as ctk
2
2
  from customtkinter import filedialog
3
3
  import json, csv, os
4
4
  from skopt.space import Real, Integer, Categorical
5
+ from alchemist_core.data.search_space import SearchSpace
5
6
  from tkinter import StringVar
6
7
  import tkinter.messagebox as messagebox
7
8
  from tksheet import Sheet # requires tksheet package
@@ -427,7 +428,52 @@ class SpaceSetupWindow(ctk.CTkToplevel):
427
428
 
428
429
  # Update the main UI if it has the necessary methods
429
430
  if hasattr(self.master, 'search_space'):
431
+ # Store the skopt-compatible dimensions for legacy UI code
430
432
  self.master.search_space = self.search_space
433
+ # Always create/update the SearchSpace manager on the master so the
434
+ # OptimizationSession and ExperimentManager get a consistent object.
435
+ try:
436
+ ss = SearchSpace().from_dict(self.master.variable_space_data)
437
+ self.master.search_space_manager = ss
438
+ # Keep the skopt-compatible reference too
439
+ try:
440
+ self.master.search_space = ss.to_skopt()
441
+ except Exception:
442
+ self.master.search_space = ss
443
+ # Ensure experiment manager is updated
444
+ if hasattr(self.master, 'experiment_manager'):
445
+ try:
446
+ self.master.experiment_manager.set_search_space(ss)
447
+ except Exception:
448
+ pass
449
+ # If there's an active OptimizationSession, update it as well
450
+ if hasattr(self.master, 'session') and self.master.session is not None:
451
+ try:
452
+ self.master.session.search_space = ss
453
+ self.master.session.experiment_manager.set_search_space(ss)
454
+ # emit an event so other UI components can react
455
+ try:
456
+ self.master.session.events.emit('search_space_loaded', {'source': 'ui'})
457
+ except Exception:
458
+ pass
459
+ except Exception:
460
+ pass
461
+ except Exception:
462
+ pass
463
+
464
+ # Let the main app know the search space changed so it can sync to session
465
+ if hasattr(self.master, '_sync_data_to_session'):
466
+ try:
467
+ self.master._sync_data_to_session()
468
+ except Exception:
469
+ pass
470
+
471
+ if hasattr(self.master, '_update_ui_state'):
472
+ try:
473
+ self.master._update_ui_state()
474
+ except Exception:
475
+ pass
476
+
431
477
  if hasattr(self.master, 'update_variables_display'):
432
478
  self.master.update_variables_display()
433
479
  elif hasattr(self.master, 'var_sheet'):
@@ -469,8 +515,7 @@ class SpaceSetupWindow(ctk.CTkToplevel):
469
515
  self.master.load_exp_button.configure(state='normal')
470
516
  if hasattr(self.master, 'gen_template_button'):
471
517
  self.master.gen_template_button.configure(state='normal')
472
- if hasattr(self.master, 'cluster_switch'):
473
- self.master.cluster_switch.configure(state='normal')
518
+ # Clustering UI removed; no cluster_switch configuration needed
474
519
 
475
520
  except Exception as e:
476
521
  print(f"Error updating main UI variables: {e}")
ui/visualizations.py CHANGED
@@ -93,11 +93,53 @@ class Visualizations:
93
93
  def initialize_figure(self):
94
94
  """Initialize the Matplotlib figure and axes."""
95
95
  if self.fig is None or self.ax is None:
96
- self.fig, self.ax = plt.subplots(figsize=(6, 4))
96
+ # Use current rcParam DPI when creating the figure so text sizes
97
+ # are consistent with the active window's DPI settings.
98
+ dpi = plt.rcParams.get('figure.dpi', 100)
99
+ self.fig, self.ax = plt.subplots(figsize=(6, 4), dpi=dpi)
97
100
 
98
101
  def open_window(self):
99
102
  """Open the visualization window."""
100
- self.initialize_figure() # Ensure the figure is initialized
103
+ # Probe DPI from the parent window (avoids creating a new Tk root).
104
+ try:
105
+ dpi = int(self.parent.winfo_fpixels('1i'))
106
+ except Exception:
107
+ dpi = plt.rcParams.get('figure.dpi', 100)
108
+
109
+ # Apply DPI to matplotlib runtime settings so text and markers scale correctly
110
+ plt.rcParams['figure.dpi'] = dpi
111
+
112
+ # Cap font sizes to avoid oversized rendering on HiDPI displays
113
+ try:
114
+ fs = plt.rcParams.get('font.size', 10)
115
+ if fs > 14:
116
+ plt.rcParams['font.size'] = 10
117
+ if plt.rcParams.get('xtick.labelsize', 10) > 12:
118
+ plt.rcParams['xtick.labelsize'] = 8
119
+ if plt.rcParams.get('ytick.labelsize', 10) > 12:
120
+ plt.rcParams['ytick.labelsize'] = 8
121
+ except Exception:
122
+ pass
123
+
124
+ self.initialize_figure() # Ensure the figure is initialized with corrected DPI
125
+ # Enforce additional rcParams to keep the figure compact and fonts reasonable
126
+ try:
127
+ plt.rcParams['axes.titlesize'] = min(12, plt.rcParams.get('axes.titlesize', 12))
128
+ plt.rcParams['axes.labelsize'] = min(10, plt.rcParams.get('axes.labelsize', 10))
129
+ plt.rcParams['legend.fontsize'] = min(9, plt.rcParams.get('legend.fontsize', 9))
130
+ plt.rcParams['xtick.labelsize'] = min(9, plt.rcParams.get('xtick.labelsize', 9))
131
+ plt.rcParams['ytick.labelsize'] = min(9, plt.rcParams.get('ytick.labelsize', 9))
132
+ plt.rcParams['lines.markersize'] = min(6, plt.rcParams.get('lines.markersize', 6))
133
+ except Exception:
134
+ pass
135
+
136
+ # Ensure the figure uses a compact size (in inches) and the detected DPI.
137
+ try:
138
+ # Prefer a slightly smaller figure to avoid huge white margins
139
+ self.fig.set_size_inches(5, 4, forward=True)
140
+ self.fig.set_dpi(dpi)
141
+ except Exception:
142
+ pass
101
143
 
102
144
  if self.search_space is None:
103
145
  print("Error: Search space is not defined.")
@@ -122,6 +164,15 @@ class Visualizations:
122
164
  visualization_window.focus_force()
123
165
  visualization_window.grab_set()
124
166
 
167
+ # Fix macOS Retina scaling by probing the new window's DPI and applying it
168
+ try:
169
+ dpi = int(visualization_window.winfo_fpixels('1i'))
170
+ except Exception:
171
+ dpi = plt.rcParams.get('figure.dpi', 100)
172
+
173
+ # Apply DPI to matplotlib runtime settings so text and markers scale correctly
174
+ plt.rcParams['figure.dpi'] = dpi
175
+
125
176
  # Top control frame for other visualizations (metrics, parity, hyperparameters)
126
177
  # Use two rows to avoid crowding
127
178
  control_container = ctk.CTkFrame(visualization_window)
@@ -191,8 +242,14 @@ class Visualizations:
191
242
  self.plot_frame = ctk.CTkFrame(main_container, height=450)
192
243
  self.plot_frame.pack(side="left", fill='both', expand=True, padx=5, pady=5)
193
244
  self.canvas = FigureCanvasTkAgg(self.fig, master=self.plot_frame)
245
+ # Draw and tighten layout before packing to reduce excess margins
246
+ try:
247
+ self.fig.tight_layout(pad=0.6)
248
+ except Exception:
249
+ pass
194
250
  self.canvas.draw()
195
- self.canvas.get_tk_widget().pack(fill='both', expand=True, padx=5, pady=5)
251
+ # Use smaller padding so the canvas doesn't create excess whitespace
252
+ self.canvas.get_tk_widget().pack(fill='both', expand=True, padx=2, pady=2)
196
253
  self.metrics_toolbar = NavigationToolbar2Tk(self.canvas, self.plot_frame)
197
254
  self.metrics_toolbar.config(background='#2E2E2E')
198
255
  self.metrics_toolbar._message_label.config(background='#2E2E2E')
@@ -1,54 +0,0 @@
1
- main.py,sha256=3sAO2QZxxibs4WRT82i2w6KVBBFmYEMNUoGiMYFowOw,126
2
- alchemist_core/__init__.py,sha256=YA4a1INzAl6iuumPEXGGrorX9weogVN20b-w-UbB9bY,1813
3
- alchemist_core/config.py,sha256=Sk5eM1okktO5bUMlMPv9yzF2fpuiyGr9LUtlCWIBDc8,3366
4
- alchemist_core/events.py,sha256=ty9nRzfZGHzk6b09dALIwrMY_5PYSv0wMaw94JLDjSk,6717
5
- alchemist_core/session.py,sha256=bZTpa5vatg3w4zSg6qaXDQbpV-WrGwaRqD_sNc4Qas8,23889
6
- alchemist_core/acquisition/__init__.py,sha256=3CYGI24OTBS66ETrlGFyHCNpfS6DBMP41MZDhvjFEzg,32
7
- alchemist_core/acquisition/base_acquisition.py,sha256=s51vGx0b0Nt91lSCiVwYP9IClugVg2VJ21dn2n_4LIs,483
8
- alchemist_core/acquisition/botorch_acquisition.py,sha256=9ofyetj6gyBzO_3y8Y50EfCxP6BiHKYXTGIHT3fx6eY,30947
9
- alchemist_core/acquisition/skopt_acquisition.py,sha256=YRdANqgiN3GWd4sn16oruN6jVnI4RLmvLhBMUfYyLp4,13115
10
- alchemist_core/data/__init__.py,sha256=wgEb03x0RzVCi0uJXOzEKXkbA2oNHom5EgSB3tKgl1E,256
11
- alchemist_core/data/experiment_manager.py,sha256=kS63mVmuTNxhI3A9io52VKGcZOcgcTIyJqrzUQuZgkw,5910
12
- alchemist_core/data/search_space.py,sha256=oA9YEF3JRWpRklHzSo_Uxlmfy7bHwZfLZFDf4_nl4ew,6230
13
- alchemist_core/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
- alchemist_core/models/ax_model.py,sha256=Fnu19Et376WxLXpApZSalIbWHQE9OQnMk41_PW69XnQ,6040
15
- alchemist_core/models/base_model.py,sha256=gIpC2eoTZcp4ozI0Rctcxt_4bLhgaE6ALYCzvuIrMZw,3145
16
- alchemist_core/models/botorch_model.py,sha256=t-zqLRpCIGwSeIyveqJTjr8MQ9zWecnJIueaWg3Geck,42026
17
- alchemist_core/models/sklearn_model.py,sha256=ID0anz8BNGKDMpQlLlzKuyey1CvaJQkf0C79Q_S3tGo,34735
18
- alchemist_core/utils/__init__.py,sha256=oQsvUqukRng8GgiZSPMM-xmB-Lv46XveJzYQr2MdkOc,99
19
- alchemist_nrel-0.2.1.dist-info/licenses/LICENSE,sha256=wdIWWEj59ztfQViDuT_9wG3L1K8afUpRSygimXw36wY,1511
20
- api/__init__.py,sha256=ODc6pq4OSImgK4xvhX_zMhqUjIc7JvLfqxKF_-Ubw7g,49
21
- api/dependencies.py,sha256=sF1YYjnFRaw7nj7Y7URKLF2Ek-EfaXqjOyV1Zbktz2g,1090
22
- api/example_client.py,sha256=aZMNuJmt00hpNEkijn5RnVEV7ZPfKzwQxucSasTrrdw,6645
23
- api/main.py,sha256=Y2oPwxPK_jfOMNkT9qLQnM6lNzaM9sdJhOybJVFf8UM,3403
24
- api/middleware/__init__.py,sha256=WM4JEg3DibymvEvQ6hx_FJkv8lKLjHD48qNouSORGxA,313
25
- api/middleware/error_handlers.py,sha256=k5hNo6W5QDjGRHUY8Le-t7ubWkwSZBFpsTKcEF0nweI,4545
26
- api/models/__init__.py,sha256=YFtp8989mH9Zjzvd8W6pXklQJXTf8zWj4I2YWnLegDQ,1204
27
- api/models/requests.py,sha256=wy8KCgf3cwJ2Yz2wEzQjCqkUT6x0VHQHFTQDVMfbUMU,7213
28
- api/models/responses.py,sha256=c_okZVP0A8MF7aH199Bl6zjoJgede9lBrH5i8R8oPXc,8445
29
- api/routers/__init__.py,sha256=Mhg62NdA6iaPy-L5HLVp_dd9aUHmJ72KtMSRyO2kusA,180
30
- api/routers/acquisition.py,sha256=7c9ifuCFeDj8osWRHgCjAwbXjhd3iEBlVLW23FOAZXI,5710
31
- api/routers/experiments.py,sha256=q7Y1y5-pIIu0hRZAQKTpllL3AGstjbCP-dUqYAnQ-hI,4946
32
- api/routers/models.py,sha256=32Ln0MtlnCEjfN3Q6Io_EBwwwGoJXb73UbQEMIcVGjI,3651
33
- api/routers/sessions.py,sha256=k4gJe8qgb-8INT04_buYAfZIfMGBxfOOxn5tcXfr6LI,4523
34
- api/routers/variables.py,sha256=TiByX1ITabBDdTSMGAPa1lGd0LBipNgDfmPsbvTEAdE,10108
35
- api/routers/visualizations.py,sha256=qP__NhhflNKEAEcLV0c_WMQvofoNWSORMXbEMQCuVgI,23783
36
- api/services/__init__.py,sha256=0jw0tkL-8CtChv5ytdXRFeIz1OTVz7Vw1UaaDo86PQs,106
37
- api/services/session_store.py,sha256=Jot2S75Qrqaw_dbfNbeJt5rwlu25abexP4BMMCIgfdE,9605
38
- ui/__init__.py,sha256=H4kWlVey7KKf3iPQi74zuM7FSOg5Gh-ii3UwSTuIp8A,1203
39
- ui/acquisition_panel.py,sha256=zF-mQDrs-Y7sf2GXYF-bPlO9UXZMTzYRMDN-Wn5FyWw,39647
40
- ui/custom_widgets.py,sha256=UXNv4DiTw3tFC0VaN1Qtcf_-9umX34uDn46-cEA6cs0,3812
41
- ui/experiment_logger.py,sha256=dP3IGaQ31sURyz7awd_VrZBWaKLH2xXEeRalWZpvVcQ,8366
42
- ui/gpr_panel.py,sha256=cXZbYndkZ7E6GowkorYqBHVStpxEKDVJv8S-ZPzGGRQ,26230
43
- ui/notifications.py,sha256=evVd9r7OMqaZyx2WWXFnL-moIjrDFmRoMKrX9hvKB_g,28003
44
- ui/pool_viz.py,sha256=RwjggEfRSSEe-4nGjxc-I-1e5_aH64DgypT_YoubLIU,8765
45
- ui/ui.py,sha256=tJZoiBRACjY07NPrDdqYJc8we1Ze4fqnxJVUCHVkFZ8,54945
46
- ui/ui_utils.py,sha256=yud2-9LvT4XBcjTyfwUX5tYGNZRlAUVlu2YpcNY1HKA,658
47
- ui/utils.py,sha256=m19YFFkEUAY46YSj6S5RBmfUFjIWOk7F8CB4oKDRRZw,1078
48
- ui/variables_setup.py,sha256=4pu91MNRZlsK-DwRNd7U619wKDdSknI5Cf744o5Lxqo,21673
49
- ui/visualizations.py,sha256=X3Arl1k2UoQK2DCQ8YBnoJ4fscvinAlPJ1hInYkKvGo,67686
50
- alchemist_nrel-0.2.1.dist-info/METADATA,sha256=AAMdcL8KyjGcyjH9Ci2pqJOLenJSZ29b_CDigeK99Ak,6892
51
- alchemist_nrel-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
52
- alchemist_nrel-0.2.1.dist-info/entry_points.txt,sha256=zTuR1EjHMjeeAtUOACu0njiTCBMoaCobFqLlQ7IPYs8,40
53
- alchemist_nrel-0.2.1.dist-info/top_level.txt,sha256=dwh-oxj7H6oAGYchcUDyfiu9UxxzCn4hUDx1oeM2k-8,27
54
- alchemist_nrel-0.2.1.dist-info/RECORD,,