Skip to content
Snippets Groups Projects
callbacks.py 8.50 KiB
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('pretrained_model_filename', 'children'),
        Output('info_filename', 'children'),
        Output('instance_filename', 'children'),
        Output('graph', 'children'),
        Output('explanation', 'children'),
        Input('ml_model_choice', 'value'),
        Input('ml_pretrained_model_choice', 'contents'),
        State('ml_pretrained_model_choice', 'filename'),
        Input('model_info_choice', 'contents'),
        State('model_info_choice', 'filename'),
        Input('ml_instance_choice', 'contents'),
        State('ml_instance_choice', 'filename'),
        Input('number_explanations', 'value'),
        Input('explanation_type', 'value'),
        Input('solver_sat', 'value'),
        Input('expl_choice', 'value'),
        Input('cont_expl_choice', 'value'),
        prevent_initial_call=True
    )
    def update_ml_type(value_ml_model, pretrained_model_contents, pretrained_model_filename, model_info, model_info_filename, \
                        instance_contents, instance_filename, enum, xtype, solver, expl_choice, cont_expl_choice):
        ctx = dash.callback_context
        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

            # Choice of pkl pretrained model
            elif ihm_id == 'ml_pretrained_model_choice':
                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, None, None, model_application.component.network, None
                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
                model_info = parse_contents_data(model_info, model_info_filename)
                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 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 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 len(model_application.instance)==0 or model_application.xtype is None:
                    raise PreventUpdate
                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 len(model_application.instance)==0 or model_application.enum<=0 :
                    raise PreventUpdate
                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 len(model_application.instance)==0 or model_application.enum<=0 or len(model_application.xtype)==0:
                    raise PreventUpdate
                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 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             

            # Choice of CxP to draw
            elif ihm_id == 'cont_expl_choice' :
                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_cont_expl(cont_expl_choice)
                return pretrained_model_filename, model_info_filename, instance_filename, model_application.component.network, model_application.component.explanation             

    @app.callback(
        Output('explanation', 'hidden'),
        Output('interaction_graph', 'hidden'),    
        Output('expl_choice', 'options'),
        Output('cont_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, {}, {}
        elif "AXp" not in explanation_type and "CXp" in explanation_type:
            return False, True, {}, {}
        else : 
            options_expls = {}
            options_cont_expls = {}
            model_application = page_application.model
            for i in range (len(model_application.list_expls)):
                options_expls[str(model_application.list_expls[i])] = model_application.list_expls[i]
            for i in range (len(model_application.list_cont_expls)):
                options_cont_expls[str(model_application.list_cont_expls[i])] = model_application.list_cont_expls[i]
            return False, False, options_expls, options_cont_expls

    @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