workbench 0.8.177__py3-none-any.whl → 0.8.227__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.
Potentially problematic release.
This version of workbench might be problematic. Click here for more details.
- workbench/__init__.py +1 -0
- workbench/algorithms/dataframe/__init__.py +1 -2
- workbench/algorithms/dataframe/compound_dataset_overlap.py +321 -0
- workbench/algorithms/dataframe/feature_space_proximity.py +168 -75
- workbench/algorithms/dataframe/fingerprint_proximity.py +422 -86
- workbench/algorithms/dataframe/projection_2d.py +44 -21
- workbench/algorithms/dataframe/proximity.py +259 -305
- workbench/algorithms/graph/light/proximity_graph.py +12 -11
- workbench/algorithms/models/cleanlab_model.py +382 -0
- workbench/algorithms/models/noise_model.py +388 -0
- workbench/algorithms/sql/column_stats.py +0 -1
- workbench/algorithms/sql/correlations.py +0 -1
- workbench/algorithms/sql/descriptive_stats.py +0 -1
- workbench/algorithms/sql/outliers.py +3 -3
- workbench/api/__init__.py +5 -1
- workbench/api/df_store.py +17 -108
- workbench/api/endpoint.py +14 -12
- workbench/api/feature_set.py +117 -11
- workbench/api/meta.py +0 -1
- workbench/api/meta_model.py +289 -0
- workbench/api/model.py +52 -21
- workbench/api/parameter_store.py +3 -52
- workbench/cached/cached_meta.py +0 -1
- workbench/cached/cached_model.py +49 -11
- workbench/core/artifacts/__init__.py +11 -2
- workbench/core/artifacts/artifact.py +5 -5
- workbench/core/artifacts/df_store_core.py +114 -0
- workbench/core/artifacts/endpoint_core.py +319 -204
- workbench/core/artifacts/feature_set_core.py +249 -45
- workbench/core/artifacts/model_core.py +135 -82
- workbench/core/artifacts/parameter_store_core.py +98 -0
- workbench/core/cloud_platform/cloud_meta.py +0 -1
- workbench/core/pipelines/pipeline_executor.py +1 -1
- workbench/core/transforms/features_to_model/features_to_model.py +60 -44
- workbench/core/transforms/model_to_endpoint/model_to_endpoint.py +43 -10
- workbench/core/transforms/pandas_transforms/pandas_to_features.py +38 -2
- workbench/core/views/training_view.py +113 -42
- workbench/core/views/view.py +53 -3
- workbench/core/views/view_utils.py +4 -4
- workbench/model_script_utils/model_script_utils.py +339 -0
- workbench/model_script_utils/pytorch_utils.py +405 -0
- workbench/model_script_utils/uq_harness.py +277 -0
- workbench/model_scripts/chemprop/chemprop.template +774 -0
- workbench/model_scripts/chemprop/generated_model_script.py +774 -0
- workbench/model_scripts/chemprop/model_script_utils.py +339 -0
- workbench/model_scripts/chemprop/requirements.txt +3 -0
- workbench/model_scripts/custom_models/chem_info/fingerprints.py +175 -0
- workbench/model_scripts/custom_models/chem_info/mol_descriptors.py +0 -1
- workbench/model_scripts/custom_models/chem_info/molecular_descriptors.py +0 -1
- workbench/model_scripts/custom_models/chem_info/morgan_fingerprints.py +1 -2
- workbench/model_scripts/custom_models/proximity/feature_space_proximity.py +194 -0
- workbench/model_scripts/custom_models/proximity/feature_space_proximity.template +8 -10
- workbench/model_scripts/custom_models/uq_models/bayesian_ridge.template +7 -8
- workbench/model_scripts/custom_models/uq_models/ensemble_xgb.template +20 -21
- workbench/model_scripts/custom_models/uq_models/feature_space_proximity.py +194 -0
- workbench/model_scripts/custom_models/uq_models/gaussian_process.template +5 -11
- workbench/model_scripts/custom_models/uq_models/ngboost.template +15 -16
- workbench/model_scripts/ensemble_xgb/ensemble_xgb.template +15 -17
- workbench/model_scripts/meta_model/generated_model_script.py +209 -0
- workbench/model_scripts/meta_model/meta_model.template +209 -0
- workbench/model_scripts/pytorch_model/generated_model_script.py +443 -499
- workbench/model_scripts/pytorch_model/model_script_utils.py +339 -0
- workbench/model_scripts/pytorch_model/pytorch.template +440 -496
- workbench/model_scripts/pytorch_model/pytorch_utils.py +405 -0
- workbench/model_scripts/pytorch_model/requirements.txt +1 -1
- workbench/model_scripts/pytorch_model/uq_harness.py +277 -0
- workbench/model_scripts/scikit_learn/generated_model_script.py +7 -12
- workbench/model_scripts/scikit_learn/scikit_learn.template +4 -9
- workbench/model_scripts/script_generation.py +15 -12
- workbench/model_scripts/uq_models/generated_model_script.py +248 -0
- workbench/model_scripts/xgb_model/generated_model_script.py +371 -403
- workbench/model_scripts/xgb_model/model_script_utils.py +339 -0
- workbench/model_scripts/xgb_model/uq_harness.py +277 -0
- workbench/model_scripts/xgb_model/xgb_model.template +367 -399
- workbench/repl/workbench_shell.py +18 -14
- workbench/resources/open_source_api.key +1 -1
- workbench/scripts/endpoint_test.py +162 -0
- workbench/scripts/lambda_test.py +73 -0
- workbench/scripts/meta_model_sim.py +35 -0
- workbench/scripts/ml_pipeline_sqs.py +122 -6
- workbench/scripts/training_test.py +85 -0
- workbench/themes/dark/custom.css +59 -0
- workbench/themes/dark/plotly.json +5 -5
- workbench/themes/light/custom.css +153 -40
- workbench/themes/light/plotly.json +9 -9
- workbench/themes/midnight_blue/custom.css +59 -0
- workbench/utils/aws_utils.py +0 -1
- workbench/utils/chem_utils/fingerprints.py +87 -46
- workbench/utils/chem_utils/mol_descriptors.py +0 -1
- workbench/utils/chem_utils/projections.py +16 -6
- workbench/utils/chem_utils/vis.py +25 -27
- workbench/utils/chemprop_utils.py +141 -0
- workbench/utils/config_manager.py +2 -6
- workbench/utils/endpoint_utils.py +5 -7
- workbench/utils/license_manager.py +2 -6
- workbench/utils/markdown_utils.py +57 -0
- workbench/utils/meta_model_simulator.py +499 -0
- workbench/utils/metrics_utils.py +256 -0
- workbench/utils/model_utils.py +260 -76
- workbench/utils/pipeline_utils.py +0 -1
- workbench/utils/plot_utils.py +159 -34
- workbench/utils/pytorch_utils.py +87 -0
- workbench/utils/shap_utils.py +11 -57
- workbench/utils/theme_manager.py +95 -30
- workbench/utils/xgboost_local_crossfold.py +267 -0
- workbench/utils/xgboost_model_utils.py +127 -220
- workbench/web_interface/components/experiments/outlier_plot.py +0 -1
- workbench/web_interface/components/model_plot.py +16 -2
- workbench/web_interface/components/plugin_unit_test.py +5 -3
- workbench/web_interface/components/plugins/ag_table.py +2 -4
- workbench/web_interface/components/plugins/confusion_matrix.py +3 -6
- workbench/web_interface/components/plugins/model_details.py +48 -80
- workbench/web_interface/components/plugins/scatter_plot.py +192 -92
- workbench/web_interface/components/settings_menu.py +184 -0
- workbench/web_interface/page_views/main_page.py +0 -1
- {workbench-0.8.177.dist-info → workbench-0.8.227.dist-info}/METADATA +31 -17
- {workbench-0.8.177.dist-info → workbench-0.8.227.dist-info}/RECORD +121 -106
- {workbench-0.8.177.dist-info → workbench-0.8.227.dist-info}/entry_points.txt +4 -0
- {workbench-0.8.177.dist-info → workbench-0.8.227.dist-info}/licenses/LICENSE +1 -1
- workbench/core/cloud_platform/aws/aws_df_store.py +0 -404
- workbench/core/cloud_platform/aws/aws_parameter_store.py +0 -280
- workbench/model_scripts/custom_models/meta_endpoints/example.py +0 -53
- workbench/model_scripts/custom_models/proximity/generated_model_script.py +0 -138
- workbench/model_scripts/custom_models/proximity/proximity.py +0 -384
- workbench/model_scripts/custom_models/uq_models/generated_model_script.py +0 -494
- workbench/model_scripts/custom_models/uq_models/mapie.template +0 -494
- workbench/model_scripts/custom_models/uq_models/meta_uq.template +0 -386
- workbench/model_scripts/custom_models/uq_models/proximity.py +0 -384
- workbench/model_scripts/ensemble_xgb/generated_model_script.py +0 -279
- workbench/model_scripts/quant_regression/quant_regression.template +0 -279
- workbench/model_scripts/quant_regression/requirements.txt +0 -1
- workbench/themes/quartz/base_css.url +0 -1
- workbench/themes/quartz/custom.css +0 -117
- workbench/themes/quartz/plotly.json +0 -642
- workbench/themes/quartz_dark/base_css.url +0 -1
- workbench/themes/quartz_dark/custom.css +0 -131
- workbench/themes/quartz_dark/plotly.json +0 -642
- workbench/utils/resource_utils.py +0 -39
- {workbench-0.8.177.dist-info → workbench-0.8.227.dist-info}/WHEEL +0 -0
- {workbench-0.8.177.dist-info → workbench-0.8.227.dist-info}/top_level.txt +0 -0
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
# Imports for XGB Model
|
|
2
|
-
import xgboost as xgb
|
|
3
|
-
import awswrangler as wr
|
|
4
|
-
from sklearn.model_selection import train_test_split
|
|
5
|
-
|
|
6
|
-
# Model Performance Scores
|
|
7
|
-
from sklearn.metrics import (
|
|
8
|
-
mean_absolute_error,
|
|
9
|
-
r2_score,
|
|
10
|
-
root_mean_squared_error
|
|
11
|
-
)
|
|
12
|
-
|
|
13
|
-
from io import StringIO
|
|
14
|
-
import json
|
|
15
|
-
import argparse
|
|
16
|
-
import os
|
|
17
|
-
import pandas as pd
|
|
18
|
-
|
|
19
|
-
# Template Placeholders
|
|
20
|
-
TEMPLATE_PARAMS = {
|
|
21
|
-
"model_type": "{{model_type}}",
|
|
22
|
-
"target_column": "{{target_column}}",
|
|
23
|
-
"features": "{{feature_list}}",
|
|
24
|
-
"model_metrics_s3_path": "{{model_metrics_s3_path}}",
|
|
25
|
-
"train_all_data": "{{train_all_data}}"
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
# Function to check if dataframe is empty
|
|
29
|
-
def check_dataframe(df: pd.DataFrame, df_name: str) -> None:
|
|
30
|
-
"""
|
|
31
|
-
Check if the provided dataframe is empty and raise an exception if it is.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
df (pd.DataFrame): DataFrame to check
|
|
35
|
-
df_name (str): Name of the DataFrame
|
|
36
|
-
"""
|
|
37
|
-
if df.empty:
|
|
38
|
-
msg = f"*** The training data {df_name} has 0 rows! ***STOPPING***"
|
|
39
|
-
print(msg)
|
|
40
|
-
raise ValueError(msg)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def match_features_case_insensitive(df: pd.DataFrame, model_features: list) -> pd.DataFrame:
|
|
44
|
-
"""
|
|
45
|
-
Matches and renames DataFrame columns to match model feature names (case-insensitive).
|
|
46
|
-
Prioritizes exact matches, then case-insensitive matches.
|
|
47
|
-
|
|
48
|
-
Raises ValueError if any model features cannot be matched.
|
|
49
|
-
"""
|
|
50
|
-
df_columns_lower = {col.lower(): col for col in df.columns}
|
|
51
|
-
rename_dict = {}
|
|
52
|
-
missing = []
|
|
53
|
-
for feature in model_features:
|
|
54
|
-
if feature in df.columns:
|
|
55
|
-
continue # Exact match
|
|
56
|
-
elif feature.lower() in df_columns_lower:
|
|
57
|
-
rename_dict[df_columns_lower[feature.lower()]] = feature
|
|
58
|
-
else:
|
|
59
|
-
missing.append(feature)
|
|
60
|
-
|
|
61
|
-
if missing:
|
|
62
|
-
raise ValueError(f"Features not found: {missing}")
|
|
63
|
-
|
|
64
|
-
# Rename the DataFrame columns to match the model features
|
|
65
|
-
return df.rename(columns=rename_dict)
|
|
66
|
-
|
|
67
|
-
if __name__ == "__main__":
|
|
68
|
-
"""The main function is for training the XGBoost Quantile Regression models"""
|
|
69
|
-
|
|
70
|
-
# Harness Template Parameters
|
|
71
|
-
target = TEMPLATE_PARAMS["target_column"]
|
|
72
|
-
features = TEMPLATE_PARAMS["features"]
|
|
73
|
-
model_metrics_s3_path = TEMPLATE_PARAMS["model_metrics_s3_path"]
|
|
74
|
-
train_all_data = TEMPLATE_PARAMS["train_all_data"]
|
|
75
|
-
validation_split = 0.2
|
|
76
|
-
quantiles = [0.025, 0.25, 0.50, 0.75, 0.975]
|
|
77
|
-
q_models = {}
|
|
78
|
-
|
|
79
|
-
# Script arguments for input/output directories
|
|
80
|
-
parser = argparse.ArgumentParser()
|
|
81
|
-
parser.add_argument("--model-dir", type=str, default=os.environ.get("SM_MODEL_DIR", "/opt/ml/model"))
|
|
82
|
-
parser.add_argument("--train", type=str, default=os.environ.get("SM_CHANNEL_TRAIN", "/opt/ml/input/data/train"))
|
|
83
|
-
parser.add_argument(
|
|
84
|
-
"--output-data-dir", type=str, default=os.environ.get("SM_OUTPUT_DATA_DIR", "/opt/ml/output/data")
|
|
85
|
-
)
|
|
86
|
-
args = parser.parse_args()
|
|
87
|
-
|
|
88
|
-
# Load training data from the specified directory
|
|
89
|
-
training_files = [
|
|
90
|
-
os.path.join(args.train, file)
|
|
91
|
-
for file in os.listdir(args.train) if file.endswith(".csv")
|
|
92
|
-
]
|
|
93
|
-
print(f"Training Files: {training_files}")
|
|
94
|
-
|
|
95
|
-
# Combine files and read them all into a single pandas dataframe
|
|
96
|
-
df = pd.concat([pd.read_csv(file, engine="python") for file in training_files])
|
|
97
|
-
|
|
98
|
-
# Check if the DataFrame is empty
|
|
99
|
-
check_dataframe(df, "training_df")
|
|
100
|
-
|
|
101
|
-
# Training data split logic
|
|
102
|
-
if train_all_data:
|
|
103
|
-
# Use all data for both training and validation
|
|
104
|
-
print("Training on all data...")
|
|
105
|
-
df_train = df.copy()
|
|
106
|
-
df_val = df.copy()
|
|
107
|
-
elif "training" in df.columns:
|
|
108
|
-
# Split data based on a 'training' column if it exists
|
|
109
|
-
print("Splitting data based on 'training' column...")
|
|
110
|
-
df_train = df[df["training"]].copy()
|
|
111
|
-
df_val = df[~df["training"]].copy()
|
|
112
|
-
else:
|
|
113
|
-
# Perform a random split if no 'training' column is found
|
|
114
|
-
print("Splitting data randomly...")
|
|
115
|
-
df_train, df_val = train_test_split(df, test_size=validation_split, random_state=42)
|
|
116
|
-
|
|
117
|
-
# Features/Target output
|
|
118
|
-
print(f"Target: {target}")
|
|
119
|
-
print(f"Features: {str(features)}")
|
|
120
|
-
print(f"Data Shape: {df.shape}")
|
|
121
|
-
|
|
122
|
-
# Prepare features and targets for training
|
|
123
|
-
X_train = df_train[features]
|
|
124
|
-
X_val = df_val[features]
|
|
125
|
-
y_train = df_train[target]
|
|
126
|
-
y_val = df_val[target]
|
|
127
|
-
|
|
128
|
-
# Train models for each of the quantiles
|
|
129
|
-
for q in quantiles:
|
|
130
|
-
params = {
|
|
131
|
-
"objective": "reg:quantileerror",
|
|
132
|
-
"quantile_alpha": q,
|
|
133
|
-
}
|
|
134
|
-
model = xgb.XGBRegressor(**params)
|
|
135
|
-
model.fit(X_train, y_train)
|
|
136
|
-
|
|
137
|
-
# Convert quantile to string
|
|
138
|
-
q_str = f"q_{int(q * 100)}" if (q * 100) == int(q * 100) else f"q_{int(q * 1000):03d}"
|
|
139
|
-
|
|
140
|
-
# Store the model
|
|
141
|
-
q_models[q_str] = model
|
|
142
|
-
|
|
143
|
-
# Run predictions for each quantile
|
|
144
|
-
quantile_predictions = {q: model.predict(X_val) for q, model in q_models.items()}
|
|
145
|
-
|
|
146
|
-
# Create a copy of the validation DataFrame and add the new columns
|
|
147
|
-
result_df = df_val[[target]].copy()
|
|
148
|
-
|
|
149
|
-
# Add the quantile predictions to the DataFrame
|
|
150
|
-
for name, preds in quantile_predictions.items():
|
|
151
|
-
result_df[name] = preds
|
|
152
|
-
|
|
153
|
-
# Add the median as the main prediction
|
|
154
|
-
result_df["prediction"] = result_df["q_50"]
|
|
155
|
-
|
|
156
|
-
# Now compute residuals on the prediction
|
|
157
|
-
result_df["residual"] = result_df[target] - result_df["prediction"]
|
|
158
|
-
result_df["residual_abs"] = result_df["residual"].abs()
|
|
159
|
-
|
|
160
|
-
# Save the results dataframe to S3
|
|
161
|
-
wr.s3.to_csv(
|
|
162
|
-
result_df,
|
|
163
|
-
path=f"{model_metrics_s3_path}/validation_predictions.csv",
|
|
164
|
-
index=False,
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
# Report Performance Metrics
|
|
168
|
-
rmse = root_mean_squared_error(result_df[target], result_df["prediction"])
|
|
169
|
-
mae = mean_absolute_error(result_df[target], result_df["prediction"])
|
|
170
|
-
r2 = r2_score(result_df[target], result_df["prediction"])
|
|
171
|
-
print(f"RMSE: {rmse:.3f}")
|
|
172
|
-
print(f"MAE: {mae:.3f}")
|
|
173
|
-
print(f"R2: {r2:.3f}")
|
|
174
|
-
print(f"NumRows: {len(result_df)}")
|
|
175
|
-
|
|
176
|
-
# Now save the quantile models
|
|
177
|
-
for name, model in q_models.items():
|
|
178
|
-
model_path = os.path.join(args.model_dir, f"{name}.json")
|
|
179
|
-
print(f"Saving model: {model_path}")
|
|
180
|
-
model.save_model(model_path)
|
|
181
|
-
|
|
182
|
-
# Also save the features (this will validate input during predictions)
|
|
183
|
-
with open(os.path.join(args.model_dir, "feature_columns.json"), "w") as fp:
|
|
184
|
-
json.dump(features, fp)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def model_fn(model_dir) -> dict:
|
|
188
|
-
"""Deserialized and return all the fitted models from the model directory.
|
|
189
|
-
|
|
190
|
-
Args:
|
|
191
|
-
model_dir (str): The directory where the models are stored.
|
|
192
|
-
|
|
193
|
-
Returns:
|
|
194
|
-
dict: A dictionary of the models.
|
|
195
|
-
"""
|
|
196
|
-
|
|
197
|
-
# Load ALL the Quantile models from the model directory
|
|
198
|
-
models = {}
|
|
199
|
-
for file in os.listdir(model_dir):
|
|
200
|
-
if file.startswith("q") and file.endswith(".json"): # The Quantile models
|
|
201
|
-
# Load the model
|
|
202
|
-
model_path = os.path.join(model_dir, file)
|
|
203
|
-
print(f"Loading model: {model_path}")
|
|
204
|
-
model = xgb.XGBRegressor()
|
|
205
|
-
model.load_model(model_path)
|
|
206
|
-
|
|
207
|
-
# Store the quantile model
|
|
208
|
-
q_name = os.path.splitext(file)[0]
|
|
209
|
-
models[q_name] = model
|
|
210
|
-
|
|
211
|
-
# Return all the models
|
|
212
|
-
return models
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
def input_fn(input_data, content_type):
|
|
216
|
-
"""Parse input data and return a DataFrame."""
|
|
217
|
-
if not input_data:
|
|
218
|
-
raise ValueError("Empty input data is not supported!")
|
|
219
|
-
|
|
220
|
-
# Decode bytes to string if necessary
|
|
221
|
-
if isinstance(input_data, bytes):
|
|
222
|
-
input_data = input_data.decode("utf-8")
|
|
223
|
-
|
|
224
|
-
if "text/csv" in content_type:
|
|
225
|
-
return pd.read_csv(StringIO(input_data))
|
|
226
|
-
elif "application/json" in content_type:
|
|
227
|
-
return pd.DataFrame(json.loads(input_data)) # Assumes JSON array of records
|
|
228
|
-
else:
|
|
229
|
-
raise ValueError(f"{content_type} not supported!")
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
def output_fn(output_df, accept_type):
|
|
233
|
-
"""Supports both CSV and JSON output formats."""
|
|
234
|
-
if "text/csv" in accept_type:
|
|
235
|
-
csv_output = output_df.fillna("N/A").to_csv(index=False) # CSV with N/A for missing values
|
|
236
|
-
return csv_output, "text/csv"
|
|
237
|
-
elif "application/json" in accept_type:
|
|
238
|
-
return output_df.to_json(orient="records"), "application/json" # JSON array of records (NaNs -> null)
|
|
239
|
-
else:
|
|
240
|
-
raise RuntimeError(f"{accept_type} accept type is not supported by this script.")
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def predict_fn(df, models) -> pd.DataFrame:
|
|
244
|
-
"""Make Predictions with our XGB Quantile Regression Model
|
|
245
|
-
|
|
246
|
-
Args:
|
|
247
|
-
df (pd.DataFrame): The input DataFrame
|
|
248
|
-
models (dict): The dictionary of models to use for predictions
|
|
249
|
-
|
|
250
|
-
Returns:
|
|
251
|
-
pd.DataFrame: The DataFrame with the predictions added
|
|
252
|
-
"""
|
|
253
|
-
|
|
254
|
-
# Grab our feature columns (from training)
|
|
255
|
-
model_dir = os.environ.get("SM_MODEL_DIR", "/opt/ml/model")
|
|
256
|
-
with open(os.path.join(model_dir, "feature_columns.json")) as fp:
|
|
257
|
-
model_features = json.load(fp)
|
|
258
|
-
print(f"Model Features: {model_features}")
|
|
259
|
-
|
|
260
|
-
# We're going match features in a case-insensitive manner, accounting for all the permutations
|
|
261
|
-
# - Model has a feature list that's any case ("Id", "taCos", "cOunT", "likes_tacos")
|
|
262
|
-
# - Incoming data has columns that are mixed case ("ID", "Tacos", "Count", "Likes_Tacos")
|
|
263
|
-
matched_df = match_features_case_insensitive(df, model_features)
|
|
264
|
-
|
|
265
|
-
# Predict the features against all the models
|
|
266
|
-
for name, model in models.items():
|
|
267
|
-
df[name] = model.predict(matched_df[model_features])
|
|
268
|
-
|
|
269
|
-
# Use the median prediction as the main prediction
|
|
270
|
-
df["prediction"] = df["q_50"]
|
|
271
|
-
|
|
272
|
-
# Estimate the standard deviation of the predictions using the interquartile range
|
|
273
|
-
df["prediction_std"] = (df["q_75"] - df["q_25"]) / 1.35
|
|
274
|
-
|
|
275
|
-
# Reorganize the columns so they are in alphabetical order
|
|
276
|
-
df = df.reindex(sorted(df.columns), axis=1)
|
|
277
|
-
|
|
278
|
-
# All done, return the DataFrame
|
|
279
|
-
return df
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# Note: In general this file should be empty (as the default inference image has all required libraries)
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dbc.themes.QUARTZ
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
h1, h2, h3, h4 {
|
|
2
|
-
color: rgb(255, 255, 255); /* We want the text to dark gray */
|
|
3
|
-
}
|
|
4
|
-
body {
|
|
5
|
-
color: rgb(240, 240, 240); /* We want the text to dark gray */
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/* Custom CSS to style bold text */
|
|
9
|
-
b, strong {
|
|
10
|
-
color: rgb(220, 140, 240); /* Replace with your desired RGB color */
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/* Links in Quartz are pink and hard to see */
|
|
14
|
-
/* Default link color */
|
|
15
|
-
a {
|
|
16
|
-
color: rgb(80, 80, 240); /* Change to your preferred color */
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/* Reduce spacing around lists */
|
|
20
|
-
p {
|
|
21
|
-
margin-bottom: 0 !important;
|
|
22
|
-
}
|
|
23
|
-
ul, ol {
|
|
24
|
-
margin-top: 0 !important;
|
|
25
|
-
margin-bottom: 0.25em !important;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/* Hover effect */
|
|
29
|
-
a:hover {
|
|
30
|
-
color: rgb(100, 100, 255); /* Change hover color */
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/* AgGrid custom CSS */
|
|
34
|
-
|
|
35
|
-
/* There's a one pixel border around the grid that we want to remove */
|
|
36
|
-
.ag-root-wrapper {
|
|
37
|
-
border: none !important; /* Force removal with !important */
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/* Box shadow and rounded corners for all AgGrid themes */
|
|
42
|
-
[class*="ag-theme-"] {
|
|
43
|
-
box-shadow: 2px 2px 6px 5px rgba(0, 0, 0, 0.25);
|
|
44
|
-
border-radius: 12px; /* Rounded corners */
|
|
45
|
-
border: 0.5px solid rgba(0, 0, 0, 0.5);
|
|
46
|
-
margin: 0;
|
|
47
|
-
padding: 0;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/* Apply styling to Workbench containers */
|
|
51
|
-
.workbench-container {
|
|
52
|
-
box-shadow: 2px 2px 6px 5px rgba(0, 0, 0, 0.2);
|
|
53
|
-
border-radius: 12px; /* Rounded corners */
|
|
54
|
-
background-color: rgb(104, 109, 195) /* Light Purple */
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/* Apply styling to custom tooltips */
|
|
58
|
-
.custom-tooltip {
|
|
59
|
-
box-shadow: 2px 2px 6px 5px rgba(0, 0, 0, 0.25);
|
|
60
|
-
border-radius: 25px; /* Rounded corners */
|
|
61
|
-
overflow: hidden; /* Ensure contents fit inside the rounded corners */
|
|
62
|
-
border: 1px solid rgba(40, 40, 40, 1); /* 1-pixel grey */
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/* Some of the HTML/Markdown will use color hints like 'green-text' or 'blue-text' */
|
|
66
|
-
.green-text {
|
|
67
|
-
color: rgb(140, 255, 140);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.blue-text {
|
|
71
|
-
color: rgb(170, 170, 255);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.pink-text {
|
|
75
|
-
color: rgb(240, 140, 240);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.red-text {
|
|
79
|
-
color: rgb(255, 140, 140);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.orange-text {
|
|
83
|
-
color: rgb(255, 195, 140);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.alert {
|
|
87
|
-
color: rgb(200, 60, 100);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.warning {
|
|
91
|
-
color: rgb(200, 140, 90);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
.good {
|
|
95
|
-
color: rgb(40, 100, 40);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/* Table styling */
|
|
100
|
-
table {
|
|
101
|
-
width: 100%;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
th {
|
|
105
|
-
padding: 10px;
|
|
106
|
-
border: 1px solid #444;
|
|
107
|
-
background-color: rgb(40, 40, 40);
|
|
108
|
-
color: rgb(160, 120, 240);
|
|
109
|
-
font-weight: bold;
|
|
110
|
-
text-align: center !important;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
td {
|
|
114
|
-
padding: 5px;
|
|
115
|
-
border: 0.5px solid #444;
|
|
116
|
-
text-align: center !important;
|
|
117
|
-
}
|