diff --git a/.gitignore b/.gitignore index 7c8041bcc2451773e574b119d7a2584292980f25..f7db4b641de813a678b90840deee40b361228a41 100644 --- a/.gitignore +++ b/.gitignore @@ -3,10 +3,4 @@ __pycache__ pages/application/DecisionTree/utils/__pycache__ pages/application/DecisionTree/__pycache__ pages/application/__pycache__ -decision_tree_classifier_20170212.pkl -push_command -adult.pkl -adult_data_00000.inst -iris_00000.txt -tests -create_pkl.py \ No newline at end of file +tests/push_command \ No newline at end of file diff --git a/assets/header.css b/assets/header.css index 8da0dd9e4f9bb5406ea42e7415ae4b068bf29c85..3a882eae1b7fdffd40dd37f87941a5508a4f29d1 100644 --- a/assets/header.css +++ b/assets/header.css @@ -36,6 +36,12 @@ div.sidebar.col-3 { background-color:gray; } +.sidebar .check-boxes{ + width: 100%; + height: 40px; + text-align: center; +} + .sidebar .upload { width: 100%; height: 50px; @@ -49,7 +55,6 @@ div.sidebar.col-3 { .sidebar .Select-control { width: 100%; - height: 30px; line-height: 30px; border-width: 1px; border-radius: 5px; @@ -60,9 +65,9 @@ div.sidebar.col-3 { background-color: rgb(26,26,26); } -.sidebar .sidebar-dropdown{ +.sidebar .dropdown{ width: 100%; - height: 40px; + height: 30px; line-height: 30px; border-width: 1px; border-radius: 5px; diff --git a/callbacks.py b/callbacks.py index 04930d6d59440aa0bbf430ede63f6201dc416a65..5ef62d601526f58dbf4d39f45ca698ee867d80ad 100644 --- a/callbacks.py +++ b/callbacks.py @@ -54,10 +54,13 @@ def register_callbacks(page_home, page_course, page_application, app): if ctx.triggered: ihm_id = ctx.triggered[0]['prop_id'].split('.')[0] model_application = page_application.model + + # Choice of model if ihm_id == 'ml_model_choice' : - model_application.update_ml_model(value_ml_model) - return None, None, None, None, None + model_application.update_ml_model(value_ml_model) + return None, None, None, None, None + # Choice of pkl pretrained model elif ihm_id == 'ml_pretrained_model_choice': if model_application.ml_model is None : raise PreventUpdate @@ -69,6 +72,7 @@ def register_callbacks(page_home, page_course, page_application, app): else : return pretrained_model_filename, None, None, None, None + # Choice of information for the model elif ihm_id == 'model_info_choice': if model_application.ml_model is None : raise PreventUpdate @@ -76,36 +80,38 @@ def register_callbacks(page_home, page_course, page_application, app): model_application.update_pretrained_model_layout_with_info(model_info, model_info_filename) return pretrained_model_filename, model_info_filename, None, model_application.component.network, None + # Choice of instance to explain elif ihm_id == 'ml_instance_choice' : - if model_application.ml_model is None or model_application.pretrained_model is None : + if model_application.ml_model is None or model_application.pretrained_model is None or model_application.enum<=0 or model_application.xtype is None : raise PreventUpdate instance = parse_contents_instance(instance_contents, instance_filename) - model_application.update_instance(instance, enum, xtype) + model_application.update_instance(instance) return pretrained_model_filename, model_info_filename, instance_filename, model_application.component.network, model_application.component.explanation + # Choice of number of expls elif ihm_id == 'number_explanations' : - if model_application.ml_model is None or model_application.pretrained_model is None or model_application.instance is None: + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.xtype is None: raise PreventUpdate - instance = parse_contents_instance(model_application.instance, instance_filename) - model_application.update_instance(instance, enum, xtype) + model_application.update_enum(enum) return pretrained_model_filename, model_info_filename, instance_filename, model_application.component.network, model_application.component.explanation + # Choice of AxP or CxP elif ihm_id == 'explanation_type' : - if model_application.ml_model is None or model_application.pretrained_model is None or model_application.instance is None: + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.enum<=0 : raise PreventUpdate - instance = parse_contents_instance(model_application.instance, instance_filename) - model_application.update_instance(instance, enum, xtype) + model_application.update_xtype(xtype) return pretrained_model_filename, model_info_filename, instance_filename, model_application.component.network, model_application.component.explanation + # Choice of solver elif ihm_id == 'solver_sat' : - if model_application.ml_model is None or model_application.pretrained_model is None or model_application.instance is None: + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.enum<=0 or len(model_application.xtype)==0: raise PreventUpdate - instance = parse_contents_instance(model_application.instance, instance_filename) - model_application.update_instance(instance, enum, xtype, solver=solver) + model_application.update_solver(solver) return pretrained_model_filename, model_info_filename, instance_filename, model_application.component.network, model_application.component.explanation + # Choice of AxP to draw elif ihm_id == 'expl_choice' : - if instance_contents is None : + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.enum<=0 or len(model_application.xtype)==0: raise PreventUpdate model_application.update_expl(expl_choice) return pretrained_model_filename, model_info_filename, instance_filename, model_application.component.network, model_application.component.explanation @@ -133,14 +139,14 @@ def register_callbacks(page_home, page_course, page_application, app): return False, False, False, options @app.callback( - Output('model_info_choice', 'disabled'), - Input('add_info_model_choice', 'value'), + Output('choice_info_div', 'hidden'), + Input('add_info_model_choice', 'on'), prevent_initial_call=True ) def add_model_info(add_info_model_choice): model_application = page_application.model model_application.update_info_needed(add_info_model_choice) - if add_info_model_choice==1: + if add_info_model_choice: return False else : return True diff --git a/callbacks_detached.py b/callbacks_detached.py new file mode 100644 index 0000000000000000000000000000000000000000..a8db16ff713479399892471d56224bd0cd9456b2 --- /dev/null +++ b/callbacks_detached.py @@ -0,0 +1,172 @@ +import dash +import pandas as pd +from dash import Input, Output, State +from dash.dependencies import Input, Output, State +from dash.exceptions import PreventUpdate + +from utils import parse_contents_graph, parse_contents_instance, parse_contents_data + + +def register_callbacks(page_home, page_course, page_application, app): + page_list = ['home', 'course', 'application'] + + @app.callback( + Output('page-content', 'children'), + Input('url', 'pathname')) + def display_page(pathname): + if pathname == '/': + return page_home + if pathname == '/application': + return page_application.view.layout + if pathname == '/course': + return page_course + + @app.callback(Output('home-link', 'active'), + Output('course-link', 'active'), + Output('application-link', 'active'), + Input('url', 'pathname')) + def navbar_state(pathname): + active_link = ([pathname == f'/{i}' for i in page_list]) + return active_link[0], active_link[1], active_link[2] + + @app.callback( + Output('graph', 'children'), + Input('ml_model_choice', 'value'), + prevent_initial_call=True + ) + def update_ml_type(value_ml_model): + model_application = page_application.model + model_application.update_ml_model(value_ml_model) + return None + + @app.callback( + Output('pretrained_model_filename', 'children'), + Output('graph', 'children'), + Input('ml_pretrained_model_choice', 'contents'), + State('ml_pretrained_model_choice', 'filename'), + prevent_initial_call=True + ) + def update_ml_pretrained_model(pretrained_model_contents, pretrained_model_filename): + model_application = page_application.model + if model_application.ml_model is None : + raise PreventUpdate + graph = parse_contents_graph(pretrained_model_contents, pretrained_model_filename) + model_application.update_pretrained_model(graph) + if not model_application.add_info : + model_application.update_pretrained_model_layout() + return pretrained_model_filename, model_application.component.network + else : + return pretrained_model_filename, None + + @app.callback( + Output('info_filename', 'children'), + Output('graph', 'children'), + Input('model_info_choice', 'contents'), + State('model_info_choice', 'filename'), + prevent_initial_call=True + ) + def update_info_model(model_info, model_info_filename): + model_application = page_application.model + if model_application.ml_model is None : + raise PreventUpdate + model_info = parse_contents_data(model_info, model_info_filename) + model_application.update_pretrained_model_layout_with_info(model_info, model_info_filename) + return model_info_filename, model_application.component.network + + @app.callback( + Output('instance_filename', 'children'), + Output('graph', 'children'), + Output('explanation', 'children'), + Input('ml_instance_choice', 'contents'), + State('ml_instance_choice', 'filename'), + prevent_initial_call=True + ) + def update_instance(instance_contents, instance_filename): + model_application = page_application.model + if model_application.ml_model is None or model_application.pretrained_model is None or model_application.enum<=0 or model_application.xtype is None : + raise PreventUpdate + instance = parse_contents_instance(instance_contents, instance_filename) + model_application.update_instance(instance) + return instance_filename, model_application.component.network, model_application.component.explanation + + @app.callback( + Output('explanation', 'children'), + Input('number_explanations', 'value'), + prevent_initial_call=True + ) + def update_enum(enum): + model_application = page_application.model + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.xtype is None: + raise PreventUpdate + model_application.update_enum(enum) + return model_application.component.explanation + + @app.callback( + Output('explanation', 'children'), + Input('explanation_type', 'value'), + prevent_initial_call=True + ) + def update_xtype(xtype): + model_application = page_application.model + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.enum<=0 : + raise PreventUpdate + model_application.update_xtype(xtype) + return model_application.component.explanation + + @app.callback( + Output('explanation', 'children'), + Input('solver_sat', 'value'), + prevent_initial_call=True +) + def update_solver(solver): + model_application = page_application.model + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.enum<=0 or len(model_application.xtype)==0: + raise PreventUpdate + model_application.update_solver(solver) + return model_application.component.explanation + + @app.callback( + Output('graph', 'children'), + Input('expl_choice', 'value'), + prevent_initial_call=True + ) + def update_expl_choice( expl_choice): + model_application = page_application.model + if model_application.ml_model is None or model_application.pretrained_model is None or len(model_application.instance)==0 or model_application.enum<=0 or len(model_application.xtype)==0: + raise PreventUpdate + model_application.update_expl(expl_choice) + return model_application.component.network + + @app.callback( + Output('explanation', 'hidden'), + Output('navigate_label', 'hidden'), + Output('navigate_dropdown', 'hidden'), + Output('expl_choice', 'options'), + Input('explanation', 'children'), + Input('explanation_type', 'value'), + prevent_initial_call=True + ) + def layout_buttons_navigate_expls(explanation, explanation_type): + if explanation is None or len(explanation_type)==0: + return True, True, True, {} + elif "AXp" not in explanation_type and "CXp" in explanation_type: + return False, True, True, {} + else : + options = {} + model_application = page_application.model + for i in range (len(model_application.list_expls)): + options[str(model_application.list_expls[i])] = model_application.list_expls[i] + return False, False, False, options + + @app.callback( + Output('choice_info_div', 'hidden'), + Input('add_info_model_choice', 'on'), + prevent_initial_call=True + ) + def add_model_info(add_info_model_choice): + model_application = page_application.model + model_application.update_info_needed(add_info_model_choice) + if add_info_model_choice: + return False + else : + return True diff --git a/pages/application/DecisionTree/DecisionTreeComponent.py b/pages/application/DecisionTree/DecisionTreeComponent.py index a1e23631c496156e327ce9903751131fa919c4c4..8a56c32349fced19e8c03889bb26fdc176b79973 100644 --- a/pages/application/DecisionTree/DecisionTreeComponent.py +++ b/pages/application/DecisionTree/DecisionTreeComponent.py @@ -15,27 +15,32 @@ from pages.application.DecisionTree.utils.dtviz import (visualize, class DecisionTreeComponent(): - def __init__(self, tree, info=None, type_info=''): - + def __init__(self, tree, type_tree='SKL', info=None, type_info=''): if info is not None and '.csv' in type_info: self.categorical = True data = Data(info) fvmap = data.mapping_features() feature_names = data.names[:-1] - - self.uploaded_dt = UploadedDecisionTree(tree, 'SKL', maxdepth=tree.get_depth(), feature_names=feature_names, nb_classes=tree.n_classes_) + self.uploaded_dt = UploadedDecisionTree(tree, type_tree, maxdepth=tree.get_depth(), feature_names=feature_names, nb_classes=tree.n_classes_) self.dt_format, self.map, features_names_mapping = self.uploaded_dt.dump(fvmap, feat_names=feature_names) - self.mapping_instance = self.create_fvmap_inverse_with_info(features_names_mapping) - elif info is not None and '.txt' in type_info : self.categorical = True fvmap = {} - - self.uploaded_dt = UploadedDecisionTree(tree, 'SKL', maxdepth=tree.get_depth(), feature_names=feature_names, nb_classes=tree.n_classes_) + feature_names = [] + for i,line in enumerate(info.split('\n')): + fid, TYPE = line.split(',')[:2] + dom = line.split(',')[2:] + assert (fid not in feature_names) + feature_names.append(fid) + assert (TYPE in ['Binary', 'Categorical']) + fvmap[f'f{i}'] = dict() + dom = sorted(dom) + for j,v in enumerate(dom): + fvmap[f'f{i}'][j] = (fid, True, v) + self.uploaded_dt = UploadedDecisionTree(tree, type_tree, maxdepth=tree.get_depth(), feature_names=feature_names, nb_classes=tree.n_classes_) self.dt_format, self.map, features_names_mapping = self.uploaded_dt.dump(fvmap, feat_names=feature_names) - self.mapping_instance = self.create_fvmap_inverse_with_info(features_names_mapping) else : self.categorical = False @@ -43,42 +48,46 @@ class DecisionTreeComponent(): feature_names = tree.feature_names_in_ except: feature_names = [f'f{i}' for i in range(tree.n_features_in_)] - - self.uploaded_dt = UploadedDecisionTree(tree, 'SKL', maxdepth=tree.get_depth(), feature_names=feature_names, nb_classes=tree.n_classes_) + self.uploaded_dt = UploadedDecisionTree(tree, type_tree, maxdepth=tree.get_depth(), feature_names=feature_names, nb_classes=tree.n_classes_) self.dt_format, self.map, features_names_mapping = self.uploaded_dt.convert_dt(feat_names=feature_names) - self.mapping_instance = self.create_fvmap_inverse_threashold(features_names_mapping) - - self.dt = DecisionTree(from_dt=self.dt_format, mapfile = self.map) + + self.mapping_instance = self.create_fvmap_inverse(features_names_mapping) + self.dt = DecisionTree(from_dt=self.dt_format, mapfile = self.map, feature_names = feature_names) dot_source = visualize(self.dt) - self.network = [dbc.Row(dash_interactive_graphviz.DashInteractiveGraphviz(dot_source=dot_source, style = {"width": "60%", + self.network = html.Div([dash_interactive_graphviz.DashInteractiveGraphviz(dot_source=dot_source, style = {"width": "60%", "height": "90%", - "background-color": "transparent"}))] + "background-color": "transparent"})]) self.explanation = [] - def create_fvmap_inverse_with_info(self, features_names_mapping) : - mapping_instance = {} - for feat in features_names_mapping : - feat_dic = {} - feature_description = feat.split(',') - name_feat, id_feat = feature_description[1].split(':') + def create_fvmap_inverse(self, instance): + def create_fvmap_inverse_with_info(features_names_mapping) : + mapping_instance = {} + for feat in features_names_mapping : + feat_dic = {} + feature_description = feat.split(',') + name_feat, id_feat = feature_description[1].split(':') - for mapping in feature_description[2:]: - real_value, mapped_value = mapping.split(':') - feat_dic[np.float32(real_value)] = int(mapped_value) - mapping_instance[name_feat] = feat_dic + for mapping in feature_description[2:]: + real_value, mapped_value = mapping.split(':') + feat_dic[np.float32(real_value)] = int(mapped_value) + mapping_instance[name_feat] = feat_dic - return mapping_instance + return mapping_instance + def create_fvmap_inverse_threashold(features_names_mapping) : + mapping_instance = {} + for feat in features_names_mapping : + feature_description = feat.split(',') + name_feat, id_feat = feature_description[1].split(':') + mapping_instance[name_feat] = float(feature_description[2].split(':')[0]) - def create_fvmap_inverse_threashold(self, features_names_mapping) : - mapping_instance = {} - for feat in features_names_mapping : - feature_description = feat.split(',') - name_feat, id_feat = feature_description[1].split(':') - mapping_instance[name_feat] = float(feature_description[2].split(':')[0]) + return mapping_instance - return mapping_instance + if self.categorical : + return create_fvmap_inverse_with_info(instance) + else : + return create_fvmap_inverse_threashold(instance) def translate_instance(self, instance): @@ -114,14 +123,17 @@ class DecisionTreeComponent(): explanation = self.dt.explain(instance_translated, enum=enum, xtype = xtype, solver=solver) dot_source = visualize_instance(self.dt, instance_translated) - self.network = [dbc.Row(dash_interactive_graphviz.DashInteractiveGraphviz( + self.network = html.Div([dash_interactive_graphviz.DashInteractiveGraphviz( dot_source=dot_source, style = {"width": "50%", "height": "80%", "background-color": "transparent"} - ))] + )]) #Creating a clean and nice text component + #instance plotting + self.explanation.append(html.H4("Instance : \n")) + self.explanation.append(html.P(str([str(instance[i]) for i in range (len(instance))]))) for k in explanation.keys() : if k != "List of path explanation(s)": if k in ["List of abductive explanation(s)","List of contrastive explanation(s)"] : @@ -140,8 +152,8 @@ class DecisionTreeComponent(): def draw_explanation(self, instance, expl) : instance = self.translate_instance(instance) dot_source = visualize_expl(self.dt, instance, expl) - self.network = [dbc.Row(dash_interactive_graphviz.DashInteractiveGraphviz( + self.network = html.Div([dash_interactive_graphviz.DashInteractiveGraphviz( dot_source=dot_source, style = {"width": "50%", "height": "80%", - "background-color": "transparent"}))] + "background-color": "transparent"})]) diff --git a/pages/application/DecisionTree/utils/data.py b/pages/application/DecisionTree/utils/data.py index d23ddb6108683ad08e41d5da10f889f163b67ad5..91aded54aaa39c6239d3a0696beafb217dc9a8a4 100644 --- a/pages/application/DecisionTree/utils/data.py +++ b/pages/application/DecisionTree/utils/data.py @@ -13,17 +13,13 @@ from __future__ import print_function import collections import itertools -import os, pickle +import pickle import six import gzip from six.moves import range import numpy as np import pandas as pd -#from sklearn.preprocessing import OneHotEncoder -from sklearn.model_selection import train_test_split - - # #============================================================================== class Data(object): diff --git a/pages/application/DecisionTree/utils/dtree.py b/pages/application/DecisionTree/utils/dtree.py index 1e7e270cc6a24a743dac1d33e9c870dda318933b..1eb9de3978b04b026de42c81dc3b600eb8b35345 100644 --- a/pages/application/DecisionTree/utils/dtree.py +++ b/pages/application/DecisionTree/utils/dtree.py @@ -45,7 +45,7 @@ class DecisionTree(): Simple decision tree class. """ - def __init__(self, from_dt=None, mapfile=None, verbose=0): + def __init__(self, from_dt=None, mapfile=None, feature_names=None, verbose=0): """ Constructor. """ @@ -62,6 +62,7 @@ class DecisionTree(): self.feids = {} self.fdoms = {} self.fvmap = {} + self.feature_names = {f'f{i}' : feature_names[i] for i, f in enumerate(feature_names)} # OHE mapping OHEMap = collections.namedtuple('OHEMap', ['dir', 'opp']) @@ -145,7 +146,6 @@ class DecisionTree(): """ Parse feature-value mapping from a file. """ - self.fvmap = {} lines = mapfile.split('\n') @@ -184,7 +184,6 @@ class DecisionTree(): """ Convert ITI trees with '!=' edges to multi-edges. """ - # new feature domains fdoms = collections.defaultdict(lambda: []) @@ -227,7 +226,6 @@ class DecisionTree(): """ Traverse the tree and extract explicit paths. """ - if root in self.terms: # store the path term = self.terms[root] @@ -242,7 +240,6 @@ class DecisionTree(): """ Run the tree and obtain the prediction given an input instance. """ - root = self.root_node depth = 0 path = [] @@ -297,7 +294,6 @@ class DecisionTree(): Hitting set based encoding of the problem. (currently not incremental -- should be fixed later) """ - sets = [] for t, paths in self.paths.items(): # ignoring the right class @@ -334,12 +330,9 @@ class DecisionTree(): """ #contaiins all the elements for explanation explanation_dic = {} - #instance plotting - explanation_dic["Instance : "] = str([str(inst[i]) for i in range (len(inst))]) self.feids = {f'f{i}': i for i, f in enumerate(inst)} inst = [(f'f{i}', int(inst[i][1])) for i,f in enumerate(inst)] - path, term, depth = self.execute(inst, pathlits) #decision path @@ -347,10 +340,8 @@ class DecisionTree(): explanation_dic["Decision path of instance : "] = decision_path_str explanation_dic["Decision path length : "] = 'Path length is :'+ str(depth) - if self.ohmap.dir: f2v = {fv[0]: fv[1] for fv in inst} - # updating fvmap for printing ohe features for fo, fis in self.ohmap.dir.items(): self.fvmap[tuple([fo, None])] = '(' + ' AND '.join([self.fvmap[tuple([fi, f2v[fi]])] for fi in fis]) + ')' @@ -394,7 +385,6 @@ class DecisionTree(): """ Enumerate contrastive explanations. """ - def process_set(done, target): for s in done: if s <= target: diff --git a/pages/application/DecisionTree/utils/dtviz.py b/pages/application/DecisionTree/utils/dtviz.py index 0c940c64d0a7e57336db3ba9bb00e0fd5171239c..21ea63920338159b71e45c44a1cd2b772084bc9f 100755 --- a/pages/application/DecisionTree/utils/dtviz.py +++ b/pages/application/DecisionTree/utils/dtviz.py @@ -10,16 +10,14 @@ # #============================================================================== -from pages.application.DecisionTree.utils.dtree import DecisionTree import getopt -import os import pygraphviz -import sys # #============================================================================== def create_legend(g): legend = g.subgraphs()[-1] + legend.graph_attr.update(size="2,2") legend.add_node("a", style = "invis") legend.add_node("b", style = "invis") legend.add_node("c", style = "invis") @@ -50,7 +48,7 @@ def visualize(dt): # non-terminal nodes for n in dt.nodes: - g.add_node(n, label=dt.nodes[n].feat) + g.add_node(n, label=dt.feature_names[dt.nodes[n].feat]) node = g.get_node(n) node.attr['shape'] = 'circle' node.attr['fontsize'] = 13 @@ -98,7 +96,7 @@ def visualize_instance(dt, instance): # non-terminal nodes for n in dt.nodes: - g.add_node(n, label=dt.nodes[n].feat) + g.add_node(n, label=dt.feature_names[dt.nodes[n].feat]) node = g.get_node(n) node.attr['shape'] = 'circle' node.attr['fontsize'] = 13 @@ -156,7 +154,7 @@ def visualize_expl(dt, instance, expl): # non-terminal nodes for n in dt.nodes: - g.add_node(n, label=dt.nodes[n].feat) + g.add_node(n, label=dt.feature_names[dt.nodes[n].feat]) node = g.get_node(n) node.attr['shape'] = 'circle' node.attr['fontsize'] = 13 diff --git a/pages/application/DecisionTree/utils/upload_tree.py b/pages/application/DecisionTree/utils/upload_tree.py index b3e1297783ae503d4ee22ae7e024aa02b4c2f7f7..98bf190cfc588cae331fff2caeeb85df06b87645 100644 --- a/pages/application/DecisionTree/utils/upload_tree.py +++ b/pages/application/DecisionTree/utils/upload_tree.py @@ -14,7 +14,6 @@ from anytree import Node, RenderTree,AsciiStyle import json import numpy as np import math -import os import six @@ -297,8 +296,8 @@ class UploadedDecisionTree: map += f"{len(self.intvs)}" for f in self.intvs: for j,t in enumerate(self.intvs[f][:-1]): - map += f"\n{f} {j} <={t}" - map += f"\n{f} {j+1} >{t}" + map += f"\n{f} {j} <={np.round(float(t),4)}" + map += f"\n{f} {j+1} >{np.round(float(t),4)}" if feat_names is not None: diff --git a/pages/application/application.py b/pages/application/application.py index 925a1b7307bc9567b8df55cbd6623da1f075f717..db54577aa48a31e87069afd59ebf34ed6a346ea0 100644 --- a/pages/application/application.py +++ b/pages/application/application.py @@ -1,5 +1,6 @@ from dash import dcc, html import dash_bootstrap_components as dbc +import dash_daq as daq from pages.application.DecisionTree.DecisionTreeComponent import DecisionTreeComponent @@ -23,6 +24,10 @@ class Model(): self.add_info = False self.model_info = '' + self.enum=1 + self.xtype = ['AXp', 'CXp'] + self.solver="g3" + self.instance = '' self.list_expls = [] @@ -47,12 +52,24 @@ class Model(): def update_pretrained_model_layout_with_info(self, model_info, model_info_filename): self.model_info = model_info - self.component = self.component_class(self.pretrained_model, self.model_info, model_info_filename) + self.component = self.component_class(self.pretrained_model, info=self.model_info, type_info=model_info_filename) - def update_instance(self, instance, enum, xtype, solver="g3"): + def update_instance(self, instance): self.instance = instance - self.list_expls = self.component.update_with_explicability(self.instance, enum, xtype, solver) + self.list_expls = self.component.update_with_explicability(self.instance, self.enum, self.xtype, self.solver) + + def update_enum(self, enum): + self.enum = enum + self.list_expls = self.component.update_with_explicability(self.instance, self.enum, self.xtype, self.solver) + def update_xtype(self, xtype): + self.xtype = xtype + self.list_expls = self.component.update_with_explicability(self.instance, self.enum, self.xtype, self.solver) + + def update_solver(self, solver): + self.solver = solver + self.list_expls = self.component.update_with_explicability(self.instance, self.enum, self.xtype, self.solver) + def update_expl(self, expl): self.expl = expl self.component.draw_explanation(self.instance, expl) @@ -62,17 +79,18 @@ class View(): def __init__(self, model): self.model = model - self.ml_menu_models = dcc.Dropdown(self.model.ml_models, + self.ml_menu_models = html.Div([ + html.Br(), + html.Label("Choose the Machine Learning algorithm :"), + html.Br(), + dcc.Dropdown(self.model.ml_models, id='ml_model_choice', - className="sidebar-dropdown") - - self.ml_library_used = dcc.Dropdown(options = [{'label': 'Scikit-learn ', 'value': "SKL"}, - {'label': 'ITI', 'value': "ITI"}, - {'label': 'IAI', 'value': "IAI"}], - id='ml_library_choice', - className="sidebar-dropdown") + className="dropdown")]) self.pretrained_model_upload = html.Div([ + html.Hr(), + html.Label("Choose the pretrained model : "), + html.Br(), dcc.Upload( id='ml_pretrained_model_choice', children=html.Div([ @@ -83,15 +101,20 @@ class View(): ), html.Div(id='pretrained_model_filename')]) - self.add_model_info_choice = dcc.RadioItems(id="add_info_model_choice", - options = [{'label': 'Yes ', 'value': 1}, - {'label': 'No', 'value': 0}], - value=0, className="sidebar-dropdown") + self.add_model_info_choice = html.Div([ + html.Hr(), + html.Label("Do you wish to upload more info for your model ? : "), + html.Br(), + daq.BooleanSwitch(id='add_info_model_choice', on=False, color="#000000",)]) - self.model_info = html.Div([ + self.model_info = html.Div(id="choice_info_div", + hidden=True, + children=[ + html.Hr(), + html.Label("Choose the pretrained model dataset (csv) or feature definition file (txt): "), + html.Br(), dcc.Upload( id='model_info_choice', - disabled=True, children=html.Div([ 'Drag and Drop or ', html.A('Select File') @@ -101,6 +124,9 @@ class View(): html.Div(id='info_filename')]) self.instance_upload = html.Div([ + html.Hr(), + html.Label("Choose the instance to explain : "), + html.Br(), dcc.Upload( id='ml_instance_choice', children=html.Div([ @@ -111,34 +137,7 @@ class View(): ), html.Div(id='instance_filename')]) - self.sidebar = dcc.Tabs(children=[ - dcc.Tab(label='Basic Parameters', children = [ - html.Br(), - html.Label("Choose the Machine Learning algorithm :"), - html.Br(), - self.ml_menu_models, - html.Hr(), - html.Label("Choose the Machine Learning library used :"), - html.Br(), - self.ml_library_used, - html.Hr(), - html.Label("Choose the pretrained model : "), - html.Br(), - self.pretrained_model_upload, - html.Hr(), - html.Label("Do you wish to upload more info for your model ? : "), - html.Br(), - self.add_model_info_choice, - html.Hr(), - html.Label("Choose the pretrained model dataset (csv) or feature definition file (txt): "), - html.Br(), - self.model_info, - html.Hr(), - html.Label("Choose the instance to explain : "), - html.Br(), - self.instance_upload], className="sidebar"), - dcc.Tab(label='Advanced Parameters', children = [ - html.Br(), + self.num_explanation = html.Div([ html.Label("Choose the number of explanations : "), html.Br(), dcc.Input( @@ -146,29 +145,48 @@ class View(): value=1, type="number", placeholder="How many explanations ?", - className="sidebar-dropdown"), - html.Hr(), + className="dropdown"), + html.Hr()]) + + self.type_explanation = html.Div([ html.Label("Choose the kind of explanation : "), html.Br(), dcc.Checklist( id="explanation_type", options={'AXp' : "Abductive Explanation", 'CXp': "Contrastive explanation"}, value = ['AXp', 'CXp'], - className="sidebar-dropdown", + className="check-boxes", inline=True), - html.Hr(), - html.Label("Choose the SAT solver : "), + html.Hr()]) + + self.solver = html.Div([ html.Label("Choose the SAT solver : "), + html.Br(), + dcc.Dropdown(['g3', 'g4', 'lgl', 'mcb', 'mcm', 'mpl', 'm22', 'mc', 'mgh'], 'g3', id='solver_sat') ]) + + self.sidebar = dcc.Tabs(children=[ + dcc.Tab(label='Basic Parameters', children = [ + self.ml_menu_models, + self.pretrained_model_upload, + self.add_model_info_choice, + self.model_info, + self.instance_upload], className="sidebar"), + dcc.Tab(label='Advanced Parameters', children = [ html.Br(), - dcc.Dropdown(['g3', 'g4', 'lgl', 'mcb', 'mcm', 'mpl', 'm22', 'mc', 'mgh'], 'g3', id='solver_sat') + self.num_explanation, + self.type_explanation, + self.solver ], className="sidebar")]) - self.expl_choice = dcc.Dropdown(self.model.list_expls, + self.expl_choice = html.Div([html.H5(id = "navigate_label", hidden=True, children="Navigate through the explanations and plot them on the tree : "), + html.Div(id='navigate_dropdown', hidden=True, + children = [dcc.Dropdown(self.model.list_expls, id='expl_choice', - className="dropdown") + className="dropdown")])]) - self.layout = dbc.Row([ dbc.Col([self.sidebar], width=3, class_name="sidebar"), + self.layout = dbc.Row([ dbc.Col([self.sidebar], + width=3, class_name="sidebar"), dbc.Col([dbc.Row(id = "graph", children=[]), - dbc.Row(html.Div([html.H5(id = "navigate_label", hidden=True, children="Navigate through the explanations and plot them on the tree : "), - html.Div(self.expl_choice, id='navigate_dropdown', hidden=True)]))], width=5, class_name="column_graph"), + dbc.Row(self.expl_choice)], + width=5, class_name="column_graph"), dbc.Col(html.Main(id = "explanation", children=[], hidden=True), width=4)]) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index aab2fcaf8910657e4d1cd96b58230fefca5b5dbc..4f70ae69cdd7f78304ed576c0745589b7d79e127 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,5 +11,6 @@ scipy>=1.2.1 dash_bootstrap_components dash_interactive_graphviz python-sat[pblib,aiger] -pygraphviz -anytree \ No newline at end of file +pygraphviz==1.9 +anytree==2.8.0 +dash_daq==0.5.0 \ No newline at end of file diff --git a/tests/adult/adult.pkl b/tests/adult/adult.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b18b4d6e77cfc501320ebd5650158dd268530d1d Binary files /dev/null and b/tests/adult/adult.pkl differ diff --git a/tests/adult/adult_2.pkl b/tests/adult/adult_2.pkl new file mode 100644 index 0000000000000000000000000000000000000000..5221943e347e0a7b2b83e0ee33e5c603396536a3 Binary files /dev/null and b/tests/adult/adult_2.pkl differ diff --git a/tests/adult/adult_3.pkl b/tests/adult/adult_3.pkl new file mode 100644 index 0000000000000000000000000000000000000000..b17bc94372fe8d7b6db981e73bf34d6f37b1d07b Binary files /dev/null and b/tests/adult/adult_3.pkl differ diff --git a/tests/adult/adult_data_00000.inst b/tests/adult/adult_data_00000.inst new file mode 100644 index 0000000000000000000000000000000000000000..c72f4e9e0aec1da4c12fdaa3b585d6d96054a30a --- /dev/null +++ b/tests/adult/adult_data_00000.inst @@ -0,0 +1 @@ +f0=1,f1=9,f2=9,f3=7,f4=9,f5=5,f6=7,f7=0,f8=5,f9=3,f10=0,f11=15 \ No newline at end of file diff --git a/tests/iris/decision_tree_classifier_20170212.pkl b/tests/iris/decision_tree_classifier_20170212.pkl new file mode 100644 index 0000000000000000000000000000000000000000..006ccc214168eed2a37f7201ccca66648f1112f7 Binary files /dev/null and b/tests/iris/decision_tree_classifier_20170212.pkl differ diff --git a/tests/iris/iris.csv b/tests/iris/iris.csv new file mode 100644 index 0000000000000000000000000000000000000000..1b9d0294d6d589f667daf28efecbd0cb0276c352 --- /dev/null +++ b/tests/iris/iris.csv @@ -0,0 +1,151 @@ +"sepal.length","sepal.width","petal.length","petal.width","variety" +5.1,3.5,1.4,.2,"Setosa" +4.9,3,1.4,.2,"Setosa" +4.7,3.2,1.3,.2,"Setosa" +4.6,3.1,1.5,.2,"Setosa" +5,3.6,1.4,.2,"Setosa" +5.4,3.9,1.7,.4,"Setosa" +4.6,3.4,1.4,.3,"Setosa" +5,3.4,1.5,.2,"Setosa" +4.4,2.9,1.4,.2,"Setosa" +4.9,3.1,1.5,.1,"Setosa" +5.4,3.7,1.5,.2,"Setosa" +4.8,3.4,1.6,.2,"Setosa" +4.8,3,1.4,.1,"Setosa" +4.3,3,1.1,.1,"Setosa" +5.8,4,1.2,.2,"Setosa" +5.7,4.4,1.5,.4,"Setosa" +5.4,3.9,1.3,.4,"Setosa" +5.1,3.5,1.4,.3,"Setosa" +5.7,3.8,1.7,.3,"Setosa" +5.1,3.8,1.5,.3,"Setosa" +5.4,3.4,1.7,.2,"Setosa" +5.1,3.7,1.5,.4,"Setosa" +4.6,3.6,1,.2,"Setosa" +5.1,3.3,1.7,.5,"Setosa" +4.8,3.4,1.9,.2,"Setosa" +5,3,1.6,.2,"Setosa" +5,3.4,1.6,.4,"Setosa" +5.2,3.5,1.5,.2,"Setosa" +5.2,3.4,1.4,.2,"Setosa" +4.7,3.2,1.6,.2,"Setosa" +4.8,3.1,1.6,.2,"Setosa" +5.4,3.4,1.5,.4,"Setosa" +5.2,4.1,1.5,.1,"Setosa" +5.5,4.2,1.4,.2,"Setosa" +4.9,3.1,1.5,.2,"Setosa" +5,3.2,1.2,.2,"Setosa" +5.5,3.5,1.3,.2,"Setosa" +4.9,3.6,1.4,.1,"Setosa" +4.4,3,1.3,.2,"Setosa" +5.1,3.4,1.5,.2,"Setosa" +5,3.5,1.3,.3,"Setosa" +4.5,2.3,1.3,.3,"Setosa" +4.4,3.2,1.3,.2,"Setosa" +5,3.5,1.6,.6,"Setosa" +5.1,3.8,1.9,.4,"Setosa" +4.8,3,1.4,.3,"Setosa" +5.1,3.8,1.6,.2,"Setosa" +4.6,3.2,1.4,.2,"Setosa" +5.3,3.7,1.5,.2,"Setosa" +5,3.3,1.4,.2,"Setosa" +7,3.2,4.7,1.4,"Versicolor" +6.4,3.2,4.5,1.5,"Versicolor" +6.9,3.1,4.9,1.5,"Versicolor" +5.5,2.3,4,1.3,"Versicolor" +6.5,2.8,4.6,1.5,"Versicolor" +5.7,2.8,4.5,1.3,"Versicolor" +6.3,3.3,4.7,1.6,"Versicolor" +4.9,2.4,3.3,1,"Versicolor" +6.6,2.9,4.6,1.3,"Versicolor" +5.2,2.7,3.9,1.4,"Versicolor" +5,2,3.5,1,"Versicolor" +5.9,3,4.2,1.5,"Versicolor" +6,2.2,4,1,"Versicolor" +6.1,2.9,4.7,1.4,"Versicolor" +5.6,2.9,3.6,1.3,"Versicolor" +6.7,3.1,4.4,1.4,"Versicolor" +5.6,3,4.5,1.5,"Versicolor" +5.8,2.7,4.1,1,"Versicolor" +6.2,2.2,4.5,1.5,"Versicolor" +5.6,2.5,3.9,1.1,"Versicolor" +5.9,3.2,4.8,1.8,"Versicolor" +6.1,2.8,4,1.3,"Versicolor" +6.3,2.5,4.9,1.5,"Versicolor" +6.1,2.8,4.7,1.2,"Versicolor" +6.4,2.9,4.3,1.3,"Versicolor" +6.6,3,4.4,1.4,"Versicolor" +6.8,2.8,4.8,1.4,"Versicolor" +6.7,3,5,1.7,"Versicolor" +6,2.9,4.5,1.5,"Versicolor" +5.7,2.6,3.5,1,"Versicolor" +5.5,2.4,3.8,1.1,"Versicolor" +5.5,2.4,3.7,1,"Versicolor" +5.8,2.7,3.9,1.2,"Versicolor" +6,2.7,5.1,1.6,"Versicolor" +5.4,3,4.5,1.5,"Versicolor" +6,3.4,4.5,1.6,"Versicolor" +6.7,3.1,4.7,1.5,"Versicolor" +6.3,2.3,4.4,1.3,"Versicolor" +5.6,3,4.1,1.3,"Versicolor" +5.5,2.5,4,1.3,"Versicolor" +5.5,2.6,4.4,1.2,"Versicolor" +6.1,3,4.6,1.4,"Versicolor" +5.8,2.6,4,1.2,"Versicolor" +5,2.3,3.3,1,"Versicolor" +5.6,2.7,4.2,1.3,"Versicolor" +5.7,3,4.2,1.2,"Versicolor" +5.7,2.9,4.2,1.3,"Versicolor" +6.2,2.9,4.3,1.3,"Versicolor" +5.1,2.5,3,1.1,"Versicolor" +5.7,2.8,4.1,1.3,"Versicolor" +6.3,3.3,6,2.5,"Virginica" +5.8,2.7,5.1,1.9,"Virginica" +7.1,3,5.9,2.1,"Virginica" +6.3,2.9,5.6,1.8,"Virginica" +6.5,3,5.8,2.2,"Virginica" +7.6,3,6.6,2.1,"Virginica" +4.9,2.5,4.5,1.7,"Virginica" +7.3,2.9,6.3,1.8,"Virginica" +6.7,2.5,5.8,1.8,"Virginica" +7.2,3.6,6.1,2.5,"Virginica" +6.5,3.2,5.1,2,"Virginica" +6.4,2.7,5.3,1.9,"Virginica" +6.8,3,5.5,2.1,"Virginica" +5.7,2.5,5,2,"Virginica" +5.8,2.8,5.1,2.4,"Virginica" +6.4,3.2,5.3,2.3,"Virginica" +6.5,3,5.5,1.8,"Virginica" +7.7,3.8,6.7,2.2,"Virginica" +7.7,2.6,6.9,2.3,"Virginica" +6,2.2,5,1.5,"Virginica" +6.9,3.2,5.7,2.3,"Virginica" +5.6,2.8,4.9,2,"Virginica" +7.7,2.8,6.7,2,"Virginica" +6.3,2.7,4.9,1.8,"Virginica" +6.7,3.3,5.7,2.1,"Virginica" +7.2,3.2,6,1.8,"Virginica" +6.2,2.8,4.8,1.8,"Virginica" +6.1,3,4.9,1.8,"Virginica" +6.4,2.8,5.6,2.1,"Virginica" +7.2,3,5.8,1.6,"Virginica" +7.4,2.8,6.1,1.9,"Virginica" +7.9,3.8,6.4,2,"Virginica" +6.4,2.8,5.6,2.2,"Virginica" +6.3,2.8,5.1,1.5,"Virginica" +6.1,2.6,5.6,1.4,"Virginica" +7.7,3,6.1,2.3,"Virginica" +6.3,3.4,5.6,2.4,"Virginica" +6.4,3.1,5.5,1.8,"Virginica" +6,3,4.8,1.8,"Virginica" +6.9,3.1,5.4,2.1,"Virginica" +6.7,3.1,5.6,2.4,"Virginica" +6.9,3.1,5.1,2.3,"Virginica" +5.8,2.7,5.1,1.9,"Virginica" +6.8,3.2,5.9,2.3,"Virginica" +6.7,3.3,5.7,2.5,"Virginica" +6.7,3,5.2,2.3,"Virginica" +6.3,2.5,5,1.9,"Virginica" +6.5,3,5.2,2,"Virginica" +6.2,3.4,5.4,2.3,"Virginica" +5.9,3,5.1,1.8,"Virginica" \ No newline at end of file diff --git a/tests/iris/iris.pkl b/tests/iris/iris.pkl new file mode 100644 index 0000000000000000000000000000000000000000..cf2d521581ec57be284bb87b75316940c16fdcb7 Binary files /dev/null and b/tests/iris/iris.pkl differ diff --git a/tests/iris/iris.txt b/tests/iris/iris.txt new file mode 100644 index 0000000000000000000000000000000000000000..d356f5d1d011df170da9dacee5ac4b2d6bfc844b --- /dev/null +++ b/tests/iris/iris.txt @@ -0,0 +1,4 @@ +sepal.length,Categorical,7.6,6.8,7.1,4.9,4.4,6.2,6,7.3,5.9,7.4,5.2,5.6,4.8,6.5,5.5,4.6,6.6,6.4,7,4.5,7.2,5.1,5.8,5.3,6.9,6.1,6.7,4.7,7.7,6.3,5.7,7.9,5.4,4.3,5 +sepal.width,Categorical,4.2,4.4,3.1,2.4,2.9,2,3.8,4.1,4,3.2,2.7,3.3,2.2,2.5,2.3,3.6,3.5,3.9,2.8,2.6,3.7,3,3.4 +petal.length,Categorical,4.2,4.9,4.4,6,5.9,5.2,5.6,4.8,1,5.5,4.6,6.6,1.1,3.8,1.5,6.4,4.1,4,4.5,1.6,3.3,1.4,5.1,1.7,5.8,3.5,3.6,5.3,1.9,6.9,6.1,6.7,4.7,3.9,1.2,1.3,6.3,5.7,3.7,5.4,3,4.3,5 +petal.width,Categorical,2.4,.2,1,2,1.1,1.5,.6,.5,2.2,.3,1.6,1.4,2.5,1.7,2.3,1.8,2.1,1.9,1.2,1.3,.1,.4 \ No newline at end of file diff --git a/tests/iris/iris01.json b/tests/iris/iris01.json new file mode 100644 index 0000000000000000000000000000000000000000..59c0840b5597ccb4347c3c2041707f0ae1d11aa0 --- /dev/null +++ b/tests/iris/iris01.json @@ -0,0 +1,4 @@ +{"sepal.length":4.9, +"sepal.width":3, +"petal.length":1.4, +"petal.width":0.2} diff --git a/tests/iris/iris2.pkl b/tests/iris/iris2.pkl new file mode 100644 index 0000000000000000000000000000000000000000..cf2d521581ec57be284bb87b75316940c16fdcb7 Binary files /dev/null and b/tests/iris/iris2.pkl differ diff --git a/tests/iris/iris_00000.txt b/tests/iris/iris_00000.txt new file mode 100644 index 0000000000000000000000000000000000000000..108004d0deba35123ce4bdbcb9fa37930d6164ba --- /dev/null +++ b/tests/iris/iris_00000.txt @@ -0,0 +1 @@ +sepal.length=4.3,sepal.width=2.0,petal.length=1.0,petal.width=0.1 \ No newline at end of file diff --git a/tests/zoo/inst/zoo_00.inst b/tests/zoo/inst/zoo_00.inst new file mode 100644 index 0000000000000000000000000000000000000000..8d6abc5618927fb2ddf49400932809448ebef26c --- /dev/null +++ b/tests/zoo/inst/zoo_00.inst @@ -0,0 +1 @@ +f0=1,f1=0,f1=0,f1=1,f1=0,f1=0,f1=1,f1=1,f1=1,f1=1,f1=0,f1=0,f1=4,f1=0,f1=0,f1=1 \ No newline at end of file diff --git a/tests/zoo/inst/zoo_01.inst b/tests/zoo/inst/zoo_01.inst new file mode 100644 index 0000000000000000000000000000000000000000..4a6df5103d348fbf79e75654cb20f9594d47e842 --- /dev/null +++ b/tests/zoo/inst/zoo_01.inst @@ -0,0 +1 @@ +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1 \ No newline at end of file diff --git a/tests/zoo/inst/zoo_02.inst b/tests/zoo/inst/zoo_02.inst new file mode 100644 index 0000000000000000000000000000000000000000..d72c0ae09ad51c4f6ec073b66e773beb18515be4 --- /dev/null +++ b/tests/zoo/inst/zoo_02.inst @@ -0,0 +1 @@ +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0 \ No newline at end of file diff --git a/tests/zoo/inst/zoo_11.inst b/tests/zoo/inst/zoo_11.inst new file mode 100644 index 0000000000000000000000000000000000000000..0fa9d7c8a871929cbe518a7be16966fc2f7b9a6d --- /dev/null +++ b/tests/zoo/inst/zoo_11.inst @@ -0,0 +1 @@ +0,1,1,0,1,0,0,0,1,1,0,0,2,1,1,0 \ No newline at end of file diff --git a/tests/zoo/zoo.csv b/tests/zoo/zoo.csv new file mode 100644 index 0000000000000000000000000000000000000000..7eb9774cdc5f452baac8ed8d4ea0efe83a466386 --- /dev/null +++ b/tests/zoo/zoo.csv @@ -0,0 +1,102 @@ +hair,feathers,eggs,milk,airborne,aquatic,predator,toothed,backbone,breathes,venomous,fins,legs,tail,domestic,catsize,class_type +1,0,0,1,0,0,1,1,1,1,0,0,4,0,0,1,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,mammal +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,fish +1,0,0,1,0,0,1,1,1,1,0,0,4,0,0,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,1,1,mammal +0,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,fish +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,fish +1,0,0,1,0,0,0,1,1,1,0,0,4,0,1,0,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +0,1,1,0,1,0,0,0,1,1,0,0,2,1,1,0,bird +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,fish +0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,invertebrate +0,0,1,0,0,1,1,0,0,0,0,0,4,0,0,0,invertebrate +0,0,1,0,0,1,1,0,0,0,0,0,6,0,0,0,invertebrate +0,1,1,0,1,0,1,0,1,1,0,0,2,1,0,0,bird +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,mammal +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,1,fish +0,0,0,1,0,1,1,1,1,1,0,1,0,1,0,1,mammal +0,1,1,0,1,0,0,0,1,1,0,0,2,1,1,0,bird +0,1,1,0,1,1,0,0,1,1,0,0,2,1,0,0,bird +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,mammal +0,1,1,0,1,0,0,0,1,1,0,0,2,1,0,1,bird +0,0,1,0,0,0,0,0,0,1,0,0,6,0,0,0,bug +0,0,1,0,0,1,1,1,1,1,0,0,4,0,0,0,amphibian +0,0,1,0,0,1,1,1,1,1,1,0,4,0,0,0,amphibian +1,0,0,1,1,0,0,1,1,1,0,0,2,1,0,0,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,2,0,1,1,mammal +0,0,1,0,1,0,0,0,0,1,0,0,6,0,0,0,bug +1,0,0,1,0,0,0,1,1,1,0,0,4,1,1,1,mammal +1,0,0,1,0,0,0,1,1,1,0,0,2,0,0,1,mammal +0,1,1,0,1,1,1,0,1,1,0,0,2,1,0,0,bird +0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,fish +1,0,0,1,0,0,0,1,1,1,0,0,4,1,1,0,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,0,mammal +0,1,1,0,1,0,1,0,1,1,0,0,2,1,0,0,bird +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,fish +1,0,1,0,1,0,0,0,0,1,1,0,6,0,1,0,bug +1,0,1,0,1,0,0,0,0,1,0,0,6,0,0,0,bug +0,1,1,0,0,0,1,0,1,1,0,0,2,1,0,0,bird +0,0,1,0,1,0,1,0,0,1,0,0,6,0,0,0,bug +0,1,1,0,1,0,0,0,1,1,0,0,2,1,0,0,bird +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +0,0,1,0,0,1,1,0,0,0,0,0,6,0,0,0,invertebrate +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,1,1,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,0,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +1,0,1,0,1,0,0,0,0,1,0,0,6,0,0,0,bug +0,0,1,0,0,1,1,1,1,1,0,0,4,1,0,0,amphibian +0,0,1,0,0,1,1,0,0,0,0,0,8,0,0,1,invertebrate +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,0,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,mammal +0,1,1,0,0,0,0,0,1,1,0,0,2,1,0,1,bird +0,1,1,0,1,0,0,0,1,1,0,0,2,1,1,0,bird +0,1,1,0,0,1,1,0,1,1,0,0,2,1,0,1,bird +0,1,1,0,1,0,0,0,1,1,0,0,2,1,0,0,bird +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,1,fish +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,fish +0,0,1,0,0,0,1,1,1,1,1,0,0,1,0,0,reptile +1,0,1,1,0,1,1,0,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,1,1,mammal +0,0,0,1,0,1,1,1,1,1,0,1,0,1,0,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,1,1,mammal +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,1,1,mammal +0,1,1,0,0,0,1,0,1,1,0,0,2,1,0,1,bird +0,0,0,0,0,0,1,0,0,1,1,0,8,1,0,0,invertebrate +0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,fish +1,0,0,1,0,1,1,1,1,1,0,1,0,0,0,1,mammal +1,0,0,1,0,1,1,1,1,1,0,1,2,1,0,1,mammal +0,0,0,0,0,1,1,1,1,0,1,0,0,1,0,0,reptile +0,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,invertebrate +0,1,1,0,1,1,1,0,1,1,0,0,2,1,0,0,bird +0,1,1,0,1,1,1,0,1,1,0,0,2,1,0,0,bird +0,0,1,0,0,0,1,1,1,1,0,0,0,1,0,0,reptile +0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,invertebrate +0,0,1,0,0,1,0,1,1,0,0,1,0,1,0,0,fish +0,1,1,0,1,0,0,0,1,1,0,0,2,1,0,0,bird +1,0,0,1,0,0,0,1,1,1,0,0,2,1,0,0,mammal +0,0,1,0,0,1,1,0,0,0,0,0,5,0,0,0,invertebrate +0,0,1,0,0,1,1,1,1,0,1,1,0,1,0,1,fish +0,1,1,0,1,1,0,0,1,1,0,0,2,1,0,1,bird +0,0,1,0,0,0,0,0,0,1,0,0,6,0,0,0,bug +0,0,1,0,0,1,0,1,1,1,0,0,4,0,0,0,amphibian +0,0,1,0,0,0,0,0,1,1,0,0,4,1,0,1,reptile +0,0,1,0,0,0,1,1,1,1,0,0,4,1,0,0,reptile +0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,1,fish +1,0,0,1,1,0,0,1,1,1,0,0,2,1,0,0,mammal +1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,0,mammal +0,1,1,0,1,0,1,0,1,1,0,0,2,1,0,1,bird +1,0,0,1,0,0,0,1,1,1,0,0,2,1,0,1,mammal +1,0,1,0,1,0,0,0,0,1,1,0,6,0,0,0,bug +1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,mammal +0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,invertebrate +0,1,1,0,1,0,0,0,1,1,0,0,2,1,0,0,bird \ No newline at end of file diff --git a/tests/zoo/zoo.dt b/tests/zoo/zoo.dt new file mode 100644 index 0000000000000000000000000000000000000000..a1ee6427913de0385b71077c93d9889e0479c78d --- /dev/null +++ b/tests/zoo/zoo.dt @@ -0,0 +1,85 @@ +41 +1 +I 1 2 3 6 9 10 12 14 17 18 20 21 22 24 28 30 33 35 37 38 +T 4 5 7 8 11 13 15 16 19 23 25 26 27 29 31 32 34 36 39 40 41 +4 T bug +5 T mammal +7 T bird +8 T bug +11 T mammal +13 T fish +15 T bird +16 T reptile +19 T mammal +23 T reptile +25 T reptile +26 T bird +27 T fish +29 T amphibian +31 T amphibian +32 T reptile +34 T invertebrate +36 T invertebrate +39 T invertebrate +40 T bug +41 T invertebrate +1 f4 0 2 +1 f4 1 9 +2 f0 0 3 +2 f0 1 6 +3 f10 0 4 +3 f10 1 5 +6 f12 1 7 +6 f12 5 7 +6 f12 9 7 +6 f12 11 7 +6 f12 3 8 +6 f12 7 8 +9 f15 0 10 +9 f15 1 17 +10 f3 0 11 +10 f3 1 12 +12 f11 0 13 +12 f11 1 14 +14 f12 1 15 +14 f12 9 15 +14 f12 3 16 +14 f12 5 16 +14 f12 7 16 +14 f12 11 16 +17 f8 0 18 +17 f8 1 33 +18 f0 0 19 +18 f0 1 20 +20 f12 1 21 +20 f12 9 21 +20 f12 3 28 +20 f12 5 28 +20 f12 7 28 +20 f12 11 28 +21 f6 0 22 +21 f6 1 27 +22 f10 0 23 +22 f10 1 24 +24 f12 9 25 +24 f12 1 26 +24 f12 3 26 +24 f12 5 26 +24 f12 7 26 +24 f12 11 26 +28 f10 0 29 +28 f10 1 30 +30 f5 0 31 +30 f5 1 32 +33 f5 0 34 +33 f5 1 35 +35 f13 0 36 +35 f13 1 37 +37 f9 0 38 +37 f9 1 41 +38 f12 1 39 +38 f12 5 39 +38 f12 9 39 +38 f12 11 39 +38 f12 3 40 +38 f12 7 40 diff --git a/tests/zoo/zoo.json b/tests/zoo/zoo.json new file mode 100644 index 0000000000000000000000000000000000000000..506568b6a24d9f5066f1673d69e24a45d1109299 --- /dev/null +++ b/tests/zoo/zoo.json @@ -0,0 +1,18 @@ +{ +"hair":1, +"feathers":0, +"eggs":0, +"milk":1, +"airborne":0, +"aquatic":0, +"predator":0, +"toothed":1, +"backbone":1, +"breathes":1, +"venomous":0, +"fins":0, +"legs":6, +"tail":1, +"domestic":0, +"catsize":1 +} diff --git a/tests/zoo/zoo.map b/tests/zoo/zoo.map new file mode 100644 index 0000000000000000000000000000000000000000..89838b19a6ef9d3425d66ce4c6ec27f5c3981fdd --- /dev/null +++ b/tests/zoo/zoo.map @@ -0,0 +1,38 @@ +Categorical +16 +f0 0 =1 +f0 1 =0 +f1 0 =1 +f1 1 =0 +f2 0 =1 +f2 1 =0 +f3 0 =1 +f3 1 =0 +f4 0 =1 +f4 1 =0 +f5 0 =1 +f5 1 =0 +f6 0 =1 +f6 1 =0 +f7 0 =1 +f7 1 =0 +f8 0 =1 +f8 1 =0 +f9 0 =1 +f9 1 =0 +f10 0 =1 +f10 1 =0 +f11 0 =1 +f11 1 =0 +f12 1 =2 +f12 3 =6 +f12 5 =5 +f12 7 =8 +f12 9 =0 +f12 11 =4 +f13 0 =1 +f13 1 =0 +f14 0 =1 +f14 1 =0 +f15 0 =1 +f15 1 =0 diff --git a/tests/zoo/zoo.pkl b/tests/zoo/zoo.pkl new file mode 100644 index 0000000000000000000000000000000000000000..edfd6540dd861d1260292b0bce1efe6d6a809461 Binary files /dev/null and b/tests/zoo/zoo.pkl differ diff --git a/utils.py b/utils.py index b3429106341c7d07009843c22547057ee72e2ab5..42b30c99af3af1b8463b3aa8e29f1834e974e0b3 100644 --- a/utils.py +++ b/utils.py @@ -2,6 +2,7 @@ import base64 import io import pickle import joblib +import json import numpy as np from dash import html @@ -43,14 +44,16 @@ def parse_contents_instance(contents, filename): try: if '.csv' in filename: data = decoded.decode('utf-8') + data = str(data).strip().split(',') + data = list(map(lambda i: tuple([i[0], np.float32(i[1])]), [i.split('=') for i in data])) elif '.txt' in filename: - data = decoded.decode('utf-8') - elif '.json' in filename: data = decoded.decode('utf-8') - else : + data = str(data).strip().split(',') + data = list(map(lambda i: tuple([i[0], np.float32(i[1])]), [i.split('=') for i in data])) + elif '.json' in filename: data = decoded.decode('utf-8') - data = str(data).strip().split(',') - data = list(map(lambda i: tuple([i[0], np.float32(i[1])]), [i.split('=') for i in data])) + data = json.loads(data) + data = list(tuple(data.items())) except Exception as e: print(e) return html.Div([