Fixed Glacier Experiments not Viewed in Counterfactuals template. Enhanced home template
This commit is contained in:
parent
c215cc38b5
commit
8a845bf156
base
handlers
__init__.py
__pycache__
__init__.cpython-310.pycajaxChartsHandler.cpython-310.pycajaxCounterfactualsHandler.cpython-310.pycajaxHomeHandler.cpython-310.pycajaxTrainHandler.cpython-310.pyc
ajaxChartsHandler.pyajaxCounterfactualsHandler.pyajaxHomeHandler.pyajaxTrainHandler.pystatic
css
img
digital_features.pngsu_logo.pngundraw_posting_photo.svgundraw_profile.svgundraw_profile_1.svgundraw_profile_2.svgundraw_profile_3.svgundraw_rocket.svg
js
templates/base
views.py
4
base/handlers/__init__.py
Normal file
4
base/handlers/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
from .ajaxHomeHandler import handler as home_handler
|
||||
from .ajaxCounterfactualsHandler import handler as counterfactuals_handler
|
||||
from .ajaxChartsHandler import handler as charts_handler
|
||||
from .ajaxTrainHandler import handler as train_handler
|
BIN
base/handlers/__pycache__/__init__.cpython-310.pyc
Normal file
BIN
base/handlers/__pycache__/__init__.cpython-310.pyc
Normal file
Binary file not shown.
BIN
base/handlers/__pycache__/ajaxChartsHandler.cpython-310.pyc
Normal file
BIN
base/handlers/__pycache__/ajaxChartsHandler.cpython-310.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
base/handlers/__pycache__/ajaxHomeHandler.cpython-310.pyc
Normal file
BIN
base/handlers/__pycache__/ajaxHomeHandler.cpython-310.pyc
Normal file
Binary file not shown.
BIN
base/handlers/__pycache__/ajaxTrainHandler.cpython-310.pyc
Normal file
BIN
base/handlers/__pycache__/ajaxTrainHandler.cpython-310.pyc
Normal file
Binary file not shown.
219
base/handlers/ajaxChartsHandler.py
Normal file
219
base/handlers/ajaxChartsHandler.py
Normal file
@ -0,0 +1,219 @@
|
||||
import base.pipeline as pipeline
|
||||
import os
|
||||
import pandas as pd
|
||||
import joblib
|
||||
from dict_and_html import *
|
||||
from .. import methods
|
||||
from ..methods import PIPELINE_PATH
|
||||
import base.pipeline as pipeline
|
||||
import json
|
||||
from django.shortcuts import HttpResponse
|
||||
|
||||
def handler(action, request):
|
||||
status = 200
|
||||
if action == "pre_trained":
|
||||
# load pre trained models
|
||||
pre_trained_model_name = request.POST.get("pre_trained")
|
||||
request.session["model_name"] = pre_trained_model_name
|
||||
# dataframe name
|
||||
df_name = request.session.get("df_name")
|
||||
|
||||
if df_name == "upload":
|
||||
df_name = request.session.get("df_name_upload_base_name")
|
||||
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + pre_trained_model_name
|
||||
)
|
||||
|
||||
model_name_dir_path = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
|
||||
# get the type of the file
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
datasets_types_pipeline = pipeline.PipelineJSON(
|
||||
datasets_types_PipelineJSON_path
|
||||
)
|
||||
dataset_type = datasets_types_pipeline.read_from_json([df_name])
|
||||
|
||||
if type(dataset_type) is list:
|
||||
dataset_type = dataset_type[0]
|
||||
|
||||
if "url" in request.POST:
|
||||
url = request.POST.get("url")
|
||||
|
||||
if url == "counterfactuals":
|
||||
# only TSNE
|
||||
tsne = joblib.load(model_name_path + "/tsne.sav")
|
||||
|
||||
# Assuming you already have your fig object created, you can update it like this:
|
||||
# Improved and modern t-SNE visualization
|
||||
tsne.update_layout(
|
||||
# Modern Legend Design
|
||||
legend=dict(
|
||||
x=0.9,
|
||||
y=0.95,
|
||||
xanchor="right",
|
||||
yanchor="top",
|
||||
bgcolor="rgba(255,255,255,0.8)", # Light semi-transparent white background
|
||||
bordercolor="rgba(0,0,0,0.1)", # Light border for contrast
|
||||
borderwidth=1,
|
||||
font=dict(size=12, color="#444"), # Subtle grey for legend text
|
||||
),
|
||||
# Tight Margins to Focus on the Plot
|
||||
margin=dict(
|
||||
l=10, r=10, t=30, b=10
|
||||
), # Very slim margins for a modern look
|
||||
# Axis Design: Minimalist and Clean
|
||||
xaxis=dict(
|
||||
title_text="", # No axis labels for a clean design
|
||||
tickfont=dict(
|
||||
size=10, color="#aaa"
|
||||
), # Light grey for tick labels
|
||||
showline=True,
|
||||
linecolor="rgba(0,0,0,0.2)", # Subtle line color for axis lines
|
||||
zeroline=False, # No zero line for a sleek look
|
||||
showgrid=False, # Hide grid lines for a minimal appearance
|
||||
ticks="outside", # Small ticks outside the axis
|
||||
ticklen=3, # Short tick marks for subtlety
|
||||
),
|
||||
yaxis=dict(
|
||||
title_text="", # No axis labels
|
||||
tickfont=dict(size=10, color="#aaa"),
|
||||
showline=True,
|
||||
linecolor="rgba(0,0,0,0.2)",
|
||||
zeroline=False,
|
||||
showgrid=False,
|
||||
ticks="outside",
|
||||
ticklen=3,
|
||||
),
|
||||
# Sleek Background
|
||||
plot_bgcolor="#fafafa", # Very light grey background for a smooth finish
|
||||
paper_bgcolor="#ffffff", # Pure white paper background
|
||||
# Modern Title with Elegant Style
|
||||
title=dict(
|
||||
text="t-SNE Visualization of Data",
|
||||
font=dict(
|
||||
size=16, color="#222", family="Helvetica, Arial, sans-serif"
|
||||
), # Classy font style
|
||||
x=0.5,
|
||||
xanchor="center",
|
||||
yanchor="top",
|
||||
pad=dict(t=15), # Padding to separate the title from the plot
|
||||
),
|
||||
)
|
||||
|
||||
# Add hover effects for a smooth user experience
|
||||
tsne.update_traces(
|
||||
hoverinfo="text+name",
|
||||
hoverlabel=dict(bgcolor="white", font_size=12, font_family="Arial"),
|
||||
)
|
||||
|
||||
context = {
|
||||
"tsne": tsne.to_html(),
|
||||
}
|
||||
else:
|
||||
# load plots
|
||||
pca = joblib.load(model_name_path + "/pca.sav")
|
||||
classification_report = joblib.load(
|
||||
model_name_path + "/classification_report.sav"
|
||||
)
|
||||
# tsne = joblib.load(model_name_path + "/tsne.sav")
|
||||
|
||||
# pipeline path
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{df_name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
|
||||
# load pipeline data
|
||||
# jsonFile = open(json_path, "r")
|
||||
# pipeline_data = json.load(jsonFile) # data becomes a dictionary
|
||||
# classifier_data = pipeline_data["classifier"][pre_trained_model_name]
|
||||
|
||||
classifier_data = jsonFile.read_from_json(
|
||||
["classifier", pre_trained_model_name]
|
||||
)
|
||||
classifier_data_flattened = methods.flatten_dict(classifier_data)
|
||||
classifier_data_df = pd.DataFrame([classifier_data_flattened])
|
||||
|
||||
if dataset_type == "tabular":
|
||||
feature_importance = joblib.load(
|
||||
model_name_path + "/feature_importance.sav"
|
||||
)
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"pca": pca.to_html(),
|
||||
"class_report": classification_report.to_html(),
|
||||
"feature_importance": feature_importance.to_html(),
|
||||
"classifier_data": classifier_data_df.to_html(),
|
||||
}
|
||||
elif dataset_type == "timeseries":
|
||||
tsne = joblib.load(model_name_path + "/tsne.sav")
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"pca": pca.to_html(),
|
||||
"class_report": classification_report.to_html(),
|
||||
"tsne": tsne.to_html(),
|
||||
"classifier_data": classifier_data_df.to_html(),
|
||||
}
|
||||
elif action == "delete_pre_trained":
|
||||
|
||||
df_name = request.session["df_name"]
|
||||
model_name = request.POST.get("model_name")
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + model_name
|
||||
)
|
||||
|
||||
print(model_name_path)
|
||||
|
||||
excel_file_name_preprocessed_path = os.path.join(
|
||||
PIPELINE_PATH,
|
||||
f"{df_name}" + "/" + df_name + "_preprocessed" + ".csv",
|
||||
)
|
||||
try:
|
||||
# Check if the file exists
|
||||
if os.path.exists(excel_file_name_preprocessed_path):
|
||||
# Delete the file
|
||||
os.remove(excel_file_name_preprocessed_path)
|
||||
# print(f"File '{excel_file_name_preprocessed_path}' has been deleted successfully.")
|
||||
else:
|
||||
print(f"File '{excel_file_name_preprocessed_path}' does not exist.")
|
||||
except Exception as e:
|
||||
print(f"An error occurred while deleting the file: {e}")
|
||||
|
||||
json_path = os.path.join(PIPELINE_PATH + f"{df_name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
jsonFile.delete_key(["classifier", model_name])
|
||||
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
# load paths
|
||||
# absolute excel_file_preprocessed_path
|
||||
|
||||
if not jsonFile.key_exists("classifier"):
|
||||
# pre trained models do not exist
|
||||
# check if dataset directory exists
|
||||
df_dir = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
if not os.path.exists(df_dir):
|
||||
df_name = None
|
||||
|
||||
context = {
|
||||
"df_name": df_name,
|
||||
"available_pretrained_models_info": [],
|
||||
}
|
||||
else:
|
||||
# if it exists
|
||||
# check the section of "classifiers"
|
||||
# folder path
|
||||
available_pretrained_models = jsonFile.read_from_json(
|
||||
["classifier"]
|
||||
).keys()
|
||||
|
||||
available_pretrained_models_info = (
|
||||
methods.create_tuple_of_models_text_value(
|
||||
available_pretrained_models
|
||||
)
|
||||
)
|
||||
context = {
|
||||
"df_name": df_name,
|
||||
"available_pretrained_models_info": available_pretrained_models_info,
|
||||
}
|
||||
return HttpResponse(json.dumps(context), status=status)
|
768
base/handlers/ajaxCounterfactualsHandler.py
Normal file
768
base/handlers/ajaxCounterfactualsHandler.py
Normal file
@ -0,0 +1,768 @@
|
||||
import base.pipeline as pipeline
|
||||
import pickle, os
|
||||
import pandas as pd
|
||||
import json
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
import joblib
|
||||
from dict_and_html import *
|
||||
from .. import methods
|
||||
from ..methods import PIPELINE_PATH
|
||||
import math
|
||||
import numpy as np
|
||||
from .. glacier.src.glacier_compute_counterfactuals import gc_compute_counterfactuals
|
||||
import base.pipeline as pipeline
|
||||
import concurrent.futures
|
||||
import json
|
||||
from django.shortcuts import HttpResponse
|
||||
|
||||
def handler(action, request):
|
||||
status = 200
|
||||
if action == "reset_graph":
|
||||
model_name = request.session.get("model_name")
|
||||
# dataframe name
|
||||
excel_file_name = request.session.get("df_name")
|
||||
# save the plots for future use
|
||||
# folder path: pipelines/<dataset name>/trained_models/<model_name>/
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{excel_file_name}" + "/trained_models/" + model_name
|
||||
)
|
||||
|
||||
model_name_dir_path = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
|
||||
tsne = joblib.load(model_name_dir_path + "/tsne.sav")
|
||||
context = {"fig": tsne.to_html()}
|
||||
elif action == "pre_trained":
|
||||
# load pre trained models
|
||||
pre_trained_model_name = request.POST.get("pre_trained")
|
||||
request.session["model_name"] = pre_trained_model_name
|
||||
# dataframe name
|
||||
df_name = request.session.get("df_name")
|
||||
|
||||
if df_name == "upload":
|
||||
df_name = request.session.get("df_name_upload_base_name")
|
||||
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + pre_trained_model_name
|
||||
)
|
||||
|
||||
model_name_dir_path = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
|
||||
# get the type of the file
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
datasets_types_pipeline = pipeline.PipelineJSON(
|
||||
datasets_types_PipelineJSON_path
|
||||
)
|
||||
dataset_type = datasets_types_pipeline.read_from_json([df_name])
|
||||
|
||||
if type(dataset_type) is list:
|
||||
dataset_type = dataset_type[0]
|
||||
|
||||
if "url" in request.POST:
|
||||
url = request.POST.get("url")
|
||||
|
||||
if url == "counterfactuals":
|
||||
# only TSNE
|
||||
tsne = joblib.load(model_name_path + "/tsne.sav")
|
||||
|
||||
# Assuming you already have your fig object created, you can update it like this:
|
||||
# Improved and modern t-SNE visualization
|
||||
tsne.update_layout(
|
||||
# Modern Legend Design
|
||||
legend=dict(
|
||||
x=0.9,
|
||||
y=0.95,
|
||||
xanchor="right",
|
||||
yanchor="top",
|
||||
bgcolor="rgba(255,255,255,0.8)", # Light semi-transparent white background
|
||||
bordercolor="rgba(0,0,0,0.1)", # Light border for contrast
|
||||
borderwidth=1,
|
||||
font=dict(size=12, color="#444"), # Subtle grey for legend text
|
||||
),
|
||||
# Tight Margins to Focus on the Plot
|
||||
margin=dict(
|
||||
l=10, r=10, t=30, b=10
|
||||
), # Very slim margins for a modern look
|
||||
# Axis Design: Minimalist and Clean
|
||||
xaxis=dict(
|
||||
title_text="", # No axis labels for a clean design
|
||||
tickfont=dict(
|
||||
size=10, color="#aaa"
|
||||
), # Light grey for tick labels
|
||||
showline=True,
|
||||
linecolor="rgba(0,0,0,0.2)", # Subtle line color for axis lines
|
||||
zeroline=False, # No zero line for a sleek look
|
||||
showgrid=False, # Hide grid lines for a minimal appearance
|
||||
ticks="outside", # Small ticks outside the axis
|
||||
ticklen=3, # Short tick marks for subtlety
|
||||
),
|
||||
yaxis=dict(
|
||||
title_text="", # No axis labels
|
||||
tickfont=dict(size=10, color="#aaa"),
|
||||
showline=True,
|
||||
linecolor="rgba(0,0,0,0.2)",
|
||||
zeroline=False,
|
||||
showgrid=False,
|
||||
ticks="outside",
|
||||
ticklen=3,
|
||||
),
|
||||
# Sleek Background
|
||||
plot_bgcolor="#fafafa", # Very light grey background for a smooth finish
|
||||
paper_bgcolor="#ffffff", # Pure white paper background
|
||||
# Modern Title with Elegant Style
|
||||
title=dict(
|
||||
text="t-SNE Visualization of Data",
|
||||
font=dict(
|
||||
size=16, color="#222", family="Helvetica, Arial, sans-serif"
|
||||
), # Classy font style
|
||||
x=0.5,
|
||||
xanchor="center",
|
||||
yanchor="top",
|
||||
pad=dict(t=15), # Padding to separate the title from the plot
|
||||
),
|
||||
)
|
||||
|
||||
# Add hover effects for a smooth user experience
|
||||
tsne.update_traces(
|
||||
hoverinfo="text+name",
|
||||
hoverlabel=dict(bgcolor="white", font_size=12, font_family="Arial"),
|
||||
)
|
||||
|
||||
context = {
|
||||
"tsne": tsne.to_html(),
|
||||
}
|
||||
else:
|
||||
# load plots
|
||||
pca = joblib.load(model_name_path + "/pca.sav")
|
||||
classification_report = joblib.load(
|
||||
model_name_path + "/classification_report.sav"
|
||||
)
|
||||
# tsne = joblib.load(model_name_path + "/tsne.sav")
|
||||
|
||||
# pipeline path
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{df_name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
|
||||
# load pipeline data
|
||||
# jsonFile = open(json_path, "r")
|
||||
# pipeline_data = json.load(jsonFile) # data becomes a dictionary
|
||||
# classifier_data = pipeline_data["classifier"][pre_trained_model_name]
|
||||
|
||||
classifier_data = jsonFile.read_from_json(
|
||||
["classifier", pre_trained_model_name]
|
||||
)
|
||||
classifier_data_flattened = methods.flatten_dict(classifier_data)
|
||||
classifier_data_df = pd.DataFrame([classifier_data_flattened])
|
||||
|
||||
if dataset_type == "tabular":
|
||||
feature_importance = joblib.load(
|
||||
model_name_path + "/feature_importance.sav"
|
||||
)
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"pca": pca.to_html(),
|
||||
"class_report": classification_report.to_html(),
|
||||
"feature_importance": feature_importance.to_html(),
|
||||
"classifier_data": classifier_data_df.to_html(),
|
||||
}
|
||||
elif dataset_type == "timeseries":
|
||||
tsne = joblib.load(model_name_path + "/tsne.sav")
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"pca": pca.to_html(),
|
||||
"class_report": classification_report.to_html(),
|
||||
"tsne": tsne.to_html(),
|
||||
"classifier_data": classifier_data_df.to_html(),
|
||||
}
|
||||
elif action == "click_graph":
|
||||
# get df used name
|
||||
df_name = request.session.get("df_name")
|
||||
if df_name == "upload":
|
||||
df_name = request.session.get("df_name_upload_base_name")
|
||||
# get model_name
|
||||
model_name = request.POST.get("model_name")
|
||||
|
||||
# preprocessed_path
|
||||
excel_file_name_preprocessed_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + "_preprocessed" + ".csv"
|
||||
)
|
||||
|
||||
excel_file_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + ".csv"
|
||||
)
|
||||
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + model_name
|
||||
)
|
||||
|
||||
# pipeline path
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{df_name}" + "/pipeline.json")
|
||||
|
||||
# load pipeline data
|
||||
# jsonFile = open(json_path, "r")
|
||||
# pipeline_data = PipelineJSON.load(jsonFile) # data becomes a dictionary
|
||||
# class_label = pipeline_data["classifier"][model_name]["class_label"]
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
class_label = jsonFile.read_from_json(
|
||||
["classifier", model_name, "class_label"]
|
||||
)
|
||||
|
||||
df = pd.read_csv(excel_file_name_path)
|
||||
|
||||
# Load your saved feature importance from a .sav file
|
||||
feature_importance_df = pd.read_csv(
|
||||
model_name_path + "/feature_importance_df.csv"
|
||||
)
|
||||
# sorted_df = feature_importance_df.sort_values(by="importance", ascending=False)
|
||||
|
||||
# x and y coordinates of the clicked point in tsne
|
||||
x_coord = request.POST["x"]
|
||||
y_coord = request.POST["y"]
|
||||
|
||||
# tsne_projections
|
||||
tsne_projections_path = os.path.join(
|
||||
PIPELINE_PATH
|
||||
+ f"{df_name}/"
|
||||
+ f"trained_models/{model_name}"
|
||||
+ "/tsne_projections.json",
|
||||
)
|
||||
|
||||
# tsne projections of all points (saved during generation of tsne)
|
||||
projections = pd.read_json(tsne_projections_path)
|
||||
projections = projections.values.tolist()
|
||||
|
||||
# projections array is a list of pairs with the (x, y)
|
||||
# [ [], [], [] ... ]
|
||||
# coordinates for a point in tsne. These are actual absolute
|
||||
# coordinates and not SVG.
|
||||
# find the pair of the projection with x and y coordinates matching that of
|
||||
# clicked point coordinates
|
||||
for clicked_id, item in enumerate(projections):
|
||||
if math.isclose(item[0], float(x_coord)) and math.isclose(
|
||||
item[1], float(y_coord)
|
||||
):
|
||||
break
|
||||
|
||||
# save clicked point projections
|
||||
request.session["clicked_point"] = item
|
||||
# get clicked point row
|
||||
row = df.iloc[[int(clicked_id)]]
|
||||
request.session["cfrow_id"] = clicked_id
|
||||
request.session["cfrow_og"] = row.to_html()
|
||||
context = {
|
||||
"row": row.to_html(index=False),
|
||||
"feature_importance_dict": feature_importance_df.to_dict(orient="records"),
|
||||
}
|
||||
elif action == "cf":
|
||||
# dataframe name
|
||||
df_name = request.session.get("df_name")
|
||||
if df_name == "upload":
|
||||
df_name = request.session.get("df_name_upload_base_name")
|
||||
|
||||
# preprocessed_path
|
||||
excel_file_name_preprocessed_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + "_preprocessed" + ".csv"
|
||||
)
|
||||
|
||||
excel_file_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + ".csv"
|
||||
)
|
||||
# which model is being used during that session
|
||||
model_name = request.POST.get("model_name")
|
||||
# path of used model
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}/" + "trained_models/" + f"{model_name}/"
|
||||
)
|
||||
model_name_dir_path = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
|
||||
# read preprocessed data
|
||||
if os.path.exists(excel_file_name_preprocessed_path):
|
||||
df = pd.read_csv(excel_file_name_preprocessed_path)
|
||||
else:
|
||||
df = pd.read_csv(excel_file_name_path)
|
||||
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
datasets_types_pipeline = pipeline.PipelineJSON(
|
||||
datasets_types_PipelineJSON_path
|
||||
)
|
||||
dataset_type = datasets_types_pipeline.read_from_json([df_name])
|
||||
|
||||
if type(dataset_type) is list:
|
||||
dataset_type = dataset_type[0]
|
||||
|
||||
df_id = request.session.get("cfrow_id")
|
||||
if dataset_type == "tabular":
|
||||
|
||||
# get row
|
||||
features_to_vary = json.loads(request.POST.get("features_to_vary"))
|
||||
|
||||
row = df.iloc[[int(df_id)]]
|
||||
|
||||
# not preprocessed
|
||||
notpre_df = pd.read_csv(excel_file_name_path)
|
||||
notpre_row = notpre_df.iloc[[int(df_id)]]
|
||||
|
||||
# if feature_to_vary has a categorical column then I cannot just
|
||||
# pass that to dice since the trained model does not contain the
|
||||
# categorical column but the one-hot-encoded sub-columns
|
||||
features_to_vary = methods.update_column_list_with_one_hot_columns(
|
||||
notpre_df, df, features_to_vary
|
||||
)
|
||||
|
||||
# pipeline path
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{df_name}" + "/pipeline.json")
|
||||
|
||||
# load pipeline data
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
class_label = jsonFile.read_from_json(
|
||||
["classifier", model_name, "class_label"]
|
||||
) # data becomes a dictionary
|
||||
|
||||
# number of counterfactuals
|
||||
# (TBD) input field value as parameter
|
||||
# in ajax
|
||||
num_counterfactuals = 5
|
||||
le = LabelEncoder()
|
||||
notpre_df[class_label] = le.fit_transform(notpre_df[class_label])
|
||||
|
||||
continuous_features = methods.get_continuous_features(df)
|
||||
non_continuous_features = methods.get_non_continuous_features(df)
|
||||
|
||||
# load used classifier
|
||||
clf = joblib.load(model_name_path + model_name + ".sav")
|
||||
|
||||
try:
|
||||
# Set up the executor to run the function in a separate thread
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
# Submit the function to the executor
|
||||
future = executor.submit(
|
||||
methods.counterfactuals,
|
||||
row,
|
||||
clf,
|
||||
df,
|
||||
class_label,
|
||||
continuous_features,
|
||||
num_counterfactuals,
|
||||
features_to_vary,
|
||||
)
|
||||
# Wait for the result with a timeout of 10 seconds
|
||||
counterfactuals = future.result(timeout=10)
|
||||
print("Counterfactuals computed successfully!")
|
||||
except concurrent.futures.TimeoutError:
|
||||
message = (
|
||||
"It seems like it took more than expected. Refresh and try again..."
|
||||
)
|
||||
context = {"message": message}
|
||||
|
||||
if counterfactuals:
|
||||
cf_df = counterfactuals[0].final_cfs_df
|
||||
counterfactuals[0].final_cfs_df.to_csv(
|
||||
model_name_path + "counterfactuals.csv", index=False
|
||||
)
|
||||
|
||||
# get coordinates of the clicked point (saved during 'click' event)
|
||||
clicked_point = request.session.get("clicked_point")
|
||||
clicked_point_df = pd.DataFrame(
|
||||
{
|
||||
"0": clicked_point[0],
|
||||
"1": clicked_point[1],
|
||||
f"{class_label}": row[class_label].astype(str),
|
||||
}
|
||||
)
|
||||
|
||||
# tSNE
|
||||
cf_df = pd.read_csv(model_name_path + "counterfactuals.csv")
|
||||
model_name_dir_path = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
tsne_path_to_augment = model_name_path + "tsne.sav"
|
||||
|
||||
tsne = methods.generateAugmentedTSNE(
|
||||
df,
|
||||
cf_df,
|
||||
num_counterfactuals,
|
||||
clicked_point_df,
|
||||
tsne_path_to_augment,
|
||||
class_label,
|
||||
)
|
||||
|
||||
tsne.update_layout(
|
||||
# Modern Legend Design
|
||||
legend=dict(
|
||||
x=0.85,
|
||||
y=0.95,
|
||||
xanchor="right",
|
||||
yanchor="top",
|
||||
bgcolor="rgba(0,0,0,0.05)", # Transparent black background for a sleek look
|
||||
bordercolor="rgba(0,0,0,0.1)", # Soft border for separation
|
||||
borderwidth=1,
|
||||
font=dict(
|
||||
size=12, color="#333"
|
||||
), # Modern grey font color for text
|
||||
),
|
||||
# Tight Margins for a Focused Plot Area
|
||||
margin=dict(
|
||||
l=20, r=20, t=40, b=40
|
||||
), # Reduced margins for a cleaner look
|
||||
# Axis Titles and Labels: Minimalist Design
|
||||
xaxis=dict(
|
||||
title_font=dict(
|
||||
size=14, color="#555"
|
||||
), # Medium grey color for axis title
|
||||
tickfont=dict(
|
||||
size=11, color="#777"
|
||||
), # Light grey color for tick labels
|
||||
showline=True,
|
||||
linecolor="rgba(0,0,0,0.15)", # Subtle line color for axis lines
|
||||
zeroline=False, # Hide the zero line for a cleaner design
|
||||
showgrid=False, # No grid lines for a modern look
|
||||
),
|
||||
yaxis=dict(
|
||||
title_font=dict(size=14, color="#555"),
|
||||
tickfont=dict(size=11, color="#777"),
|
||||
showline=True,
|
||||
linecolor="rgba(0,0,0,0.15)",
|
||||
zeroline=False,
|
||||
showgrid=False,
|
||||
),
|
||||
# Sleek Background Design
|
||||
plot_bgcolor="white", # Crisp white background for a modern touch
|
||||
paper_bgcolor="white", # Ensure the entire background is uniform
|
||||
# Title: Modern Font and Centered
|
||||
title=dict(
|
||||
text="t-SNE Visualization of Data",
|
||||
font=dict(
|
||||
size=18, color="#333", family="Arial, sans-serif"
|
||||
), # Modern font style
|
||||
x=0.5,
|
||||
xanchor="center",
|
||||
yanchor="top",
|
||||
pad=dict(t=10), # Padding to give the title breathing space
|
||||
),
|
||||
)
|
||||
|
||||
pickle.dump(tsne, open(model_name_path + "tsne_cfs.sav", "wb"))
|
||||
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"model_name": model_name,
|
||||
"tsne": tsne.to_html(),
|
||||
"num_counterfactuals": num_counterfactuals,
|
||||
"default_counterfactual": "1",
|
||||
"clicked_point": notpre_row.to_html(),
|
||||
"counterfactual": cf_df.iloc[[1]].to_html(),
|
||||
}
|
||||
|
||||
else:
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"model_name": model_name,
|
||||
"message": "Please try again with different features.",
|
||||
}
|
||||
elif dataset_type == "timeseries":
|
||||
model_name = request.POST["model_name"]
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}/" + "trained_models/" + f"{model_name}/"
|
||||
)
|
||||
path = model_name_path
|
||||
if model_name == "glacier":
|
||||
constraint = request.POST["constraint"]
|
||||
path = os.path.join(
|
||||
PIPELINE_PATH
|
||||
+ f"{df_name}/"
|
||||
+ "trained_models/"
|
||||
+ f"{model_name}/"
|
||||
+ f"{constraint}/"
|
||||
)
|
||||
|
||||
X_test_path = os.path.join(model_name_path + "X_test.csv")
|
||||
y_test_path = os.path.join(model_name_path + "y_test.npy")
|
||||
y_pred_path = os.path.join(path + "y_pred.npy")
|
||||
X_cf_path = os.path.join(path + "X_cf.npy")
|
||||
cf_pred_path = os.path.join(path + "cf_pred.npy")
|
||||
|
||||
X_test = pd.read_csv(X_test_path)
|
||||
y_test = np.load(y_test_path)
|
||||
y_pred = np.load(y_pred_path)
|
||||
X_cf = np.load(X_cf_path)
|
||||
cf_pred = np.load(cf_pred_path)
|
||||
|
||||
if model_name != "glacier":
|
||||
scaler = joblib.load(model_name_path + "/min_max_scaler.sav")
|
||||
X_test = pd.DataFrame(scaler.inverse_transform(X_test))
|
||||
X_cf = scaler.inverse_transform(X_cf)
|
||||
|
||||
fig = methods.ecg_plot_counterfactuals(
|
||||
int(df_id), X_test, y_test, y_pred, X_cf, cf_pred
|
||||
)
|
||||
|
||||
context = {
|
||||
"df_name": df_name,
|
||||
"fig": fig.to_html(),
|
||||
"dataset_type": dataset_type,
|
||||
}
|
||||
elif action == "compute_cf":
|
||||
model_name = request.POST.get("model_name")
|
||||
if model_name == "glacier":
|
||||
constraint_type = request.POST.get("constraint")
|
||||
w_value = request.POST.get("w_value")
|
||||
df_name = request.session.get("df_name")
|
||||
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}/" + "trained_models/" + f"{model_name}/"
|
||||
)
|
||||
model_name_path_constraint = model_name_path + f"{constraint_type}/"
|
||||
if not os.path.exists(model_name_path_constraint):
|
||||
os.makedirs(model_name_path_constraint)
|
||||
|
||||
# https://github.com/wildboar-foundation/wildboar/blob/master/docs/guide/explain/counterfactuals.rst#id27
|
||||
classifier = joblib.load(model_name_path + "/classifier.sav")
|
||||
|
||||
# pipeline path
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{df_name}" + "/pipeline.json")
|
||||
# load pipeline data
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
autoencoder = jsonFile.read_from_json(
|
||||
["classifier", model_name, "autoencoder"]
|
||||
)
|
||||
|
||||
experiment_dict = {"constraint": constraint_type, "w_value": w_value}
|
||||
|
||||
# if "experiments" in pipeline_data["classifier"][model_name]:
|
||||
# # if there exists key with value "experiments"
|
||||
# keys = pipeline_data["classifier"][model_name]["experiments"].keys()
|
||||
# last_key_int = int(list(keys)[-1])
|
||||
# last_key_int_incr_str = str(last_key_int + 1)
|
||||
# else:
|
||||
# last_key_int_incr_str = "0"
|
||||
# experiment_key_dict = {"experiments": {last_key_int_incr_str: {}}}
|
||||
# pipeline_data["classifier"][model_name].update(experiment_key_dict)
|
||||
|
||||
# outter_dict = {last_key_int_incr_str: experiment_dict}
|
||||
# pipeline_data["classifier"][model_name]["experiments"].update(outter_dict)
|
||||
|
||||
if jsonFile.key_exists("experiments"):
|
||||
keys = jsonFile.read_from_json(
|
||||
["classifier", model_name, "experiments"]
|
||||
).keys()
|
||||
last_key_int = int(list(keys)[-1])
|
||||
last_key_int_incr_str = str(last_key_int + 1)
|
||||
else:
|
||||
last_key_int_incr_str = "0"
|
||||
experiment_key_dict = {"experiments": {last_key_int_incr_str: {}}}
|
||||
jsonFile.update_json(
|
||||
["classifier", model_name], experiment_key_dict
|
||||
)
|
||||
|
||||
outter_dict = {last_key_int_incr_str: experiment_dict}
|
||||
jsonFile.update_json(
|
||||
["classifier", model_name, "experiments"], outter_dict
|
||||
)
|
||||
|
||||
if autoencoder == "Yes":
|
||||
autoencoder = joblib.load(model_name_path + "/autoencoder.sav")
|
||||
else:
|
||||
autoencoder = None
|
||||
|
||||
gc_compute_counterfactuals(
|
||||
model_name_path,
|
||||
model_name_path_constraint,
|
||||
constraint_type,
|
||||
[0.0001],
|
||||
float(w_value),
|
||||
0.5,
|
||||
classifier,
|
||||
autoencoder,
|
||||
)
|
||||
path = model_name_path_constraint
|
||||
context = {"experiment_dict": experiment_dict}
|
||||
elif action == "counterfactual_select":
|
||||
|
||||
# if <select> element is used, and a specific counterfactual
|
||||
# is inquired to be demonstrated:
|
||||
df_name = request.session.get("df_name")
|
||||
df_name = request.session.get("df_name")
|
||||
if df_name == "upload":
|
||||
df_name = request.session.get("df_name_upload_base_name")
|
||||
|
||||
model_name = request.session.get("model_name")
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + model_name
|
||||
)
|
||||
|
||||
excel_file_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + ".csv"
|
||||
)
|
||||
|
||||
# pipeline path
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{df_name}" + "/pipeline.json")
|
||||
# load pipeline data
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
|
||||
class_label = jsonFile.read_from_json(
|
||||
["classifier", model_name, "class_label"]
|
||||
)
|
||||
|
||||
# decode counterfactual to original values
|
||||
preprocessing_list = jsonFile.read_from_json(
|
||||
["classifier", model_name, "preprocessing"]
|
||||
)
|
||||
|
||||
df = pd.read_csv(excel_file_name_path)
|
||||
cf_df = pd.read_csv(model_name_path + "/counterfactuals.csv")
|
||||
cf_id = request.POST["cf_id"]
|
||||
row = cf_df.iloc[[int(cf_id)]]
|
||||
|
||||
if "id" in df.columns:
|
||||
df = df.drop("id", axis=1)
|
||||
|
||||
dec_row = methods.decode_cf(
|
||||
df, row, class_label, model_name_path, preprocessing_list
|
||||
)
|
||||
|
||||
fig = joblib.load(model_name_path + "/tsne_cfs.sav")
|
||||
|
||||
# tsne stores data for each class in different data[]
|
||||
# index.
|
||||
# data[0] is class A
|
||||
# data[1] is class B
|
||||
# ...
|
||||
# data[n-2] is counterfactuals
|
||||
# data[n-1] is clicked point
|
||||
|
||||
fig_data_array_length = len(fig.data)
|
||||
for i in range(fig_data_array_length - 2):
|
||||
fig.data[i].update(
|
||||
opacity=0.3,
|
||||
)
|
||||
|
||||
# last one, data[n-1], contains clicked point
|
||||
l = fig.data[fig_data_array_length - 1]
|
||||
clicked_id = -1
|
||||
for clicked_id, item in enumerate(list(zip(l.x, l.y))):
|
||||
if math.isclose(
|
||||
item[0], request.session.get("clicked_point")[0]
|
||||
) and math.isclose(item[1], request.session.get("clicked_point")[1]):
|
||||
break
|
||||
|
||||
# data[n-2] contains counterfactuals
|
||||
fig.data[fig_data_array_length - 2].update(
|
||||
selectedpoints=[int(cf_id)],
|
||||
unselected=dict(
|
||||
marker=dict(
|
||||
opacity=0.3,
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
fig.data[fig_data_array_length - 1].update(
|
||||
selectedpoints=[clicked_id],
|
||||
unselected=dict(
|
||||
marker=dict(
|
||||
opacity=0.3,
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
if "id" in df.columns:
|
||||
df = df.drop("id", axis=1)
|
||||
|
||||
# order the columns
|
||||
dec_row = dec_row[df.columns]
|
||||
clicked_point_row_id = request.session.get("cfrow_id")
|
||||
|
||||
# return only the differences
|
||||
dec_row = dec_row.reset_index(drop=True)
|
||||
df2 = df.iloc[[int(clicked_point_row_id)]].reset_index(drop=True)
|
||||
difference = dec_row.loc[
|
||||
:,
|
||||
[
|
||||
methods.compare_values(dec_row[col].iloc[0], df2[col].iloc[0])
|
||||
for col in dec_row.columns
|
||||
],
|
||||
]
|
||||
|
||||
merged_df = pd.concat([df2[difference.columns], difference], ignore_index=True)
|
||||
|
||||
context = {
|
||||
"row": merged_df.to_html(index=False),
|
||||
"fig": fig.to_html(),
|
||||
}
|
||||
elif action == "class_label_selection":
|
||||
|
||||
df_name = request.session.get("df_name")
|
||||
|
||||
if df_name == "upload":
|
||||
df_name = request.session["df_name_upload_base_name"]
|
||||
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
|
||||
dataset_type_json = pipeline.PipelineJSON(datasets_types_PipelineJSON_path)
|
||||
|
||||
dataset_type = dataset_type_json.read_from_json([df_name])
|
||||
|
||||
if isinstance(dataset_type, list):
|
||||
dataset_type = dataset_type[0]
|
||||
|
||||
# preprocessed_path
|
||||
excel_file_name_preprocessed_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + "_preprocessed" + ".csv"
|
||||
)
|
||||
|
||||
excel_file_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + ".csv"
|
||||
)
|
||||
|
||||
# which model is being used during that session
|
||||
model_name = request.POST.get("model_name")
|
||||
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + model_name
|
||||
)
|
||||
|
||||
X_test_path = os.path.join(
|
||||
PIPELINE_PATH
|
||||
+ f"{df_name}"
|
||||
+ "/trained_models"
|
||||
+ f"/{model_name}"
|
||||
+ "/X_test.csv"
|
||||
)
|
||||
y_test_path = os.path.join(
|
||||
PIPELINE_PATH
|
||||
+ f"{df_name}"
|
||||
+ "/trained_models"
|
||||
+ f"/{model_name}"
|
||||
+ "/y_test.npy"
|
||||
)
|
||||
|
||||
X_test = pd.read_csv(X_test_path)
|
||||
y_test = np.load(y_test_path)
|
||||
|
||||
if model_name != "glacier":
|
||||
scaler = joblib.load(model_name_path + "/min_max_scaler.sav")
|
||||
X_test = pd.DataFrame(scaler.inverse_transform(X_test))
|
||||
|
||||
if dataset_type == "timeseries":
|
||||
class_label = request.POST.get("class_label")
|
||||
cfrow_id = request.POST.get("cfrow_id")
|
||||
|
||||
class_label = (
|
||||
int(class_label)
|
||||
if class_label.isdigit()
|
||||
else (
|
||||
float(class_label)
|
||||
if class_label.replace(".", "", 1).isdigit()
|
||||
else class_label
|
||||
)
|
||||
)
|
||||
|
||||
fig, index = methods.get_ecg_entry(
|
||||
X_test, y_test, int(cfrow_id), class_label
|
||||
)
|
||||
request.session["cfrow_id"] = index
|
||||
request.session["class_label"] = class_label
|
||||
context = {"fig": fig.to_html(), "dataset_type": dataset_type}
|
||||
return HttpResponse(json.dumps(context), status=status)
|
437
base/handlers/ajaxHomeHandler.py
Normal file
437
base/handlers/ajaxHomeHandler.py
Normal file
@ -0,0 +1,437 @@
|
||||
import base.pipeline as pipeline
|
||||
import os
|
||||
from dict_and_html import *
|
||||
from .. import methods
|
||||
from ..methods import PIPELINE_PATH
|
||||
from django.core.files.storage import FileSystemStorage
|
||||
import random
|
||||
import base.pipeline as pipeline
|
||||
import shutil
|
||||
import json
|
||||
from django.shortcuts import HttpResponse
|
||||
|
||||
def handler(action, request):
|
||||
status = 200
|
||||
if action == "upload_dataset":
|
||||
|
||||
uploaded_file = request.FILES["excel_file"] # Get the file from request.FILES
|
||||
dataset_type = request.POST.get("dataset_type")
|
||||
|
||||
# action to add dataset when from radio button click
|
||||
# add name of used dataframe in session for future use
|
||||
request.session["df_name"] = "upload"
|
||||
name = uploaded_file.name
|
||||
|
||||
# Split the name and extension
|
||||
base_name, extension = os.path.splitext(name)
|
||||
request.session["df_name_upload_base_name"] = base_name
|
||||
request.session["df_name_upload_extension"] = extension
|
||||
|
||||
df_name = base_name
|
||||
|
||||
df_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{base_name}",
|
||||
)
|
||||
|
||||
if not os.path.exists(df_name_path):
|
||||
os.makedirs(df_name_path)
|
||||
|
||||
fs = FileSystemStorage() # FileSystemStorage to save the file
|
||||
|
||||
# Save the file with the new filename
|
||||
fs = FileSystemStorage(location=df_name_path)
|
||||
filename = fs.save(uploaded_file.name, uploaded_file) # Save file
|
||||
|
||||
request.session["excel_file_name"] = df_name_path
|
||||
|
||||
excel_file_name_path = os.path.join(PIPELINE_PATH + f"{base_name}" + "/" + name)
|
||||
|
||||
df = methods.get_dataframe(excel_file_name_path)
|
||||
|
||||
## update the datasets_types json file
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "dataset_types_pipeline.json"
|
||||
)
|
||||
jsonFile = pipeline.PipelineJSON(datasets_types_PipelineJSON_path)
|
||||
|
||||
# with open(datasets_types_PipelineJSON_path, "r") as jsonFile:
|
||||
# datasets_types_PipelineJSON = pipeline.load(
|
||||
# jsonFile
|
||||
# ) # data becomes a dictionary
|
||||
|
||||
jsonFile.append_to_json({df_name: [dataset_type, "uploaded"]})
|
||||
dataset_type = jsonFile.read_from_json([df_name])[0]
|
||||
uploaded_files = jsonFile.get_keys_with_value("uploaded")
|
||||
|
||||
# datasets_types_PipelineJSON[df_name] = dataset_type
|
||||
# with open(datasets_types_PipelineJSON_path, "w") as file:
|
||||
# pipeline.dump(
|
||||
# datasets_types_PipelineJSON, file, indent=4
|
||||
# ) # Write with pretty print (indent=4)
|
||||
|
||||
if df.columns.str.contains(" ").any():
|
||||
df.columns = df.columns.str.replace(" ", "_")
|
||||
# if columns contain space
|
||||
os.remove(excel_file_name_path)
|
||||
df.to_csv(excel_file_name_path, index=None)
|
||||
df = methods.get_dataframe(excel_file_name_path)
|
||||
|
||||
if "id" in df.columns:
|
||||
df.drop(["id"], axis=1, inplace=True)
|
||||
df.to_csv(excel_file_name_path, index=False)
|
||||
|
||||
# if dataset_type == "tabular":
|
||||
# # tabular datasets
|
||||
# features = df.columns
|
||||
# feature1 = df.columns[3]
|
||||
# feature2 = df.columns[2]
|
||||
|
||||
# labels = list(df.select_dtypes(include=["object", "category"]).columns)
|
||||
# # Find binary columns (columns with only two unique values, including numerics)
|
||||
# binary_columns = [col for col in df.columns if df[col].nunique() == 2]
|
||||
|
||||
# # Combine categorical and binary columns into one list
|
||||
# labels = list(set(labels + binary_columns))
|
||||
|
||||
# label = random.choice(labels)
|
||||
# fig = methods.stats(
|
||||
# excel_file_name_path,
|
||||
# dataset_type,
|
||||
# None,
|
||||
# None,
|
||||
# feature1,
|
||||
# feature2,
|
||||
# label,
|
||||
# df_name,
|
||||
# )
|
||||
|
||||
# # tabular dataset
|
||||
# request.session["data_to_display"] = df[:10].to_html()
|
||||
# request.session["features"] = list(features)
|
||||
# request.session["feature1"] = feature1
|
||||
# request.session["feature2"] = feature2
|
||||
# request.session["labels"] = list(labels)
|
||||
# request.session["curlabel"] = label
|
||||
# request.session["fig"] = fig
|
||||
|
||||
# context = {
|
||||
# "dataset_type": dataset_type,
|
||||
# "data_to_display": df[:10].to_html(),
|
||||
# "fig": fig,
|
||||
# "features": list(features), # error if not a list
|
||||
# "feature1": feature1,
|
||||
# "feature2": feature2,
|
||||
# "labels": list(labels),
|
||||
# "curlabel": label,
|
||||
# "df_name": request.session["df_name"],
|
||||
# }
|
||||
# elif dataset_type == "timeseries":
|
||||
# fig, fig1 = methods.stats(excel_file_name_path, dataset_type)
|
||||
# request.session["fig"] = fig
|
||||
# request.session["fig1"] = fig1
|
||||
# context = {
|
||||
# "dataset_type": dataset_type,
|
||||
# "df_name": df_name,
|
||||
# "fig": fig,
|
||||
# "fig1": fig1,
|
||||
# }
|
||||
|
||||
context = {"dataset_type": dataset_type, "df_name": df_name}
|
||||
context.update({"uploaded_files": uploaded_files})
|
||||
|
||||
if dataset_type == "timeseries":
|
||||
target_labels = list(df.iloc[:, -1].unique())
|
||||
context.update({"target_labels": target_labels})
|
||||
|
||||
request.session["context"] = context
|
||||
elif action == "delete_uploaded_file":
|
||||
dataset_name = request.POST.get("dataset_name")
|
||||
dataset_path = os.path.join(PIPELINE_PATH + f"/{dataset_name}")
|
||||
|
||||
# pipeline path
|
||||
datasets_types_pipeline_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
# load pipeline data
|
||||
datasets_types_pipeline = pipeline.PipelineJSON(datasets_types_pipeline_path)
|
||||
datasets_types_pipeline.delete_key([dataset_name])
|
||||
|
||||
request.FILES["excel_file"] = None
|
||||
request.session["df_name"] = None
|
||||
|
||||
# check if there exist uploaded files
|
||||
uploaded_files = datasets_types_pipeline.get_keys_with_value(
|
||||
"uploaded"
|
||||
)
|
||||
if uploaded_files == []:
|
||||
uploaded_files = None
|
||||
try:
|
||||
shutil.rmtree(dataset_path)
|
||||
except Exception as error:
|
||||
print(error)
|
||||
|
||||
context = {"uploaded_files": uploaded_files}
|
||||
elif action == "dataset" or action == "uploaded_datasets":
|
||||
|
||||
# action to add dataset when from radio button click
|
||||
name = request.POST.get("df_name")
|
||||
request.session["df_name"] = name
|
||||
|
||||
# if name == "upload":
|
||||
# name = request.session.get("df_name_upload_base_name")
|
||||
|
||||
if action == "dataset" and name == "upload":
|
||||
request.session["upload"] = 1
|
||||
context = {"upload": 1}
|
||||
else:
|
||||
|
||||
if name == "timeseries":
|
||||
name = request.session.get("df_name")
|
||||
|
||||
excel_file_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{name}" + "/" + name + ".csv",
|
||||
)
|
||||
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
datasets_types_PipelineJSON = pipeline.PipelineJSON(
|
||||
datasets_types_PipelineJSON_path
|
||||
)
|
||||
dataset_type = datasets_types_PipelineJSON.read_from_json([name])
|
||||
uploaded_files = datasets_types_PipelineJSON.get_keys_with_value(
|
||||
"uploaded"
|
||||
)
|
||||
|
||||
if request.POST.get("df_name") == "upload" or action == "uploaded_datasets":
|
||||
if type(dataset_type) is list:
|
||||
dataset_type = dataset_type[0]
|
||||
|
||||
if request.POST.get("df_name") != "upload" or action == "uploaded_datasets":
|
||||
if os.path.exists(excel_file_name_path):
|
||||
df = methods.get_dataframe(excel_file_name_path)
|
||||
df.columns = df.columns.str.replace(" ", "_")
|
||||
request.session["excel_file_name"] = excel_file_name_path
|
||||
|
||||
json_path = os.path.join(
|
||||
PIPELINE_PATH + f"{name}" + "/pipeline.json"
|
||||
)
|
||||
if not os.path.exists(json_path):
|
||||
PipelineJSON = pipeline.PipelineJSON(json_path)
|
||||
PipelineJSON.append_to_json({"name": name})
|
||||
|
||||
if "tabular" == dataset_type:
|
||||
|
||||
if "id" in df.columns:
|
||||
df.drop(["id"], axis=1, inplace=True)
|
||||
df.to_csv(excel_file_name_path, index=False)
|
||||
|
||||
# tabular datasets
|
||||
features = df.columns
|
||||
feature1 = df.columns[3]
|
||||
feature2 = df.columns[2]
|
||||
label = ""
|
||||
|
||||
labels = list(
|
||||
df.select_dtypes(include=["object", "category"]).columns
|
||||
)
|
||||
# Find binary columns (columns with only two unique values, including numerics)
|
||||
binary_columns = [
|
||||
col for col in df.columns if df[col].nunique() == 2
|
||||
]
|
||||
|
||||
# Combine categorical and binary columns into one list
|
||||
labels = list(set(labels + binary_columns))
|
||||
label = random.choice(labels)
|
||||
fig = methods.stats(
|
||||
excel_file_name_path,
|
||||
dataset_type,
|
||||
feature1=feature1,
|
||||
feature2=feature2,
|
||||
label=label,
|
||||
)
|
||||
|
||||
# tabular dataset
|
||||
request.session["data_to_display"] = df[:10].to_html()
|
||||
request.session["features"] = list(features)
|
||||
request.session["feature1"] = feature1
|
||||
request.session["feature2"] = feature2
|
||||
request.session["labels"] = list(labels)
|
||||
request.session["curlabel"] = label
|
||||
request.session["fig"] = fig
|
||||
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"data_to_display": df[:10].to_html(),
|
||||
"fig": fig,
|
||||
"features": list(features), # error if not a list
|
||||
"feature1": feature1,
|
||||
"feature2": feature2,
|
||||
"labels": list(labels),
|
||||
"curlabel": label,
|
||||
"uploaded_files": list(uploaded_files),
|
||||
}
|
||||
elif dataset_type == "timeseries":
|
||||
|
||||
json_path = os.path.join(
|
||||
PIPELINE_PATH, f"{name}" + "/pipeline.json"
|
||||
)
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
|
||||
pos = jsonFile.read_from_json(["pos"])
|
||||
neg = jsonFile.read_from_json(["neg"])
|
||||
|
||||
fig, fig1 = methods.stats(
|
||||
excel_file_name_path,
|
||||
dataset_type,
|
||||
int(pos),
|
||||
int(neg),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
name=name,
|
||||
)
|
||||
# timeseries
|
||||
request.session["fig"] = fig
|
||||
request.session["fig1"] = fig1
|
||||
context = {
|
||||
"fig": fig,
|
||||
"fig1": fig1,
|
||||
"dataset_type": dataset_type,
|
||||
}
|
||||
else:
|
||||
context = {"uploaded_files": list(uploaded_files)}
|
||||
else:
|
||||
context = {}
|
||||
|
||||
if (
|
||||
action == "uploaded_datasets"
|
||||
and "upload" in request.session
|
||||
and request.session["upload"] == 1
|
||||
):
|
||||
request.session["upload"] = 1
|
||||
context.update({"upload": 1, "df_name": name})
|
||||
print(name)
|
||||
else:
|
||||
request.session["upload"] = 0
|
||||
elif action == "dataset_charts":
|
||||
df_name = request.POST.get("df_name")
|
||||
request.session["df_name"] = df_name
|
||||
context = {}
|
||||
elif action == "select_class_labels_for_uploaded_timeseries":
|
||||
name = request.session["df_name"]
|
||||
|
||||
if name == "upload":
|
||||
name = request.session["df_name_upload_base_name"]
|
||||
|
||||
pos = request.POST.get("positive_label")
|
||||
neg = request.POST.get("negative_label")
|
||||
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
|
||||
jsonFile.append_to_json({"name": name})
|
||||
jsonFile.append_to_json({"pos": pos})
|
||||
jsonFile.append_to_json({"neg": neg})
|
||||
|
||||
context = {}
|
||||
elif action == "timeseries-dataset":
|
||||
|
||||
# action to add dataset when from radio button click
|
||||
name = request.POST.get("timeseries_dataset")
|
||||
|
||||
# add name of used dataframe in session for future use
|
||||
request.session["df_name"] = name
|
||||
excel_file_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{name}" + "/" + name + ".csv",
|
||||
)
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
datasets_types_PipelineJSON = pipeline.PipelineJSON(
|
||||
datasets_types_PipelineJSON_path
|
||||
)
|
||||
if os.path.exists(excel_file_name_path):
|
||||
|
||||
dataset_type = datasets_types_PipelineJSON.read_from_json([name])
|
||||
|
||||
df = methods.get_dataframe(excel_file_name_path)
|
||||
df.columns = df.columns.str.replace(" ", "_")
|
||||
request.session["excel_file_name"] = excel_file_name_path
|
||||
|
||||
# find the available pre trained datasets
|
||||
# check the pipeline file
|
||||
json_path = os.path.join(PIPELINE_PATH, f"{name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
|
||||
preprocessing_info = {"name": name}
|
||||
dataset_camel = methods.convert_to_camel_case(name)
|
||||
if "Ecg" in dataset_camel:
|
||||
dataset_camel = dataset_camel.replace("Ecg", "ECG")
|
||||
experiment = methods.fetch_line_by_dataset(
|
||||
PIPELINE_PATH + "/glacier_experiments.txt",
|
||||
dataset_camel,
|
||||
)
|
||||
if experiment is not None:
|
||||
stripped_arguments = methods.extract_arguments_from_line(experiment)
|
||||
|
||||
indices_to_keys = {
|
||||
1: "pos",
|
||||
2: "neg",
|
||||
}
|
||||
|
||||
# Create a dictionary by fetching items from the list at the specified indices
|
||||
inner_dict = {
|
||||
key: stripped_arguments[index] for index, key in indices_to_keys.items()
|
||||
}
|
||||
preprocessing_info.update(inner_dict)
|
||||
jsonFile.append_to_json(preprocessing_info)
|
||||
|
||||
pos = inner_dict["pos"]
|
||||
neg = inner_dict["neg"]
|
||||
fig, fig1 = methods.stats(
|
||||
excel_file_name_path, dataset_type, int(pos), int(neg), name=name
|
||||
)
|
||||
# timeseries
|
||||
request.session["fig"] = fig
|
||||
request.session["fig1"] = fig1
|
||||
context = {"fig": fig, "fig1": fig1, "dataset_type": dataset_type}
|
||||
else:
|
||||
context = {}
|
||||
elif action == "stat":
|
||||
|
||||
name = request.session.get("df_name")
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
jsonFile = pipeline.PipelineJSON(datasets_types_PipelineJSON_path)
|
||||
dataset_type = jsonFile.read_from_json([name])
|
||||
|
||||
if type(dataset_type) is list:
|
||||
dataset_type = dataset_type[0]
|
||||
|
||||
file_path = os.path.join(
|
||||
PIPELINE_PATH + f"{name}" + "/" + name + ".csv",
|
||||
)
|
||||
if dataset_type == "tabular":
|
||||
feature1 = request.POST.get("feature1")
|
||||
feature2 = request.POST.get("feature2")
|
||||
label = request.POST.get("label")
|
||||
else:
|
||||
feature1 = request.POST.get("feature1")
|
||||
feature2 = []
|
||||
label = []
|
||||
|
||||
fig = methods.stats(
|
||||
file_path,
|
||||
dataset_type,
|
||||
None,
|
||||
None,
|
||||
feature1=feature1,
|
||||
feature2=feature2,
|
||||
label=label,
|
||||
)
|
||||
context = {
|
||||
"fig": fig,
|
||||
}
|
||||
return HttpResponse(json.dumps(context), status=status)
|
464
base/handlers/ajaxTrainHandler.py
Normal file
464
base/handlers/ajaxTrainHandler.py
Normal file
@ -0,0 +1,464 @@
|
||||
import base.pipeline as pipeline
|
||||
import pickle, os
|
||||
import pandas as pd
|
||||
import json
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
from dict_and_html import *
|
||||
from .. import methods
|
||||
from ..methods import PIPELINE_PATH
|
||||
import numpy as np
|
||||
from collections import defaultdict
|
||||
import base.pipeline as pipeline
|
||||
import json
|
||||
from django.shortcuts import HttpResponse
|
||||
|
||||
def handler(action, request):
|
||||
status = 200
|
||||
if action == "train":
|
||||
# train a new model
|
||||
# parameters sent via ajax
|
||||
model_name = request.POST.get("model_name")
|
||||
df_name = request.session.get("df_name")
|
||||
|
||||
# dataframe name
|
||||
if df_name == "upload":
|
||||
df_name = request.session.get("df_name_upload_base_name")
|
||||
|
||||
request.session["model_name"] = model_name
|
||||
test_set_ratio = ""
|
||||
if "test_set_ratio" in request.POST:
|
||||
test_set_ratio = request.POST.get("test_set_ratio")
|
||||
|
||||
datasets_types_PipelineJSON_path = os.path.join(
|
||||
PIPELINE_PATH + "/dataset_types_pipeline.json"
|
||||
)
|
||||
jsonFile = pipeline.PipelineJSON(datasets_types_PipelineJSON_path)
|
||||
dataset_type = jsonFile.read_from_json([df_name])
|
||||
|
||||
if type(dataset_type) is list:
|
||||
dataset_type = dataset_type[0]
|
||||
|
||||
if "array_preprocessing" in request.POST:
|
||||
array_preprocessing = request.POST.get("array_preprocessing")
|
||||
|
||||
if dataset_type == "tabular":
|
||||
class_label = request.POST.get("class_label")
|
||||
preprocessing_info = {
|
||||
"preprocessing": array_preprocessing,
|
||||
"test_set_ratio": test_set_ratio,
|
||||
"explainability": {"technique": "dice"},
|
||||
"class_label": class_label,
|
||||
}
|
||||
elif dataset_type == "timeseries":
|
||||
if model_name != "glacier":
|
||||
preprocessing_info = {
|
||||
"preprocessing": array_preprocessing,
|
||||
"test_set_ratio": test_set_ratio,
|
||||
"explainability": {"technique": model_name},
|
||||
}
|
||||
else:
|
||||
# Path to the Bash script
|
||||
autoencoder = request.POST.get("autoencoder")
|
||||
preprocessing_info = {
|
||||
"autoencoder": autoencoder,
|
||||
"explainability": {"technique": model_name},
|
||||
}
|
||||
|
||||
# absolute excel_file_name_path
|
||||
excel_file_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/" + df_name + ".csv"
|
||||
)
|
||||
|
||||
# load paths
|
||||
# absolute excel_file_preprocessed_path
|
||||
excel_file_name_preprocessed_path = os.path.join(
|
||||
PIPELINE_PATH,
|
||||
f"{df_name}" + "/" + df_name + "_preprocessed" + ".csv",
|
||||
)
|
||||
|
||||
json_path = os.path.join(PIPELINE_PATH + f"{df_name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
# save the plots for future use
|
||||
# folder path: pipelines/<dataset name>/trained_models/<model_name>/
|
||||
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + model_name
|
||||
)
|
||||
|
||||
model_name_dir_path = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
|
||||
if os.path.exists(excel_file_name_preprocessed_path) == True:
|
||||
# if preprocessed_file exists
|
||||
# delete it and do preprocessing again
|
||||
# maybe should optimize it for cases
|
||||
# where the preprocessing is the same with
|
||||
# the one applited on the existing file
|
||||
os.remove(excel_file_name_preprocessed_path)
|
||||
|
||||
# generate filename
|
||||
idx = excel_file_name_path.index(".")
|
||||
excel_file_name_preprocessed = (
|
||||
df_name[:idx] + "_preprocessed" + excel_file_name_path[idx:]
|
||||
)
|
||||
|
||||
# save file for preprocessing
|
||||
preprocess_df = pd.read_csv(excel_file_name_path)
|
||||
request.session["excel_file_name_preprocessed"] = excel_file_name_preprocessed
|
||||
|
||||
# make the dir
|
||||
if not os.path.exists(model_name_path):
|
||||
os.makedirs(model_name_path)
|
||||
|
||||
try:
|
||||
if dataset_type == "tabular":
|
||||
le = LabelEncoder()
|
||||
preprocess_df[class_label] = le.fit_transform(
|
||||
preprocess_df[class_label]
|
||||
)
|
||||
|
||||
if "array_preprocessing" in request.POST:
|
||||
preprocess_df = methods.preprocess(
|
||||
preprocess_df,
|
||||
array_preprocessing,
|
||||
excel_file_name_path,
|
||||
dataset_type,
|
||||
model_name_path,
|
||||
class_label,
|
||||
)
|
||||
elif dataset_type == "timeseries":
|
||||
|
||||
pos = jsonFile.read_from_json(["pos"])
|
||||
neg = jsonFile.read_from_json(["neg"])
|
||||
pos_label, neg_label = 1, 0
|
||||
|
||||
if pos != pos_label:
|
||||
preprocess_df.iloc[:, -1] = preprocess_df.iloc[:, -1].apply(
|
||||
lambda x: pos_label if x == int(pos) else x
|
||||
)
|
||||
if neg != neg_label:
|
||||
preprocess_df.iloc[:, -1] = preprocess_df.iloc[:, -1].apply(
|
||||
lambda x: neg_label if x == int(neg) else x
|
||||
)
|
||||
if "array_preprocessing" in request.POST:
|
||||
preprocess_df = methods.preprocess(
|
||||
preprocess_df,
|
||||
array_preprocessing,
|
||||
excel_file_name_path,
|
||||
dataset_type,
|
||||
model_name_path,
|
||||
)
|
||||
|
||||
pca = methods.generatePCA(preprocess_df)
|
||||
|
||||
# TSNE
|
||||
if dataset_type == "tabular":
|
||||
tsne, projections = methods.generateTSNE(
|
||||
preprocess_df, dataset_type, class_label
|
||||
)
|
||||
else:
|
||||
tsne, projections = methods.generateTSNE(preprocess_df, dataset_type)
|
||||
|
||||
if dataset_type == "tabular":
|
||||
# training
|
||||
feature_importance, classification_report, importance_dict = (
|
||||
methods.training(
|
||||
preprocess_df,
|
||||
model_name,
|
||||
float(test_set_ratio),
|
||||
class_label,
|
||||
dataset_type,
|
||||
df_name,
|
||||
model_name_path,
|
||||
)
|
||||
)
|
||||
|
||||
# feature importance on the original categorical columns (if they exist)
|
||||
df = pd.read_csv(excel_file_name_path)
|
||||
df = df.drop(class_label, axis=1)
|
||||
|
||||
# Initialize a dictionary to hold aggregated feature importances
|
||||
categorical_columns = methods.get_categorical_features(df)
|
||||
|
||||
if categorical_columns != []:
|
||||
aggregated_importance = {}
|
||||
encoded_columns = methods.update_column_list_with_one_hot_columns(
|
||||
df, preprocess_df, df.columns
|
||||
)
|
||||
|
||||
feature_mapping = defaultdict(list)
|
||||
for col in encoded_columns:
|
||||
for original_col in categorical_columns:
|
||||
if col.startswith(original_col + "_"):
|
||||
feature_mapping[original_col].append(col)
|
||||
break
|
||||
else:
|
||||
feature_mapping[col].append(
|
||||
col
|
||||
) # If no match, map to itself
|
||||
|
||||
# Aggregate the feature importances
|
||||
for original_feature, encoded_columns in feature_mapping.items():
|
||||
if encoded_columns: # Check if encoded_columns is not empty
|
||||
if original_feature not in encoded_columns:
|
||||
aggregated_importance[original_feature] = np.sum(
|
||||
[
|
||||
importance_dict.get(col, 0)
|
||||
for col in encoded_columns
|
||||
]
|
||||
)
|
||||
else:
|
||||
aggregated_importance[original_feature] = (
|
||||
importance_dict.get(original_feature, 0)
|
||||
)
|
||||
|
||||
importance_df = pd.DataFrame(
|
||||
{
|
||||
"feature": list(aggregated_importance.keys()),
|
||||
"importance": list(aggregated_importance.values()),
|
||||
}
|
||||
)
|
||||
|
||||
importance_df.to_csv(
|
||||
model_name_path + "/feature_importance_df.csv", index=None
|
||||
)
|
||||
else:
|
||||
# if no categorical columns
|
||||
# Combine feature names with their respective importance values
|
||||
feature_importance_df = pd.DataFrame(
|
||||
{
|
||||
"feature": importance_dict.keys(),
|
||||
"importance": importance_dict.values(),
|
||||
}
|
||||
)
|
||||
|
||||
feature_importance_df.to_csv(
|
||||
model_name_path + "/feature_importance_df.csv", index=None
|
||||
)
|
||||
|
||||
# save some files
|
||||
pickle.dump(
|
||||
classification_report,
|
||||
open(model_name_path + "/classification_report.sav", "wb"),
|
||||
)
|
||||
pickle.dump(
|
||||
feature_importance,
|
||||
open(model_name_path + "/feature_importance.sav", "wb"),
|
||||
)
|
||||
pickle.dump(le, open(model_name_path + "/label_encoder.sav", "wb"))
|
||||
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"pca": pca.to_html(),
|
||||
"class_report": classification_report.to_html(),
|
||||
"feature_importance": feature_importance.to_html(),
|
||||
}
|
||||
elif dataset_type == "timeseries":
|
||||
|
||||
path = model_name_path
|
||||
dataset_camel = methods.convert_to_camel_case(df_name)
|
||||
if "Ecg" in dataset_camel:
|
||||
dataset_camel = dataset_camel.replace("Ecg", "ECG")
|
||||
|
||||
experiment = methods.fetch_line_by_dataset(
|
||||
PIPELINE_PATH + "/glacier_experiments.txt",
|
||||
dataset_camel,
|
||||
)
|
||||
|
||||
if experiment is not None:
|
||||
stripped_arguments = methods.extract_arguments_from_line(experiment)
|
||||
|
||||
if model_name == "glacier":
|
||||
classification_report = methods.training(
|
||||
preprocess_df,
|
||||
model_name,
|
||||
float(test_set_ratio) if test_set_ratio != "" else 0,
|
||||
"",
|
||||
dataset_type,
|
||||
df_name,
|
||||
path,
|
||||
autoencoder,
|
||||
stripped_arguments,
|
||||
)
|
||||
else:
|
||||
classification_report = methods.training(
|
||||
preprocess_df,
|
||||
model_name,
|
||||
float(test_set_ratio) if test_set_ratio != "" else 0,
|
||||
"",
|
||||
dataset_type,
|
||||
df_name,
|
||||
path,
|
||||
)
|
||||
|
||||
pickle.dump(
|
||||
classification_report,
|
||||
open(path + "/classification_report.sav", "wb"),
|
||||
)
|
||||
|
||||
context = {
|
||||
"dataset_type": dataset_type,
|
||||
"pca": pca.to_html(),
|
||||
"tsne": tsne.to_html(),
|
||||
"class_report": classification_report.to_html(),
|
||||
}
|
||||
|
||||
# save the plots
|
||||
pickle.dump(tsne, open(model_name_path + "/tsne.sav", "wb"))
|
||||
pickle.dump(pca, open(model_name_path + "/pca.sav", "wb"))
|
||||
|
||||
# save projections file for future use
|
||||
with open(model_name_path + "/tsne_projections.json", "w") as f:
|
||||
json.dump(projections.tolist(), f, indent=2)
|
||||
|
||||
if jsonFile.key_exists("classifier"):
|
||||
temp_json = {model_name: preprocessing_info}
|
||||
jsonFile.update_json(["classifier"], temp_json)
|
||||
else:
|
||||
temp_jason = {
|
||||
"preprocessed_name": df_name + "_preprocessed.csv",
|
||||
"classifier": {model_name: preprocessing_info},
|
||||
}
|
||||
jsonFile.append_to_json(temp_jason)
|
||||
|
||||
classifier_data = jsonFile.read_from_json(["classifier", model_name])
|
||||
classifier_data_html = dict_and_html(classifier_data)
|
||||
context.update({"classifier_data": classifier_data_html})
|
||||
preprocess_df.to_csv(excel_file_name_preprocessed_path, index=False)
|
||||
status = 200
|
||||
|
||||
except FileNotFoundError as e:
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
context = methods.format_error_context(
|
||||
e, "File error. Please check if all required files are available."
|
||||
)
|
||||
status = 400
|
||||
|
||||
except PermissionError as e:
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
context = methods.format_error_context(
|
||||
e, "Permission error. Ensure appropriate file permissions."
|
||||
)
|
||||
status = 400
|
||||
|
||||
except KeyError as e:
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
context = methods.format_error_context(
|
||||
e, f"Key error. Missing expected key {str(e)}. Verify dataset and configuration settings."
|
||||
)
|
||||
status = 400
|
||||
|
||||
except ValueError as e:
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
context = methods.format_error_context(
|
||||
e, "Data error. Please verify the data format and preprocessing steps."
|
||||
)
|
||||
status = 400
|
||||
|
||||
except TypeError as e:
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
context = methods.format_error_context(
|
||||
e, "Type error. Check for data type compatibility in operations."
|
||||
)
|
||||
status = 400
|
||||
|
||||
except Exception as e:
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
context = methods.format_error_context(
|
||||
e, "An unexpected error occurred. Please review the code and data."
|
||||
)
|
||||
status = 400
|
||||
elif action == "delete_pre_trained":
|
||||
|
||||
df_name = request.session["df_name"]
|
||||
model_name = request.POST.get("model_name")
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{df_name}" + "/trained_models/" + model_name
|
||||
)
|
||||
|
||||
print(model_name_path)
|
||||
|
||||
excel_file_name_preprocessed_path = os.path.join(
|
||||
PIPELINE_PATH,
|
||||
f"{df_name}" + "/" + df_name + "_preprocessed" + ".csv",
|
||||
)
|
||||
try:
|
||||
# Check if the file exists
|
||||
if os.path.exists(excel_file_name_preprocessed_path):
|
||||
# Delete the file
|
||||
os.remove(excel_file_name_preprocessed_path)
|
||||
# print(f"File '{excel_file_name_preprocessed_path}' has been deleted successfully.")
|
||||
else:
|
||||
print(f"File '{excel_file_name_preprocessed_path}' does not exist.")
|
||||
except Exception as e:
|
||||
print(f"An error occurred while deleting the file: {e}")
|
||||
|
||||
json_path = os.path.join(PIPELINE_PATH + f"{df_name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
jsonFile.delete_key(["classifier", model_name])
|
||||
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
# load paths
|
||||
# absolute excel_file_preprocessed_path
|
||||
|
||||
if not jsonFile.key_exists("classifier"):
|
||||
# pre trained models do not exist
|
||||
# check if dataset directory exists
|
||||
df_dir = os.path.join(PIPELINE_PATH + f"{df_name}")
|
||||
if not os.path.exists(df_dir):
|
||||
df_name = None
|
||||
|
||||
context = {
|
||||
"df_name": df_name,
|
||||
"available_pretrained_models_info": [],
|
||||
}
|
||||
else:
|
||||
# if it exists
|
||||
# check the section of "classifiers"
|
||||
# folder path
|
||||
available_pretrained_models = jsonFile.read_from_json(
|
||||
["classifier"]
|
||||
).keys()
|
||||
|
||||
available_pretrained_models_info = (
|
||||
methods.create_tuple_of_models_text_value(
|
||||
available_pretrained_models
|
||||
)
|
||||
)
|
||||
context = {
|
||||
"df_name": df_name,
|
||||
"available_pretrained_models_info": available_pretrained_models_info,
|
||||
}
|
||||
elif action == "discard_model":
|
||||
name = request.session["df_name"]
|
||||
model_name = request.session["model_name"]
|
||||
model_name_path = os.path.join(
|
||||
PIPELINE_PATH + f"{name}" + "/trained_models/" + model_name
|
||||
)
|
||||
# should delete model folder
|
||||
# should delete classifier from json
|
||||
# should delete preprocessed path too
|
||||
methods.remove_dir_and_empty_parent(model_name_path)
|
||||
# load paths
|
||||
# absolute excel_file_preprocessed_path
|
||||
excel_file_name_preprocessed_path = os.path.join(
|
||||
PIPELINE_PATH,
|
||||
f"{name}" + "/" + name + "_preprocessed" + ".csv",
|
||||
)
|
||||
try:
|
||||
# Check if the file exists
|
||||
if os.path.exists(excel_file_name_preprocessed_path):
|
||||
# Delete the file
|
||||
os.remove(excel_file_name_preprocessed_path)
|
||||
# print(f"File '{excel_file_name_preprocessed_path}' has been deleted successfully.")
|
||||
else:
|
||||
print(f"File '{excel_file_name_preprocessed_path}' does not exist.")
|
||||
except Exception as e:
|
||||
print(f"An error occurred while deleting the file: {e}")
|
||||
|
||||
json_path = os.path.join(PIPELINE_PATH + f"{name}" + "/pipeline.json")
|
||||
jsonFile = pipeline.PipelineJSON(json_path)
|
||||
jsonFile.delete_key(["classifier",model_name])
|
||||
|
||||
context = {}
|
||||
|
||||
return HttpResponse(json.dumps(context), status=status)
|
@ -4884,30 +4884,6 @@ input[type="button"].btn-block {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 5px solid #fff;
|
||||
border-bottom-color: #ff3d00;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
animation: rotation 1s linear infinite;
|
||||
}
|
||||
|
||||
.loader_small {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border: 3px solid #fff;
|
||||
margin-left: 5px;
|
||||
border-bottom-color: #ff3d00;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
animation: rotation 1s linear infinite;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
@ -12097,22 +12073,6 @@ button.btn-primary:hover {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
/* Loader styling */
|
||||
.loader {
|
||||
border: 4px solid #f3f3f3;
|
||||
border-top: 4px solid #007bff;
|
||||
border-radius: 50%;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
/* Keyframes for loader spin */
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* Preprocessing checkboxes styling */
|
||||
.form-check-inline .form-check-label {
|
||||
margin-left: 5px;
|
||||
@ -12529,7 +12489,7 @@ h6 {
|
||||
animation: fadeIn 0.8s ease forwards;
|
||||
}
|
||||
|
||||
/* Loader Style */
|
||||
/* Existing Loader Spinner */
|
||||
.loader {
|
||||
display: inline-block;
|
||||
width: 1.5rem;
|
||||
@ -12541,10 +12501,45 @@ h6 {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* Keyframes for spinner animation */
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Loader Overlay */
|
||||
.loader-overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.8); /* Semi-transparent white background */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10; /* Ensure it overlays the content */
|
||||
}
|
||||
|
||||
/* Spinner Loader */
|
||||
.spinner-border {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border: 4px solid rgba(0, 0, 0, 0.1);
|
||||
border-top-color: #007bff; /* Customize color */
|
||||
border-radius: 50%;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
|
||||
/* Keyframes for spinner animation */
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Enhanced style for the modal trigger button */
|
||||
.info-button {
|
||||
background: none;
|
||||
@ -12586,4 +12581,401 @@ table th, .sticky-top-table table td {
|
||||
/* Hover effect for rows */
|
||||
.sticky-top-table table tbody tr:hover {
|
||||
background-color: #eaf1f8; /* Soft highlight on hover */
|
||||
}
|
||||
}
|
||||
|
||||
/* Modal Styling */
|
||||
#deleteFileModal .modal-content {
|
||||
border-radius: 4px;
|
||||
padding: 0;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
#deleteFileModal .modal-header {
|
||||
padding: 0.5rem 1rem;
|
||||
border-bottom: none;
|
||||
}
|
||||
#deleteFileModal .modal-title {
|
||||
font-size: 1rem;
|
||||
color: #d9534f;
|
||||
}
|
||||
#deleteFileModal .modal-body {
|
||||
font-size: 0.9rem;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* Custom Buttons */
|
||||
.custom-btn-secondary,
|
||||
.custom-btn-danger {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.4rem 1rem;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.custom-btn-secondary {
|
||||
color: #555;
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.custom-btn-secondary:hover {
|
||||
background-color: #e2e6ea;
|
||||
}
|
||||
|
||||
.custom-btn-danger {
|
||||
color: #fff;
|
||||
background-color: #d9534f;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.custom-btn-danger:hover {
|
||||
background-color: #c9302c;
|
||||
}
|
||||
|
||||
/* Delete icon next to file names */
|
||||
.delete-file-icon {
|
||||
font-size: 1.2rem;
|
||||
color: #bbb;
|
||||
cursor: pointer;
|
||||
transition: color 0.2s;
|
||||
}
|
||||
.delete-file-icon:hover {
|
||||
color: #d9534f;
|
||||
}
|
||||
|
||||
.custom-alert {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 5px 10px;
|
||||
border-radius: 8px;
|
||||
background-color: #eafaf1;
|
||||
color: #28a745;
|
||||
font-size: 14px;
|
||||
max-width: 250px;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity 0.4s ease, transform 0.4s ease;
|
||||
}
|
||||
|
||||
.custom-alert.show {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.loader i {
|
||||
font-size: 1.2em;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.card-header h6 {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
font-size: 0.85rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
/* Add to your CSS file */
|
||||
.blur-effect {
|
||||
transition: filter 0.3s ease, opacity 0.3s ease;
|
||||
}
|
||||
|
||||
/* Ensure the modal respects the maximum height */
|
||||
#modelAnalysisModal .modal-content {
|
||||
max-height: 80vh; /* Adjust the maximum height as needed */
|
||||
overflow-y: auto; /* Add vertical scrolling when content exceeds height */
|
||||
}
|
||||
|
||||
/* Style for the modal body */
|
||||
#modelAnalysisModal .modal-body {
|
||||
padding: 20px; /* Add some padding for better readability */
|
||||
}
|
||||
|
||||
/* Optional: Keep the tabs navigation fixed at the top inside the modal */
|
||||
#modelAnalysisModal .nav-tabs {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1020;
|
||||
background-color: #f8f9fa; /* Match with modal header background */
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
/* Optional: Add smooth scrolling */
|
||||
#modelAnalysisModal .modal-content::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
#modelAnalysisModal .modal-content::-webkit-scrollbar-thumb {
|
||||
background-color: #6c757d; /* Darker thumb for scrollbar */
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#modelAnalysisModal .modal-content::-webkit-scrollbar-track {
|
||||
background-color: #f8f9fa; /* Light track for scrollbar */
|
||||
}
|
||||
|
||||
/* Make the modal footer fixed to the bottom of the modal */
|
||||
#modelAnalysisModal .modal-footer {
|
||||
position: sticky; /* Keep it at the bottom of the modal body */
|
||||
bottom: 0;
|
||||
z-index: 1050; /* Ensure it appears above the modal body content */
|
||||
background-color: #fff; /* Match the modal's background color */
|
||||
border-top: 1px solid #dee2e6; /* Optional: Add a top border */
|
||||
box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.1); /* Optional: Add subtle shadow */
|
||||
}
|
||||
|
||||
/* Adjust the modal body to account for the footer's height */
|
||||
#modelAnalysisModal .modal-body {
|
||||
max-height: calc(80vh - 60px); /* Subtract the approximate footer height */
|
||||
overflow-y: auto; /* Enable scrolling if content exceeds height */
|
||||
}
|
||||
|
||||
/* Minimal animations and transitions */
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: all 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Button hover effect */
|
||||
.btn-outline-primary {
|
||||
border: 2px solid #007bff;
|
||||
color: #007bff;
|
||||
background: none;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
background: #007bff;
|
||||
color: #fff;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* Card hover effect */
|
||||
.feature-card {
|
||||
transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.feature-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Typography tweaks */
|
||||
h1, h2, h3 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.separator {
|
||||
height: 2px;
|
||||
background-color: #ddd;
|
||||
width: 100px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
transition: background-color 0.3s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #0056b3;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-control-prev-icon, .carousel-control-next-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
}
|
||||
|
||||
.carousel-indicators li {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
|
||||
#backToTop {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
display: none;
|
||||
z-index: 1000;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
#backToTop:hover {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
body.dark-mode {
|
||||
background-color: #121212;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.dark-mode .bg-light {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
.dark-mode .text-dark {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.dark-mode .btn-primary {
|
||||
background-color: #0056b3;
|
||||
border-color: #0056b3;
|
||||
}
|
||||
/* Background Enhancements */
|
||||
#home_intro {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
background: linear-gradient(145deg, #f3f4f6, #ffffff);
|
||||
}
|
||||
|
||||
#home_intro .background-shape {
|
||||
position: absolute;
|
||||
width: 180px; /* Reduced size */
|
||||
height: 180px; /* Reduced size */
|
||||
background: rgba(0, 123, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
filter: blur(60px);
|
||||
z-index: 0;
|
||||
animation: float 5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
#home_intro .background-shape.shape-1 {
|
||||
top: -40px;
|
||||
left: -40px;
|
||||
}
|
||||
|
||||
#home_intro .background-shape.shape-2 {
|
||||
bottom: -40px;
|
||||
right: -40px;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
/* Keyframe Animation for Background Shapes */
|
||||
@keyframes float {
|
||||
0%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(15px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Logo Styling */
|
||||
#home_intro .logos .logo {
|
||||
max-height: 60px; /* Smaller logo size */
|
||||
filter: drop-shadow(0 3px 5px rgba(0, 0, 0, 0.1));
|
||||
transition: transform 0.3s ease, filter 0.3s ease;
|
||||
}
|
||||
|
||||
#home_intro .logos .logo:hover {
|
||||
transform: scale(1.1);
|
||||
filter: drop-shadow(0 5px 7px rgba(0, 0, 0, 0.2));
|
||||
}
|
||||
|
||||
/* Animation for Fading in */
|
||||
.fade-in {
|
||||
animation: fadeIn 1s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive Styling */
|
||||
@media (max-width: 768px) {
|
||||
#home_intro .logos {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
#home_intro .logos .logo {
|
||||
margin-bottom: 8px; /* Reduced spacing */
|
||||
}
|
||||
}
|
||||
|
||||
/* Overall Styling */
|
||||
.collapse {
|
||||
padding: 20px;
|
||||
line-height: 1.6;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.collapse h4 {
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.collapse ul {
|
||||
padding: 0;
|
||||
margin: 20px 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.collapse ul li {
|
||||
display: inline-block;
|
||||
margin: 0 15px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.collapse ul li i {
|
||||
font-size: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.collapse p {
|
||||
text-align: justify;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.collapse a.btn {
|
||||
font-size: 14px;
|
||||
padding: 10px 20px;
|
||||
border: 1px solid #007bff;
|
||||
color: #007bff;
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
.collapse a.btn:hover {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
BIN
base/static/img/digital_features.png
Normal file
BIN
base/static/img/digital_features.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 12 KiB |
BIN
base/static/img/su_logo.png
Normal file
BIN
base/static/img/su_logo.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 40 KiB |
File diff suppressed because one or more lines are too long
Before (image error) Size: 36 KiB |
@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 108.3 108.3" style="enable-background:new 0 0 108.3 108.3;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#E6E6E6;}
|
||||
.st1{fill:#FFB8B8;}
|
||||
.st2{fill:#575A89;}
|
||||
.st3{fill:#2F2E41;}
|
||||
</style>
|
||||
<g id="Group_45" transform="translate(-191 -152.079)">
|
||||
<g id="Group_30" transform="translate(282.246 224.353)">
|
||||
<path id="Path_944" class="st0" d="M17.1-18.1c0,10.5-3,20.8-8.8,29.6c-1.2,1.9-2.5,3.6-4,5.3c-3.4,4-7.3,7.4-11.6,10.3
|
||||
c-1.2,0.8-2.4,1.5-3.6,2.2c-6.5,3.6-13.7,5.8-21,6.5c-1.7,0.2-3.4,0.2-5.1,0.2c-4.7,0-9.4-0.6-14-1.8c-2.6-0.7-5.1-1.6-7.6-2.6
|
||||
c-1.3-0.5-2.5-1.1-3.7-1.8c-2.9-1.5-5.6-3.3-8.2-5.3c-1.2-0.9-2.3-1.9-3.4-2.9C-95.8,1.3-97.1-33-76.8-54.9s54.6-23.3,76.5-2.9
|
||||
C10.8-47.6,17.1-33.2,17.1-18.1L17.1-18.1z"/>
|
||||
<path id="Path_945" class="st1" d="M-50.2-13.2c0,0,4.9,13.7,1.1,21.4s6,16.4,6,16.4s25.8-13.1,22.5-19.7s-8.8-15.3-7.7-20.8
|
||||
L-50.2-13.2z"/>
|
||||
<ellipse id="Ellipse_185" class="st1" cx="-40.6" cy="-25.5" rx="17.5" ry="17.5"/>
|
||||
<path id="Path_946" class="st2" d="M-51.1,34.2c-2.6-0.7-5.1-1.6-7.6-2.6l0.5-13.3l4.9-11c1.1,0.9,2.3,1.6,3.5,2.3
|
||||
c0.3,0.2,0.6,0.3,0.9,0.5c4.6,2.2,12.2,4.2,19.5-1.3c2.7-2.1,5-4.7,6.7-7.6L-8.8,9l0.7,8.4l0.8,9.8c-1.2,0.8-2.4,1.5-3.6,2.2
|
||||
c-6.5,3.6-13.7,5.8-21,6.5c-1.7,0.2-3.4,0.2-5.1,0.2C-41.8,36.1-46.5,35.4-51.1,34.2z"/>
|
||||
<path id="Path_947" class="st2" d="M-47.7-0.9L-47.7-0.9l-0.7,7.2l-0.4,3.8l-0.5,5.6l-1.8,18.5c-2.6-0.7-5.1-1.6-7.6-2.6
|
||||
c-1.3-0.5-2.5-1.1-3.7-1.8c-2.9-1.5-5.6-3.3-8.2-5.3l-1.9-9l0.1-0.1L-47.7-0.9z"/>
|
||||
<path id="Path_948" class="st2" d="M-10.9,29.3c-6.5,3.6-13.7,5.8-21,6.5c0.4-6.7,1-13.1,1.6-18.8c0.3-2.9,0.7-5.7,1.1-8.2
|
||||
c1.2-8,2.5-13.5,3.4-14.2l6.1,4L4.9,7.3l-0.5,9.5c-3.4,4-7.3,7.4-11.6,10.3C-8.5,27.9-9.7,28.7-10.9,29.3z"/>
|
||||
<path id="Path_949" class="st2" d="M-70.5,24.6c-1.2-0.9-2.3-1.9-3.4-2.9l0.9-6.1l0.7-0.1l3.1-0.4l6.8,14.8
|
||||
C-65.2,28.3-67.9,26.6-70.5,24.6L-70.5,24.6z"/>
|
||||
<path id="Path_950" class="st2" d="M8.3,11.5c-1.2,1.9-2.5,3.6-4,5.3c-3.4,4-7.3,7.4-11.6,10.3c-1.2,0.8-2.4,1.5-3.6,2.2l-0.6-2.8
|
||||
l3.5-9.1l4.2-11.1l8.8,1.1C6.1,8.7,7.2,10.1,8.3,11.5z"/>
|
||||
<path id="Path_951" class="st3" d="M-23.9-41.4c-2.7-4.3-6.8-7.5-11.6-8.9l-3.6,2.9l1.4-3.3c-1.2-0.2-2.3-0.2-3.5-0.2l-3.2,4.1
|
||||
l1.3-4c-5.6,0.7-10.7,3.7-14,8.3c-4.1,5.9-4.8,14.1-0.8,20c1.1-3.4,2.4-6.6,3.5-9.9c0.9,0.1,1.7,0.1,2.6,0l1.3-3.1l0.4,3
|
||||
c4.2-0.4,10.3-1.2,14.3-1.9l-0.4-2.3l2.3,1.9c1.2-0.3,1.9-0.5,1.9-0.7c2.9,4.7,5.8,7.7,8.8,12.5C-22.1-29.8-20.2-35.3-23.9-41.4z"
|
||||
/>
|
||||
<ellipse id="Ellipse_186" class="st1" cx="-24.9" cy="-26.1" rx="1.2" ry="2.4"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before (image error) Size: 2.8 KiB |
@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="_x38_8ce59e9-c4b8-4d1d-9d7a-ce0190159aa8"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 231.8 231.8"
|
||||
style="enable-background:new 0 0 231.8 231.8;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.5;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:#F5F5F5;}
|
||||
.st3{fill:#333333;}
|
||||
.st4{fill:#4E73DF;}
|
||||
.st5{opacity:0.1;enable-background:new ;}
|
||||
.st6{fill:#BE7C5E;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="115.89" y1="525.2" x2="115.89" y2="756.98" gradientTransform="matrix(1 0 0 -1 0 756.98)">
|
||||
<stop offset="0" style="stop-color:#808080;stop-opacity:0.25"/>
|
||||
<stop offset="0.54" style="stop-color:#808080;stop-opacity:0.12"/>
|
||||
<stop offset="1" style="stop-color:#808080;stop-opacity:0.1"/>
|
||||
</linearGradient>
|
||||
<circle class="st1" cx="115.9" cy="115.9" r="115.9"/>
|
||||
</g>
|
||||
<circle class="st2" cx="115.9" cy="115.3" r="113.4"/>
|
||||
<path class="st3" d="M71.6,116.3c0,0-12.9,63.4-19.9,59.8c0,0,67.7,58.5,127.5,0c0,0-10.5-44.6-25.7-59.8H71.6z"/>
|
||||
<path class="st4" d="M116.2,229c22.2,0,43.9-6.5,62.4-18.7c-4.2-22.8-20.1-24.1-20.1-24.1H70.8c0,0-15,1.2-19.7,22.2
|
||||
C70.1,221.9,92.9,229.1,116.2,229z"/>
|
||||
<circle class="st3" cx="115" cy="112.8" r="50.3"/>
|
||||
<path class="st5" d="M97.3,158.4h35.1l0,0v28.1c0,9.7-7.8,17.5-17.5,17.5l0,0c-9.7,0-17.5-7.9-17.5-17.5L97.3,158.4L97.3,158.4z"/>
|
||||
<path class="st6" d="M100.7,157.1h28.4c1.9,0,3.4,1.5,3.4,3.3v0v24.7c0,9.7-7.8,17.5-17.5,17.5l0,0c-9.7,0-17.5-7.9-17.5-17.5v0
|
||||
v-24.7C97.4,158.6,98.9,157.1,100.7,157.1z"/>
|
||||
<path class="st5" d="M97.4,171.6c11.3,4.2,23.8,4.3,35.1,0.1v-4.3H97.4V171.6z"/>
|
||||
<circle class="st6" cx="115" cy="123.7" r="50.3"/>
|
||||
<path class="st3" d="M66.9,104.6h95.9c0,0-8.2-38.7-44.4-36.2S66.9,104.6,66.9,104.6z"/>
|
||||
<ellipse class="st6" cx="65.8" cy="121.5" rx="4.7" ry="8.8"/>
|
||||
<ellipse class="st6" cx="164" cy="121.5" rx="4.7" ry="8.8"/>
|
||||
<path class="st5" d="M66.9,105.9h95.9c0,0-8.2-38.7-44.4-36.2S66.9,105.9,66.9,105.9z"/>
|
||||
</svg>
|
Before (image error) Size: 2.1 KiB |
@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="_x38_8ce59e9-c4b8-4d1d-9d7a-ce0190159aa8"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 231.8 231.8"
|
||||
style="enable-background:new 0 0 231.8 231.8;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.5;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:#F5F5F5;}
|
||||
.st3{fill:#4E73DF;}
|
||||
.st4{fill:#72351C;}
|
||||
.st5{opacity:0.1;enable-background:new ;}
|
||||
.st6{fill:#FDA57D;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="115.89" y1="526.22" x2="115.89" y2="758" gradientTransform="matrix(1 0 0 -1 0 758)">
|
||||
<stop offset="0" style="stop-color:#808080;stop-opacity:0.25"/>
|
||||
<stop offset="0.54" style="stop-color:#808080;stop-opacity:0.12"/>
|
||||
<stop offset="1" style="stop-color:#808080;stop-opacity:0.1"/>
|
||||
</linearGradient>
|
||||
<circle class="st1" cx="115.9" cy="115.9" r="115.9"/>
|
||||
</g>
|
||||
<circle class="st2" cx="116.1" cy="115.1" r="113.4"/>
|
||||
<path class="st3" d="M116.2,229c22.2,0,43.9-6.5,62.4-18.7c-4.2-22.9-20.1-24.2-20.1-24.2H70.8c0,0-15,1.2-19.7,22.2
|
||||
C70.1,221.9,92.9,229.1,116.2,229z"/>
|
||||
<circle class="st4" cx="115" cy="112.8" r="54.8"/>
|
||||
<path class="st5" d="M97.3,158.4h35.1l0,0v28.1c0,9.7-7.8,17.6-17.5,17.6c0,0,0,0,0,0l0,0c-9.7,0-17.5-7.9-17.5-17.5L97.3,158.4
|
||||
L97.3,158.4z"/>
|
||||
<path class="st6" d="M100.7,157.1h28.4c1.9,0,3.3,1.5,3.3,3.4v24.7c0,9.7-7.9,17.5-17.5,17.5l0,0c-9.7,0-17.5-7.9-17.5-17.5v-24.7
|
||||
C97.3,158.6,98.8,157.1,100.7,157.1L100.7,157.1z"/>
|
||||
<path class="st5" d="M97.4,171.6c11.3,4.2,23.8,4.3,35.1,0.1v-4.3H97.4V171.6z"/>
|
||||
<circle class="st6" cx="115" cy="123.7" r="50.3"/>
|
||||
<path class="st5" d="M79.2,77.9c0,0,21.2,43,81,18l-13.9-21.8l-24.7-8.9L79.2,77.9z"/>
|
||||
<path class="st4" d="M79.2,77.3c0,0,21.2,43,81,18l-13.9-21.8l-24.7-8.9L79.2,77.3z"/>
|
||||
<path class="st4" d="M79,74.4c1.4-4.4,3.9-8.4,7.2-11.7c9.9-9.8,26.1-11.8,34.4-23c1.8,3.1,0.7,7.1-2.4,8.9
|
||||
c-0.2,0.1-0.4,0.2-0.6,0.3c8-0.1,17.2-0.8,21.7-7.3c2.3,5.3,1.3,11.4-2.5,15.7c7.1,0.3,14.6,5.1,15.1,12.2c0.3,4.7-2.6,9.1-6.5,11.9
|
||||
s-8.5,3.9-13.1,4.9C118.8,89.2,70.3,101.6,79,74.4z"/>
|
||||
<path class="st4" d="M165.3,124.1H164L138,147.2c-25-11.7-43.3,0-43.3,0l-27.2-22.1l-2.7,0.3c0.8,27.8,23.9,49.6,51.7,48.9
|
||||
C143.6,173.5,165.3,151.3,165.3,124.1L165.3,124.1z M115,156.1c-9.8,0-17.7-2-17.7-4.4s7.9-4.4,17.7-4.4s17.7,2,17.7,4.4
|
||||
S124.7,156.1,115,156.1L115,156.1z"/>
|
||||
<ellipse class="st6" cx="64.7" cy="123.6" rx="4.7" ry="8.8"/>
|
||||
<ellipse class="st6" cx="165.3" cy="123.6" rx="4.7" ry="8.8"/>
|
||||
</svg>
|
Before (image error) Size: 2.6 KiB |
@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="_x38_8ce59e9-c4b8-4d1d-9d7a-ce0190159aa8"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 231.8 231.8"
|
||||
style="enable-background:new 0 0 231.8 231.8;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.5;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{fill:#F5F5F5;}
|
||||
.st3{fill:#4E73DF;}
|
||||
.st4{fill:#F55F44;}
|
||||
.st5{opacity:0.1;enable-background:new ;}
|
||||
.st6{fill:#FDA57D;}
|
||||
.st7{fill:#333333;}
|
||||
</style>
|
||||
<g class="st0">
|
||||
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="115.89" y1="9.36" x2="115.89" y2="241.14" gradientTransform="matrix(1 0 0 -1 0 241.14)">
|
||||
<stop offset="0" style="stop-color:#808080;stop-opacity:0.25"/>
|
||||
<stop offset="0.54" style="stop-color:#808080;stop-opacity:0.12"/>
|
||||
<stop offset="1" style="stop-color:#808080;stop-opacity:0.1"/>
|
||||
</linearGradient>
|
||||
<circle class="st1" cx="115.9" cy="115.9" r="115.9"/>
|
||||
</g>
|
||||
<circle class="st2" cx="116.1" cy="115.1" r="113.4"/>
|
||||
<path class="st3" d="M116.2,229c22.2,0,43.8-6.5,62.3-18.7c-4.2-22.8-20.1-24.2-20.1-24.2H70.8c0,0-15,1.2-19.7,22.2
|
||||
C70.1,221.9,92.9,229.1,116.2,229z"/>
|
||||
<circle class="st4" cx="115" cy="112.8" r="54.8"/>
|
||||
<path class="st5" d="M97.3,158.4h35.1l0,0v28.1c0,9.7-7.9,17.5-17.5,17.5l0,0l0,0c-9.7,0-17.5-7.9-17.5-17.5l0,0L97.3,158.4
|
||||
L97.3,158.4z"/>
|
||||
<path class="st6" d="M100.7,157.1h28.4c1.9,0,3.4,1.5,3.4,3.4l0,0v24.7c0,9.7-7.9,17.5-17.5,17.5l0,0l0,0c-9.7,0-17.5-7.9-17.5-17.5
|
||||
l0,0v-24.7C97.4,158.6,98.8,157.1,100.7,157.1L100.7,157.1L100.7,157.1z"/>
|
||||
<path class="st5" d="M97.4,171.6c11.3,4.2,23.8,4.3,35.1,0.1v-4.3H97.4V171.6z"/>
|
||||
<circle class="st6" cx="115" cy="123.7" r="50.3"/>
|
||||
<circle class="st4" cx="114.9" cy="57.1" r="20.2"/>
|
||||
<circle class="st4" cx="114.9" cy="37.1" r="13.3"/>
|
||||
<path class="st4" d="M106.2,68.2c-9.9-4.4-14.5-15.8-10.5-25.9c-0.1,0.3-0.3,0.6-0.4,0.9c-4.6,10.2,0,22.2,10.2,26.8
|
||||
s22.2,0,26.8-10.2c0.1-0.3,0.2-0.6,0.4-0.9C127.6,68.5,116,72.6,106.2,68.2z"/>
|
||||
<path class="st5" d="M79.2,77.9c0,0,21.2,43,81,18l-13.9-21.8l-24.7-8.9L79.2,77.9z"/>
|
||||
<path class="st4" d="M79.2,77.3c0,0,21.2,43,81,18l-13.9-21.8l-24.7-8.9L79.2,77.3z"/>
|
||||
<path class="st7" d="M95.5,61.6c13-1,26.1-1,39.2,0C134.7,61.6,105.8,64.3,95.5,61.6z"/>
|
||||
<path class="st4" d="M118,23c-1,0-2,0-3,0.2h0.8c7.3,0.2,13.1,6.4,12.8,13.7c-0.2,6.2-4.7,11.5-10.8,12.6
|
||||
c7.3,0.1,13.3-5.8,13.4-13.2C131.2,29.1,125.3,23.1,118,23L118,23z"/>
|
||||
<ellipse class="st6" cx="64.7" cy="123.6" rx="4.7" ry="8.8"/>
|
||||
<ellipse class="st6" cx="165.3" cy="123.6" rx="4.7" ry="8.8"/>
|
||||
<polygon class="st4" points="76,78.6 85.8,73.5 88,81.6 82,85.7 "/>
|
||||
</svg>
|
Before (image error) Size: 2.7 KiB |
@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="b759170a-51c3-4e2f-999d-77dec9fd6d11"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 650.9 610.5"
|
||||
style="enable-background:new 0 0 650.9 610.5;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#AFC0E0;}
|
||||
.st1{opacity:0.2;fill:#FFFFFF;enable-background:new ;}
|
||||
.st2{opacity:0.1;enable-background:new ;}
|
||||
.st3{fill:#E3E8F4;}
|
||||
.st4{fill:#4E73DF;}
|
||||
</style>
|
||||
<path class="st0" d="M174,321c-2-1.6-4.2-3-6.6-4.2c-51.8-26.2-157,67.8-157,67.8L0,372.7c0,0,42.1-43.8,92.4-117.3
|
||||
c45.2-66.1,150.7-51.8,171.4-48.3c2.3,0.4,3.6,0.7,3.6,0.7C298.7,288.3,174,321,174,321z"/>
|
||||
<path class="st1" d="M269.4,213.9c-0.6-2-1.3-4-2-6c0,0-1.2-0.2-3.6-0.7c-20.7-3.5-126.2-17.8-171.4,48.3C42.1,329,0,372.7,0,372.7
|
||||
l5.9,6.7c0,0,42.1-43.8,92.4-117.3C143.3,196.3,248,210.2,269.4,213.9z"/>
|
||||
<path class="st0" d="M337.7,533.4c-79.2,40.8-127.8,77.1-127.8,77.1l-10.5-11.9c0,0,111.1-96.8,85.3-150.9c-0.5-1.2-1.2-2.3-1.9-3.4
|
||||
c0,0,47.9-119.6,123.9-78.5c0,0,0.1,1,0.2,2.9C407.8,387.8,409.7,496.3,337.7,533.4z"/>
|
||||
<path class="st2" d="M174,321c-2-1.6-4.2-3-6.6-4.2c29.3-38.9,61.5-75.5,96.3-109.7c2.3,0.4,3.6,0.7,3.6,0.7
|
||||
C298.7,288.3,174,321,174,321z"/>
|
||||
<path class="st2" d="M406.9,368.6c-38.6,29.6-79.4,56.1-122.3,79.1c-0.5-1.2-1.2-2.3-1.9-3.4c0,0,47.9-119.6,123.9-78.5
|
||||
C406.7,365.7,406.8,366.7,406.9,368.6z"/>
|
||||
<path class="st3" d="M263.6,455.5c-20.3,10.4-41.6,20.5-64,30.2c-33.6,14.6-51.5-2.2-80.7-91.5c0,0,12.5-22.5,37.2-57
|
||||
c54.3-75.8,167.5-209.1,336.1-286.7C542.7,27.1,596.1,10.1,650.9,0c0,0-9.1,68.8-62,160.1S439.1,365.3,263.6,455.5z"/>
|
||||
<circle class="st0" cx="435.6" cy="199.7" r="71.6"/>
|
||||
<path class="st4" d="M469.2,237.9c-21,18.6-53.1,16.6-71.7-4.5c-7.8-8.8-12.2-20-12.7-31.8c-0.2-4.7,0.3-9.4,1.4-14
|
||||
c0.5-2,1.1-4.1,1.9-6c2.9-7.7,7.7-14.5,13.8-19.9c0.3-0.3,0.6-0.5,0.9-0.8c17.1-14.4,41.5-15.9,60.3-3.8c3.5,2.3,6.7,4.9,9.5,7.9
|
||||
l1,1.1C492.2,187.2,490.2,219.3,469.2,237.9C469.2,237.8,469.2,237.9,469.2,237.9z"/>
|
||||
<path class="st0" d="M588.9,160.1c-83-35.2-96.8-109.6-96.8-109.6C542.7,27,596.1,10.1,650.9,0C650.9,0,641.8,68.8,588.9,160.1z"/>
|
||||
<path class="st0" d="M263.6,455.5c-13.7,7.1-27.9,13.9-42.6,20.7c-7,3.2-14.1,6.4-21.4,9.5c-10.9,4.7-51.5-2.2-80.7-91.5
|
||||
c0,0,4.1-7.3,12.1-20c6.1-9.6,14.5-22.2,25.1-37c0,0,11,33.2,41.1,67.3C215.8,425.7,238.4,443,263.6,455.5z"/>
|
||||
<path class="st3" d="M221,476.2c-7,3.2-14.1,6.4-21.4,9.5c-10.9,4.7-51.5-2.2-80.7-91.5c0,0,4.1-7.3,12.1-20
|
||||
C131,374.2,170.2,456.9,221,476.2z"/>
|
||||
<path class="st1" d="M463.2,157l-0.1,0l-60.1,3.9c-0.3,0.3-0.6,0.5-0.9,0.8c-6.2,5.4-10.9,12.3-13.8,19.9l84.5-16.6L463.2,157z"/>
|
||||
<path class="st1" d="M438.8,194.3l-53.9,7.3c-0.2-4.7,0.3-9.4,1.4-14l52.8,1.4L438.8,194.3z"/>
|
||||
<path class="st1" d="M131.7,408.7c0,0,12.5-22.5,37.2-57C223.2,276,336.4,142.7,504.9,65c45.6-21.1,93.3-36.9,142.5-47.3
|
||||
C650.1,6.4,650.9,0,650.9,0c-54.8,10.1-108.2,27-158.7,50.5c-168.6,77.7-281.8,211-336.1,286.7c-24.7,34.4-37.2,57-37.2,57
|
||||
c11.5,35.3,26.6,57,40.5,70.3C149.4,451.4,139.7,433.3,131.7,408.7z"/>
|
||||
</svg>
|
Before (image error) Size: 3.1 KiB |
@ -1,29 +0,0 @@
|
||||
$(document).ready(function () {
|
||||
//Highlight clicked row
|
||||
document.getElementById('reset_div').addEventListener('click', function () {
|
||||
// on click reset the graph
|
||||
// if reset button exists, hide it
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
$("#run_counterfactual_loader").show()
|
||||
$("#reset").remove()
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken },
|
||||
data: {'action': "reset_graph" },
|
||||
success: function (ret) {
|
||||
$("#run_counterfactual_loader").hide()
|
||||
if ($("#og_cf_row") && $("#og_cf_headers")) {
|
||||
$("#og_cf_row").hide()
|
||||
$("#og_cf_headers").hide()
|
||||
}
|
||||
ret = JSON.parse(ret)
|
||||
fig = ret["fig"]
|
||||
document.getElementById("tsne").innerHTML = "";
|
||||
$("#tsne").append(fig)
|
||||
},
|
||||
error: function (ret) {
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
@ -308,6 +308,7 @@ $(document).ready(function () {
|
||||
});
|
||||
data_to_pass = { 'action': "cf", "features_to_vary": JSON.stringify(features_to_vary), "model_name": model_name }
|
||||
}
|
||||
|
||||
// hide button and original point row
|
||||
// replace with loader
|
||||
$("#cfbtn_loader").show()
|
||||
|
613
base/static/js/home.js
Executable file
613
base/static/js/home.js
Executable file
@ -0,0 +1,613 @@
|
||||
import { create_dataframe, create_selection, create_uploaded_file_radio, showSuccessMessage, showLoader, clearPreviousContent, resetContainers } from './methods.js';
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
// Add visibility to fade-in elements on scroll
|
||||
const fadeElements = document.querySelectorAll('.fade-in');
|
||||
|
||||
const elementInView = (el, percentageScroll = 100) => {
|
||||
const elementTop = el.getBoundingClientRect().top;
|
||||
return elementTop <= (window.innerHeight || document.documentElement.clientHeight) * (percentageScroll / 100);
|
||||
};
|
||||
|
||||
const displayFadeElement = (element) => {
|
||||
element.classList.add('visible');
|
||||
};
|
||||
|
||||
const handleFadeAnimation = () => {
|
||||
fadeElements.forEach((el) => {
|
||||
if (elementInView(el)) {
|
||||
displayFadeElement(el);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', () => {
|
||||
handleFadeAnimation();
|
||||
});
|
||||
|
||||
// Initial check for elements already in view
|
||||
handleFadeAnimation();
|
||||
|
||||
function fetchDatasetData(df_name) {
|
||||
const csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
showLoader(true);
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken },
|
||||
data: { 'action': "dataset", 'df_name': df_name },
|
||||
success: function (values) {
|
||||
showLoader(false);
|
||||
handleSuccessResponse(values);
|
||||
$("#new_or_load").show();
|
||||
},
|
||||
error: function (ret) {
|
||||
console.error("Failed to fetch dataset:", ret);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleSuccessResponse(values) {
|
||||
if (!values) return;
|
||||
|
||||
clearPreviousContent();
|
||||
const ret = JSON.parse(values);
|
||||
const datasetType = ret["dataset_type"];
|
||||
|
||||
if (datasetType === "tabular") {
|
||||
setupTabularDataset(ret);
|
||||
} else if (datasetType === "timeseries") {
|
||||
setupTimeseriesDataset(ret);
|
||||
}
|
||||
}
|
||||
|
||||
function setupTabularDataset(ret) {
|
||||
const { data_to_display: df, fig, features, feature1, feature2, labels, curlabel } = ret;
|
||||
|
||||
const selection1 = create_selection(features, "feature1", null, feature1);
|
||||
const selection2 = create_selection(features, "feature2", null, feature2);
|
||||
const selection3 = create_selection(labels, "label", null, curlabel);
|
||||
|
||||
const tb = create_dataframe(df, "df_container");
|
||||
|
||||
$("#model_container, #df, #df_stats").fadeIn(200);
|
||||
$("#df_div").append(tb);
|
||||
$("#selection").append(selection1, selection2, selection3);
|
||||
|
||||
const figDiv = $("<div>", { id: 'stats_container', class: "plotly_fig" }).html(fig);
|
||||
$("#stats_div").append(figDiv);
|
||||
}
|
||||
|
||||
function setupTimeseriesDataset(ret) {
|
||||
const { fig, fig1 } = ret;
|
||||
|
||||
const figDiv = $("<div>", { id: 'ts_confidence_container', class: "plotly_fig" }).html(fig);
|
||||
const figDiv1 = $("<div>", { id: 'ts_stats_container', class: "plotly_fig" }).html(fig1);
|
||||
|
||||
$("#ts_stats, #ts_confidence").fadeIn(200);
|
||||
$("#ts_stats_div").append(figDiv);
|
||||
$("#ts_confidence_div").append(figDiv1);
|
||||
}
|
||||
|
||||
$('.btn-dataset').click(function (e) {
|
||||
const df_name = $(this).is('#upload') ? "upload" : $(this).attr('id');
|
||||
$("#new_or_load_cached").hide();
|
||||
resetContainers();
|
||||
$("#upload_col").toggle(df_name === "upload");
|
||||
$("#timeseries-datasets").toggle(df_name === "timeseries");
|
||||
|
||||
$(this).toggleClass("active").siblings().removeClass("active");
|
||||
$(this).addClass("active");
|
||||
|
||||
const timeseries_dataset = df_name === "timeseries" ? $("input:radio[name=timeseries_dataset]:checked").val() : "";
|
||||
if (timeseries_dataset || (df_name !== "timeseries")) {
|
||||
fetchDatasetData(timeseries_dataset || df_name);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("viewModelsButton").addEventListener("click", function () {
|
||||
// Prompt or redirect the user to the pre-trained models section
|
||||
window.location.href = "/charts.html"; // Replace with the actual URL
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
$('#timeseries-datasets').change(function () {
|
||||
if ($("input[name=timeseries_dataset]:checked").length > 0) {
|
||||
|
||||
var timeseries_dataset = $("input:radio[name=timeseries_dataset]:checked").val();
|
||||
|
||||
$("#df_container").hide();
|
||||
$("#stats_container").hide();
|
||||
$("#figs").hide();
|
||||
|
||||
$("#ts_confidence_cached").hide()
|
||||
$("#ts_stats_cached").hide()
|
||||
|
||||
$("#ts_confidence").hide()
|
||||
$("#ts_stats").hide()
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
|
||||
$("#loader_ds").show();
|
||||
$("#loader_stats").show();
|
||||
|
||||
$("#new_or_load").hide();
|
||||
$("#new_or_load_cached").hide();
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken, },
|
||||
data: { 'action': "timeseries-dataset", 'timeseries_dataset': timeseries_dataset },
|
||||
success: function (values) {
|
||||
$("#loader_ds").hide();
|
||||
$("#loader_stats").hide();
|
||||
// fetch data
|
||||
// remove data if already displayed
|
||||
if (document.getElementById("df_container")) {
|
||||
$("#pretrained_radio").remove();
|
||||
$("#df_container").remove();
|
||||
$("#stats_container").remove();
|
||||
$("#feature1").remove();
|
||||
$("#feature2").remove();
|
||||
$("#label").remove();
|
||||
}
|
||||
|
||||
$("#new_or_load").show();
|
||||
|
||||
if (document.getElementById("ts_confidence_container")) {
|
||||
$("#ts_confidence_container").remove();
|
||||
$("#ts_stats_container").remove();
|
||||
}
|
||||
|
||||
var ret = JSON.parse(values)
|
||||
var dataset_type = ret["dataset_type"]
|
||||
|
||||
if (values) {
|
||||
// timeseries
|
||||
// var feature = ret["feature"]
|
||||
var fig = ret["fig"]
|
||||
var fig1 = ret["fig1"]
|
||||
|
||||
var iDiv = document.createElement('div');
|
||||
iDiv.id = 'ts_confidence_container';
|
||||
iDiv.innerHTML = fig;
|
||||
iDiv.setAttribute("class", "plotly_fig")
|
||||
|
||||
var iDiv1 = document.createElement('div');
|
||||
iDiv1.id = 'ts_stats_container';
|
||||
iDiv1.innerHTML = fig1;
|
||||
iDiv1.setAttribute("class", "plotly_fig")
|
||||
|
||||
$("#ts_stats").show();
|
||||
$("#ts_confidence").show();
|
||||
|
||||
$("#ts_stats_div").append(iDiv);
|
||||
$("#ts_confidence_div").append(iDiv1);
|
||||
}
|
||||
},
|
||||
error: function (ret) {
|
||||
console.log("All bad")
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// $(document).ready(function () {
|
||||
// $('#radio_buttons').change(function () {
|
||||
// if ($("input[name=uploaded_file]:checked").length > 0) {
|
||||
// var uploaded_dataset = $("input:radio[name=uploaded_file]:checked").val();
|
||||
|
||||
// if (document.getElementById("df_container")) {
|
||||
// $("#df").hide();
|
||||
// $("#df_stats").hide();
|
||||
// }
|
||||
|
||||
// if (document.getElementById("df_cached")) {
|
||||
// $("#df_cached").hide()
|
||||
// $("#df_stats_cached").hide()
|
||||
// }
|
||||
|
||||
// if (document.getElementById("ts_confidence")) {
|
||||
// $("#ts_confidence").hide()
|
||||
// $("#ts_stats").hide()
|
||||
// }
|
||||
|
||||
// if (document.getElementById("ts_confidence_cached")) {
|
||||
// $("#ts_confidence_cached").hide()
|
||||
// $("#ts_stats_cached").hide()
|
||||
// }
|
||||
|
||||
// $("#new_or_load").hide()
|
||||
// var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
|
||||
// $("#loader_ds").show();
|
||||
// $("#loader_stats").show();
|
||||
|
||||
// $.ajax({
|
||||
// method: 'POST',
|
||||
// url: '',
|
||||
// headers: { 'X-CSRFToken': csrftoken, },
|
||||
// data: { 'action': "uploaded_datasets", 'df_name': uploaded_dataset },
|
||||
// success: function (values) {
|
||||
// $("#loader_ds").hide();
|
||||
// $("#loader_stats").hide();
|
||||
// $("#new_or_load").show()
|
||||
// // fetch data
|
||||
// // remove data if already displayed
|
||||
// if (document.getElementById("df_container")) {
|
||||
// $("#pretrained_radio").remove();
|
||||
// $("#df_container").remove();
|
||||
// $("#stats_container").remove();
|
||||
// $("#feature1").remove();
|
||||
// $("#feature2").remove();
|
||||
// $("#label").remove();
|
||||
// }
|
||||
|
||||
// if (document.getElementById("df_cached")) {
|
||||
// $("#df_cached").remove()
|
||||
// $("#df_stats_cached").remove()
|
||||
// $("#ts_confidence_cached").remove()
|
||||
// $("#ts_stats_cached").remove()
|
||||
// }
|
||||
|
||||
// if (document.getElementById("ts_confidence_container")) {
|
||||
// $("#ts_confidence_container").remove();
|
||||
// $("#ts_stats_container").remove();
|
||||
// }
|
||||
|
||||
// var ret = JSON.parse(values)
|
||||
// var dataset_type = ret["dataset_type"]
|
||||
|
||||
// if (values) {
|
||||
// if (dataset_type == "tabular") {
|
||||
// var df = ret["data_to_display"]
|
||||
// var fig = ret["fig"]
|
||||
// var features = ret["features"]
|
||||
// var feature1 = ret["feature1"]
|
||||
// var feature2 = ret["feature2"]
|
||||
|
||||
// // cur labels
|
||||
// var labels = ret["labels"]
|
||||
// var curlabel = ret["curlabel"]
|
||||
|
||||
// var selection1 = create_selection(features, "feature1", null, feature1)
|
||||
// var selection2 = create_selection(features, "feature2", null, feature2)
|
||||
// var selection3 = create_selection(labels, "label", null, curlabel)
|
||||
|
||||
// // create table
|
||||
// var tb = create_dataframe(df, "df_container")
|
||||
|
||||
// $("#model_container").show()
|
||||
// $("#df").show();
|
||||
// $("#df_stats").show();
|
||||
|
||||
// // append new data
|
||||
// $("#df_div").append(tb);
|
||||
// $("#selection").append(selection1);
|
||||
// $("#selection").append(selection2);
|
||||
// $("#selection").append(selection3);
|
||||
|
||||
// // append fig
|
||||
// var iDiv = document.createElement('div');
|
||||
// iDiv.id = 'stats_container';
|
||||
// iDiv.innerHTML = fig;
|
||||
// iDiv.setAttribute("class", "plotly_fig")
|
||||
|
||||
// $("#stats_div").append(iDiv);
|
||||
// } else if (dataset_type == "timeseries") {
|
||||
|
||||
// // timeseries
|
||||
// // var feature = ret["feature"]
|
||||
// var fig = ret["fig"]
|
||||
// var fig1 = ret["fig1"]
|
||||
|
||||
// var iDiv = document.createElement('div');
|
||||
// iDiv.id = 'ts_confidence_container';
|
||||
// iDiv.innerHTML = fig;
|
||||
// iDiv.setAttribute("class", "plotly_fig")
|
||||
|
||||
// var iDiv1 = document.createElement('div');
|
||||
// iDiv1.id = 'ts_stats_container';
|
||||
// iDiv1.innerHTML = fig1;
|
||||
// iDiv1.setAttribute("class", "plotly_fig")
|
||||
|
||||
// $("#ts_stats").show();
|
||||
// $("#ts_confidence").show();
|
||||
|
||||
// $("#ts_stats_div").append(iDiv);
|
||||
// $("#ts_confidence_div").append(iDiv1);
|
||||
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// error: function (ret) {
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// })
|
||||
// });
|
||||
|
||||
// $('#upload_btn').click(function (event) {
|
||||
// event.preventDefault(); // Prevent default form submission
|
||||
|
||||
// var datasetType = $('input[name="dataset_type"]:checked').val();
|
||||
// var fileInput = $('#doc')[0].files[0];
|
||||
// var csrfToken = $('input[name="csrfmiddlewaretoken"]').val();
|
||||
|
||||
// if (!datasetType || !fileInput) {
|
||||
// alert('Please select a dataset type and choose a file to upload.');
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Use FormData to handle file upload
|
||||
// var formData = new FormData();
|
||||
// formData.append('action', 'upload_dataset');
|
||||
// formData.append('dataset_type', datasetType);
|
||||
// formData.append('excel_file', fileInput);
|
||||
// formData.append('csrfmiddlewaretoken', csrfToken);
|
||||
|
||||
// $("#cfbtn_loader").show();
|
||||
|
||||
// $.ajax({
|
||||
// url: '', // Replace with your Django view URL for uploading
|
||||
// type: 'POST',
|
||||
// data: formData,
|
||||
// processData: false, // Prevent jQuery from processing data
|
||||
// contentType: false, // Prevent jQuery from setting content type
|
||||
// success: function (response) {
|
||||
// try {
|
||||
// var ret = JSON.parse(response);
|
||||
// var df_name = ret["df_name"];
|
||||
// var uploaded_files = ret["uploaded_files"];
|
||||
// var counter = uploaded_files.length - 1;
|
||||
|
||||
// // Add uploaded file to the list
|
||||
// alert("here")
|
||||
// $("#radio_buttons").append(create_uploaded_file_radio(df_name, counter));
|
||||
|
||||
// // Check if target_labels exist in the response
|
||||
// if (ret["target_labels"]) {
|
||||
// populateLabelModal(ret["target_labels"]); // Populate the modal for label selection
|
||||
// }
|
||||
|
||||
// showSuccessMessage();
|
||||
// } catch (error) {
|
||||
// console.error("Error processing response:", error);
|
||||
// alert("An error occurred while processing the upload response.");
|
||||
// } finally {
|
||||
// $("#cfbtn_loader").hide();
|
||||
// }
|
||||
// },
|
||||
// error: function (xhr, status, error) {
|
||||
// console.error("Error uploading:", status, error);
|
||||
// alert("An error occurred during upload. Please try again.");
|
||||
// $("#cfbtn_loader").hide();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
|
||||
// function populateLabelModal(targetLabels) {
|
||||
// const positiveDropdown = $("#positive-label");
|
||||
// const negativeDropdown = $("#negative-label");
|
||||
// const errorContainer = $("#selection-error");
|
||||
|
||||
// // Populate dropdowns
|
||||
// updateDropdownOptions(positiveDropdown, targetLabels, null);
|
||||
// updateDropdownOptions(negativeDropdown, targetLabels, null);
|
||||
|
||||
// // Reset error message
|
||||
// errorContainer.addClass("d-none").text("");
|
||||
|
||||
// // Open the modal
|
||||
// $("#labelSelectionModal").modal({
|
||||
// backdrop: 'static', // Prevent closing when clicking outside
|
||||
// keyboard: false // Prevent closing with "Escape"
|
||||
// });
|
||||
|
||||
// let selectedPositive = null;
|
||||
// let selectedNegative = null;
|
||||
|
||||
// // Handle changes in positive dropdown
|
||||
// positiveDropdown.off("change").on("change", function () {
|
||||
// selectedPositive = $(this).val();
|
||||
// updateDropdownOptions(negativeDropdown, targetLabels, selectedPositive, selectedNegative);
|
||||
// validateSelection(selectedPositive, selectedNegative);
|
||||
// });
|
||||
|
||||
// // Handle changes in negative dropdown
|
||||
// negativeDropdown.off("change").on("change", function () {
|
||||
// selectedNegative = $(this).val();
|
||||
// updateDropdownOptions(positiveDropdown, targetLabels, selectedNegative, selectedPositive);
|
||||
// validateSelection(selectedPositive, selectedNegative);
|
||||
// });
|
||||
|
||||
// $("#save-label-choices").click(function (event) {
|
||||
// if (validateSelection(selectedPositive, selectedNegative, true)) {
|
||||
// var csrfToken = $('input[name="csrfmiddlewaretoken"]').val();
|
||||
// var formData = new FormData();
|
||||
|
||||
// formData.append('action', 'select_class_labels_for_uploaded_timeseries');
|
||||
// formData.append('positive_label', selectedPositive);
|
||||
// formData.append('negative_label', selectedNegative);
|
||||
// formData.append('csrfToken', csrfToken);
|
||||
// // Show loader
|
||||
// $("#loader_ds").removeClass("d-none");
|
||||
|
||||
// // Disable the Save button to prevent duplicate submissions
|
||||
// $("#save-label-choices").prop("disabled", true);
|
||||
|
||||
// $.ajax({
|
||||
// url: '', // Replace with your Django view URL for uploading
|
||||
// type: 'POST',
|
||||
// headers: { 'X-CSRFToken': csrfToken, },
|
||||
// data: formData,
|
||||
// processData: false, // Prevent jQuery from processing data
|
||||
// contentType: false, // Prevent jQuery from setting content type
|
||||
// success: function (response) {
|
||||
// console.log('Labels saved successfully:', response);
|
||||
|
||||
// // Hide loader
|
||||
// $("#loader_ds").addClass("d-none");
|
||||
|
||||
// // Enable the Save button
|
||||
// $("#save-label-choices").prop("disabled", false);
|
||||
|
||||
// // Close the modal
|
||||
// $("#labelSelectionModal").modal("hide");
|
||||
|
||||
// // Optionally update the UI with the response
|
||||
// },
|
||||
// error: function (xhr) {
|
||||
// const errorContainer = $("#selection-error");
|
||||
// const errorMessage = xhr.responseJSON?.message || 'An error occurred while saving labels.';
|
||||
// errorContainer.html(`<i class="fas fa-exclamation-triangle"></i> ${errorMessage}`)
|
||||
// .removeClass("d-none");
|
||||
|
||||
// // Hide loader
|
||||
// $("#loader_ds").addClass("d-none");
|
||||
|
||||
// // Enable the Save button
|
||||
// $("#save-label-choices").prop("disabled", false);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
// /**
|
||||
// * Helper function to retrieve CSRF token.
|
||||
// * Assumes the CSRF token is stored in a cookie named 'csrftoken'.
|
||||
// * @returns {string} - CSRF token value.
|
||||
// */
|
||||
// function getCSRFToken() {
|
||||
// const name = 'csrftoken';
|
||||
// const cookies = document.cookie.split(';');
|
||||
// for (let cookie of cookies) {
|
||||
// cookie = cookie.trim();
|
||||
// if (cookie.startsWith(name + '=')) {
|
||||
// return cookie.substring(name.length + 1);
|
||||
// }
|
||||
// }
|
||||
// return '';
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Update dropdown options dynamically, excluding the currently selected value in the other dropdown.
|
||||
// * @param {jQuery} dropdown - The dropdown to update.
|
||||
// * @param {Array} options - The list of options to populate.
|
||||
// * @param {string|null} exclude - The value to exclude from the dropdown options.
|
||||
// * @param {string|null} currentValue - The current value of the dropdown being updated.
|
||||
// */
|
||||
// function updateDropdownOptions(dropdown, options, exclude, currentValue = null) {
|
||||
// dropdown.empty(); // Clear existing options
|
||||
|
||||
// // Add default placeholder
|
||||
// dropdown.append('<option value="" disabled>Select a label</option>');
|
||||
|
||||
// // Repopulate options, excluding the selected value from the other dropdown
|
||||
// options.forEach(option => {
|
||||
// if (option !== exclude) {
|
||||
// dropdown.append(
|
||||
// `<option value="${option}" ${option === currentValue ? "selected" : ""}>${option}</option>`
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
|
||||
// // Reset dropdown if the current value is no longer valid
|
||||
// if (exclude === currentValue) {
|
||||
// dropdown.val("");
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Validate the selected positive and negative labels.
|
||||
// * @param {string|null} positive - The selected positive label.
|
||||
// * @param {string|null} negative - The selected negative label.
|
||||
// * @param {boolean} showError - Whether to show an error message on failure.
|
||||
// * @returns {boolean} - Returns true if the selection is valid, otherwise false.
|
||||
// */
|
||||
// function validateSelection(positive, negative, showError = false) {
|
||||
// const errorContainer = $("#selection-error");
|
||||
|
||||
// if (!positive || !negative) {
|
||||
// if (showError) {
|
||||
// errorContainer.text("You must select both a positive and a negative label!").removeClass("d-none");
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// if (positive === negative) {
|
||||
// if (showError) {
|
||||
// errorContainer.text("Positive and Negative labels must be different!").removeClass("d-none");
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// // Clear error if valid
|
||||
// errorContainer.addClass("d-none").text("");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
document.getElementById("selection").addEventListener("change", function (e) {
|
||||
var feature1 = document.getElementById("feature1").value
|
||||
var feature2 = document.getElementById("feature2").value
|
||||
var label = document.getElementById("label").value
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
$("#stats_container").remove()
|
||||
$('#loader_stats').show()
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken, },
|
||||
data: { 'action': "stat", 'feature1': feature1, 'feature2': feature2, 'label': label },
|
||||
success: function (ret) {
|
||||
$('#loader_stats').hide()
|
||||
var ret = JSON.parse(ret)
|
||||
var fig = ret["fig"]
|
||||
var iDiv = document.createElement('div');
|
||||
iDiv.id = 'stats_container';
|
||||
iDiv.insertAdjacentHTML('beforeend', fig);
|
||||
$("#stats_div").append(iDiv);
|
||||
|
||||
},
|
||||
error: function (ret) {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (document.getElementById("selection_cached")) {
|
||||
document.getElementById("selection_cached").addEventListener("change", function (e) {
|
||||
|
||||
var feature1 = document.getElementById("feature1_cached").value
|
||||
var feature2 = document.getElementById("feature2_cached").value
|
||||
var label = document.getElementById("label_cached").value
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
$("#stats_container_cached").html("")
|
||||
$('#loader_stats_cached').show()
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken, },
|
||||
data: { 'action': "stat", 'feature1': feature1, 'feature2': feature2, 'label': label },
|
||||
success: function (ret) {
|
||||
$('#loader_stats_cached').hide()
|
||||
var ret = JSON.parse(ret)
|
||||
var fig = ret["fig"]
|
||||
var iDiv = document.createElement('div');
|
||||
iDiv.id = 'stats_container_cached';
|
||||
iDiv.insertAdjacentHTML('beforeend', fig);
|
||||
$("#stats_container_cached").html(fig)
|
||||
// $("#stats_container_cached").append(iDiv);
|
||||
|
||||
},
|
||||
error: function (ret) {
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
function enterdata() {
|
||||
//Highlight clicked row
|
||||
document.getElementById('upload_btn').addEventListener('click', function () {
|
||||
var data1 = new FormData()
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
data1.append('excel_file', $('#doc')[0].files[0])
|
||||
console.log(data1)
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken, },
|
||||
data: { 'action': "upload_csv", 'data': data1 },
|
||||
success: function (ret) {
|
||||
console.log(ret)
|
||||
},
|
||||
error: function (ret) {
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
@ -73,20 +73,48 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
if (document.getElementById("backToDatasetButton")) {
|
||||
document.getElementById("backToDatasetButton").addEventListener("click", function () {
|
||||
// Redirect to the dataset selection section
|
||||
window.location.href = "/#dataset_selection"; // Replace with the actual URL
|
||||
window.location.href = "/#dataset_selection";
|
||||
});
|
||||
}
|
||||
|
||||
if (document.getElementById("viewCounterfactualsButton")) {
|
||||
document.getElementById("viewCounterfactualsButton").addEventListener("click", function () {
|
||||
// Redirect to the counterfactuals view section
|
||||
window.location.href = "/counterfactuals.html"; // Replace with the actual URL
|
||||
window.location.href = "/counterfactuals.html";
|
||||
});
|
||||
}
|
||||
|
||||
if (document.getElementById("viewPreTrainedButton")) {
|
||||
document.getElementById("viewPreTrainedButton").addEventListener("click", function () {
|
||||
// Redirect to the counterfactuals view section
|
||||
window.location.href = "/charts.html"; // Replace with the actual URL
|
||||
// Redirect to the pre trained view section
|
||||
window.location.href = "/charts.html";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// JavaScript to handle delete functionality
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
document.getElementById("radio_buttons").addEventListener("click", function (event) {
|
||||
// Identify if the click originated from the button or its child span
|
||||
let targetButton = event.target.closest(".delete-file-icon");
|
||||
console.log(targetButton)
|
||||
// Only proceed if a delete-file-icon button was clicked
|
||||
if (targetButton) {
|
||||
// Get the filename from the data-file attribute
|
||||
const fileName = targetButton.getAttribute("data-file");
|
||||
|
||||
const fileNameValue = targetButton.getAttribute("data-file-value");
|
||||
|
||||
// Set the file name in the modal for display
|
||||
document.getElementById("fileToDeleteName").innerText = fileName;
|
||||
|
||||
// Set the filename in the confirm button for reference during deletion
|
||||
document.getElementById("confirmDeleteButton").setAttribute("data-file", fileName);
|
||||
|
||||
document.getElementById("confirmDeleteButton").setAttribute("data-file-value", fileNameValue);
|
||||
|
||||
// Show the delete confirmation modal
|
||||
$('#deleteFileModal').modal('show');
|
||||
}
|
||||
});
|
||||
});
|
@ -81,10 +81,10 @@ function transpose_table(tableHtml) {
|
||||
for (let colIndex = 0; colIndex < colNames.length; colIndex++) {
|
||||
transposedHtml += `<tr><td>${colNames[colIndex]}</td>`;
|
||||
transposedHtml += `<td>${rows[colIndex]}</td>`;
|
||||
transposedHtml += `<td>${rows[colIndex + colNames.length ]}</td>`;
|
||||
transposedHtml += `<td>${rows[colIndex + colNames.length]}</td>`;
|
||||
transposedHtml += '</tr>';
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
for (let colIndex = 0; colIndex < colNames.length; colIndex++) {
|
||||
transposedHtml += `<tr><td>${colNames[colIndex]}</td>`;
|
||||
transposedHtml += `<td>${rows[colIndex]}</td>`;
|
||||
@ -98,6 +98,108 @@ function transpose_table(tableHtml) {
|
||||
return transposedHtml;
|
||||
}
|
||||
|
||||
function create_uploaded_file_radio(name, counter) {
|
||||
var formCheckDiv = document.createElement("div");
|
||||
formCheckDiv.className = "form-check mb-1 d-flex align-items-center";
|
||||
|
||||
// Create the radio input element
|
||||
var radioInput = document.createElement("input");
|
||||
radioInput.className = "form-check-input mr-2";
|
||||
radioInput.type = "radio";
|
||||
radioInput.name = "uploaded_file";
|
||||
radioInput.id = "file_" + counter;
|
||||
radioInput.value = name;
|
||||
radioInput.required = true;
|
||||
|
||||
// Create the label element
|
||||
var label = document.createElement("label");
|
||||
label.className = "form-check-label mr-auto";
|
||||
label.htmlFor = "file_" + counter;
|
||||
label.innerText = name;
|
||||
|
||||
// Create the delete button
|
||||
var deleteButton = document.createElement("button");
|
||||
deleteButton.className = "delete-file-icon p-0 ml-2 text-muted close";
|
||||
deleteButton.type = "button";
|
||||
deleteButton.dataset.file = name;
|
||||
deleteButton.setAttribute("aria-label", "Delete " + name);
|
||||
|
||||
// Create the '×' span inside the delete button
|
||||
var deleteIcon = document.createElement("span");
|
||||
deleteIcon.setAttribute("aria-hidden", "true");
|
||||
deleteIcon.innerHTML = "×";
|
||||
|
||||
// Append the delete icon to the delete button
|
||||
deleteButton.appendChild(deleteIcon);
|
||||
|
||||
// Append the radio input, label, and delete button to the container div
|
||||
formCheckDiv.appendChild(radioInput);
|
||||
formCheckDiv.appendChild(label);
|
||||
formCheckDiv.appendChild(deleteButton);
|
||||
|
||||
return formCheckDiv
|
||||
}
|
||||
|
||||
|
||||
function showSuccessMessage() {
|
||||
const successMessage = document.getElementById("success-message");
|
||||
successMessage.classList.remove("d-none");
|
||||
|
||||
// Add a slight delay to trigger the transition
|
||||
setTimeout(() => successMessage.classList.add("show"), 10);
|
||||
|
||||
// Automatically hide the message after a few seconds
|
||||
setTimeout(() => hideSuccessMessage(), 3000);
|
||||
}
|
||||
|
||||
function hideSuccessMessage() {
|
||||
const successMessage = document.getElementById("success-message");
|
||||
successMessage.classList.remove("show");
|
||||
|
||||
// Delay hiding the element fully until after the transition
|
||||
setTimeout(() => successMessage.classList.add("d-none"), 400);
|
||||
}
|
||||
|
||||
function showLoader(show, ids = ["#loader_ds", "#loader_stats"]) {
|
||||
ids.forEach(id => {
|
||||
$(id).toggle(show);
|
||||
});
|
||||
}
|
||||
function resetContainers(ids = [
|
||||
"#df_container",
|
||||
"#stats_container",
|
||||
"#figs",
|
||||
"#df",
|
||||
"#df_stats",
|
||||
"#df_cached",
|
||||
"#df_stats_cached",
|
||||
"#ts_confidence_cached",
|
||||
"#ts_stats_cached",
|
||||
"#ts_confidence",
|
||||
"#ts_stats"
|
||||
]) {
|
||||
ids.forEach(id => {
|
||||
$(id).hide();
|
||||
});
|
||||
}
|
||||
|
||||
function clearPreviousContent(ids = [
|
||||
"#df_container",
|
||||
"#stats_container",
|
||||
"#pretrained_radio",
|
||||
"#feature1",
|
||||
"#feature2",
|
||||
"#label",
|
||||
"#ts_confidence_container",
|
||||
"#ts_stats_container"
|
||||
]) {
|
||||
ids.forEach(id => {
|
||||
const element = document.querySelector(id);
|
||||
if (element) element.remove();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export {
|
||||
create_selection, create_dataframe, create_div, transpose_table
|
||||
create_selection, create_dataframe, create_div, transpose_table, create_uploaded_file_radio, showSuccessMessage, hideSuccessMessage, showLoader, clearPreviousContent, resetContainers
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
import { create_dataframe, create_selection } from './methods.js';
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
function showLoader(show) {
|
||||
$("#loader, #loader_stats").toggle(show);
|
||||
}
|
||||
|
||||
function resetContainers() {
|
||||
$("#df_container, #stats_container, #figs, #df, #df_stats, #df_cached, #df_stats_cached, #ts_confidence_cached, #ts_stats_cached, #ts_confidence, #ts_stats").hide();
|
||||
}
|
||||
|
||||
function clearPreviousContent() {
|
||||
["#df_container", "#stats_container", "#pretrained_radio", "#feature1", "#feature2", "#label", "#ts_confidence_container", "#ts_stats_container"].forEach(id => {
|
||||
if ($(id).length) $(id).remove();
|
||||
});
|
||||
}
|
||||
|
||||
function fetchDatasetData(df_name) {
|
||||
const csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
showLoader(true);
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken },
|
||||
data: { 'action': "dataset", 'df_name': df_name },
|
||||
success: function (values) {
|
||||
showLoader(false);
|
||||
handleSuccessResponse(values);
|
||||
},
|
||||
error: function (ret) {
|
||||
console.error("Failed to fetch dataset:", ret);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleSuccessResponse(values) {
|
||||
if (!values) return;
|
||||
|
||||
clearPreviousContent();
|
||||
const ret = JSON.parse(values);
|
||||
const datasetType = ret["dataset_type"];
|
||||
|
||||
if (datasetType === "tabular") {
|
||||
setupTabularDataset(ret);
|
||||
} else if (datasetType === "timeseries") {
|
||||
setupTimeseriesDataset(ret);
|
||||
}
|
||||
}
|
||||
|
||||
function setupTabularDataset(ret) {
|
||||
const { data_to_display: df, fig, features, feature1, feature2, labels, curlabel } = ret;
|
||||
|
||||
const selection1 = create_selection(features, "feature1", null, feature1);
|
||||
const selection2 = create_selection(features, "feature2", null, feature2);
|
||||
const selection3 = create_selection(labels, "label", null, curlabel);
|
||||
|
||||
const tb = create_dataframe(df, "df_container");
|
||||
|
||||
$("#model_container, #df, #df_stats").fadeIn(200);
|
||||
$("#df_div").append(tb);
|
||||
$("#selection").append(selection1, selection2, selection3);
|
||||
|
||||
const figDiv = $("<div>", { id: 'stats_container', class: "plotly_fig" }).html(fig);
|
||||
$("#stats_div").append(figDiv);
|
||||
}
|
||||
|
||||
function setupTimeseriesDataset(ret) {
|
||||
const { fig, fig1 } = ret;
|
||||
|
||||
const figDiv = $("<div>", { id: 'ts_confidence_container', class: "plotly_fig" }).html(fig);
|
||||
const figDiv1 = $("<div>", { id: 'ts_stats_container', class: "plotly_fig" }).html(fig1);
|
||||
|
||||
$("#ts_stats, #ts_confidence").fadeIn(200);
|
||||
$("#ts_stats_div").append(figDiv);
|
||||
$("#ts_confidence_div").append(figDiv1);
|
||||
}
|
||||
|
||||
$('.btn-dataset').click(function (e) {
|
||||
const df_name = $(this).is('#upload') ? "upload" : $(this).attr('id');
|
||||
resetContainers();
|
||||
$("#upload_col").toggle(df_name === "upload");
|
||||
$("#timeseries-datasets").toggle(df_name === "timeseries");
|
||||
|
||||
$(this).toggleClass("active").siblings().removeClass("active");
|
||||
$(this).addClass("active");
|
||||
const timeseries_dataset = df_name === "timeseries" ? $("input:radio[name=timeseries_dataset]:checked").val() : "";
|
||||
if (timeseries_dataset || df_name !== "timeseries") {
|
||||
fetchDatasetData(timeseries_dataset || df_name);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("viewModelsButton").addEventListener("click", function () {
|
||||
// Prompt or redirect the user to the pre-trained models section
|
||||
window.location.href = "/charts.html"; // Replace with the actual URL
|
||||
});
|
@ -1,10 +1,7 @@
|
||||
import { create_dataframe, create_div, transpose_table } from './methods.js'
|
||||
|
||||
// pretrained model selection and
|
||||
// train new model selection (not execution)
|
||||
import { create_dataframe, create_div } from './methods.js'
|
||||
|
||||
$(document).ready(function () {
|
||||
$('#pre_trained_models').change(function () {
|
||||
$('#radio_buttons').change(function () {
|
||||
if ($("input[name=modeling_options]:checked").length > 0) {
|
||||
|
||||
// pre trained model selected
|
||||
@ -18,8 +15,6 @@ $(document).ready(function () {
|
||||
var url = ""
|
||||
|
||||
if (currentUrl.includes('charts.html')) {
|
||||
$("#figs").hide();
|
||||
$("#figs_2").hide();
|
||||
|
||||
// if they already exist, remove them and update them
|
||||
if (document.getElementById("principle_component_analysis")) {
|
||||
@ -118,4 +113,77 @@ $(document).ready(function () {
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('confirmDeleteButton').addEventListener('click', function () {
|
||||
const fileNameValue = this.getAttribute('data-file-value');
|
||||
const fileName = this.getAttribute('data-file');
|
||||
const csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
const uploadedDataset = $("input:radio[name=radio_buttons]:checked").val();
|
||||
// AJAX request to delete file
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '', // Add the URL where this request should go
|
||||
data: {
|
||||
action: 'delete_pre_trained',
|
||||
model_name: fileNameValue,
|
||||
csrfmiddlewaretoken: csrftoken // Django CSRF token
|
||||
},
|
||||
success: function () {
|
||||
// Remove the file entry from the UI
|
||||
const fileElement = $(`[data-file="${fileName}"]`).closest('.form-check');
|
||||
fileElement.remove();
|
||||
|
||||
// Check if there are any remaining .form-check elements
|
||||
if ($('#radio_buttons .form-check').length === 0) {
|
||||
// Replace the #radio_buttons content with the fallback message
|
||||
const radioButtonsContainer = document.querySelector('#radio_buttons');
|
||||
radioButtonsContainer.innerHTML = `
|
||||
<p class="text-danger">
|
||||
There are no available pre-trained models.
|
||||
Please <a href="/train.html" class="text-primary">train a model</a>.
|
||||
</p>
|
||||
`;
|
||||
}
|
||||
|
||||
// Attach a success message to the modal
|
||||
const modalBody = document.querySelector('#deleteFileModal .modal-body');
|
||||
modalBody.innerHTML = `
|
||||
<div class="alert alert-success mb-3" role="alert">
|
||||
<i class="fas fa-check-circle mr-2"></i>
|
||||
The file <strong>${fileName}</strong> has been successfully deleted.
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Optionally hide the modal after a delay
|
||||
setTimeout(() => {
|
||||
$('#deleteFileModal').modal('hide');
|
||||
modalBody.innerHTML = ''; // Clear the message after hiding
|
||||
}, 2000);
|
||||
|
||||
// Reset containers if the deleted file is the uploaded dataset
|
||||
if (fileName === uploadedDataset) {
|
||||
resetContainers();
|
||||
}
|
||||
},
|
||||
|
||||
error: function () {
|
||||
// Attach an error message to the modal
|
||||
const modalBody = document.querySelector('#deleteFileModal .modal-body');
|
||||
modalBody.innerHTML = `
|
||||
<div class="alert alert-danger mb-3" role="alert">
|
||||
<i class="fas fa-times-circle mr-2"></i>
|
||||
An error occurred while deleting the file. Please try again.
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Optionally reset the modal content after a delay
|
||||
setTimeout(() => {
|
||||
modalBody.innerHTML = `
|
||||
<p class="mb-1">Delete <span id="fileToDeleteName" class="font-weight-bold"></span> pre-trained classifier on <span class="font-weight-bold"> {{ df_name }} </span> dataset?</p>
|
||||
<small class="text-muted">This action is permanent.</small>
|
||||
`;
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,81 +1,73 @@
|
||||
import { create_dataframe, create_selection } from './methods.js'
|
||||
import { create_dataframe, create_selection } from './methods.js';
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$('#timeseries-datasets').change(function () {
|
||||
if ($("input[name=timeseries_dataset]:checked").length > 0) {
|
||||
const selectedDataset = $("input[name=timeseries_dataset]:checked").val();
|
||||
|
||||
var timeseries_dataset = $("input:radio[name=timeseries_dataset]:checked").val();
|
||||
if (selectedDataset) {
|
||||
resetContainers();
|
||||
toggleSkeletons(true);
|
||||
|
||||
$("#df_container").hide();
|
||||
$("#stats_container").hide();
|
||||
$("#figs").hide();
|
||||
|
||||
$("#ts_confidence_cached").hide()
|
||||
$("#ts_stats_cached").hide()
|
||||
|
||||
$("#ts_confidence").hide()
|
||||
$("#ts_stats").hide()
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
|
||||
$("#loader").show();
|
||||
$("#loader_stats").show();
|
||||
const csrfToken = $("[name=csrfmiddlewaretoken]").val();
|
||||
|
||||
// AJAX request to fetch the dataset
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken, },
|
||||
data: { 'action': "timeseries-dataset", 'timeseries_dataset': timeseries_dataset },
|
||||
success: function (values) {
|
||||
$("#loader").hide();
|
||||
$("#loader_stats").hide();
|
||||
// fetch data
|
||||
// remove data if already displayed
|
||||
if (document.getElementById("df_container")) {
|
||||
$("#pretrained_radio").remove();
|
||||
$("#df_container").remove();
|
||||
$("#stats_container").remove();
|
||||
$("#feature1").remove();
|
||||
$("#feature2").remove();
|
||||
$("#label").remove();
|
||||
}
|
||||
|
||||
if (document.getElementById("ts_confidence_container")) {
|
||||
$("#ts_confidence_container").remove();
|
||||
$("#ts_stats_container").remove();
|
||||
}
|
||||
|
||||
var ret = JSON.parse(values)
|
||||
var dataset_type = ret["dataset_type"]
|
||||
|
||||
if (values) {
|
||||
// timeseries
|
||||
// var feature = ret["feature"]
|
||||
var fig = ret["fig"]
|
||||
var fig1 = ret["fig1"]
|
||||
|
||||
var iDiv = document.createElement('div');
|
||||
iDiv.id = 'ts_confidence_container';
|
||||
iDiv.innerHTML = fig;
|
||||
iDiv.setAttribute("class", "plotly_fig")
|
||||
|
||||
var iDiv1 = document.createElement('div');
|
||||
iDiv1.id = 'ts_stats_container';
|
||||
iDiv1.innerHTML = fig1;
|
||||
iDiv1.setAttribute("class", "plotly_fig")
|
||||
|
||||
$("#ts_stats").show();
|
||||
$("#ts_confidence").show();
|
||||
|
||||
$("#ts_stats_div").append(iDiv);
|
||||
$("#ts_confidence_div").append(iDiv1);
|
||||
}
|
||||
url: '', // Specify your endpoint here
|
||||
headers: { 'X-CSRFToken': csrfToken },
|
||||
data: { action: "timeseries-dataset", timeseries_dataset: selectedDataset },
|
||||
success: function (response) {
|
||||
alert("herereererer")
|
||||
toggleSkeletons(false);
|
||||
handleTimeseriesResponse(response);
|
||||
},
|
||||
error: function (ret) {
|
||||
console.log("All bad")
|
||||
error: function (error) {
|
||||
toggleSkeletons(false);
|
||||
console.error("An error occurred:", error);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Reset the containers by hiding any previous data.
|
||||
*/
|
||||
function resetContainers() {
|
||||
const elementsToHide = [
|
||||
"#df_div", "#stats_div", "#ts_confidence_div", "#ts_stats_div"
|
||||
];
|
||||
elementsToHide.forEach(selector => $(selector).empty().hide());
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle skeleton loaders for a smooth user experience.
|
||||
* @param {boolean} show - Whether to show or hide the skeleton loaders.
|
||||
*/
|
||||
function toggleSkeletons(show) {
|
||||
const skeletonSelectors = [
|
||||
"#df_skeleton", "#stats_skeleton", "#ts_confidence_skeleton", "#ts_stats_skeleton"
|
||||
];
|
||||
skeletonSelectors.forEach(selector => $(selector).toggle(show));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the response for timeseries dataset.
|
||||
* @param {Object|string} response - The server response.
|
||||
*/
|
||||
function handleTimeseriesResponse(response) {
|
||||
try {
|
||||
const data = JSON.parse(response);
|
||||
if (!data) throw new Error("Invalid response format");
|
||||
|
||||
// Populate data and stats
|
||||
if (data.fig) {
|
||||
$("#ts_confidence_div").html(data.fig).show();
|
||||
}
|
||||
if (data.fig1) {
|
||||
$("#ts_stats_div").html(data.fig1).show();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to process response:", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,118 +0,0 @@
|
||||
import { create_dataframe, create_selection } from './methods.js'
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
$('#uploaded_file').change(function () {
|
||||
if ($("input[name=uploaded_file]:checked").length > 0) {
|
||||
|
||||
var uploaded_dataset = $("input:radio[name=uploaded_file]:checked").val();
|
||||
|
||||
$("#df_container").hide();
|
||||
$("#stats_container").hide();
|
||||
$("#figs").hide();
|
||||
|
||||
$("#ts_confidence_cached").hide()
|
||||
$("#ts_stats_cached").hide()
|
||||
|
||||
$("#ts_confidence").hide()
|
||||
$("#ts_stats").hide()
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
|
||||
$("#loader").show();
|
||||
$("#loader_stats").show();
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken, },
|
||||
data: { 'action': "uploaded_datasets", 'df_name': uploaded_dataset },
|
||||
success: function (values) {
|
||||
$("#loader").hide();
|
||||
$("#loader_stats").hide();
|
||||
// fetch data
|
||||
// remove data if already displayed
|
||||
if (document.getElementById("df_container")) {
|
||||
$("#pretrained_radio").remove();
|
||||
$("#df_container").remove();
|
||||
$("#stats_container").remove();
|
||||
$("#feature1").remove();
|
||||
$("#feature2").remove();
|
||||
$("#label").remove();
|
||||
}
|
||||
|
||||
if (document.getElementById("ts_confidence_container")) {
|
||||
$("#ts_confidence_container").remove();
|
||||
$("#ts_stats_container").remove();
|
||||
}
|
||||
|
||||
var ret = JSON.parse(values)
|
||||
var dataset_type = ret["dataset_type"]
|
||||
|
||||
if (values) {
|
||||
if (dataset_type == "tabular") {
|
||||
var df = ret["data_to_display"]
|
||||
var fig = ret["fig"]
|
||||
var features = ret["features"]
|
||||
var feature1 = ret["feature1"]
|
||||
var feature2 = ret["feature2"]
|
||||
|
||||
// cur labels
|
||||
var labels = ret["labels"]
|
||||
var curlabel = ret["curlabel"]
|
||||
|
||||
var selection1 = create_selection(features, "feature1", null, feature1)
|
||||
var selection2 = create_selection(features, "feature2", null, feature2)
|
||||
var selection3 = create_selection(labels, "label", null, curlabel)
|
||||
|
||||
// create table
|
||||
var tb = create_dataframe(df, "df_container")
|
||||
|
||||
$("#model_container").show()
|
||||
$("#df").show();
|
||||
$("#df_stats").show();
|
||||
|
||||
// append new data
|
||||
$("#df_div").append(tb);
|
||||
$("#selection").append(selection1);
|
||||
$("#selection").append(selection2);
|
||||
$("#selection").append(selection3);
|
||||
|
||||
// append fig
|
||||
var iDiv = document.createElement('div');
|
||||
iDiv.id = 'stats_container';
|
||||
iDiv.innerHTML = fig;
|
||||
iDiv.setAttribute("class", "plotly_fig")
|
||||
|
||||
$("#stats_div").append(iDiv);
|
||||
} else if (dataset_type == "timeseries") {
|
||||
|
||||
// timeseries
|
||||
// var feature = ret["feature"]
|
||||
var fig = ret["fig"]
|
||||
var fig1 = ret["fig1"]
|
||||
|
||||
var iDiv = document.createElement('div');
|
||||
iDiv.id = 'ts_confidence_container';
|
||||
iDiv.innerHTML = fig;
|
||||
iDiv.setAttribute("class", "plotly_fig")
|
||||
|
||||
var iDiv1 = document.createElement('div');
|
||||
iDiv1.id = 'ts_stats_container';
|
||||
iDiv1.innerHTML = fig1;
|
||||
iDiv1.setAttribute("class", "plotly_fig")
|
||||
|
||||
$("#ts_stats").show();
|
||||
$("#ts_confidence").show();
|
||||
|
||||
$("#ts_stats_div").append(iDiv);
|
||||
$("#ts_confidence_div").append(iDiv1);
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function (ret) {
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
@ -1,6 +1,5 @@
|
||||
// train a new model
|
||||
import { create_dataframe, create_div, change_nav_text } from './methods.js'
|
||||
change_nav_text("train_nav")
|
||||
import { create_dataframe, create_div } from './methods.js'
|
||||
|
||||
$(document).ready(function () {
|
||||
|
||||
@ -26,57 +25,285 @@ $(document).ready(function () {
|
||||
});
|
||||
|
||||
$('.train_test').click(function () {
|
||||
// get preprocessing variables, model and test set ratio
|
||||
// send ajax request to back end and wait for results
|
||||
var array_preprocessing = []
|
||||
const classifier = document.getElementById("classifier").value;
|
||||
const errorMessage = $("#error_message_new_x_2");
|
||||
|
||||
$("#loader_train").show();
|
||||
var test_set_ratio
|
||||
var classifier = document.getElementById("classifier").value
|
||||
var class_label = ""
|
||||
var autoencoder = ""
|
||||
var data_to_pass = {}
|
||||
if (classifier != "wildboar_knn" && classifier != "wildboar_rsf" && classifier != "glacier") {
|
||||
class_label = document.getElementById("class_label_train").value
|
||||
test_set_ratio = document.getElementById("slider").value
|
||||
document.getElementsByName("boxes").forEach(function (elem) {
|
||||
if (elem.checked == true) {
|
||||
array_preprocessing.push(elem.value);
|
||||
}
|
||||
});
|
||||
data_to_pass = { 'action': "train", 'model_name': classifier, 'test_set_ratio': test_set_ratio, 'array_preprocessing': JSON.stringify(array_preprocessing), 'class_label': class_label }
|
||||
} else if (classifier == "glacier") {
|
||||
// time series data, no class label
|
||||
autoencoder = document.getElementById("autoencoder").value
|
||||
// TODO: maybe add test set ratio
|
||||
data_to_pass = { 'action': "train", 'model_name': classifier, 'autoencoder': autoencoder }
|
||||
} else if (classifier == "wildboar_knn" || classifier == "wildboar_rsf") {
|
||||
test_set_ratio = document.getElementById("slider").value
|
||||
document.getElementsByName("boxes").forEach(function (elem) {
|
||||
if (elem.checked == true) {
|
||||
array_preprocessing.push(elem.value);
|
||||
}
|
||||
});
|
||||
data_to_pass = { 'action': "train", 'model_name': classifier, 'test_set_ratio': test_set_ratio, 'array_preprocessing': JSON.stringify(array_preprocessing) }
|
||||
let array_preprocessing = [];
|
||||
let test_set_ratio, class_label, autoencoder;
|
||||
let data_to_pass = {};
|
||||
|
||||
// Helper function to show errors
|
||||
function showError(message) {
|
||||
errorMessage.text(message);
|
||||
errorMessage.show();
|
||||
}
|
||||
// ajax request for training
|
||||
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
|
||||
// Helper function to get checked values of checkboxes by name
|
||||
function getCheckedValues(name) {
|
||||
return Array.from(document.getElementsByName(name))
|
||||
.filter((elem) => elem.checked)
|
||||
.map((elem) => elem.value);
|
||||
}
|
||||
|
||||
// Check if a classifier is selected
|
||||
if (!classifier) {
|
||||
// Show loader while training
|
||||
showError("Please select a classifier before proceeding.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if at least one preprocessing checkbox is checked
|
||||
const anyPreprocessingChecked = getCheckedValues("boxes").length > 0;
|
||||
|
||||
if (!anyPreprocessingChecked && classifier !== "glacier") {
|
||||
showError("Please select at least one preprocessing option.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide the error message if validations pass
|
||||
errorMessage.hide();
|
||||
|
||||
$("#train_test_btn").hide()
|
||||
|
||||
// Show loader while training
|
||||
$("#loader_train").removeClass("d-none").show();
|
||||
|
||||
// Set up data to pass based on classifier
|
||||
if (classifier === "glacier") {
|
||||
autoencoder = document.getElementById("autoencoder").value;
|
||||
data_to_pass = {
|
||||
action: "train",
|
||||
model_name: classifier,
|
||||
autoencoder: autoencoder
|
||||
};
|
||||
} else {
|
||||
test_set_ratio = document.getElementById("slider").value;
|
||||
class_label = document.getElementById("class_label_train")?.value || "";
|
||||
array_preprocessing = getCheckedValues("boxes");
|
||||
|
||||
data_to_pass = {
|
||||
action: "train",
|
||||
model_name: classifier,
|
||||
test_set_ratio: test_set_ratio,
|
||||
array_preprocessing: JSON.stringify(array_preprocessing),
|
||||
class_label: class_label
|
||||
};
|
||||
}
|
||||
|
||||
// AJAX request for training
|
||||
const csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: '',
|
||||
headers: { 'X-CSRFToken': csrftoken, },
|
||||
headers: { 'X-CSRFToken': csrftoken },
|
||||
data: data_to_pass,
|
||||
processData: true, // This should be `true` for form data
|
||||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8', // Standard form content type,
|
||||
success: function (values) {
|
||||
processData: true,
|
||||
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
success: function (ret) {
|
||||
$("#loader_train").hide();
|
||||
|
||||
try {
|
||||
$("#train_test_btn").show()
|
||||
|
||||
// if they already exist, remove them and update them
|
||||
if (document.getElementById("principle_component_analysis")) {
|
||||
$("#principle_component_analysis").remove();
|
||||
}
|
||||
if (document.getElementById("class_report")) {
|
||||
$("#class_report").remove();
|
||||
}
|
||||
if (document.getElementById("feature_importance")) {
|
||||
$("#feature_importance").remove();
|
||||
}
|
||||
if (document.getElementById("classifier_data")) {
|
||||
$("#classifier_data").remove();
|
||||
}
|
||||
if (document.getElementById("tsne_plot")) {
|
||||
$("#tsne_plot").remove();
|
||||
}
|
||||
|
||||
var ret = JSON.parse(ret)
|
||||
// Parse successful response data
|
||||
const class_report = ret["class_report"];
|
||||
const classifier_data = ret["classifier_data"];
|
||||
const pca = ret["pca"];
|
||||
const dataset_type = ret["dataset_type"];
|
||||
$("#tab").show();
|
||||
|
||||
if (dataset_type == "timeseries") {
|
||||
// For timeseries datasets
|
||||
const tsne = ret["tsne"];
|
||||
$("#tsne-tab-nav").show();
|
||||
const col_div_tsne = create_div("tsne_plot", "plotly_fig");
|
||||
col_div_tsne.insertAdjacentHTML('beforeend', tsne);
|
||||
$("#tsne_container").append(col_div_tsne);
|
||||
} else {
|
||||
// For other datasets
|
||||
$("#feature-tab-nav").show();
|
||||
const feature_importance = ret["feature_importance"];
|
||||
const col_div_fi = create_div("feature_importance", "plotly_fig");
|
||||
col_div_fi.insertAdjacentHTML('beforeend', feature_importance);
|
||||
$("#fi_container").append(col_div_fi);
|
||||
}
|
||||
|
||||
// Create and append dataframes
|
||||
const tb = create_dataframe(classifier_data, "details_container");
|
||||
const cr_tb = create_dataframe(class_report, "cr_container");
|
||||
|
||||
// Create and append plots
|
||||
const col_div_pca = create_div("principle_component_analysis", "plotly_fig");
|
||||
col_div_pca.insertAdjacentHTML('beforeend', pca);
|
||||
|
||||
const col_div_class_report = create_div("class_report", "plotly_fig sticky-top-table");
|
||||
col_div_class_report.append(cr_tb);
|
||||
|
||||
const col_div_classifier_data = create_div("classifier_data", "plotly_fig sticky-top-table");
|
||||
col_div_classifier_data.append(tb);
|
||||
|
||||
// Append content to modal tabs
|
||||
$("#classification_report").append(col_div_class_report);
|
||||
$("#details").append(col_div_classifier_data);
|
||||
$("#pca_container").append(col_div_pca);
|
||||
|
||||
// Show modal for analysis
|
||||
$("#modelAnalysisModal").modal("show");
|
||||
|
||||
} catch (e) {
|
||||
console.error("Error processing response:", e);
|
||||
$("#modelAnalysisModal").modal("show");
|
||||
}
|
||||
},
|
||||
error: function (ret) {
|
||||
$("#loader_train").hide();
|
||||
|
||||
// Prepare error message
|
||||
const errorMessage = $("#error_message_new_x_2");
|
||||
const errorMessageText = $("#error_message_text");
|
||||
let backendErrorMessage = "An error occurred."; // Default message
|
||||
|
||||
try {
|
||||
if (ret.responseJSON && ret.responseJSON.message) {
|
||||
backendErrorMessage = ret.responseJSON.message + ret.responseJSON.line;
|
||||
} else if (ret.responseText) {
|
||||
const parsedResponse = JSON.parse(ret.responseText);
|
||||
backendErrorMessage = parsedResponse.message || backendErrorMessage;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error parsing error response:", e);
|
||||
backendErrorMessage = ret.responseText || "Unknown error.";
|
||||
}
|
||||
|
||||
// Display error message and trigger modal
|
||||
errorMessageText.text(backendErrorMessage);
|
||||
errorMessage.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("discard-model").addEventListener("click", function () {
|
||||
// Append a confirmation message to the modal
|
||||
const modalBody = document.querySelector("#modelAnalysisModal .modal-body");
|
||||
const messageContainer = document.createElement("div");
|
||||
messageContainer.id = "discard-message";
|
||||
messageContainer.className = "alert"; // Bootstrap class for alert styles
|
||||
|
||||
// Add a message to confirm the user's decision
|
||||
messageContainer.classList.add("alert-warning");
|
||||
messageContainer.innerHTML = `
|
||||
<i class="fas fa-exclamation-triangle mr-2"></i>
|
||||
Are you sure you want to discard this model? This action cannot be undone.
|
||||
<div class="mt-3">
|
||||
<button id="confirm-discard" class="btn btn-danger btn-sm">Yes, Discard</button>
|
||||
<button id="cancel-discard" class="btn btn-secondary btn-sm">Cancel</button>
|
||||
</div>
|
||||
`;
|
||||
modalBody.appendChild(messageContainer);
|
||||
|
||||
// Add event listeners for confirm and cancel buttons
|
||||
document.getElementById("confirm-discard").addEventListener("click", function () {
|
||||
// Data to send in the AJAX request
|
||||
const data = { action: "discard_model" };
|
||||
|
||||
// Fetch CSRF token (assuming Django or similar framework)
|
||||
const csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||
|
||||
// Send AJAX POST request to the backend
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "", // Replace with your actual backend URL
|
||||
headers: { "X-CSRFToken": csrftoken }, // Include CSRF token
|
||||
data: data,
|
||||
success: function (response) {
|
||||
// Update the modal with a success message
|
||||
messageContainer.classList.remove("alert-warning");
|
||||
messageContainer.classList.add("alert-success");
|
||||
messageContainer.innerHTML = `
|
||||
<i class="fas fa-check-circle mr-2"></i>
|
||||
The model has been successfully discarded.
|
||||
`;
|
||||
|
||||
// Optionally close the modal after a delay
|
||||
setTimeout(() => {
|
||||
$("#modelAnalysisModal").modal("hide");
|
||||
// Optionally refresh the page or update UI
|
||||
// location.reload(); // Uncomment to refresh the page
|
||||
}, 2000);
|
||||
},
|
||||
error: function (xhr) {
|
||||
// Update the modal with an error message
|
||||
messageContainer.classList.remove("alert-warning");
|
||||
messageContainer.classList.add("alert-danger");
|
||||
const errorMessage = xhr.responseJSON?.message || "An error occurred while discarding the model.";
|
||||
messageContainer.innerHTML = `
|
||||
<i class="fas fa-times-circle mr-2"></i>
|
||||
Failed to discard the model: ${errorMessage}.
|
||||
`;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Cancel discard operation
|
||||
document.getElementById("cancel-discard").addEventListener("click", function () {
|
||||
// Remove the confirmation message
|
||||
modalBody.removeChild(messageContainer);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById("save-model").addEventListener("click", function () {
|
||||
// Get the modal body element
|
||||
const modalBody = document.querySelector("#modelAnalysisModal .modal-body");
|
||||
|
||||
// Create a confirmation message container
|
||||
const confirmationMessage = document.createElement("div");
|
||||
confirmationMessage.className = "alert alert-success mt-3"; // Bootstrap alert styles
|
||||
confirmationMessage.innerHTML = `
|
||||
<i class="fas fa-check-circle mr-2"></i>
|
||||
The model has been successfully saved!
|
||||
`;
|
||||
|
||||
// Clear existing content in the modal body (optional)
|
||||
modalBody.innerHTML = "";
|
||||
|
||||
// Append the confirmation message to the modal body
|
||||
modalBody.appendChild(confirmationMessage);
|
||||
|
||||
// Set a timeout to hide the modal after showing the message
|
||||
setTimeout(() => {
|
||||
$("#modelAnalysisModal").modal("hide");
|
||||
|
||||
// Optionally reset the modal body content after hiding
|
||||
setTimeout(() => {
|
||||
modalBody.innerHTML = `
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle mr-2"></i>
|
||||
After training your model/classifier, you should now decide whether to <strong>keep</strong> it or <strong>discard</strong> it based on its performance metrics and visualizations below.
|
||||
</div>
|
||||
<!-- Tabs Navigation and other content here -->
|
||||
`;
|
||||
}, 500); // Small delay to ensure the modal is fully hidden before resetting
|
||||
}, 2000); // Hide the modal after 2 seconds
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
|
@ -60,11 +60,11 @@
|
||||
<div class="card-body">
|
||||
{% csrf_token %}
|
||||
<p class="text-muted"><strong>Select a pre-trained model below to view its detailed analysis:</strong></p>
|
||||
<div id="pre_trained_models">
|
||||
<div id="radio_buttons">
|
||||
{% if not df_name %}
|
||||
<p class="text-muted">The available pre-trained models will show up here. You first need to <a href="/" class="text-primary">pick or upload a dataset</a>.</p>
|
||||
{% elif not available_pretrained_models_info %}
|
||||
<p class="text-danger">There are no available pre-trained models for <b>{{df_name}}</b>. Please <a href="/train.html" class="text-primary">train a model</a>.</p>
|
||||
<p class="text-danger">There are no available pre-trained models. Please <a href="/train.html" class="text-primary">train a model</a>.</p>
|
||||
{% else %}
|
||||
{% for value, text in available_pretrained_models_info %}
|
||||
<div class="form-check py-1">
|
||||
@ -78,6 +78,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Figures Section: Classification, PCA, Feature Importance -->
|
||||
<div class="row" id="tab" style="display:none;">
|
||||
<div class="col-lg-12">
|
||||
@ -147,6 +148,28 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Minimal Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteFileModal" tabindex="-1" role="dialog" aria-labelledby="deleteFileModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content border-0 shadow-sm">
|
||||
<div class="modal-header border-0">
|
||||
<h6 class="modal-title text-danger" id="deleteFileModalLabel">Confirm Deletion</h6>
|
||||
<button type="button" class="close text-muted" data-dismiss="modal" aria-label="Close" style="font-size: 1.2rem;">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body text-center py-3">
|
||||
<p class="mb-1">Delete <span id="fileToDeleteName" class="font-weight-bold"></span> pre trained classifier on <span class="font-weight-bold"> {{ df_name }} </span> dataset?</p>
|
||||
<small class="text-muted">This action is permanent.</small>
|
||||
</div>
|
||||
<div class="modal-footer justify-content-center border-0">
|
||||
<button type="button" class="custom-btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="custom-btn-danger" id="confirmDeleteButton">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3" id="new_or_load">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div class="text-center mt-4 d-flex justify-content-center">
|
||||
|
@ -134,7 +134,7 @@
|
||||
<i class="fas fa-info-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-body" id="radio_buttons">
|
||||
{% csrf_token %}
|
||||
{% if not df_name %}
|
||||
<p class="text-muted">
|
||||
@ -195,13 +195,13 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="alert alert-warning text-center mb-0">No pre-computed experiments available.</div>
|
||||
<div class="alert alert-warning text-center mb-0" id="no-pre-computed">No pre-computed experiments available.</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal for Glacier Overview -->
|
||||
<div class="modal fade" id="glacierInfoModal" tabindex="-1" role="dialog" aria-labelledby="glacierInfoModalLabel" aria-hidden="true">
|
||||
@ -278,9 +278,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Column: New Experiment Details -->
|
||||
<div class="row" id="new_experiment_details" style="display:none;">
|
||||
<div class="col-xl-4 col-lg-4 mb-4" >
|
||||
<!-- <div class="row" id="new_experiment_details" style="display:none;" style="padding-top: 50px;">
|
||||
<div class="col-xl-4 col-lg-4 mb-4">
|
||||
<div class="card border-0 shadow-sm h-100">
|
||||
<div class="card-header bg-light text-dark py-3 d-flex justify-content-between align-items-center">
|
||||
<h6 class="m-0 font-weight-bold">New Experiment Details</h6>
|
||||
@ -299,7 +300,6 @@
|
||||
<input name="w_value" id="slider" type="range" min="0" max="1" step="0.1" class="w-100 mb-2">
|
||||
<output id="value" class="d-block text-center font-weight-bold"></output>
|
||||
|
||||
<!-- Run Experiment Button -->
|
||||
<div class="d-flex justify-content-center mt-4">
|
||||
<div id="error_message_new_x" class="alert alert-danger text-center" style="display: none; width: 100%; max-width: 400px;" role="alert">
|
||||
<i class="fas fa-exclamation-triangle"></i> Please correct errors before proceeding.
|
||||
@ -310,8 +310,75 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- Modal Structure -->
|
||||
<div class="modal fade" id="newExperimentModal" tabindex="-1" role="dialog" aria-labelledby="newExperimentModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content shadow-lg">
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="newExperimentModalLabel">New Experiment Details</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body p-4">
|
||||
<!-- Constraint Selection -->
|
||||
<div class="form-group mb-4">
|
||||
<label for="constraint" class="font-weight-bold text-muted">Constraint</label>
|
||||
<select required id="constraint" class="form-control" aria-describedby="constraintHelp">
|
||||
<option value="" disabled selected hidden>Select constraints for counterfactuals</option>
|
||||
<option value="unconstrained">Unconstrained</option>
|
||||
<option value="local">Local</option>
|
||||
<option value="global">Global</option>
|
||||
<option value="uniform">Uniform</option>
|
||||
</select>
|
||||
<small id="constraintHelp" class="form-text text-muted">Choose the type of constraint for the experiment.</small>
|
||||
</div>
|
||||
|
||||
<!-- Predicted Margin Weight -->
|
||||
<div class="form-group mb-4">
|
||||
<label for="slider" class="font-weight-bold text-muted">Predicted Margin Weight</label>
|
||||
<input name="w_value" id="slider" type="range" min="0" max="1" step="0.1" class="form-control-range">
|
||||
<output id="value" class="d-block text-center font-weight-bold mt-2">0.5</output>
|
||||
</div>
|
||||
|
||||
<!-- Error Message -->
|
||||
<div id="error_message_new_x" class="alert d-none" role="alert"></div>
|
||||
|
||||
<!-- Success Message -->
|
||||
<div id="success_message" class="alert alert-success d-none" role="alert"></div>
|
||||
|
||||
<!-- Run Experiment Button -->
|
||||
<div class="d-flex justify-content-center mt-4">
|
||||
<button class="btn btn-primary btn-lg compute_counterfactual d-flex align-items-center" id="cfbtn_2" role="button" name="cf">
|
||||
<i class="fas fa-play-circle mr-2"></i> Run New Experiment!
|
||||
</button>
|
||||
</div>
|
||||
<div class="row justify-content-center align-items-center my-4">
|
||||
<div id="cfbtn_loader_2" class="col-auto" style="display:none;">
|
||||
<div class="d-flex align-items-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm text-primary mr-2" role="status"></div>
|
||||
<span>Processing...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
// Update slider output dynamically
|
||||
const slider = document.getElementById("slider");
|
||||
const output = document.getElementById("value");
|
||||
slider.addEventListener("input", () => {
|
||||
output.textContent = slider.value;
|
||||
});
|
||||
</script>
|
||||
<!-- Optional Column: Class Label -->
|
||||
{% if dataset_type == "timeseries" %}
|
||||
<div class="row" id="class_label_container" style="display: none; padding-top: 70px;">
|
||||
@ -374,8 +441,12 @@
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-center mt-4">
|
||||
<div id="error_message_new_x_2" class="alert alert-danger text-center" style="display: none; width: 100%; max-width: 400px;" role="alert">
|
||||
<i class="fas fa-exclamation-triangle"></i> Please correct errors before proceeding.
|
||||
<div id="error_message_new_x_2" class="alert alert-danger alert-dismissible text-center" style="display: none; width: 100%; max-width: 400px;" role="alert">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span>Please correct errors before proceeding.</span>
|
||||
<button type="button" class="close" aria-label="Close" onclick="$('#error_message_new_x_2').hide();">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -6,128 +6,288 @@
|
||||
<!-- Main Content -->
|
||||
<div id="content">
|
||||
|
||||
<!-- Introduction Section with Collapsible Content -->
|
||||
<div id="home_intro" class="intro-section py-5 bg-light text-center">
|
||||
<div class="container">
|
||||
<h1 class="h3 text-dark mb-3">
|
||||
Welcome to <a href="https://datascience.dsv.su.se/projects/extremum.html" target="_blank" class="text-primary">Extremum Dashboard</a>
|
||||
<!-- Intro Section -->
|
||||
<div id="home_intro" class="intro-section py-5 text-center position-relative">
|
||||
<div class="container">
|
||||
<!-- Animated Background Graphics -->
|
||||
<div class="background-shape shape-1"></div>
|
||||
<div class="background-shape shape-2"></div>
|
||||
|
||||
<!-- Main Heading -->
|
||||
<div class="intro-content position-relative">
|
||||
<div class="logos d-flex justify-content-center align-items-center mb-4 fade-in">
|
||||
<img src="{% static 'img/su_logo.png' %}" alt="Stockholm University Logo" class="logo su-logo mx-3">
|
||||
<img src="{% static 'img/digital_features.png' %}" alt="Digital Features Logo" class="logo df-logo mx-3">
|
||||
</div>
|
||||
<h1 class="display-4 text-dark mb-4 fade-in">
|
||||
Welcome to the <a href="https://datascience.dsv.su.se/projects/extremum.html" target="_blank" class="text-primary">Extremum Dashboard</a>
|
||||
</h1>
|
||||
<p class="lead text-muted">An efficient way to explore health informatics and time-series datasets with ease.</p>
|
||||
<p class="lead text-muted fade-in mx-auto" style="max-width: 800px;">
|
||||
Your gateway to exploring health informatics and time-series datasets with ease.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Learn More Button with Expand/Collapse Functionality -->
|
||||
<button class="btn btn-outline-secondary mb-3" type="button" data-toggle="collapse" data-target="#introContent" aria-expanded="false" aria-controls="introContent" id="toggleIntro">
|
||||
<span class="mr-1">Read More</span>
|
||||
<i class="fas fa-chevron-down ml-2"></i>
|
||||
</button>
|
||||
|
||||
<!-- Collapsible Content for "Learn More" -->
|
||||
<div class="collapse" id="introContent">
|
||||
<p class="text-muted">
|
||||
The Extremum Dashboard supports researchers and data enthusiasts by providing tools for dataset selection, advanced visualization, and statistical analysis.
|
||||
<div class="about-project-section py-5 position-relative">
|
||||
<div class="container" style="padding-top:250px;">
|
||||
<!-- Main Section with Split Layout -->
|
||||
<div class="about-project-section py-5 position-relative fade-in">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<!-- Content Section -->
|
||||
<div class="col-lg-7">
|
||||
<h2 class="h4 text-dark mb-3 fade-in">About the Extremum Dashboard</h2>
|
||||
<p class="text-muted fade-in">
|
||||
The <strong>Extremum Dashboard</strong>, developed by <strong>Stockholm University</strong>, is part of the
|
||||
<a href="https://datascience.dsv.su.se/projects/extremum.html" target="_blank" class="text-primary">EXTREMUM project</a>. It combines advanced AI with ethical practices to improve healthcare outcomes.
|
||||
</p>
|
||||
<ul class="list-unstyled mt-4 fade-in">
|
||||
<li class="mb-3">
|
||||
<i class="fas fa-layer-group text-primary mr-2"></i>
|
||||
<strong>Unified Data Representation:</strong> Seamlessly integrate complex medical datasets.
|
||||
</li>
|
||||
<li class="mb-3">
|
||||
<i class="fas fa-brain text-success mr-2"></i>
|
||||
<strong>Explainable Predictive Models:</strong> Build AI solutions that are interpretable and reliable.
|
||||
</li>
|
||||
<li class="mb-3">
|
||||
<i class="fas fa-balance-scale text-warning mr-2"></i>
|
||||
<strong>Ethical Compliance:</strong> Ensure AI aligns with ethical and legal standards.
|
||||
</li>
|
||||
</ul>
|
||||
<button class="btn btn-primary rounded-pill px-4 mt-4 fade-in" type="button" data-toggle="collapse" data-target="#extremumDetails" aria-expanded="false" aria-controls="extremumDetails">
|
||||
Learn More <i class="fas fa-chevron-down ml-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Image Section -->
|
||||
<div class="col-lg-5 text-center">
|
||||
<img src="https://datascience.dsv.su.se/img/logo/dsgroup.png"
|
||||
alt="EXTREMUM Visualization"
|
||||
class="img-fluid rounded shadow-lg fade-in"
|
||||
loading="lazy"
|
||||
style="max-height: 250px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="collapse mt-4 fade-in" id="extremumDetails">
|
||||
<div class="text-muted mx-auto" style="max-width: 700px;">
|
||||
<h4 class="h5 text-dark text-center mb-3">About the EXTREMUM Project</h4>
|
||||
<p>
|
||||
The <strong>EXTREMUM Project</strong> focuses on developing an explainable machine learning platform to analyze complex medical data. It addresses two key healthcare areas:
|
||||
</p>
|
||||
<ul class="list-unstyled text-left mx-auto" style="max-width: 600px;">
|
||||
<li><i class="fas fa-database text-primary mr-2"></i><strong>Dataset Selection:</strong> Choose from preloaded datasets or upload your own for tailored analysis.</li>
|
||||
<li><i class="fas fa-chart-line text-success mr-2"></i><strong>Timeseries Analysis:</strong> Explore timeseries datasets with customizable parameters and statistical insights.</li>
|
||||
<li><i class="fas fa-eye text-info mr-2"></i><strong>Interactive Visualization:</strong> View tabular data and statistical insights with interactive graphs.</li>
|
||||
<ul class="list-unstyled text-center my-4">
|
||||
<li class="mb-3">
|
||||
<i class="fas fa-heartbeat text-danger"></i>
|
||||
<span class="ml-2">Adverse Drug Event Detection</span>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fas fa-stethoscope text-info"></i>
|
||||
<span class="ml-2">Cardiovascular Disease Detection</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="text-muted">This platform turns data into actionable insights effortlessly!</p>
|
||||
<p>
|
||||
This project integrates medical data sources, builds interpretable predictive models, and ensures ethical integrity in machine learning.
|
||||
</p>
|
||||
<p class="text-center">
|
||||
<a href="https://datascience.dsv.su.se/projects/extremum.html" target="_blank" class="btn btn-outline-primary rounded-pill">
|
||||
Learn More
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Feature Carousel Section -->
|
||||
<div class="feature-carousel py-5 bg-light mt-5 fade-in">
|
||||
<div class="container">
|
||||
<h3 class="h4 text-dark text-center mb-4">Key Innovations in EXTREMUM</h3>
|
||||
<p class="text-muted text-center mx-auto mb-5" style="max-width: 700px;">
|
||||
Discover the powerful tools and methodologies developed under the EXTREMUM project, designed to revolutionize explainable AI for healthcare applications.
|
||||
</p>
|
||||
<div id="carouselFeatures" class="carousel slide" data-ride="carousel" data-interval="5000" data-pause="hover">
|
||||
<ol class="carousel-indicators">
|
||||
<li data-target="#carouselFeatures" data-slide-to="0" class="active" tabindex="0" aria-label="Feature 1"></li>
|
||||
<li data-target="#carouselFeatures" data-slide-to="1" tabindex="0" aria-label="Feature 2"></li>
|
||||
</ol>
|
||||
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active">
|
||||
<div class="feature-card p-5 shadow rounded text-center">
|
||||
<i class="fas fa-wave-square text-info fa-3x mb-4"></i>
|
||||
<h5 class="text-dark">Wildboar</h5>
|
||||
<p class="text-muted">
|
||||
Created by <strong>Isak Samsten</strong>, Wildboar is a Python library for temporal machine learning, offering tools for classification, regression, and explainability.
|
||||
</p>
|
||||
<a href="https://github.com/wildboar-foundation/wildboar" target="_blank" class="btn btn-primary rounded-pill px-4 py-2 mt-3">
|
||||
Learn More <i class="fas fa-external-link-alt ml-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="carousel-item">
|
||||
<div class="feature-card p-5 shadow rounded text-center">
|
||||
<i class="fas fa-snowflake text-primary fa-3x mb-4"></i>
|
||||
<h5 class="text-dark">Glacier</h5>
|
||||
<p class="text-muted">
|
||||
Developed by <strong>Zhendong Wang</strong>, Glacier generates counterfactual explanations for time series classification, ensuring realistic and interpretable results.
|
||||
</p>
|
||||
<a href="https://github.com/zhendong3wang/learning-time-series-counterfactuals" target="_blank" class="btn btn-primary rounded-pill px-4 py-2 mt-3">
|
||||
Learn More <i class="fas fa-external-link-alt ml-2"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="carousel-control-prev" href="#carouselFeatures" role="button" data-slide="prev">
|
||||
<span class="carousel-control-prev-icon bg-dark rounded-circle p-2" aria-hidden="true"></span>
|
||||
<span class="sr-only">Previous</span>
|
||||
</a>
|
||||
<a class="carousel-control-next" href="#carouselFeatures" role="button" data-slide="next">
|
||||
<span class="carousel-control-next-icon bg-dark rounded-circle p-2" aria-hidden="true"></span>
|
||||
<span class="sr-only">Next</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- New Key Features or Benefits Section -->
|
||||
<div class="key-features-section py-5 text-center bg-white">
|
||||
|
||||
<div>
|
||||
<!-- Call to Action Section -->
|
||||
<div class="separator-section py-5 text-center bg-light">
|
||||
<div class="container">
|
||||
<h2 class="h4 text-gray-800 mb-4">Why Use Extremum Dashboard?</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="feature-card border-0 p-3 shadow-sm animate-card">
|
||||
<i class="fas fa-bolt text-primary fa-2x mb-3"></i>
|
||||
<h5 class="text-dark">Fast & Efficient</h5>
|
||||
<p class="text-muted">Quickly analyze large datasets with optimized performance and get insights in seconds.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="feature-card border-0 p-3 shadow-sm animate-card">
|
||||
<i class="fas fa-chart-pie text-success fa-2x mb-3"></i>
|
||||
<h5 class="text-dark">Comprehensive Visualizations</h5>
|
||||
<p class="text-muted">Access a wide range of visualizations to understand your data better.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="feature-card border-0 p-3 shadow-sm animate-card">
|
||||
<i class="fas fa-lock text-info fa-2x mb-3"></i>
|
||||
<h5 class="text-dark">Secure & Reliable</h5>
|
||||
<p class="text-muted">Your data is safe with us, with top-notch security measures in place.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="h5 text-dark mb-4 fade-in">Ready to start your journey?</h3>
|
||||
<button class="btn btn-outline-primary fade-in" onclick="document.getElementById('dataset_selection').scrollIntoView({behavior: 'smooth'})">
|
||||
Explore Datasets <i class="fas fa-arrow-down ml-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Separator Section with Interactive Scroll Button -->
|
||||
<div class="separator-section py-4 text-center">
|
||||
<hr class="w-50 mx-auto mb-4">
|
||||
<button class="btn btn-primary btn-lg" onclick="document.getElementById('dataset_selection').scrollIntoView({behavior: 'smooth'})">
|
||||
Start Exploring Datasets
|
||||
<i class="fas fa-arrow-down ml-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="cool-separator my-5">
|
||||
<hr>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- Page Heading -->
|
||||
<!-- Combined Heading and Button Group for Dataset Selection -->
|
||||
<div class="text-center mb-5" style="padding-top:250px;">
|
||||
<h2 id="dataset_selection" class="h4 mb-4 text-dark">Choose a Dataset</h2>
|
||||
|
||||
<!-- Dataset Selection Button Group -->
|
||||
<div class="row justify-content-center">
|
||||
<!-- Combined Heading and Button Group for Dataset Selection -->
|
||||
<style>
|
||||
/* Section Styling */
|
||||
.dataset-section {
|
||||
padding: 100px 20px;
|
||||
background-color: #f8f9fa;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dataset-section h2 {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.dataset-section p {
|
||||
font-size: 0.95rem;
|
||||
color: #666;
|
||||
margin-bottom: 2rem;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Button Styling */
|
||||
.btn-dataset {
|
||||
font-size: 1rem;
|
||||
font-weight: 500;
|
||||
border: 1px solid #ccc;
|
||||
color: #333;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 12px 20px;
|
||||
margin: 10px;
|
||||
transition: all 0.2s ease;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.btn-dataset:hover {
|
||||
border-color: #007bff;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.btn-dataset.active {
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border-color: #007bff;
|
||||
}
|
||||
|
||||
/* Responsive Alignment */
|
||||
.dataset-section .row {
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.btn-dataset {
|
||||
width: 180px;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="dataset-section" style="padding-top:300px;">
|
||||
<!-- Title -->
|
||||
<h2 id="dataset_selection">Choose Your Dataset</h2>
|
||||
<p>
|
||||
Select a dataset to visualize its graphs and perform advanced operations like using pre-trained models
|
||||
or computing counterfactuals. Your choice will be used throughout the session.
|
||||
</p>
|
||||
|
||||
<!-- Dataset Selection Buttons -->
|
||||
<div class="row">
|
||||
{% csrf_token %}
|
||||
|
||||
|
||||
<!-- Breast Cancer Dataset -->
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-dataset px-4 py-2 mb-2 {% if df_name == 'breast-cancer' %}active{% endif %}" id="breast-cancer">
|
||||
<i class="fas fa-dna"></i> Breast Cancer
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-dataset {% if df_name == 'breast-cancer' %}active{% endif %}" id="breast-cancer">
|
||||
Breast Cancer
|
||||
</button>
|
||||
|
||||
<!-- Stroke Dataset -->
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-dataset px-4 py-2 mb-2 {% if df_name == 'stroke' %}active{% endif %}" id="stroke">
|
||||
<i class="fas fa-heartbeat"></i> Stroke
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-dataset {% if df_name == 'stroke' %}active{% endif %}" id="stroke">
|
||||
Stroke
|
||||
</button>
|
||||
|
||||
<!-- Timeseries Dataset -->
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-dataset px-4 py-2 mb-2 {% if dataset_type == 'timeseries' %}active{% endif %}" id="timeseries">
|
||||
<i class="fas fa-chart-line"></i> Timeseries
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="btn btn-dataset {% if dataset_type == 'timeseries' %}active{% endif %}" id="timeseries">
|
||||
Timeseries
|
||||
</button>
|
||||
|
||||
<!-- Upload Dataset -->
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-dataset px-4 py-2 mb-2 {% if upload %}active{% endif %}" id="upload">
|
||||
<i class="fas fa-upload"></i> Upload
|
||||
</button>
|
||||
</div>
|
||||
<!-- Upload Dataset (Optional) -->
|
||||
<!-- Uncomment if needed
|
||||
<button type="button" class="btn btn-dataset {% if upload == 1 %}active{% endif %}" id="upload">
|
||||
Upload Dataset
|
||||
</button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Upload Form Section -->
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-xl-5 col-lg-5" id="upload_col" {% if upload %} style="display: block;" {% else %} style="display: none;" {% endif %}>
|
||||
<div class="card shadow-sm mb-4 border-0 animate-card">
|
||||
<div class="card-body">
|
||||
<!-- <div class="row justify-content-center">
|
||||
<div class="col-xl-5 col-lg-6" id="upload_col" {% if upload %} style="display: block;" {% else %} style="display: none;" {% endif %}>
|
||||
<div class="card shadow-sm border-0 animate-card">
|
||||
<div class="card-header bg-primary text-muted d-flex align-items-center">
|
||||
<h6 class="mb-0">Upload Dataset</h6>
|
||||
<i class="fas fa-upload ml-auto"></i>
|
||||
</div>
|
||||
<div class="card-body bg-light">
|
||||
<div class="row">
|
||||
<!-- Left Column: Form Section -->
|
||||
<div class="col-md-6">
|
||||
<div class="col-md-7 mb-4">
|
||||
<form id="csv_form" method="POST" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<fieldset class="form-group mb-3">
|
||||
|
||||
<fieldset class="form-group mb-4">
|
||||
<legend class="col-form-label small text-secondary font-weight-semibold">Data Type</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="dataset_type" id="tabular" value="tabular" required>
|
||||
@ -138,43 +298,81 @@
|
||||
<label class="form-check-label" for="timeseries">Timeseries</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="small text-secondary font-weight-semibold" for="doc">Upload File</label>
|
||||
|
||||
<div class="form-group mb-4">
|
||||
<label class="small text-secondary font-weight-semibold" for="doc">Select File</label>
|
||||
<input class="form-control-file" type="file" id="doc" name="excel_file" required>
|
||||
<small class="text-muted d-block mt-1">Supported format: CSV</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input class="btn btn-primary btn-sm mt-2" type="submit" value="Upload" id="upload_btn">
|
||||
|
||||
<div class="form-group d-flex align-items-center w-100">
|
||||
<input class="btn btn-primary btn-sm mr-3" type="submit" value="Upload" id="upload_btn">
|
||||
|
||||
<div class="loader" id="cfbtn_loader" style="display: none; margin-left: 5px;">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
</div>
|
||||
|
||||
<div id="success-message" class="alert alert-success custom-alert d-none ml-3 mb-0" role="alert">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span class="ml-2">File uploaded successfully.</span>
|
||||
<button type="button" class="close ml-auto p-0" aria-label="Close" onclick="hideSuccessMessage();">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Right Column: Uploaded Files Section -->
|
||||
<div class="col-md-6" id="uploaded_file">
|
||||
<fieldset class="form-group mb-3">
|
||||
|
||||
<div class="col-md-5 mb-5">
|
||||
<fieldset class="form-group mb-4">
|
||||
<legend class="col-form-label small text-secondary font-weight-semibold">Uploaded Files</legend>
|
||||
{% if uploaded_files %}
|
||||
<fieldset class="form-group">
|
||||
<fieldset class="form-group" id="radio_buttons">
|
||||
{% for uploaded_file in uploaded_files %}
|
||||
<div class="form-check mb-1">
|
||||
<input class="form-check-input" type="radio" name="uploaded_file" id="uploaded_file_{{ forloop.counter }}" value="{{ uploaded_file }}" required>
|
||||
<label class="form-check-label" for="uploaded_file_{{ forloop.counter }}">{{ uploaded_file }}</label>
|
||||
<div class="form-check mb-2 d-flex align-items-center">
|
||||
<input class="form-check-input mr-2" type="radio" {% if df_name == uploaded_file %} checked {% endif %} name="uploaded_file" id="element_{{ forloop.counter }}" value="{{ uploaded_file }}" required>
|
||||
<label class="form-check-label mr-auto" for="element_{{ forloop.counter }}">{{ uploaded_file }}</label>
|
||||
<button type="button" class="delete-file-icon p-0 ml-2 text-muted close" data-file="{{ uploaded_file }}" data-file-value="{{uploaded_file}}" aria-label="Delete {{ uploaded_file }}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</fieldset>
|
||||
{% else %}
|
||||
<p class="small text-muted">No files uploaded.</p>
|
||||
<p class="small text-muted">No files uploaded yet. Please upload a dataset to select it here.</p>
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-white text-center">
|
||||
<small class="text-muted">Manage your datasets effectively. Ensure data is accurate and up-to-date.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- Minimal Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteFileModal" tabindex="-1" role="dialog" aria-labelledby="deleteFileModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content border-0 shadow-sm">
|
||||
<div class="modal-header border-0">
|
||||
<h6 class="modal-title text-danger" id="deleteFileModalLabel">Confirm Deletion</h6>
|
||||
<button type="button" class="close text-muted" data-dismiss="modal" aria-label="Close" style="font-size: 1.2rem;">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body text-center py-3">
|
||||
<p class="mb-1">Delete <span id="fileToDeleteName" class="font-weight-bold"></span>?</p>
|
||||
<small class="text-muted">This action is permanent.</small>
|
||||
</div>
|
||||
<div class="modal-footer justify-content-center border-0">
|
||||
<button type="button" class="custom-btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="custom-btn-danger" id="confirmDeleteButton">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Timeseries Dataset Selection -->
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-5" {% if dataset_type != "timeseries" %} style="display:none;" {% endif %} id="timeseries-datasets">
|
||||
@ -269,7 +467,58 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Window -->
|
||||
<div class="modal fade" id="labelSelectionModal" tabindex="-1" aria-labelledby="labelSelectionModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="labelSelectionModalLabel">Assign Positive and Negative Labels</h5>
|
||||
</div>
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
{% csrf_token %}
|
||||
<p class="text-muted">Please assign one label as <strong>Positive</strong> and another as <strong>Negative</strong>.</p>
|
||||
<!-- Positive Label Dropdown -->
|
||||
<div class="form-group">
|
||||
<label for="positive-label" class="font-weight-semibold">Positive Label</label>
|
||||
<select id="positive-label" class="form-control">
|
||||
<option value="" disabled selected>Select a positive label</option>
|
||||
<!-- Options populated dynamically -->
|
||||
</select>
|
||||
</div>
|
||||
<!-- Negative Label Dropdown -->
|
||||
<div class="form-group mt-3">
|
||||
<label for="negative-label" class="font-weight-semibold">Negative Label</label>
|
||||
<select id="negative-label" class="form-control">
|
||||
<option value="" disabled selected>Select a negative label</option>
|
||||
<!-- Options populated dynamically -->
|
||||
</select>
|
||||
</div>
|
||||
<!-- Error Message -->
|
||||
<div id="selection-error" class="alert alert-danger d-none mt-3">
|
||||
<i class="fas fa-exclamation-triangle"></i> Labels must be different. Please select one positive and one negative label.
|
||||
</div>
|
||||
<!-- Loader -->
|
||||
<div id="loader" class="d-none text-center mt-3">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="sr-only">Loading...</span>
|
||||
</div>
|
||||
<p>Saving your choices...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" id="save-label-choices">Save Choices</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% if dataset_type == "tabular" and df_name and data_to_display %}
|
||||
|
||||
<div class="row mb-4">
|
||||
<!-- Data Card with Original ID -->
|
||||
<div class="col-lg-6" id="df_cached">
|
||||
@ -317,7 +566,20 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3" id="new_or_load_cached">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div class="text-center mt-4">
|
||||
<button id="viewModelsButton" class="btn btn-view-models">
|
||||
View Pre-trained Models
|
||||
<i class="fas fa-arrow-right ml-2"></i> <!-- Font Awesome icon for added appeal -->
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% elif dataset_type == "timeseries" %}
|
||||
|
||||
<div class="row mb-4">
|
||||
<!-- Confidence Interval Card with Original ID -->
|
||||
<div class="col-lg-6" id="ts_confidence_cached">
|
||||
@ -343,20 +605,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
<!-- Loader -->
|
||||
<div class="row">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<span class="loader" id="loader" style="display: none;"></span>
|
||||
<div class="row mt-3" id="new_or_load_cached">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div class="text-center mt-4">
|
||||
<button id="viewPreTrainedButton" class="btn btn-view-models">
|
||||
View Pre-trained Models
|
||||
<i class="fas fa-arrow-right ml-2"></i> <!-- Font Awesome icon for added appeal -->
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3" id="new_or_load">
|
||||
{% endif %}
|
||||
<!-- Loader -->
|
||||
<div class="d-flex justify-content-center">
|
||||
<span class="loader" id="loader_ds" style="display: none;"></span>
|
||||
</div>
|
||||
<div class="row mt-3" id="new_or_load" style="display:none;">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div class="text-center mt-4">
|
||||
<button id="viewModelsButton" class="btn btn-view-models">
|
||||
<button id="viewPreTrainedButton" class="btn btn-view-models">
|
||||
View Pre-trained Models
|
||||
<i class="fas fa-arrow-right ml-2"></i> <!-- Font Awesome icon for added appeal -->
|
||||
</button>
|
||||
@ -365,9 +634,6 @@
|
||||
</div>
|
||||
|
||||
<!-- JavaScript -->
|
||||
<script type="module" src="{% static 'js/radio_dataset.js' %}"></script>
|
||||
<script type="module" src="{% static 'js/selection_change.js' %}"></script>
|
||||
<script type="module" src="{% static 'js/radio_timeseries_dataset.js' %}"></script>
|
||||
<script type="module" src="{% static 'js/radio_uploaded_dataset.js' %}"></script>
|
||||
<script type="module" src="{% static 'js/home.js' %}"></script>
|
||||
|
||||
{% endblock content%}
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
<div class="row">
|
||||
{% if df_name %}
|
||||
<div class="col-xl-10 col-lg-10">
|
||||
<div class="col-xl-12 col-lg-12">
|
||||
<div class="card shadow-sm mb-4 border-0 animate-card">
|
||||
<div class="card-header bg-light text-dark py-3 d-flex flex-row align-items-center justify-content-between"> <!-- Softer background and font color -->
|
||||
<h6 class="m-0">DataFrame Summary Information</h6> <!-- Reduced emphasis -->
|
||||
@ -33,7 +33,6 @@
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xl-3 col-lg-3">
|
||||
<div class="py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<h6 class="m-0 text-muted">Classifier</h6> <!-- Text-muted for subtlety -->
|
||||
@ -63,7 +62,7 @@
|
||||
|
||||
<!-- Test set ratio slider -->
|
||||
<div class="row" style="padding-top:20px;">
|
||||
<div class="col-xl-6 col-lg-6" id="ratio" {% if dataset_type == "timeseries" %} style="display:none;" {% endif %}>
|
||||
<div class="col-xl-4 col-lg-4" id="ratio" {% if dataset_type == "timeseries" %} style="display:none;" {% endif %}>
|
||||
<div class="py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<h6 class="m-0 text-muted">Test Set Ratio</h6>
|
||||
</div>
|
||||
@ -71,7 +70,7 @@
|
||||
<output id="value"></output>
|
||||
</div>
|
||||
{% if dataset_type == "tabular" %}
|
||||
<div class="col-xl-4 col-lg-4" id="class_label" style="display:none;">
|
||||
<div class="col-xl-4 col-lg-4" id="class_label">
|
||||
<div class="py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<h6 class="m-0 text-muted">Class Label</h6>
|
||||
</div>
|
||||
@ -94,17 +93,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Action Button Section -->
|
||||
<div class="row justify-content-md-center" style="padding-top:30px;">
|
||||
{% csrf_token %}
|
||||
<button class="btn btn-outline-primary train_test" role="button" disabled>Go!</button> <!-- Outlined button for minimalistic style -->
|
||||
<div id="loader_train" style="display: none;">
|
||||
<div class="col-sm d-flex justify-content-center">
|
||||
<span class="loader"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -121,6 +110,142 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-4">
|
||||
<div id="error_message_new_x_2" class="alert alert-danger alert-dismissible text-center" style="display: none; width: 100%; max-width: 400px;" role="alert">
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
<span id="error_message_text">Please correct errors before proceeding.</span>
|
||||
<button type="button" class="close" aria-label="Close" onclick="$('#error_message_new_x_2').hide();">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modal Window -->
|
||||
<div class="modal fade" id="modelAnalysisModal" tabindex="-1" aria-labelledby="modelAnalysisModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<!-- Modal Header -->
|
||||
<div class="modal-header bg-light text-dark">
|
||||
<h5 class="modal-title" id="modelAnalysisModalLabel">Model Analysis and Decision</h5>
|
||||
</div>
|
||||
<!-- Modal Body -->
|
||||
<div class="modal-body">
|
||||
<!-- Prompt Message -->
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle mr-2"></i>
|
||||
After training your model/classifier, you should now decide whether to <strong>keep</strong> it or <strong>discard</strong> it based on its performance metrics and visualizations below.
|
||||
</div>
|
||||
|
||||
<!-- Tabs Navigation -->
|
||||
<ul class="nav nav-tabs" id="analysisTabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="classification-tab" data-toggle="tab" href="#classification" role="tab" aria-controls="classification" aria-selected="false">
|
||||
<i class="fas fa-chart-line mr-2"></i>Classification Report
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="details-tab" data-toggle="tab" href="#details" role="tab" aria-controls="details" aria-selected="false">
|
||||
<i class="fas fa-info-circle mr-2"></i>Classifier Details
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="pca-tab" data-toggle="tab" href="#pca" role="tab" aria-controls="pca" aria-selected="true">
|
||||
<i class="fas fa-project-diagram mr-2"></i>PCA
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" id="feature-tab-nav" style="display: none;">
|
||||
<a class="nav-link" id="fi-tab" data-toggle="tab" href="#feature" role="tab" aria-controls="feature" aria-selected="false">
|
||||
<i class="fas fa-th mr-2"></i>Feature Importance
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" id="tsne-tab-nav" style="display: none;">
|
||||
<a class="nav-link" id="tsne-tab" data-toggle="tab" href="#tsne" role="tab" aria-controls="tsne" aria-selected="true">
|
||||
<i class="fas fa-clone mr-2"></i>TSNE
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Tabs Content -->
|
||||
<div class="tab-content mt-3" id="analysisTabsContent">
|
||||
<!-- Classification Report Tab -->
|
||||
<div class="tab-pane fade" id="classification" role="tabpanel" aria-labelledby="classification-tab">
|
||||
<div id="classification_report" class="p-3"></div>
|
||||
</div>
|
||||
|
||||
<!-- Classifier Details Tab -->
|
||||
<div class="tab-pane fade" id="details" role="tabpanel" aria-labelledby="details-tab">
|
||||
<div id="details_content" class="p-3 overflow-auto"></div>
|
||||
</div>
|
||||
|
||||
<!-- PCA Tab -->
|
||||
<div class="tab-pane fade show active" id="pca" role="tabpanel" aria-labelledby="pca-tab">
|
||||
<div id="pca_container" class="p-3"></div>
|
||||
</div>
|
||||
|
||||
<!-- Feature Importance Tab -->
|
||||
<div class="tab-pane fade" id="feature" role="tabpanel" aria-labelledby="fi-tab">
|
||||
<div id="fi_container" class="p-3"></div>
|
||||
</div>
|
||||
|
||||
<!-- TSNE Tab -->
|
||||
<div class="tab-pane fade" id="tsne" role="tabpanel" aria-labelledby="tsne-tab">
|
||||
<div id="tsne_container" class="p-3"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% csrf_token %}
|
||||
|
||||
<!-- Modal Footer -->
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" id="save-model">
|
||||
<i class="fas fa-save mr-2"></i>Save Model
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger" id="discard-model">
|
||||
<i class="fas fa-trash-alt mr-2"></i>Discard Model
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center align-items-center my-4">
|
||||
<!-- CSRF Token -->
|
||||
{% csrf_token %}
|
||||
|
||||
<!-- Button -->
|
||||
<div class="col-auto" id="train_test_btn">
|
||||
<button class="btn btn-primary train_test align-items-center px-4 py-2 shadow-sm">
|
||||
<i class="fas fa-play mr-2"></i>
|
||||
Start Training
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Loader -->
|
||||
<div id="loader_train" class="col-auto d-none">
|
||||
<div class="d-flex align-items-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm text-primary mr-2" role="status"></div>
|
||||
<span>Processing...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3" id="new_or_load">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div class="text-center mt-4 d-flex justify-content-center">
|
||||
<!-- Back to Dataset Selection Button -->
|
||||
<button id="backToDatasetButton" class="btn btn-view-models mr-3">
|
||||
<i class="fas fa-arrow-left mr-2"></i> Back to Dataset Selection
|
||||
</button>
|
||||
|
||||
<!-- View Counterfactuals Button -->
|
||||
<button id="viewPreTrainedButton" class="btn btn-view-models">
|
||||
View Pre-Trained Models <i class="fas fa-arrow-right ml-2"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<script src="{% static 'js/slider.js' %}"></script>
|
||||
|
1515
base/views.py
1515
base/views.py
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user