alchemist-nrel 0.3.1__py3-none-any.whl → 0.3.2__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.
- alchemist_core/__init__.py +2 -2
- alchemist_core/acquisition/botorch_acquisition.py +83 -126
- alchemist_core/data/experiment_manager.py +181 -12
- alchemist_core/models/botorch_model.py +292 -63
- alchemist_core/models/sklearn_model.py +145 -13
- alchemist_core/session.py +3330 -31
- alchemist_core/utils/__init__.py +3 -1
- alchemist_core/utils/acquisition_utils.py +60 -0
- alchemist_core/visualization/__init__.py +45 -0
- alchemist_core/visualization/helpers.py +130 -0
- alchemist_core/visualization/plots.py +1449 -0
- {alchemist_nrel-0.3.1.dist-info → alchemist_nrel-0.3.2.dist-info}/METADATA +13 -13
- {alchemist_nrel-0.3.1.dist-info → alchemist_nrel-0.3.2.dist-info}/RECORD +31 -26
- {alchemist_nrel-0.3.1.dist-info → alchemist_nrel-0.3.2.dist-info}/WHEEL +1 -1
- api/main.py +1 -1
- api/models/requests.py +52 -0
- api/models/responses.py +79 -2
- api/routers/experiments.py +333 -8
- api/routers/sessions.py +84 -9
- api/routers/visualizations.py +6 -4
- api/routers/websocket.py +2 -2
- api/services/session_store.py +295 -71
- api/static/assets/index-B6Cf6s_b.css +1 -0
- api/static/assets/{index-DWfIKU9j.js → index-B7njvc9r.js} +201 -196
- api/static/index.html +2 -2
- ui/gpr_panel.py +11 -5
- ui/target_column_dialog.py +299 -0
- ui/ui.py +52 -5
- api/static/assets/index-sMIa_1hV.css +0 -1
- {alchemist_nrel-0.3.1.dist-info → alchemist_nrel-0.3.2.dist-info}/entry_points.txt +0 -0
- {alchemist_nrel-0.3.1.dist-info → alchemist_nrel-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {alchemist_nrel-0.3.1.dist-info → alchemist_nrel-0.3.2.dist-info}/top_level.txt +0 -0
api/static/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/NEW_ICON.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>ALchemist - Active Learning Toolkit</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-B7njvc9r.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-B6Cf6s_b.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
ui/gpr_panel.py
CHANGED
|
@@ -505,14 +505,17 @@ class GaussianProcessPanel(ctk.CTkFrame):
|
|
|
505
505
|
print(f" RMSE = {session_metrics.get('rmse', 'N/A'):.3f}")
|
|
506
506
|
print("Learned hyperparameters:", self.main_app.learned_hyperparameters)
|
|
507
507
|
|
|
508
|
-
# Initialize
|
|
508
|
+
# Initialize visualization with model results
|
|
509
|
+
# Get target column name from experiment manager
|
|
510
|
+
target_col = self.main_app.experiment_manager.target_columns[0]
|
|
511
|
+
|
|
509
512
|
self.visualizations = Visualizations(
|
|
510
513
|
parent=self,
|
|
511
514
|
search_space=self.main_app.search_space,
|
|
512
515
|
gpr_model=self.main_app.gpr_model,
|
|
513
516
|
exp_df=self.main_app.exp_df,
|
|
514
|
-
encoded_X=self.main_app.exp_df.drop(columns=
|
|
515
|
-
encoded_y=self.main_app.exp_df[
|
|
517
|
+
encoded_X=self.main_app.exp_df.drop(columns=target_col),
|
|
518
|
+
encoded_y=self.main_app.exp_df[target_col]
|
|
516
519
|
)
|
|
517
520
|
self.visualizations.rmse_values = self.main_app.rmse_values
|
|
518
521
|
self.visualizations.mae_values = self.main_app.mae_values
|
|
@@ -532,13 +535,16 @@ class GaussianProcessPanel(ctk.CTkFrame):
|
|
|
532
535
|
# VISUALIZATIONS
|
|
533
536
|
# ==========================
|
|
534
537
|
def initialize_visualizations(self):
|
|
538
|
+
# Get target column name from experiment manager
|
|
539
|
+
target_col = self.main_app.experiment_manager.target_columns[0]
|
|
540
|
+
|
|
535
541
|
self.visualizations = Visualizations(
|
|
536
542
|
parent=self,
|
|
537
543
|
search_space=self.main_app.search_space,
|
|
538
544
|
gpr_model=self.main_app.gpr_model,
|
|
539
545
|
exp_df=self.main_app.exp_df,
|
|
540
|
-
encoded_X=self.main_app.exp_df.drop(columns=
|
|
541
|
-
encoded_y=self.main_app.exp_df[
|
|
546
|
+
encoded_X=self.main_app.exp_df.drop(columns=target_col),
|
|
547
|
+
encoded_y=self.main_app.exp_df[target_col]
|
|
542
548
|
)
|
|
543
549
|
self.visualizations.rmse_values = self.main_app.rmse_values
|
|
544
550
|
self.visualizations.mae_values = self.main_app.mae_values
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Target Column Selection Dialog
|
|
3
|
+
|
|
4
|
+
Allows users to select which column(s) in their CSV should be treated as optimization targets.
|
|
5
|
+
Supports both single-objective and multi-objective optimization.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import customtkinter as ctk
|
|
9
|
+
from typing import List, Optional, Tuple
|
|
10
|
+
import tkinter as tk
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TargetColumnDialog(ctk.CTkToplevel):
|
|
14
|
+
"""
|
|
15
|
+
Dialog for selecting target columns when loading experimental data.
|
|
16
|
+
|
|
17
|
+
Features:
|
|
18
|
+
- Single/Multi-objective mode toggle
|
|
19
|
+
- Column selection (dropdown for single, checkboxes for multi)
|
|
20
|
+
- Validation before confirming
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, parent, available_columns: List[str], default_column: str = None):
|
|
24
|
+
"""
|
|
25
|
+
Initialize the target column selection dialog.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
parent: Parent window
|
|
29
|
+
available_columns: List of column names available in the CSV
|
|
30
|
+
default_column: Default column to select (if it exists in available_columns)
|
|
31
|
+
"""
|
|
32
|
+
super().__init__(parent)
|
|
33
|
+
|
|
34
|
+
self.title("Select Target Column(s)")
|
|
35
|
+
self.geometry("500x400")
|
|
36
|
+
self.resizable(False, False)
|
|
37
|
+
|
|
38
|
+
# Make dialog modal
|
|
39
|
+
self.transient(parent)
|
|
40
|
+
self.grab_set()
|
|
41
|
+
|
|
42
|
+
# Store data
|
|
43
|
+
self.available_columns = available_columns
|
|
44
|
+
self.default_column = default_column if default_column in available_columns else None
|
|
45
|
+
self.result = None # Will store selected column(s) when confirmed
|
|
46
|
+
|
|
47
|
+
# UI state
|
|
48
|
+
self.mode = "single" # "single" or "multi"
|
|
49
|
+
self.checkbox_vars = {} # For multi-objective mode
|
|
50
|
+
|
|
51
|
+
self._create_ui()
|
|
52
|
+
|
|
53
|
+
# Center the dialog
|
|
54
|
+
self.update_idletasks()
|
|
55
|
+
x = parent.winfo_x() + (parent.winfo_width() // 2) - (self.winfo_width() // 2)
|
|
56
|
+
y = parent.winfo_y() + (parent.winfo_height() // 2) - (self.winfo_height() // 2)
|
|
57
|
+
self.geometry(f"+{x}+{y}")
|
|
58
|
+
|
|
59
|
+
def _create_ui(self):
|
|
60
|
+
"""Create the dialog UI elements."""
|
|
61
|
+
# Header
|
|
62
|
+
header_frame = ctk.CTkFrame(self, fg_color="transparent")
|
|
63
|
+
header_frame.pack(fill="x", padx=20, pady=(20, 10))
|
|
64
|
+
|
|
65
|
+
ctk.CTkLabel(
|
|
66
|
+
header_frame,
|
|
67
|
+
text="Select Target Column(s)",
|
|
68
|
+
font=ctk.CTkFont(size=16, weight="bold")
|
|
69
|
+
).pack(anchor="w")
|
|
70
|
+
|
|
71
|
+
ctk.CTkLabel(
|
|
72
|
+
header_frame,
|
|
73
|
+
text="Choose which column(s) to optimize:",
|
|
74
|
+
font=ctk.CTkFont(size=12),
|
|
75
|
+
text_color="gray"
|
|
76
|
+
).pack(anchor="w", pady=(5, 0))
|
|
77
|
+
|
|
78
|
+
# Mode selector (Single vs Multi-objective)
|
|
79
|
+
mode_frame = ctk.CTkFrame(self)
|
|
80
|
+
mode_frame.pack(fill="x", padx=20, pady=10)
|
|
81
|
+
|
|
82
|
+
ctk.CTkLabel(
|
|
83
|
+
mode_frame,
|
|
84
|
+
text="Optimization Mode:",
|
|
85
|
+
font=ctk.CTkFont(size=12, weight="bold")
|
|
86
|
+
).pack(side="left", padx=(10, 20))
|
|
87
|
+
|
|
88
|
+
self.mode_var = ctk.StringVar(value="single")
|
|
89
|
+
|
|
90
|
+
self.single_radio = ctk.CTkRadioButton(
|
|
91
|
+
mode_frame,
|
|
92
|
+
text="Single-Objective",
|
|
93
|
+
variable=self.mode_var,
|
|
94
|
+
value="single",
|
|
95
|
+
command=self._on_mode_change
|
|
96
|
+
)
|
|
97
|
+
self.single_radio.pack(side="left", padx=10)
|
|
98
|
+
|
|
99
|
+
self.multi_radio = ctk.CTkRadioButton(
|
|
100
|
+
mode_frame,
|
|
101
|
+
text="Multi-Objective",
|
|
102
|
+
variable=self.mode_var,
|
|
103
|
+
value="multi",
|
|
104
|
+
command=self._on_mode_change
|
|
105
|
+
)
|
|
106
|
+
self.multi_radio.pack(side="left", padx=10)
|
|
107
|
+
|
|
108
|
+
# Column selection area (content changes based on mode)
|
|
109
|
+
self.selection_frame = ctk.CTkFrame(self)
|
|
110
|
+
self.selection_frame.pack(fill="both", expand=True, padx=20, pady=10)
|
|
111
|
+
|
|
112
|
+
self._update_selection_ui()
|
|
113
|
+
|
|
114
|
+
# Buttons
|
|
115
|
+
button_frame = ctk.CTkFrame(self, fg_color="transparent")
|
|
116
|
+
button_frame.pack(fill="x", padx=20, pady=(10, 20))
|
|
117
|
+
|
|
118
|
+
ctk.CTkButton(
|
|
119
|
+
button_frame,
|
|
120
|
+
text="Cancel",
|
|
121
|
+
command=self._on_cancel,
|
|
122
|
+
width=100
|
|
123
|
+
).pack(side="right", padx=(10, 0))
|
|
124
|
+
|
|
125
|
+
ctk.CTkButton(
|
|
126
|
+
button_frame,
|
|
127
|
+
text="Confirm",
|
|
128
|
+
command=self._on_confirm,
|
|
129
|
+
width=100
|
|
130
|
+
).pack(side="right")
|
|
131
|
+
|
|
132
|
+
def _on_mode_change(self):
|
|
133
|
+
"""Handle mode change between single and multi-objective."""
|
|
134
|
+
self.mode = self.mode_var.get()
|
|
135
|
+
self._update_selection_ui()
|
|
136
|
+
|
|
137
|
+
def _update_selection_ui(self):
|
|
138
|
+
"""Update the column selection UI based on current mode."""
|
|
139
|
+
# Clear existing widgets
|
|
140
|
+
for widget in self.selection_frame.winfo_children():
|
|
141
|
+
widget.destroy()
|
|
142
|
+
|
|
143
|
+
if self.mode == "single":
|
|
144
|
+
self._create_single_objective_ui()
|
|
145
|
+
else:
|
|
146
|
+
self._create_multi_objective_ui()
|
|
147
|
+
|
|
148
|
+
def _create_single_objective_ui(self):
|
|
149
|
+
"""Create UI for single-objective mode (dropdown)."""
|
|
150
|
+
ctk.CTkLabel(
|
|
151
|
+
self.selection_frame,
|
|
152
|
+
text="Select target column:",
|
|
153
|
+
font=ctk.CTkFont(size=12)
|
|
154
|
+
).pack(anchor="w", padx=20, pady=(20, 10))
|
|
155
|
+
|
|
156
|
+
# Dropdown menu
|
|
157
|
+
self.column_var = ctk.StringVar(value=self.default_column or self.available_columns[0])
|
|
158
|
+
|
|
159
|
+
self.column_dropdown = ctk.CTkOptionMenu(
|
|
160
|
+
self.selection_frame,
|
|
161
|
+
variable=self.column_var,
|
|
162
|
+
values=self.available_columns,
|
|
163
|
+
width=400
|
|
164
|
+
)
|
|
165
|
+
self.column_dropdown.pack(padx=20, pady=10)
|
|
166
|
+
|
|
167
|
+
# Info text
|
|
168
|
+
info_frame = ctk.CTkFrame(self.selection_frame, fg_color="transparent")
|
|
169
|
+
info_frame.pack(fill="x", padx=20, pady=(20, 10))
|
|
170
|
+
|
|
171
|
+
ctk.CTkLabel(
|
|
172
|
+
info_frame,
|
|
173
|
+
text="💡 Tip: This column will be maximized or minimized during optimization.",
|
|
174
|
+
font=ctk.CTkFont(size=11),
|
|
175
|
+
text_color="gray",
|
|
176
|
+
wraplength=400,
|
|
177
|
+
justify="left"
|
|
178
|
+
).pack(anchor="w")
|
|
179
|
+
|
|
180
|
+
def _create_multi_objective_ui(self):
|
|
181
|
+
"""Create UI for multi-objective mode (checkboxes)."""
|
|
182
|
+
ctk.CTkLabel(
|
|
183
|
+
self.selection_frame,
|
|
184
|
+
text="Select target columns (2 or more):",
|
|
185
|
+
font=ctk.CTkFont(size=12)
|
|
186
|
+
).pack(anchor="w", padx=20, pady=(20, 10))
|
|
187
|
+
|
|
188
|
+
# Scrollable frame for checkboxes
|
|
189
|
+
checkbox_frame = ctk.CTkScrollableFrame(
|
|
190
|
+
self.selection_frame,
|
|
191
|
+
height=150
|
|
192
|
+
)
|
|
193
|
+
checkbox_frame.pack(fill="both", expand=True, padx=20, pady=10)
|
|
194
|
+
|
|
195
|
+
# Create checkboxes for each column
|
|
196
|
+
self.checkbox_vars = {}
|
|
197
|
+
for col in self.available_columns:
|
|
198
|
+
var = ctk.BooleanVar(value=False)
|
|
199
|
+
self.checkbox_vars[col] = var
|
|
200
|
+
|
|
201
|
+
checkbox = ctk.CTkCheckBox(
|
|
202
|
+
checkbox_frame,
|
|
203
|
+
text=col,
|
|
204
|
+
variable=var
|
|
205
|
+
)
|
|
206
|
+
checkbox.pack(anchor="w", pady=5, padx=10)
|
|
207
|
+
|
|
208
|
+
# Info text
|
|
209
|
+
info_frame = ctk.CTkFrame(self.selection_frame, fg_color="transparent")
|
|
210
|
+
info_frame.pack(fill="x", padx=20, pady=(10, 10))
|
|
211
|
+
|
|
212
|
+
ctk.CTkLabel(
|
|
213
|
+
info_frame,
|
|
214
|
+
text="💡 Tip: Multi-objective optimization finds trade-offs between objectives.",
|
|
215
|
+
font=ctk.CTkFont(size=11),
|
|
216
|
+
text_color="gray",
|
|
217
|
+
wraplength=400,
|
|
218
|
+
justify="left"
|
|
219
|
+
).pack(anchor="w")
|
|
220
|
+
|
|
221
|
+
def _on_confirm(self):
|
|
222
|
+
"""Handle confirm button click."""
|
|
223
|
+
if self.mode == "single":
|
|
224
|
+
# Single-objective: return selected column as string
|
|
225
|
+
selected = self.column_var.get()
|
|
226
|
+
if selected:
|
|
227
|
+
self.result = selected
|
|
228
|
+
self.destroy()
|
|
229
|
+
else:
|
|
230
|
+
# Multi-objective: return list of selected columns
|
|
231
|
+
selected = [col for col, var in self.checkbox_vars.items() if var.get()]
|
|
232
|
+
if len(selected) < 2:
|
|
233
|
+
# Show error - need at least 2 objectives
|
|
234
|
+
error_dialog = ctk.CTkToplevel(self)
|
|
235
|
+
error_dialog.title("Invalid Selection")
|
|
236
|
+
error_dialog.geometry("350x150")
|
|
237
|
+
error_dialog.transient(self)
|
|
238
|
+
error_dialog.grab_set()
|
|
239
|
+
|
|
240
|
+
ctk.CTkLabel(
|
|
241
|
+
error_dialog,
|
|
242
|
+
text="⚠️ Multi-Objective Mode",
|
|
243
|
+
font=ctk.CTkFont(size=14, weight="bold")
|
|
244
|
+
).pack(pady=(20, 10))
|
|
245
|
+
|
|
246
|
+
ctk.CTkLabel(
|
|
247
|
+
error_dialog,
|
|
248
|
+
text="Please select at least 2 target columns\nfor multi-objective optimization.",
|
|
249
|
+
font=ctk.CTkFont(size=12)
|
|
250
|
+
).pack(pady=10)
|
|
251
|
+
|
|
252
|
+
ctk.CTkButton(
|
|
253
|
+
error_dialog,
|
|
254
|
+
text="OK",
|
|
255
|
+
command=error_dialog.destroy,
|
|
256
|
+
width=100
|
|
257
|
+
).pack(pady=10)
|
|
258
|
+
|
|
259
|
+
# Center error dialog
|
|
260
|
+
error_dialog.update_idletasks()
|
|
261
|
+
x = self.winfo_x() + (self.winfo_width() // 2) - (error_dialog.winfo_width() // 2)
|
|
262
|
+
y = self.winfo_y() + (self.winfo_height() // 2) - (error_dialog.winfo_height() // 2)
|
|
263
|
+
error_dialog.geometry(f"+{x}+{y}")
|
|
264
|
+
return
|
|
265
|
+
|
|
266
|
+
self.result = selected
|
|
267
|
+
self.destroy()
|
|
268
|
+
|
|
269
|
+
def _on_cancel(self):
|
|
270
|
+
"""Handle cancel button click."""
|
|
271
|
+
self.result = None
|
|
272
|
+
self.destroy()
|
|
273
|
+
|
|
274
|
+
def get_result(self) -> Optional[str | List[str]]:
|
|
275
|
+
"""
|
|
276
|
+
Get the user's selection.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
String for single-objective, list for multi-objective, or None if cancelled
|
|
280
|
+
"""
|
|
281
|
+
return self.result
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def show_target_column_dialog(parent, available_columns: List[str],
|
|
285
|
+
default_column: str = None) -> Optional[str | List[str]]:
|
|
286
|
+
"""
|
|
287
|
+
Show target column selection dialog and return user's choice.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
parent: Parent window
|
|
291
|
+
available_columns: List of column names available in the CSV
|
|
292
|
+
default_column: Default column to select (if it exists)
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Selected column(s) or None if cancelled
|
|
296
|
+
"""
|
|
297
|
+
dialog = TargetColumnDialog(parent, available_columns, default_column)
|
|
298
|
+
parent.wait_window(dialog)
|
|
299
|
+
return dialog.get_result()
|
ui/ui.py
CHANGED
|
@@ -519,6 +519,46 @@ class ALchemistApp(ctk.CTk):
|
|
|
519
519
|
|
|
520
520
|
if file_path:
|
|
521
521
|
try:
|
|
522
|
+
# First, read the CSV to check for target column
|
|
523
|
+
import pandas as pd
|
|
524
|
+
preview_df = pd.read_csv(file_path)
|
|
525
|
+
|
|
526
|
+
# Check if any configured target column exists
|
|
527
|
+
# Default to looking for 'Output' if no target_columns configured
|
|
528
|
+
expected_targets = getattr(self.experiment_manager, 'target_columns', ['Output'])
|
|
529
|
+
missing_targets = [col for col in expected_targets if col not in preview_df.columns]
|
|
530
|
+
|
|
531
|
+
# If target column(s) missing, show selection dialog
|
|
532
|
+
target_columns_to_use = None
|
|
533
|
+
if missing_targets:
|
|
534
|
+
# Get non-metadata columns that could be targets
|
|
535
|
+
metadata_cols = {'Iteration', 'Reason', 'Noise'}
|
|
536
|
+
available_cols = [col for col in preview_df.columns if col not in metadata_cols]
|
|
537
|
+
|
|
538
|
+
if not available_cols:
|
|
539
|
+
raise ValueError("CSV file contains no columns that could be target columns.")
|
|
540
|
+
|
|
541
|
+
# Show target selection dialog
|
|
542
|
+
from ui.target_column_dialog import show_target_column_dialog
|
|
543
|
+
selected = show_target_column_dialog(
|
|
544
|
+
parent=self,
|
|
545
|
+
available_columns=available_cols,
|
|
546
|
+
default_column='output' if 'output' in available_cols else None
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
if selected is None:
|
|
550
|
+
# User cancelled
|
|
551
|
+
print("Data loading cancelled by user.")
|
|
552
|
+
return
|
|
553
|
+
|
|
554
|
+
target_columns_to_use = selected if isinstance(selected, list) else [selected]
|
|
555
|
+
print(f"User selected target column(s): {target_columns_to_use}")
|
|
556
|
+
else:
|
|
557
|
+
target_columns_to_use = expected_targets
|
|
558
|
+
|
|
559
|
+
# Configure experiment manager with selected target columns
|
|
560
|
+
self.experiment_manager.target_columns = target_columns_to_use
|
|
561
|
+
|
|
522
562
|
# Load experiments using the ExperimentManager
|
|
523
563
|
self.experiment_manager.load_from_csv(file_path)
|
|
524
564
|
|
|
@@ -536,6 +576,7 @@ class ALchemistApp(ctk.CTk):
|
|
|
536
576
|
|
|
537
577
|
# Log the data loading
|
|
538
578
|
print(f"Loaded {len(self.exp_df)} experiment points from {file_path}")
|
|
579
|
+
print(f"Target column(s): {target_columns_to_use}")
|
|
539
580
|
if 'Noise' in self.exp_df.columns:
|
|
540
581
|
print("Notice: Noise column detected. This will be used for model regularization if available.")
|
|
541
582
|
|
|
@@ -1695,8 +1736,9 @@ class ALchemistApp(ctk.CTk):
|
|
|
1695
1736
|
# Ensure metadata columns have correct types
|
|
1696
1737
|
exp_df_clean = self.exp_df.copy()
|
|
1697
1738
|
|
|
1698
|
-
# Define metadata columns
|
|
1699
|
-
|
|
1739
|
+
# Define metadata columns (including configured target columns)
|
|
1740
|
+
target_cols = set(self.experiment_manager.target_columns) if hasattr(self.experiment_manager, 'target_columns') else {'Output'}
|
|
1741
|
+
metadata_cols = target_cols | {'Noise', 'Iteration', 'Reason'}
|
|
1700
1742
|
|
|
1701
1743
|
# Ensure Iteration is numeric
|
|
1702
1744
|
if 'Iteration' in exp_df_clean.columns:
|
|
@@ -1706,9 +1748,10 @@ class ALchemistApp(ctk.CTk):
|
|
|
1706
1748
|
if 'Reason' in exp_df_clean.columns:
|
|
1707
1749
|
exp_df_clean['Reason'] = exp_df_clean['Reason'].astype(str).replace('nan', 'Manual')
|
|
1708
1750
|
|
|
1709
|
-
# Ensure
|
|
1710
|
-
|
|
1711
|
-
|
|
1751
|
+
# Ensure target columns are numeric
|
|
1752
|
+
for target_col in target_cols:
|
|
1753
|
+
if target_col in exp_df_clean.columns:
|
|
1754
|
+
exp_df_clean[target_col] = pd.to_numeric(exp_df_clean[target_col], errors='coerce')
|
|
1712
1755
|
|
|
1713
1756
|
# Ensure Noise is numeric if present
|
|
1714
1757
|
if 'Noise' in exp_df_clean.columns:
|
|
@@ -1745,6 +1788,10 @@ class ALchemistApp(ctk.CTk):
|
|
|
1745
1788
|
# Copy cleaned data to session's experiment manager
|
|
1746
1789
|
self.session.experiment_manager.df = exp_df_clean
|
|
1747
1790
|
|
|
1791
|
+
# Copy target_columns configuration to session's experiment manager
|
|
1792
|
+
if hasattr(self.experiment_manager, 'target_columns'):
|
|
1793
|
+
self.session.experiment_manager.target_columns = self.experiment_manager.target_columns
|
|
1794
|
+
|
|
1748
1795
|
# Update local exp_df with cleaned version
|
|
1749
1796
|
self.exp_df = exp_df_clean
|
|
1750
1797
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 98%;--foreground: 222.2 84% 4.9%;--card: 0 0% 100%;--card-foreground: 222.2 84% 4.9%;--popover: 0 0% 100%;--popover-foreground: 222.2 84% 4.9%;--primary: 217 91% 50%;--primary-foreground: 0 0% 100%;--secondary: 214 32% 88%;--secondary-foreground: 222.2 47.4% 11.2%;--muted: 210 40% 93%;--muted-foreground: 215.4 16.3% 40%;--accent: 210 40% 93%;--accent-foreground: 222.2 47.4% 11.2%;--destructive: 0 84.2% 50%;--destructive-foreground: 0 0% 100%;--border: 214.3 31.8% 85%;--input: 214.3 31.8% 85%;--ring: 217 91% 50%;--radius: .5rem}.dark{--background: 220 13% 13%;--foreground: 210 40% 98%;--card: 220 13% 16%;--card-foreground: 210 40% 98%;--popover: 220 13% 16%;--popover-foreground: 210 40% 98%;--primary: 211 100% 65%;--primary-foreground: 220 13% 13%;--secondary: 217.2 32.6% 20%;--secondary-foreground: 210 40% 98%;--muted: 220 13% 20%;--muted-foreground: 215 15% 65%;--accent: 220 13% 20%;--accent-foreground: 210 40% 98%;--destructive: 0 70% 55%;--destructive-foreground: 210 40% 98%;--border: 220 13% 24%;--input: 220 13% 24%;--ring: 211 100% 65%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));margin:0;min-height:100vh;font-feature-settings:"kern" 1,"liga" 1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code,.tabular-nums{font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.bottom-0{bottom:0}.left-0{left:0}.right-0{right:0}.top-0{top:0}.z-50{z-index:50}.col-span-1{grid-column:span 1 / span 1}.col-span-2{grid-column:span 2 / span 2}.col-span-3{grid-column:span 3 / span 3}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-top:2rem;margin-bottom:2rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-4{margin-left:1rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-0\.5{height:.125rem}.h-12{height:3rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-96{height:24rem}.h-auto{height:auto}.h-full{height:100%}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-\[120px\]{max-height:120px}.max-h-\[450px\]{max-height:450px}.max-h-\[85vh\]{max-height:85vh}.max-h-\[90vh\]{max-height:90vh}.min-h-0{min-height:0px}.min-h-\[550px\]{min-height:550px}.min-h-screen{min-height:100vh}.w-12{width:3rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-8{width:2rem}.w-80{width:20rem}.w-\[320px\]{width:320px}.w-\[580px\]{width:580px}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-6{gap:1.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1\.5{row-gap:.375rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-500\/20{border-color:#f59e0b33}.border-blue-500\/20{border-color:#3b82f633}.border-blue-500\/30{border-color:#3b82f64d}.border-border{border-color:hsl(var(--border))}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-destructive\/30{border-color:hsl(var(--destructive) / .3)}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-green-500\/20{border-color:#22c55e33}.border-input{border-color:hsl(var(--input))}.border-muted{border-color:hsl(var(--muted))}.border-muted-foreground\/20{border-color:hsl(var(--muted-foreground) / .2)}.border-primary{border-color:hsl(var(--primary))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-background{background-color:hsl(var(--background))}.bg-black\/50{background-color:#00000080}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-500\/5{background-color:#3b82f60d}.bg-card{background-color:hsl(var(--card))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-600{--tw-bg-opacity: 1;background-color:rgb(22 163 74 / var(--tw-bg-opacity, 1))}.bg-muted{background-color:hsl(var(--muted))}.bg-muted\/20{background-color:hsl(var(--muted) / .2)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-secondary{background-color:hsl(var(--secondary))}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.pb-1\.5{padding-bottom:.375rem}.pb-2{padding-bottom:.5rem}.pr-2{padding-right:.5rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-6xl{font-size:3.75rem;line-height:1}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-tight{line-height:1.25}.tracking-wide{letter-spacing:.025em}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-amber-700{--tw-text-opacity: 1;color:rgb(180 83 9 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-blue-600{--tw-text-opacity: 1;color:rgb(37 99 235 / var(--tw-text-opacity, 1))}.text-destructive{color:hsl(var(--destructive))}.text-foreground{color:hsl(var(--foreground))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-orange-600{--tw-text-opacity: 1;color:rgb(234 88 12 / var(--tw-text-opacity, 1))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-purple-500{--tw-text-opacity: 1;color:rgb(168 85 247 / var(--tw-text-opacity, 1))}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.text-yellow-600{--tw-text-opacity: 1;color:rgb(202 138 4 / var(--tw-text-opacity, 1))}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}::-webkit-scrollbar{width:8px;height:8px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:hsl(var(--muted-foreground) / .3);border-radius:4px}::-webkit-scrollbar-thumb:hover{background:hsl(var(--muted-foreground) / .5)}*{scrollbar-width:thin;scrollbar-color:hsl(var(--muted-foreground) / .3) transparent}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-destructive\/10:hover{background-color:hsl(var(--destructive) / .1)}.hover\:bg-green-700:hover{--tw-bg-opacity: 1;background-color:rgb(21 128 61 / var(--tw-bg-opacity, 1))}.hover\:bg-muted\/5:hover{background-color:hsl(var(--muted) / .05)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-muted\/80:hover{background-color:hsl(var(--muted) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-secondary\/90:hover{background-color:hsl(var(--secondary) / .9)}.hover\:text-destructive\/80:hover{color:hsl(var(--destructive) / .8)}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-primary\/80:hover{color:hsl(var(--primary) / .8)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-primary\/50:focus{--tw-ring-color: hsl(var(--primary) / .5)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.dark\:text-amber-500:is(.dark *){--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.dark\:text-green-500:is(.dark *){--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}@media(min-width:768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}@media(min-width:1024px){.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|