42 Commits

Author SHA1 Message Date
Ricardo Montañana Gómez
765112073c Update README.md 2025-05-06 14:04:14 +02:00
69e21584bd Fix tests in python 3.13 2024-12-16 01:27:34 +01:00
419c899c94 Fix some errors in tests 2024-12-16 00:53:11 +01:00
2a2ed81a6c Fix Arff datasets mistake
Fix table_report partial mistake
2024-12-14 23:50:58 +01:00
4c5502611a Update version and copyright 2024-09-18 16:00:31 +02:00
Ricardo Montañana Gómez
70f1da5fc7 Merge pull request #10 from Doctorado-ML/flask
Flask
2024-03-13 16:18:55 +01:00
Ricardo Montañana Gómez
14dba5edb8 Merge branch 'main' into flask 2024-03-13 16:18:47 +01:00
a31d62263d Remove Bayesian classifiers 2024-03-13 16:16:35 +01:00
3f3a18e4fe Remove Bayesian Classifiers 2024-03-12 16:01:03 +01:00
6844d13973 Update format to report 2023-06-26 11:07:12 +02:00
4b17cc2230 Add boostAODE model 2023-06-26 10:09:01 +02:00
257cb8e95a Fix excel route in select 2023-06-02 16:51:19 +02:00
34b4cb6477 Add automatic download excel files 2023-06-01 20:48:53 +02:00
0b258595f9 Fix datasets 2023-06-01 11:44:03 +02:00
ff25581e99 Separate folders 2023-06-01 11:40:41 +02:00
aeec3a65af Fix checkboxes on change page 2023-06-01 01:49:23 +02:00
b7d26b82b1 flavour fix 2023-06-01 01:14:38 +02:00
f7ed11562b Add format to report_best 2023-06-01 01:11:06 +02:00
a51fed6281 Begin best results report 2023-05-31 23:30:51 +02:00
7d5f3058c3 add blueprint to app 2023-05-31 17:21:35 +02:00
54d141e861 Create separate app 2023-05-31 17:00:48 +02:00
04ea568c71 Refactor macros and font family 2023-05-31 14:29:25 +02:00
d8285eb2bb Add excel to report datasets 2023-05-31 01:35:40 +02:00
5f7fb7d5ac Begin add datasets report with excel 2023-05-30 17:04:33 +02:00
dd3cb91951 Fix compare problem in Excel files 2023-05-30 00:47:24 +02:00
40af738ed9 Add persistence of checkbox compare on app 2023-05-30 00:08:36 +02:00
10c352fdb5 Add double click to show file 2023-05-29 23:07:10 +02:00
1b362f2110 Add wait cursor during ajax 2023-05-29 22:37:05 +02:00
007c419979 Add generate excel fault tolerance with compare 2023-05-29 20:07:00 +02:00
2df055334c Add select all/none buttons with icons 2023-05-29 19:35:54 +02:00
395a64abb7 Add button reset and refactor buttons in select
Change position of excel button in report
2023-05-29 18:53:08 +02:00
8fe4b888b8 Add icons to actions 2023-05-29 16:47:03 +02:00
60086b3925 container-fluid and error tolerance in compare 2023-05-29 12:06:44 +02:00
c55a0b29ab Add compare with best results in reports 2023-05-29 11:50:49 +02:00
c2415576c9 Add excel to report 2023-05-28 23:14:14 +02:00
663a0b0258 Add select row to report 2023-05-28 20:06:33 +02:00
655c1db889 Fix row selection in bootstrap 2023-05-28 18:09:11 +02:00
e17e7d4e00 Generate excel file from results 2023-05-28 18:03:20 +02:00
be62e38e77 Add title and score to select page 2023-05-28 11:56:14 +02:00
83cfc3e5f5 Enhance report templates 2023-05-28 03:20:15 +02:00
3928b9c583 Change partials criteria 2023-05-28 03:12:12 +02:00
219b626061 Add flask templates 2023-05-28 00:04:30 +02:00
46 changed files with 1179 additions and 68 deletions

View File

@@ -1,7 +1,4 @@
[![CI](https://github.com/Doctorado-ML/benchmark/actions/workflows/main.yml/badge.svg)](https://github.com/Doctorado-ML/benchmark/actions/workflows/main.yml)
[![codecov](https://codecov.io/gh/Doctorado-ML/benchmark/branch/main/graph/badge.svg?token=ZRP937NDSG)](https://codecov.io/gh/Doctorado-ML/benchmark) [![codecov](https://codecov.io/gh/Doctorado-ML/benchmark/branch/main/graph/badge.svg?token=ZRP937NDSG)](https://codecov.io/gh/Doctorado-ML/benchmark)
[![Quality Gate Status](https://sonar.rmontanana.es/api/project_badges/measure?project=benchmark&metric=alert_status&token=336a6e501988888543c3153baa91bad4b9914dd2)](https://sonar.rmontanana.es/dashboard?id=benchmark)
[![Technical Debt](https://sonar.rmontanana.es/api/project_badges/measure?project=benchmark&metric=sqale_index&token=336a6e501988888543c3153baa91bad4b9914dd2)](https://sonar.rmontanana.es/dashboard?id=benchmark)
![https://img.shields.io/badge/python-3.8%2B-blue](https://img.shields.io/badge/python-3.8%2B-brightgreen) ![https://img.shields.io/badge/python-3.8%2B-blue](https://img.shields.io/badge/python-3.8%2B-brightgreen)
# benchmark # benchmark

View File

@@ -13,21 +13,27 @@ ALL_METRICS = (
class EnvData: class EnvData:
@staticmethod def __init__(self):
def load(): self.args = {}
args = {}
def load(self):
try: try:
with open(Files.dot_env) as f: with open(Files.dot_env) as f:
for line in f.read().splitlines(): for line in f.read().splitlines():
if line == "" or line.startswith("#"): if line == "" or line.startswith("#"):
continue continue
key, value = line.split("=") key, value = line.split("=")
args[key] = value self.args[key] = value
except FileNotFoundError: except FileNotFoundError:
print(NO_ENV, file=sys.stderr) print(NO_ENV, file=sys.stderr)
exit(1) exit(1)
else: else:
return args return self.args
def save(self):
with open(Files.dot_env, "w") as f:
for key, value in self.args.items():
f.write(f"{key}={value}\n")
class EnvDefault(argparse.Action): class EnvDefault(argparse.Action):
@@ -35,7 +41,7 @@ class EnvDefault(argparse.Action):
def __init__( def __init__(
self, envvar, required=True, default=None, mandatory=False, **kwargs self, envvar, required=True, default=None, mandatory=False, **kwargs
): ):
self._args = EnvData.load() self._args = EnvData().load()
self._overrides = {} self._overrides = {}
if required and not mandatory: if required and not mandatory:
default = self._args[envvar] default = self._args[envvar]
@@ -229,6 +235,19 @@ class Arguments(argparse.ArgumentParser):
"help": "number of folds", "help": "number of folds",
}, },
], ],
"output": [
("-o", "--output"),
{
"type": str,
"default": "local",
"choices": ["local", "docker"],
"required": False,
"help": (
"in be_flask tells if it is running in local or "
"in docker {local, docker}"
),
},
],
"platform": [ "platform": [
("-P", "--platform"), ("-P", "--platform"),
{ {

View File

@@ -32,6 +32,8 @@ class DatasetsArff:
def get_range_features(X, c_features): def get_range_features(X, c_features):
if c_features.strip() == "all": if c_features.strip() == "all":
return list(range(X.shape[1])) return list(range(X.shape[1]))
if c_features.strip() == "none":
return []
return json.loads(c_features) return json.loads(c_features)
def load(self, name, class_name): def load(self, name, class_name):
@@ -109,7 +111,7 @@ class DatasetsSurcov:
class Datasets: class Datasets:
def __init__(self, dataset_name=None, discretize=None): def __init__(self, dataset_name=None, discretize=None):
env_data = EnvData.load() env_data = EnvData().load()
# DatasetsSurcov, DatasetsTanveer, DatasetsArff,... # DatasetsSurcov, DatasetsTanveer, DatasetsArff,...
source_name = getattr( source_name = getattr(
__import__(__name__), __import__(__name__),
@@ -129,29 +131,28 @@ class Datasets:
def _init_names(self, dataset_name): def _init_names(self, dataset_name):
file_name = os.path.join(self.dataset.folder(), Files.index) file_name = os.path.join(self.dataset.folder(), Files.index)
default_class = "class"
self.continuous_features = {} self.continuous_features = {}
with open(file_name) as f: with open(file_name) as f:
sets = f.read().splitlines() sets = f.read().splitlines()
sets = [x for x in sets if not x.startswith("#")] sets = [x for x in sets if not x.startswith("#")]
class_names = [default_class] * len(sets) results = []
if "," in sets[0]:
result = []
class_names = [] class_names = []
for data in sets: for set_name in sets:
name, class_name, features = data.split(",", 2) try:
result.append(name) name, class_name, features = set_name.split(";")
except ValueError:
class_name = "class"
features = "all"
name = set_name
results.append(name)
class_names.append(class_name) class_names.append(class_name)
features = features.strip()
self.continuous_features[name] = features self.continuous_features[name] = features
sets = result
else:
for name in sets:
self.continuous_features[name] = None
# Set as dataset list the dataset passed as argument # Set as dataset list the dataset passed as argument
if dataset_name is None: if dataset_name is None:
return class_names, sets return class_names, results
try: try:
class_name = class_names[sets.index(dataset_name)] class_name = class_names[results.index(dataset_name)]
except ValueError: except ValueError:
raise ValueError(f"Unknown dataset: {dataset_name}") raise ValueError(f"Unknown dataset: {dataset_name}")
return [class_name], [dataset_name] return [class_name], [dataset_name]

View File

@@ -22,7 +22,7 @@ from .Arguments import EnvData
class Randomized: class Randomized:
@staticmethod @staticmethod
def seeds(): def seeds():
return json.loads(EnvData.load()["seeds"]) return json.loads(EnvData().load()["seeds"])
class BestResults: class BestResults:
@@ -117,7 +117,7 @@ class Experiment:
discretize=None, discretize=None,
folds=5, folds=5,
): ):
env_data = EnvData.load() env_data = EnvData().load()
today = datetime.now() today = datetime.now()
self.time = today.strftime("%H:%M:%S") self.time = today.strftime("%H:%M:%S")
self.date = today.strftime("%Y-%m-%d") self.date = today.strftime("%Y-%m-%d")

View File

@@ -8,7 +8,8 @@ from sklearn.ensemble import (
) )
from sklearn.svm import SVC from sklearn.svm import SVC
from stree import Stree from stree import Stree
from bayesclass.clfs import TAN, KDB, AODE, KDBNew, TANNew, AODENew
# from bayesclass.clfs import TAN, KDB, AODE, KDBNew, TANNew, AODENew, BoostAODE
from wodt import Wodt from wodt import Wodt
from odte import Odte from odte import Odte
from xgboost import XGBClassifier from xgboost import XGBClassifier
@@ -39,12 +40,13 @@ class Models:
def define_models(random_state): def define_models(random_state):
return { return {
"STree": Stree(random_state=random_state), "STree": Stree(random_state=random_state),
"TAN": TAN(random_state=random_state), # "TAN": TAN(random_state=random_state),
"KDB": KDB(k=2), # "KDB": KDB(k=2),
"TANNew": TANNew(random_state=random_state), # "TANNew": TANNew(random_state=random_state),
"KDBNew": KDBNew(k=2), # "KDBNew": KDBNew(k=2),
"AODENew": AODENew(random_state=random_state), # "AODENew": AODENew(random_state=random_state),
"AODE": AODE(random_state=random_state), # "AODE": AODE(random_state=random_state),
# "BoostAODE": BoostAODE(random_state=random_state),
"Cart": DecisionTreeClassifier(random_state=random_state), "Cart": DecisionTreeClassifier(random_state=random_state),
"ExtraTree": ExtraTreeClassifier(random_state=random_state), "ExtraTree": ExtraTreeClassifier(random_state=random_state),
"Wodt": Wodt(random_state=random_state), "Wodt": Wodt(random_state=random_state),

View File

@@ -71,7 +71,6 @@ class Report(BaseReport):
self._load_best_results( self._load_best_results(
self.data["score_name"], self.data["model"] self.data["score_name"], self.data["model"]
) )
self._compare_totals = {}
self.header_line("*") self.header_line("*")
self.header_line( self.header_line(
f" {self.data['model']} ver. {self.data['version']}" f" {self.data['model']} ver. {self.data['version']}"

View File

@@ -52,10 +52,11 @@ class BaseReport(abc.ABC):
self.score_name = self.data["score_name"] self.score_name = self.data["score_name"]
self.__load_env_data() self.__load_env_data()
self.__compute_best_results_ever() self.__compute_best_results_ever()
self._compare_totals = {}
def __load_env_data(self): def __load_env_data(self):
# Set the labels for nodes, leaves, depth # Set the labels for nodes, leaves, depth
env_data = EnvData.load() env_data = EnvData().load()
self.nodes_label = env_data["nodes"] self.nodes_label = env_data["nodes"]
self.leaves_label = env_data["leaves"] self.leaves_label = env_data["leaves"]
self.depth_label = env_data["depth"] self.depth_label = env_data["depth"]
@@ -107,10 +108,12 @@ class BaseReport(abc.ABC):
status = ( status = (
Symbols.cross Symbols.cross
if accuracy <= max_value if accuracy <= max_value
else Symbols.upward_arrow else (
Symbols.upward_arrow
if accuracy > max_value if accuracy > max_value
else " " else " "
) )
)
if status != " ": if status != " ":
if status not in self._compare_totals: if status not in self._compare_totals:
self._compare_totals[status] = 1 self._compare_totals[status] = 1
@@ -148,8 +151,11 @@ class BaseReport(abc.ABC):
class StubReport(BaseReport): class StubReport(BaseReport):
def __init__(self, file_name): def __init__(self, file_name, compare=False):
self.compare = compare
super().__init__(file_name=file_name, best_file=False) super().__init__(file_name=file_name, best_file=False)
if self.compare:
self._load_best_results(self.score_name, self.data["model"])
def print_line(self, line) -> None: def print_line(self, line) -> None:
pass pass
@@ -157,6 +163,11 @@ class StubReport(BaseReport):
def header(self) -> None: def header(self) -> None:
self.title = self.data["title"] self.title = self.data["title"]
self.duration = self.data["duration"] self.duration = self.data["duration"]
self.model = self.data["model"]
self.date = self.data["date"]
self.time = self.data["time"]
self.metric = self.data["score_name"]
self.platform = self.data["platform"]
def footer(self, accuracy: float) -> None: def footer(self, accuracy: float) -> None:
self.accuracy = accuracy self.accuracy = accuracy
@@ -165,7 +176,7 @@ class StubReport(BaseReport):
class Summary: class Summary:
def __init__(self, hidden=False, compare=False) -> None: def __init__(self, hidden=False, compare=False) -> None:
self.results = Files().get_all_results(hidden=hidden) self.results = Files.get_all_results(hidden=hidden)
self.data = [] self.data = []
self.data_filtered = [] self.data_filtered = []
self.datasets = {} self.datasets = {}
@@ -191,9 +202,11 @@ class Summary:
self.models.add(model) self.models.add(model)
report = StubReport( report = StubReport(
os.path.join( os.path.join(
(
Folders.hidden_results Folders.hidden_results
if self.hidden if self.hidden
else Folders.results, else Folders.results
),
result, result,
) )
) )

View File

@@ -299,11 +299,11 @@ class ReportDatasets:
color2 = "#FDE9D9" color2 = "#FDE9D9"
color3 = "#B1A0C7" color3 = "#B1A0C7"
def __init__(self, excel=False, book=None): def __init__(self, excel=False, book=None, output=True):
self.excel = excel self.excel = excel
self.env = EnvData().load() self.env = EnvData().load()
self.close = False self.close = False
self.output = True self.output = output
self.header_text = f"Datasets used in benchmark ver. {__version__}" self.header_text = f"Datasets used in benchmark ver. {__version__}"
if excel: if excel:
self.max_length = 0 self.max_length = 0
@@ -620,7 +620,7 @@ class Benchmark:
self.__compute_best_results_ever() self.__compute_best_results_ever()
def __compute_best_results_ever(self): def __compute_best_results_ever(self):
args = EnvData.load() args = EnvData().load()
key = args["source_data"] key = args["source_data"]
best = BestResultsEver() best = BestResultsEver()
_, self.best_score_value = best.get_name_value(key, self._score) _, self.best_score_value = best.get_name_value(key, self._score)

View File

@@ -15,6 +15,7 @@ class Folders:
img = "img" img = "img"
excel = "excel" excel = "excel"
sql = "sql" sql = "sql"
current = os.getcwd()
@staticmethod @staticmethod
def src(): def src():
@@ -108,7 +109,8 @@ class Files:
) )
return None return None
def get_all_results(self, hidden) -> list[str]: @staticmethod
def get_all_results(hidden) -> list[str]:
result_path = os.path.join( result_path = os.path.join(
".", Folders.hidden_results if hidden else Folders.results ".", Folders.hidden_results if hidden else Folders.results
) )
@@ -117,7 +119,7 @@ class Files:
else: else:
raise ValueError(f"{result_path} does not exist") raise ValueError(f"{result_path} does not exist")
result = [] result = []
prefix, suffix = self.results_suffixes() prefix, suffix = Files.results_suffixes()
for result_file in files_list: for result_file in files_list:
if result_file.startswith(prefix) and result_file.endswith(suffix): if result_file.startswith(prefix) and result_file.endswith(suffix):
result.append(result_file) result.append(result_file)

View File

@@ -10,7 +10,7 @@ from .Results import Report
from ._version import __version__ from ._version import __version__
__author__ = "Ricardo Montañana Gómez" __author__ = "Ricardo Montañana Gómez"
__copyright__ = "Copyright 2020-2023, Ricardo Montañana Gómez" __copyright__ = "Copyright 2020-2024, Ricardo Montañana Gómez"
__license__ = "MIT License" __license__ = "MIT License"
__author_email__ = "ricardo.montanana@alu.uclm.es" __author_email__ = "ricardo.montanana@alu.uclm.es"

View File

@@ -1 +1 @@
__version__ = "0.5.0" __version__ = "1.0.1"

View File

20
benchmark/scripts/app/app.py Executable file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/env python
from benchmark.Arguments import EnvData
from flask import Flask
from .main import main, OUTPUT
FRAMEWORK = "framework"
FRAMEWORKS = "frameworks"
TEST = "test"
def create_app(output="local"):
app = Flask(__name__)
config = EnvData().load()
app.register_blueprint(main)
app.config[FRAMEWORK] = config[FRAMEWORK]
app.config[FRAMEWORKS] = ["bootstrap", "bulma"]
app.config[OUTPUT] = output
app.jinja_env.auto_reload = True
app.config["TEMPLATES_AUTO_RELOAD"] = True
return app

210
benchmark/scripts/app/main.py Executable file
View File

@@ -0,0 +1,210 @@
#!/usr/bin/env python
import os
import json
import shutil
import xlsxwriter
from dotenv import dotenv_values
from benchmark.Utils import Files, Folders
from benchmark.Arguments import EnvData
from benchmark.ResultsBase import StubReport
from benchmark.ResultsFiles import Excel, ReportDatasets
from benchmark.Datasets import Datasets
from flask import Blueprint, current_app, send_file
from flask import render_template, request, redirect, url_for
main = Blueprint("main", __name__)
FRAMEWORK = "framework"
FRAMEWORKS = "frameworks"
OUTPUT = "output"
TEST = "test"
class AjaxResponse:
def __init__(self, success, file_name, code=200):
self.success = success
self.file_name = file_name
self.code = code
def to_string(self):
return (
json.dumps(
{
"success": self.success,
"file": self.file_name,
"output": current_app.config[OUTPUT],
}
),
self.code,
{"ContentType": "application/json"},
)
def process_data(file_name, compare, data):
report = StubReport(
os.path.join(Folders.results, file_name), compare=compare
)
new_list = []
for result in data["results"]:
symbol = report._compute_status(result["dataset"], result["score"])
result["symbol"] = symbol if symbol != " " else "&nbsp;"
new_list.append(result)
data["results"] = new_list
# Compute summary with explanation of symbols
summary = {}
for key, value in report._compare_totals.items():
summary[key] = (report._status_meaning(key), value)
return summary
@main.route("/index/<compare>")
@main.route("/")
def index(compare="False"):
# Get a list of files in a directory
files = {}
names = Files.get_all_results(hidden=False)
for name in names:
report = StubReport(os.path.join(Folders.results, name))
report.report()
files[name] = {
"duration": report.duration,
"score": report.score,
"title": report.title,
}
candidate = current_app.config[FRAMEWORKS].copy()
candidate.remove(current_app.config[FRAMEWORK])
return render_template(
"select.html",
files=files,
candidate=candidate[0],
framework=current_app.config[FRAMEWORK],
compare=compare.capitalize() == "True",
)
@main.route("/datasets/<compare>")
def datasets(compare):
dt = Datasets()
datos = []
for dataset in dt:
datos.append(dt.get_attributes(dataset))
return render_template(
"datasets.html",
datasets=datos,
compare=compare,
framework=current_app.config[FRAMEWORK],
)
@main.route("/showfile/<file_name>/<compare>")
def showfile(file_name, compare, back=None):
compare = compare.capitalize() == "True"
back = request.args["url"] if back is None else back
app_config = dotenv_values(".env")
with open(os.path.join(Folders.results, file_name)) as f:
data = json.load(f)
try:
summary = process_data(file_name, compare, data)
except Exception as e:
return render_template("error.html", message=str(e), compare=compare)
return render_template(
"report.html",
data=data,
file=file_name,
summary=summary,
framework=current_app.config[FRAMEWORK],
back=back,
app_config=app_config,
)
@main.route("/show", methods=["post"])
def show():
selected_file = request.form["selected-file"]
compare = request.form["compare"]
return showfile(
file_name=selected_file,
compare=compare,
back=url_for(
"main.index", compare=compare, output=current_app.config[OUTPUT]
),
)
@main.route("/excel", methods=["post"])
def excel():
selected_files = request.json["selectedFiles"]
compare = request.json["compare"]
book = None
if selected_files[0] == "datasets":
# Create a list of datasets
report = ReportDatasets(excel=True, output=False)
report.report()
excel_name = os.path.join(Folders.excel, Files.datasets_report_excel)
if current_app.config[OUTPUT] == "local":
Files.open(excel_name, test=current_app.config[TEST])
return AjaxResponse(True, Files.datasets_report_excel).to_string()
try:
for file_name in selected_files:
file_name_result = os.path.join(Folders.results, file_name)
if book is None:
file_excel = os.path.join(Folders.excel, Files.be_list_excel)
book = xlsxwriter.Workbook(
file_excel, {"nan_inf_to_errors": True}
)
excel = Excel(
file_name=file_name_result,
book=book,
compare=compare,
)
excel.report()
except Exception as e:
if book is not None:
book.close()
return AjaxResponse(
False, "Could not create excel file, " + str(e)
).to_string()
if book is not None:
book.close()
if current_app.config[OUTPUT] == "local":
Files.open(file_excel, test=current_app.config[TEST])
return AjaxResponse(True, Files.be_list_excel).to_string()
@main.route("/download/<file_name>")
def download(file_name):
src = os.path.join(Folders.current, Folders.excel, file_name)
dest = os.path.join(
Folders.src(), "scripts", "app", "static", "excel", file_name
)
shutil.copyfile(src, dest)
return send_file(dest, as_attachment=True)
@main.route("/config/<framework>/<compare>")
def config(framework, compare):
if framework not in current_app.config[FRAMEWORKS]:
message = f"framework {framework} not supported"
return render_template("error.html", message=message)
env = EnvData()
env.load()
env.args[FRAMEWORK] = framework
env.save()
current_app.config[FRAMEWORK] = framework
return redirect(url_for("main.index", compare=compare))
@main.route("/best_results/<file>/<compare>")
def best_results(file, compare):
compare = compare.capitalize() == "True"
try:
with open(os.path.join(Folders.results, file)) as f:
data = json.load(f)
except Exception as e:
return render_template("error.html", message=str(e), compare=compare)
return render_template(
"report_best.html",
data=data,
compare=compare,
framework=current_app.config[FRAMEWORK],
)

View File

@@ -0,0 +1,30 @@
.alternate-font {
font-family: Arial;
}
tbody {
font-family: Courier;
}
.tag {
cursor: pointer;
}
.ajaxLoading {
cursor: progress !important;
}
#file-table tbody tr.selected td {
background-color: #0dcaf0;
color: white;
}
#report-table tbody tr.selected td {
background-color: #0dcaf0;
color: white;
}
.btn-small {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
}

View File

@@ -0,0 +1 @@
*.xlsx

View File

@@ -0,0 +1,29 @@
function excelFiles(selectedFiles, compare) {
var data = {
"selectedFiles": selectedFiles,
"compare": compare
};
// send data to server with ajax post
$.ajax({
type:'POST',
url:'/excel',
data: JSON.stringify(data),
contentType: "application/json",
dataType: 'json',
success: function(data){
if (data.success) {
if (data.output == "local") {
alert("Se ha generado el archivo " + data.file);
} else {
window.open('/download/' + data.file, "_blank");
}
} else {
alert(data.file);
}
},
error: function (xhr, ajaxOptions, thrownError) {
var mensaje = JSON.parse(xhr.responseText || '{\"mensaje\": \"Error indeterminado\"}');
alert(mensaje.mensaje);
}
});
}

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous" />
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500,600" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.25/css/jquery.dataTables.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/MaterialDesign-Webfont/7.1.96/css/materialdesignicons.css" integrity="sha512-lD1LHcZ8tFHvMFNeo6qOLY/HjzSPCasPJOAoir22byDxlZI1R71S5lZel8zRL2TZ+Dut1wOHfYgSU2lHXuL00w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}" />
</head>
<body>
{% block content %}
{% endblock %}
</body>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
{% block jscript %}
{% endblock %}
</html>

View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.3/css/bulma.min.css" />
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.25/css/jquery.dataTables.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/MaterialDesign-Webfont/7.1.96/css/materialdesignicons.css" integrity="sha512-lD1LHcZ8tFHvMFNeo6qOLY/HjzSPCasPJOAoir22byDxlZI1R71S5lZel8zRL2TZ+Dut1wOHfYgSU2lHXuL00w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}" />
</head>
<body>
{% block content %}
{% endblock %}
</body>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
{% block jscript %}
{% endblock %}
</html>

View File

@@ -0,0 +1,68 @@
{% extends 'base_' ~ framework ~ '.html' %}
{% macro javascript(file) %}
<script src="{{ url_for('static', filename=file) }}"></script>
{% endmacro %}
{% if framework == 'bootstrap' %}
{% set button_class = 'btn btn-primary btn-small' %}
{% set h1_class = 'text-center' %}
{% set table_class = 'table table-striped table-hover table-bordered' %}
{% set head_class = 'bg-primary text-white' %}
{% set text_right = 'text-end' %}
{% set container = 'container' %}
{% set selected = 'selected' %}
{%- macro header(title, close, url) -%}
<div class="p-4 bg-primary text-white">
{%- if close -%}
<button type="button" class="btn-close" aria-label="Close" onclick="location.href = '{{ url }}'"></button>
{%- endif -%}
<h1 class="alternate-font">{{ title }}</h1>
</div>
{%- endmacro -%}
{% else %}
{% set button_class = 'button is-primary is-small' %}
{% set h1_class = 'title is-1 has-text-centered' %}
{% set table_class = 'table is-striped is-hoverable cell-border is-bordered' %}
{% set head_class = 'is-selected' %}
{% set text_right = 'has-text-right' %}
{% set container = 'container' %}
{% set selected = 'is-selected' %}
{%- macro header(title, close, url) -%}
<div class="hero is-info is-bold">
<div class="hero-body">
{%- if close -%}
<button class="delete is-large" onclick="location.href = '{{ url }}'"></button>
{%- endif -%}
<h1 class="is-size-3 alternate-font">{{ title }}</h1>
</div>
</div>
{%- endmacro -%}
{% endif %}
{% block content %}
<div class="{{ container }}">
{{ header('Benchmark Datasets Report', True, url_for('main.index', compare = compare)) }}
<button class="{{ button_class }}" onclick="excelFiles(['datasets'], false)"><i class="mdi mdi-file-excel"></i> Excel</button>
{% include 'partials/datasets_table.html' %}
</div>
{% endblock %}
{% block jscript %}
{{ javascript("js/excelFiles.js") }}
<script>
$(document).ready(function () {
$(document).ajaxStart(function(){
$("body").addClass('ajaxLoading');
});
$(document).ajaxStop(function(){
$("body").removeClass('ajaxLoading');
});
});
// Check if row is selected
$('#file-table tbody').on('click', 'tr', function () {
if ($(this).hasClass('{{ selected }}')) {
$(this).removeClass('{{ selected }}');
} else {
$('#file-table tbody tr.{{ selected }}').removeClass("{{ selected }}")
$(this).addClass('{{ selected }}');
}
});
</script>
{% endblock %}

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="alert alert-danger my-5" role="alert">
<h4 class="alert-heading"><button class="btn-close btn-sm" type="button"
onclick="location.href='/index/{{ compare }}';"></button>Error</h4>
<p>There was an error processing action, {{ message }}. Please try again later.</p>
<hr>
<p class="mb-0">If the problem persists, please contact support.</p>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,22 @@
$(document).ready(function () {
// Check if row is selected
$('#report-table tbody').on('click', 'tr', function () {
if ($(this).hasClass('{{ selected }}')) {
$(this).removeClass('{{ selected }}');
} else {
$('#report-table tbody tr.{{ selected }}').removeClass("{{ selected }}")
$(this).addClass('{{ selected }}');
}
});
$(document).ajaxStart(function(){
$("body").addClass('ajaxLoading');
});
$(document).ajaxStop(function(){
$("body").removeClass('ajaxLoading');
});
});
function excelFile() {
var selectedFiles = ["{{ file }}"];
var compare = "{{ compare }}" == "True";
excelFiles(selectedFiles, compare)
}

View File

@@ -0,0 +1,97 @@
$(document).ready(function () {
var table = $("#file-table").DataTable({
paging: true,
searching: true,
ordering: true,
info: true,
"select.items": "row",
pageLength: 25,
columnDefs: [
{
targets: 8,
orderable: false,
},
],
//"language": {
// "lengthMenu": "_MENU_"
//}
});
$('#file-table').on( 'draw.dt', function () {
enable_disable_best_buttons();
} );
// Check if row is selected
$("#file-table tbody").on("click", "tr", function () {
if ($(this).hasClass("{{ select.selected() }}")) {
$(this).removeClass("{{ select.selected() }}");
} else {
table
.$("tr.{{ select.selected() }}")
.removeClass("{{ select.selected() }}");
$(this).addClass("{{ select.selected() }}");
}
});
// Show file with doubleclick
$("#file-table tbody").on("dblclick", "tr", function () {
showFile($(this).attr("id"));
});
$(document).ajaxStart(function () {
$("body").addClass("ajaxLoading");
});
$(document).ajaxStop(function () {
$("body").removeClass("ajaxLoading");
});
$('#compare').change(function() {
enable_disable_best_buttons();
});
enable_disable_best_buttons();
});
function enable_disable_best_buttons(){
if ($('#compare').is(':checked')) {
$("[name='best_buttons']").addClass("tag is-link is-normal");
$("[name='best_buttons']").removeAttr("hidden");
} else {
$("[name='best_buttons']").removeClass("tag is-link is-normal");
$("[name='best_buttons']").attr("hidden", true);
}
}
function showFile(selectedFile) {
var form = $(
'<form action="/show" method="post">' +
'<input type="hidden" name="selected-file" value="' +
selectedFile +
'" />' +
'<input type="hidden" name="compare" value=' +
$("#compare").is(":checked") +
" />" +
"</form>"
);
$("body").append(form);
form.submit();
}
function excel() {
var checkbox = document.getElementsByName("selected_files");
var selectedFiles = [];
for (var i = 0; i < checkbox.length; i++) {
if (checkbox[i].checked) {
selectedFiles.push(checkbox[i].value);
}
}
if (selectedFiles.length == 0) {
alert("Select at least one file");
return;
}
var compare = $("#compare").is(":checked");
excelFiles(selectedFiles, compare);
}
function setCheckBoxes(value) {
var checkbox = document.getElementsByName("selected_files");
for (i = 0; i < checkbox.length; i++) {
checkbox[i].checked = value;
}
}
function redirectDouble(route, parameter) {
location.href = "/"+ route + "/" + parameter + "/" + $("#compare").is(":checked");
}
function redirectSimple(route) {
location.href = "/" + route + "/" + $("#compare").is(":checked");
}

View File

@@ -0,0 +1,56 @@
{%- macro header(title, close=False, url="") -%}
<div class="p-4 bg-primary text-white">
{%- if close -%}
<button type="button" class="btn-close" aria-label="Close" onclick="location.href = '{{url}}'"></button>
{%- endif -%}
<h1 class="alternate-font">{{ title }}</h1>
</div>
{%- endmacro -%}
{%- macro get_table_class() -%}
table table-striped table-hover table-bordered
{%- endmacro -%}
{%- macro icon(icon_name) -%}
<i class="mdi mdi-{{icon_name}}"></i>
{%- endmacro -%}
{%- macro get_button(text, action) -%}
<button class="btn btn-primary btn-small" onclick="{{ action }}">{{ text|safe }}</button>
{%- endmacro -%}
{%- macro get_button_class() -%}
button btn-primary btn-small
{%- endmacro %}
{%- macro get_button_tag(icon_name, method, visible=True, name="") -%}
<button class="btn btn-primary btn-small" onclick="{{ method }}" {{ "" if visible else "hidden='true'" }} {{ "" if name=="" else "name='" + name +"'"}}><i class="mdi mdi-{{ icon_name }}"></i></button>
{%- endmacro -%}
{%- macro get_button_reset() -%}
<button class="btn btn-primary btn-small btn-danger" onclick="setCheckBoxes(false)"><i class="mdi mdi-checkbox-multiple-blank"></i></button>
{%- endmacro -%}
{%- macro get_button_all() -%}
<button class="btn btn-primary btn-small btn-success" onclick="setCheckBoxes(true)"><i class="mdi mdi-checkbox-multiple-marked"></i></button>
{%- endmacro -%}
{%- macro get_tag_class() -%}
badge bg-info bg-small
{%- endmacro -%}
{%- macro get_container_class() -%}
container-fluid
{%- endmacro -%}
{%- macro selected() -%}
selected
{%- endmacro -%}
{%- macro get_level_class() -%}
navbar
{%- endmacro -%}
{%- macro get_align_right() -%}
text-end
{%- endmacro -%}
{%- macro get_left_position() -%}
float-left
{%- endmacro -%}
{%- macro get_right_position() -%}
float-right
{%- endmacro -%}
{%- macro get_row_head_class() -%}
bg-primary text-white
{%- endmacro -%}
{%- macro get_align_center() -%}
text-center
{%- endmacro -%}

View File

@@ -0,0 +1,58 @@
{%- macro header(title, close=False, url="") -%}
<div class="hero is-info is-bold">
<div class="hero-body">
{%- if close -%}
<button class="delete is-large" onclick="location.href = '{{ url }}'"></button>
{%- endif -%}
<h1 class="is-size-3 alternate-font">{{ title }}</h1>
</div>
</div>
{%- endmacro -%}
{%- macro get_table_class() -%}
table is-striped is-hoverable cell-border is-bordered
{%- endmacro -%}
{%- macro icon(icon_name) -%}
<i class="mdi mdi-{{icon_name}}"></i>
{%- endmacro -%}
{%- macro get_button(text, action) -%}
<button class="button is-primary is-small" onclick="{{ action }}">{{ text|safe }}</button>
{%- endmacro -%}
{%- macro get_button_tag(icon_name, method, visible=True, name="") -%}
<span class="{{ "tag is-link is-normal" if visible else "" }}" type="button" onclick="{{ method }}" {{ "" if visible else "hidden='true'" }} {{ "" if name=="" else "name='" + name +"'"}}>{{icon(icon_name)}}</span>
{%- endmacro -%}
{%- macro get_button_reset() -%}
<span class="tag is-link is-danger" type="button" onclick="setCheckBoxes(false)"><i class="mdi mdi-checkbox-multiple-blank"></i></span>
{%- endmacro -%}
{%- macro get_button_all() -%}
<span class="tag is-link is-success" type="button" onclick="setCheckBoxes(true)"><i class="mdi mdi-checkbox-multiple-marked"></i></span>
{%- endmacro -%}
{%- macro get_tag_class() -%}
tag is-info is-small
{%- endmacro -%}
{%- macro get_container_class() -%}
container is-fluid
{%- endmacro -%}
{%- macro selected() -%}
is-selected
{%- endmacro -%}
{%- macro get_level_class() -%}
level
{%- endmacro -%}
{%- macro get_align_right() -%}
has-text-right
{%- endmacro -%}
{%- macro get_align_center() -%}
has-text-center
{%- endmacro -%}
{%- macro get_left_position() -%}
float-left
{%- endmacro -%}
{%- macro get_right_position() -%}
float-right
{%- endmacro -%}
{%- macro get_row_head_class() -%}
is-selected
{%- endmacro -%}
{%- macro get_align_center() -%}
has-text-center
{%- endmacro -%}

View File

@@ -0,0 +1,27 @@
{% extends "base_" ~ framework ~ ".html" %}
{% block content %}
<table id="file-table" class="{{ table_class }}">
<thead>
<tr class="{{ head_class }}">
<th class="{{ text_center }}">Dataset</th>
<th class="{{ text_center }}">Samples</th>
<th class="{{ text_center }}">Features</th>
<th class="{{ text_center }}">Cont. Feat.</th>
<th class="{{ text_center }}">Classes</th>
<th class="{{ text_center }}">Balance</th>
</tr>
</thead>
<tbody>
{% for dataset in datasets %}
<tr>
<td>{{ dataset.dataset }}</td>
<td class="{{ text_right }}">{{ "{:,}".format(dataset.samples) }}</td>
<td class="{{ text_right }}">{{ "{:,}".format(dataset.features) }}</td>
<td class="{{ text_right }}">{{ dataset.cont_features }}</td>
<td class="{{ text_right }}">{{ dataset.classes }}</td>
<td>{{ dataset.balance }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,14 @@
{% for item in data.results %}
<tr>
<td>{{ item.dataset }}</td>
<td class="{{ right }}">{{ '{:,}'.format(item.samples) }}</td>
<td class="{{ right }}">{{"%d" % item.features}}</td>
<td class="{{ right }}">{{"%d" % item.classes}}</td>
<td class="{{ right }}">{{ '{:,.2f}'.format(item.nodes|float) }}</td>
<td class="{{ right }}">{{ '{:,.2f}'.format(item.leaves|float) }}</td>
<td class="{{ right }}">{{ '{:,.2f}'.format(item.depth|float) }}</td>
<td class="{{ right }}">{{"%.6f±%.4f" % (item.score, item.score_std)}} {{ item.symbol|safe }}</td>
<td class="{{ right }}">{{"%.6f±%.4f" % (item.time, item.time_std)}}</td>
<td class="{{ center }}">{{ item.hyperparameters }}</td>
</tr>
{% endfor %}

View File

@@ -0,0 +1,102 @@
<div id="app">
<section class="section">
<div class="container-fluid">
<div class="p-4 bg-primary text-white">
<button type="button"
class="btn-close"
aria-label="Close"
onclick="location.href = '{{ back }}'"></button>
<h1>{{ data.title }}</h1>
</div>
<div>
<table class="table table-bordered">
<thead>
<tr class="bg-info text-white">
<th class="text-center">Platform</th>
<th class="text-center">Model</th>
<th class="text-center">Date</th>
<th class="text-center">Time</th>
{% if data.duration > 7200 %}
{% set unit = "h" %}
{% set divider = 3600 %}
{% else %}
{% set unit = "min" %}
{% set divider = 60 %}
{% endif %}
<th class="text-center">Duration ({{ unit }})</th>
<th class="text-center">Stratified</th>
<th class="text-center">Discretized</th>
<th class="text-center"># Folds</th>
</tr>
<tr>
<th class="text-center">{{ data.platform }}</th>
<th class="text-center">{{ data.model }} {{ data.version }}</th>
<th class="text-center">{{ data.date }}</th>
<th class="text-center">{{ data.time }}</th>
<th class="text-center">{{ "%.2f" % (data.duration/divider) }}</th>
<th class="text-center">{{ data.stratified }}</th>
<th class="text-center">{{ data.discretized }}</th>
<th class="text-center">{{ data.folds }}</th>
</tr>
<tr>
<th class="text-center bg-info text-white">Language</th>
<th class="text-center" colspan=3>{{ data.language }} {{ data.language_version }}</th>
<th class="text-center bg-info text-white">Seeds</th>
<th class="text-center" colspan=6>{{ data.seeds }}</th>
</tr>
</thead>
</table>
<div>
<button class="{{ button }}" onclick="excelFile()">
<i class="mdi mdi-file-excel"></i> Excel
</button>
</div>
<table id="report-table"
class="table table-striped table-hover table-bordered">
<thead>
<tr class="bg-primary text-white">
<th class="text-center">Dataset</th>
<th class="text-center">Samples</th>
<th class="text-center">Features</th>
<th class="text-center">Classes</th>
<th class="text-center">{{ app_config.nodes }}</th>
<th class="text-center">{{ app_config.leaves }}</th>
<th class="text-center">{{ app_config.depth }}</th>
<th class="text-center">{{ data.score_name|capitalize }}</th>
<th class="text-center">Time</th>
<th class="text-center">hyperparameters</th>
</tr>
</thead>
<tbody>
{% include "partials/table_report.html" %}
</tbody>
</table>
{% if summary|length > 0 %}
<div class="col-4 col-lg-4">
<table class="table table-bordered">
<thead>
<tr>
<th class="text-center bg-primary text-white">Symbol</th>
<th class="text-center bg-primary text-white">Meaning</th>
<th class="text-center bg-primary text-white">Count</th>
</tr>
</thead>
{% include "partials/table_summary.html" %}
</table>
</div>
{% endif %}
<button type="button"
class="btn-close"
aria-label="Close"
onclick="location.href = '{{ back }}'"></button>
<h7>
<b>
Total score: {{ "%.6f" % (data.results | sum(attribute="score") ) }}
</b>
</h7>
<h7>
Number of files: {{ data.results | length }}
</h7>
</div>
</section>
</div>

View File

@@ -0,0 +1,100 @@
<div id="app">
<header>
<div class="container is-fluid">
<div class="hero is-info is-bold">
<div class="hero-body">
<button class="delete is-large" onclick="location.href = '{{ back }}'"></button>
<h1 class="is-size-3">{{ data.title }}</h1>
</div>
</div>
</div>
</header>
<section class="section">
<div class="container is-fluid">
<div>
<table class="table is-fullwidth is-striped is-bordered">
<thead>
<tr class="is-selected">
<th class="has-text-centered">Platform</th>
<th class="has-text-centered">Model</th>
<th class="has-text-centered">Date</th>
<th class="has-text-centered">Time</th>
{% if data.duration > 7200 %}
{% set unit = "h" %}
{% set divider = 3600 %}
{% else %}
{% set unit = "min" %}
{% set divider = 60 %}
{% endif %}
<th class="has-text-centered">Duration ({{ unit }})</th>
<th class="has-text-centered">Stratified</th>
<th class="has-text-centered">Discretized</th>
<th class="has-text-centered"># Folds</th>
</tr>
<tr>
<th class="has-text-centered">{{ data.platform }}</th>
<th class="has-text-centered">{{ data.model }} {{ data.version }}</th>
<th class="has-text-centered">{{ data.date }}</th>
<th class="has-text-centered">{{ data.time }}</th>
<th class="has-text-centered">{{ "%.2f" % (data.duration/divider) }}</th>
<th class="has-text-centered">{{ data.stratified }}</th>
<th class="has-text-centered">{{ data.discretized }}</th>
<th class="has-text-centered">{{ data.folds }}</th>
</tr>
<tr>
<th class="has-text-center is-selected">Language</th>
<th class="has-text-centered" colspan=3>{{ data.language }} {{ data.language_version }}</th>
<th class="has-text-centered is-selected">Seeds</th>
<th class="has-text-centered" colspan=6>{{ data.seeds }}</th>
</tr>
</thead>
</table>
<div>
<button class="{{ button }}" onclick="excelFile()">
<i class="mdi mdi-file-excel"></i> Excel
</button>
</div>
<table id="report-table"
class="table is-fullwidth is-striped is-hoverable is-bordered">
<thead>
<tr class="is-selected">
<th class="has-text-centered">Dataset</th>
<th class="has-text-centered">Samples</th>
<th class="has-text-centered">Features</th>
<th class="has-text-centered">Classes</th>
<th class="has-text-centered">{{ app_config.nodes }}</th>
<th class="has-text-centered">{{ app_config.leaves }}</th>
<th class="has-text-centered">{{ app_config.depth }}</th>
<th class="has-text-centered">{{ data.score_name|capitalize }}</th>
<th class="has-text-centered">Time</th>
<th class="has-text-centered">hyperparameters</th>
</tr>
</thead>
<tbody>
{% include "partials/table_report.html" %}
</tbody>
</table>
{% if summary|length > 0 %}
<div class="col-2 col-lg-2">
<table class="table is-bordered">
<thead>
<tr class="is-selected">
<th class="has-text-centered">Symbol</th>
<th class="has-text-centered">Meaning</th>
<th class="has-text-centered">Count</th>
</tr>
</thead>
{% include "partials/table_summary.html" %}
</table>
</div>
{% endif %}
<h2 class="has-text-white has-background-primary">
<b>
<button class="delete" onclick="location.href = '{{ back }}'"></button>
Total score: {{ "%.6f" % (data.results | sum(attribute="score") ) }}
</b>
</h2>
<h2>Number of files: {{ data.results | length }}</h2>
</div>
</section>
</div>

View File

@@ -0,0 +1,41 @@
<table id="file-table" class="{{ select.get_table_class() }}">
<thead>
<tr>
<th>Model</th>
<th>Metric</th>
<th>Platform</th>
<th>Date</th>
<th>Time</th>
<th>Stratified</th>
<th>Title</th>
<th>Score</th>
<th>{{ select.get_button_reset()|safe }} {{ select.get_button_all()|safe }}</th>
</tr>
</thead>
<tbody>
{% for file, data in files.items() %}
{% set parts = file.split('_') %}
{% set stratified = parts[6].split('.')[0] %}
<tr id="{{ file }}">
<td>{{ parts[2] }}</td>
<td>{{ parts[1] }}</td>
<td>{{ parts[3] }}</td>
<td>{{ parts[4] }}</td>
<td>{{ parts[5] }}</td>
<td>{{ 'True' if stratified =='1' else 'False' }}</td>
<td>{{ "%s" % data["title"] }}</td>
<td class="{{ select.get_align_right() }}">{{ "%.6f" % data["score"] }}</td>
<td>
{{ select.get_button_tag("table-eye", "showFile('" ~ file ~ "')") | safe }}
{% set file_best = "best_results_" ~ parts[1] ~ "_" ~ parts[2] ~ ".json" %}
{{ select.get_button_tag("star-circle-outline", "redirectDouble('best_results', '" ~ file_best ~ "')", visible=False, name="best_buttons") | safe }}
<input
type="checkbox"
name="selected_files"
value="{{ file }}"
/>
</td>
</tr>
{% endfor %}
</tbody>
</table>

View File

@@ -0,0 +1,15 @@
<div class="{{ select.get_container_class() }}">
{{ select.header("Benchmark Results") }}
<div class="{{ select.get_level_class() }}">
<div class="{{ select.get_left_position() }}">
{{ select.get_button("Use " ~ candidate, "redirectDouble('config', '" ~ candidate ~ "')")|safe }}
{{ select.get_button(select.icon("excel") ~ " Excel", "excel()")|safe }}
{{ select.get_button(select.icon("database-eye") ~ " Datasets", "redirectSimple('datasets')")|safe }}
</div>
<div class="{{ select.get_right_position() }}">
<input type="checkbox" id="compare" name="compare" {% if compare %} {{ "checked" }} {% endif %}>
<span class="{{ select.get_tag_class() }}">Comparing with best results</span>
</div>
</div>
{% include "partials/table_select.html" %}
</div>

View File

@@ -0,0 +1,13 @@
{% for key, value in summary.items() %}
<tr>
<td class="{{ center }}">
{{key}}
</td>
<td >
{{value[0]}}
</td>
<td class={{ right }}>
{{'{:,}'.format(value[1])}}
</td>
</tr>
{% endfor %}

View File

@@ -0,0 +1,29 @@
{% macro javascript(file) %}
<script src="{{ url_for('static', filename=file) }}"></script>
{% endmacro %}
{% set title = 'Report Viewer' %}
{% extends 'base_' ~ framework ~ '.html' %}
{% block content %}
{% if framework == 'bootstrap' %}
{% set center = 'text-center' %}
{% set right = 'text-end' %}
{% set button = 'btn btn-primary' %}
{% include 'partials/table_report_bootstrap.html' %}
{% else %}
{% set center = 'has-text-centered' %}
{% set right = 'has-text-right' %}
{% set button = 'button is-primary' %}
{% include 'partials/table_report_bulma.html' %}
{% endif %}
{% endblock %}
{% block jscript %}
{% if framework == 'bootstrap' %}
{% set selected = 'selected' %}
{% else %}
{% set selected = 'is-selected' %}
{% endif %}
<script>
{% include "js/report.js" %}
</script>
{{ javascript("js/excelFiles.js") }}
{% endblock %}

View File

@@ -0,0 +1,47 @@
{% set title = "Best Results" %}
{% extends "base_" ~ framework ~ ".html" %}
{% import "partials/cfg_select_" ~ framework ~ ".jinja" as select %}
{% block content %}
<div class="container">
{{ select.header(title, True, url_for("main.index", compare=compare)) }}
<table id="file-table" class="{{ select.get_table_class() }}">
<thead>
<tr class="{{ select.get_row_head_class() }}">
<th class="{{ select.get_align_center() }}">Dataset</th>
<th class="{{ select.get_align_center() }}">Score</th>
<th class="{{ select.get_align_center() }}">Hyperparameters</th>
<th class="{{ select.get_align_center() }}">File</th>
</tr>
</thead>
<tbody>
{% for dataset, info in data.items() %}
<tr>
<td>{{ dataset }}</td>
<td class="{{ select.get_align_right() }}">{{ '%9.7f' % info[0] }}</td>
<td class="{{ select.get_align_center() }}">{{ info[1] }}</td>
<td>
{% set url = url_for(request.endpoint, **request.view_args)|urlencode %}
<a href="{{ url_for('main.showfile', file_name = info[2], compare = compare) }}?url={{ url }}">{{ info[2] }}</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
{% block jscript %}
<script>
$(document).ready(function () {
// Check if row is selected
$('#file-table tbody').on('click', 'tr', function () {
if ($(this).hasClass('{{ select.selected() }}')) {
$(this).removeClass('{{ select.selected() }}');
} else {
$('#file-table tbody tr.{{ select.selected() }}').removeClass("{{ select.selected() }}")
$(this).addClass('{{ select.selected() }}');
}
});
});
</script>
{% endblock %}

View File

@@ -0,0 +1,20 @@
{% macro javascript(file) %}
<script src="{{ url_for('static', filename=file) }}"></script>
{% endmacro %}
{% set title = 'Benchmark Results' %}
{% extends 'base_' ~ framework ~ '.html' %}
{% import 'partials/cfg_select_' ~ framework ~ '.jinja' as select %}
{% block content %}
{% include 'partials/table_select_design.html' %}
{% endblock %}
{% block jscript %}
<script src="https://cdn.datatables.net/1.10.25/js/jquery.dataTables.min.js"></script>
{% if framework == 'bootstrap' %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js" integrity="sha384-cuYeSxntonz0PPNlHhBs68uyIAVpIIOZZ5JqeqvYYIcEL727kskC66kF92t6Xl2V" crossorigin="anonymous"></script>
{% endif %}
<script>
{% include'/js/select.js' %}
</script>
{{ javascript('js/excelFiles.js') }}
{% endblock %}

18
benchmark/scripts/be_flask.py Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env python
import webbrowser
from benchmark.Arguments import Arguments
from benchmark.scripts.app.app import create_app, TEST, OUTPUT
# Launch a flask server to serve the results
def main(args_test=None):
arguments = Arguments(prog="be_flask")
arguments.xset("output")
args = arguments.parse(args_test)
app = create_app()
app.config[TEST] = args_test is not None
app.config[OUTPUT] = args.output
print("Output is ", args.output)
if args.output == "local":
webbrowser.open_new("http://127.0.0.1:1234/")
app.run(port=1234, host="0.0.0.0")

View File

@@ -68,7 +68,7 @@ class ArgumentsTest(TestBase):
test_args = ["-n", "3", "-k", "date"] test_args = ["-n", "3", "-k", "date"]
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
arguments.parse(test_args) arguments.parse(test_args)
self.assertRegexpMatches( self.assertRegex(
stderr.getvalue(), stderr.getvalue(),
r"error: the following arguments are required: -m/--model", r"error: the following arguments are required: -m/--model",
) )
@@ -79,7 +79,7 @@ class ArgumentsTest(TestBase):
test_args = ["-n", "3", "-m", "SVC"] test_args = ["-n", "3", "-m", "SVC"]
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
arguments.parse(test_args) arguments.parse(test_args)
self.assertRegexpMatches( self.assertRegex(
stderr.getvalue(), stderr.getvalue(),
r"error: the following arguments are required: -k/--key", r"error: the following arguments are required: -k/--key",
) )
@@ -114,7 +114,7 @@ class ArgumentsTest(TestBase):
test_args = None test_args = None
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
arguments.parse(test_args) arguments.parse(test_args)
self.assertRegexpMatches( self.assertRegex(
stderr.getvalue(), stderr.getvalue(),
r"error: the following arguments are required: -m/--model, " r"error: the following arguments are required: -m/--model, "
"-k/--key, --title", "-k/--key, --title",

View File

@@ -102,7 +102,7 @@ class ModelTest(TestBase):
test = { test = {
"STree": ((11, 6, 4), 1.0), "STree": ((11, 6, 4), 1.0),
"Wodt": ((303, 152, 50), 0.9382022471910112), "Wodt": ((303, 152, 50), 0.9382022471910112),
"ODTE": ((7.86, 4.43, 3.37), 1.0), "ODTE": ((786, 443, 337), 1.0),
"Cart": ((23, 12, 5), 1.0), "Cart": ((23, 12, 5), 1.0),
"SVC": ((0, 0, 0), 0.7078651685393258), "SVC": ((0, 0, 0), 0.7078651685393258),
"RandomForest": ((21.3, 11, 5.26), 1.0), "RandomForest": ((21.3, 11, 5.26), 1.0),

View File

@@ -118,7 +118,7 @@ class UtilTest(TestBase):
def test_Files_get_results(self): def test_Files_get_results(self):
os.chdir(os.path.dirname(os.path.abspath(__file__))) os.chdir(os.path.dirname(os.path.abspath(__file__)))
self.assertCountEqual( self.assertCountEqual(
Files().get_all_results(hidden=False), Files.get_all_results(hidden=False),
[ [
"results_accuracy_STree_iMac27_2021-10-27_09:40:40_0.json", "results_accuracy_STree_iMac27_2021-10-27_09:40:40_0.json",
"results_accuracy_STree_iMac27_2021-09-30_11:42:07_0.json", "results_accuracy_STree_iMac27_2021-09-30_11:42:07_0.json",
@@ -130,7 +130,7 @@ class UtilTest(TestBase):
], ],
) )
self.assertCountEqual( self.assertCountEqual(
Files().get_all_results(hidden=True), Files.get_all_results(hidden=True),
[ [
"results_accuracy_STree_iMac27_2021-11-01_23:55:16_0.json", "results_accuracy_STree_iMac27_2021-11-01_23:55:16_0.json",
"results_accuracy_XGBoost_MacBookpro16_2022-05-04_11:00:35_" "results_accuracy_XGBoost_MacBookpro16_2022-05-04_11:00:35_"
@@ -143,7 +143,7 @@ class UtilTest(TestBase):
# check with results # check with results
os.rename(Folders.results, f"{Folders.results}.test") os.rename(Folders.results, f"{Folders.results}.test")
try: try:
Files().get_all_results(hidden=False) Files.get_all_results(hidden=False)
except ValueError: except ValueError:
pass pass
else: else:
@@ -153,7 +153,7 @@ class UtilTest(TestBase):
# check with hidden_results # check with hidden_results
os.rename(Folders.hidden_results, f"{Folders.hidden_results}.test") os.rename(Folders.hidden_results, f"{Folders.hidden_results}.test")
try: try:
Files().get_all_results(hidden=True) Files.get_all_results(hidden=True)
except ValueError: except ValueError:
pass pass
else: else:

View File

@@ -1,2 +1,2 @@
iris,class,all iris;class;all
wine,class,[0, 1] wine;class;[0, 1]

View File

@@ -6,7 +6,7 @@
"kernel": "liblinear", "kernel": "liblinear",
"multiclass_strategy": "ovr" "multiclass_strategy": "ovr"
}, },
"v. 1.3.1, Computed on Test on 2022-02-22 at 12:00:00 took 1s" "v. 1.4.0, Computed on Test on 2022-02-22 at 12:00:00 took 1s"
], ],
"balloons": [ "balloons": [
0.625, 0.625,
@@ -15,6 +15,6 @@
"kernel": "linear", "kernel": "linear",
"multiclass_strategy": "ovr" "multiclass_strategy": "ovr"
}, },
"v. 1.3.1, Computed on Test on 2022-02-22 at 12:00:00 took 1s" "v. 1.4.0, Computed on Test on 2022-02-22 at 12:00:00 took 1s"
] ]
} }

View File

@@ -120,7 +120,7 @@ class BeMainTest(TestBase):
module.main(parameter) module.main(parameter)
self.assertEqual(msg.exception.code, 2) self.assertEqual(msg.exception.code, 2)
self.assertEqual(stderr.getvalue(), "") self.assertEqual(stderr.getvalue(), "")
self.assertRegexpMatches(stdout.getvalue(), message) self.assertRegex(stdout.getvalue(), message)
def test_be_main_best_params_non_existent(self): def test_be_main_best_params_non_existent(self):
model = "GBC" model = "GBC"

View File

@@ -1,4 +1,4 @@
1;1;"Datasets used in benchmark ver. 0.5.0" 1;1;"Datasets used in benchmark ver. 1.0.1"
2;1;" Default score accuracy" 2;1;" Default score accuracy"
2;2;"Cross validation" 2;2;"Cross validation"
2;6;"5 Folds" 2;6;"5 Folds"

View File

@@ -1,4 +1,4 @@
Datasets used in benchmark ver. 0.5.0 Datasets used in benchmark ver. 1.0.1
Dataset Sampl. Feat. Cont Cls Balance Dataset Sampl. Feat. Cont Cls Balance
============================== ====== ===== ==== === ========================================== ============================== ====== ===== ==== === ==========================================

View File

@@ -5,7 +5,7 @@ odte
cython cython
fimdlp fimdlp
mufs mufs
bayesclass @ git+ssh://git@github.com/doctorado-ml/bayesclass.git #bayesclass @ git+ssh://git@github.com/doctorado-ml/bayesclass.git
xlsxwriter xlsxwriter
openpyxl openpyxl
tqdm tqdm
@@ -13,3 +13,4 @@ xgboost
graphviz graphviz
Wodt @ git+ssh://git@github.com/doctorado-ml/Wodt.git#egg=Wodt Wodt @ git+ssh://git@github.com/doctorado-ml/Wodt.git#egg=Wodt
unittest-xml-reporting unittest-xml-reporting
flask

View File

@@ -39,6 +39,7 @@ def script_names():
"report", "report",
"summary", "summary",
"init_project", "init_project",
"flask",
] ]
result = [] result = []
for script in scripts: for script in scripts: