Merge pull request #10 from Doctorado-ML/flask

Flask
This commit is contained in:
Ricardo Montañana Gómez
2024-03-13 16:18:55 +01:00
committed by GitHub
36 changed files with 1126 additions and 23 deletions

View File

@@ -13,21 +13,27 @@ ALL_METRICS = (
class EnvData:
@staticmethod
def load():
args = {}
def __init__(self):
self.args = {}
def load(self):
try:
with open(Files.dot_env) as f:
for line in f.read().splitlines():
if line == "" or line.startswith("#"):
continue
key, value = line.split("=")
args[key] = value
self.args[key] = value
except FileNotFoundError:
print(NO_ENV, file=sys.stderr)
exit(1)
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):
@@ -35,7 +41,7 @@ class EnvDefault(argparse.Action):
def __init__(
self, envvar, required=True, default=None, mandatory=False, **kwargs
):
self._args = EnvData.load()
self._args = EnvData().load()
self._overrides = {}
if required and not mandatory:
default = self._args[envvar]
@@ -229,6 +235,19 @@ class Arguments(argparse.ArgumentParser):
"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": [
("-P", "--platform"),
{

View File

@@ -109,7 +109,7 @@ class DatasetsSurcov:
class Datasets:
def __init__(self, dataset_name=None, discretize=None):
env_data = EnvData.load()
env_data = EnvData().load()
# DatasetsSurcov, DatasetsTanveer, DatasetsArff,...
source_name = getattr(
__import__(__name__),

View File

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

View File

@@ -9,7 +9,7 @@ from sklearn.ensemble import (
from sklearn.svm import SVC
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 odte import Odte
from xgboost import XGBClassifier
@@ -46,6 +46,7 @@ class Models:
# "KDBNew": KDBNew(k=2),
# "AODENew": AODENew(random_state=random_state),
# "AODE": AODE(random_state=random_state),
# "BoostAODE": BoostAODE(random_state=random_state),
"Cart": DecisionTreeClassifier(random_state=random_state),
"ExtraTree": ExtraTreeClassifier(random_state=random_state),
"Wodt": Wodt(random_state=random_state),

View File

@@ -71,7 +71,6 @@ class Report(BaseReport):
self._load_best_results(
self.data["score_name"], self.data["model"]
)
self._compare_totals = {}
self.header_line("*")
self.header_line(
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.__load_env_data()
self.__compute_best_results_ever()
self._compare_totals = {}
def __load_env_data(self):
# Set the labels for nodes, leaves, depth
env_data = EnvData.load()
env_data = EnvData().load()
self.nodes_label = env_data["nodes"]
self.leaves_label = env_data["leaves"]
self.depth_label = env_data["depth"]
@@ -148,8 +149,11 @@ class BaseReport(abc.ABC):
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)
if self.compare:
self._load_best_results(self.score_name, self.data["model"])
def print_line(self, line) -> None:
pass
@@ -165,7 +169,7 @@ class StubReport(BaseReport):
class Summary:
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_filtered = []
self.datasets = {}

View File

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

View File

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

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 " "
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 = '/index/{{ compare }}'"></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 = '/index/{{ compare }}'"></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

@@ -118,7 +118,7 @@ class UtilTest(TestBase):
def test_Files_get_results(self):
os.chdir(os.path.dirname(os.path.abspath(__file__)))
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-09-30_11:42:07_0.json",
@@ -130,7 +130,7 @@ class UtilTest(TestBase):
],
)
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_XGBoost_MacBookpro16_2022-05-04_11:00:35_"
@@ -143,7 +143,7 @@ class UtilTest(TestBase):
# check with results
os.rename(Folders.results, f"{Folders.results}.test")
try:
Files().get_all_results(hidden=False)
Files.get_all_results(hidden=False)
except ValueError:
pass
else:
@@ -153,7 +153,7 @@ class UtilTest(TestBase):
# check with hidden_results
os.rename(Folders.hidden_results, f"{Folders.hidden_results}.test")
try:
Files().get_all_results(hidden=True)
Files.get_all_results(hidden=True)
except ValueError:
pass
else:

View File

@@ -13,3 +13,4 @@ xgboost
graphviz
Wodt @ git+ssh://git@github.com/doctorado-ml/Wodt.git#egg=Wodt
unittest-xml-reporting
flask

View File

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