], style={'display': 'flex'}), html.Div([ html.Div([ ], id='plot4'), html.Div([ ], id='plot5') ], style={'display': 'flex'}) # TODO3: Add a division with two empty divisions inside. See above disvision for example. # Callback function definition # TODO4: Add 5 ouput components @app.callback( [Output(component_id='plot1', component_property='children'), Output(component_id='plot2', component_property='children'), Output(component_id='plot3', component_property='children'), Output(component_id='plot4', component_property='children'), Output(component_id='plot5', component_property='children')], [Input(component_id='input-type', component_property='value'), Input(component_id='input-year', component_property='value')], # REVIEW4: Holding output state till user enters all the form information. In this case, it will be chart type and year [State("plot1", 'children'), State("plot2", "children"), State("plot3", "children"), State("plot4", "children"), State("plot5", "children") ]) # Add computation to callback function and return graph def get_graph(chart, year, children1, children2, c3, c4, c5): # Select data df = airline_data[airline_data['Year']==int(year)] if chart == 'OPT1': # Compute required information for creating graph from the data bar_data, line_data, div_data, map_data, tree_data = compute_data_choice_1(df) # Number of flights under different cancellation categories bar_fig = px.bar(bar_data, x='Month', y='Flights', color='CancellationCode', title='Monthly Flight Cancellation')
def init_app(self): app = JupyterDash(__name__) # app = dash.Dash() app.css.config.serve_locally = True app.scripts.config.serve_locally = True # self.add_rec(['main', 'MLPClassifier'], 'alpha=0.1', self.icicle_data) # self.add_rec(['main', 'MLPClassifier'], 'alpha=0.01', self.icicle_data) def df_to_dict(ut): data = {} for col_name in self.hierarchy_path: for i, g in ut.groupby(col_name): data_key = g[col_name].iloc[0] data[data_key] = {} data = copy.deepcopy(self.icicle_data) icicle_plot_fig = icicle_plot.Icicle(id='icicle_plot_fig', value='main/', label='my-label', low=self.low_color, high=self.high_color, data=data) def make_ints(row): for col in self.hierarchy_path: if row[col] != None: try: row[col] = float(row[col].split("=")[1]) except: row[col] return row pc_data_numeric = self.pc_data.apply(make_ints, axis=1) pc = go.Figure(data=[go.Scatter(x=[], y=[])]) if self.pc_data is not 0 and not self.pc_data.empty: pc = px.parallel_coordinates(pc_data_numeric.apply(make_ints, axis=1), color="accuracy", dimensions=self.hierarchy_path + ['accuracy'], color_continuous_scale='RdBu', height=350) pc_o = pc marks = {} for i in range(0, 100, 10): marks[i / 100] = str(i / 100) button_style = { "background-color": "#008CBA", "border": "none", "color": "white", "padding": "15px 32px", "text-align": "center", "display": "inline-block", "font-size": 16, "margin": "4px 2px", "cursor": "pointer", "width": "150px", "border-radius": "5%" } app.layout = html.Div( [ html.Div( [ html.Div(icicle_plot_fig, id='icicle-wrap'), dcc.Graph(id='pc', figure=pc, style={'height': 350}), dcc.Interval( id='interval-component', interval=1000, # in milliseconds n_intervals=0), dcc.Interval( id='interval-component2', interval=1000, # in milliseconds n_intervals=0), dcc.Interval(id='interval-loading', interval=100, n_intervals=0), html.H3('Sand Box', id='sandboxtext'), dcc.Textarea(id='sandbox', value='', style={ 'height': 120, 'width': '90%' }), html.Div([ html.Button('Execute', id='execute-button', style=button_style), dcc.Loading(id="loading", children=html.Div( [html.Div(id='output')]), type="circle", style={'margin-bottom': '6%'}) ]) ], style={ 'width': '87%', 'height': '100%', 'float': 'left' }), html.Div([ dcc.RangeSlider(id='metric-slider', min=0, max=1, step=0.01, value=[0, 1], marks=marks, vertical=True, verticalHeight=500) ], style={ 'margin-left': '90%', 'margin-top': '2%' }) # html.Div([ # html.H3('Sand Box', id='sandboxtext', style={"text-align": 'center'}), # dcc.Textarea( # id='sandbox', # value='', # style={'height': 400} # ), # html.Div([ # html.Button('Execute', id='execute-button', style=button_style), # dcc.Loading( # id="loading", # children=html.Div([ # html.Div(id='output') # ]), # type="circle" # ) # ], style= {'right': 37, 'position': 'absolute'}) # ], style={'margin-left': '5%'}) ], style={ 'height': '100%', 'overflow': 'hidden' }) @app.callback(Output('icicle-wrap', 'children'), [ Input('metric-slider', 'value'), Input('interval-component', 'n_intervals') ]) def update_icicle(rangeData, n): trigger_context = dash.callback_context.triggered[0]['prop_id'] if len(dash.callback_context.triggered ) <= 1 and self.update_available == False and ( trigger_context == 'interval-component.n_intervals' or trigger_context == '.'): raise PreventUpdate # revert to original state data = copy.deepcopy(self.icicle_data) # print(data) if not self.pc_data.empty: # delete entries self.remove_nodes_out_of_range(rangeData[0], rangeData[1], data) filtered_accs = self.pc_data.query( "accuracy >= " + str(rangeData[0]) + " and accuracy <= " + str(rangeData[1]))['accuracy'] self.low_color = filtered_accs.min() self.high_color = filtered_accs.max() if rangeData != self.rangeDataOld: self.id_updater += 1 self.rangeDataOld = rangeData if self.update_available: # print("update vailable") self.id_updater += 1 self.update_available = False # id is dictionary for Dash pattern matching callbacks return icicle_plot.Icicle(id={ 'role': 'icicle_plot_fig', 'index': self.id_updater }, value='main/', label='my-label', low=self.low_color, high=self.high_color, data=data) @app.callback(Output('pc', 'figure'), [ Input({ 'role': 'icicle_plot_fig', 'index': ALL }, 'value'), Input('metric-slider', 'value'), Input('interval-component2', 'n_intervals') ]) def update_pc(clickData, rangeData, n): if self.pc_data.empty: return go.Figure(data=[go.Scatter(x=[], y=[])]) trigger_context = dash.callback_context.triggered[0]['prop_id'] if len(dash.callback_context.triggered ) <= 1 and self.update_available == False and ( trigger_context == 'interval-component2.n_intervals'): raise PreventUpdate pc_data_copy = self.pc_data if len(clickData) == 0: if self.update_available: pc = px.parallel_coordinates( pc_data_copy.apply(make_ints, axis=1), color="accuracy", dimensions=self.hierarchy_path + ['accuracy'], color_continuous_scale='RdBu', height=350) return pc raise PreventUpdate # return self.pc # revert to original state # delete entries pc_data_copy = pc_data_copy.query("accuracy >= " + str(rangeData[0]) + " and accuracy <= " + str(rangeData[1])) if isinstance(clickData, list): clickData = clickData[0] if 'recommendationval' in clickData: raise PreventUpdate if clickData.split("/")[:-2] == []: pc = px.parallel_coordinates(pc_data_copy.apply(make_ints, axis=1), color="accuracy", dimensions=self.hierarchy_path + ['accuracy'], color_continuous_scale='RdBu', height=350) return pc if clickData: click_path = clickData.split("/")[:-1][1:] subset_counter = len(click_path) if click_path == []: return pc_o selected_df = pc_data_copy j = -1 for i in click_path: j += 1 if "=" in i: comps_name = i.split("=") hyp_name = comps_name[0] hyp_val = comps_name[1] selected_df = selected_df[selected_df.apply( lambda x: x['model_params'][hyp_name] == hyp_val if hyp_name in x['model_params'] else False, axis=1)] else: selected_df = selected_df[selected_df['model'] == i] sample_vals = selected_df.iloc[0] labels_pc = {} for i in self.hierarchy_path[subset_counter:]: if sample_vals[i]: labels_pc[i] = sample_vals[i].split("=")[0] selected_df = selected_df.apply(make_ints, axis=1) self.pc = px.parallel_coordinates( selected_df, color="accuracy", dimensions=self.hierarchy_path[subset_counter:] + ['accuracy'], labels=labels_pc, color_continuous_scale='RdBu', height=350) # print(pc_data_copy.apply(make_ints, axis=1)) return self.pc self.pc = px.parallel_coordinates(pc_data_copy.apply(make_ints, axis=1), color="accuracy", dimensions=self.hierarchy_path + ['accuracy'], color_continuous_scale='RdBu', height=350) return self.pc @app.callback( Output('sandbox', 'value'), [Input({ 'role': 'icicle_plot_fig', 'index': ALL }, 'value')]) def update_sandbox(clickData): if len(clickData) == 0: raise PreventUpdate if isinstance(clickData, list): clickData = clickData[0] if 'recommendationval' in clickData: # update the sand box clickData = clickData.replace(" recommendationval", "") model_name = "" params_rec = {} for i in clickData.split("/"): if 'main' in i or not i or not i.strip(): continue # model name if '=' not in i: model_name = i continue try: params_rec[i.split("=")[0]] = float(i.split( "=")[1]) # for int, long, float and complex if params_rec[i.split("=")[0]].is_integer(): params_rec[i.split("=")[0]] = int( params_rec[i.split("=")[0]]) except ValueError: params_rec[i.split("=")[0]] = i.split("=")[1] code = "app.experiment(\nlibrary = 'sklearn',\nmodel = " + model_name + ",\nparams = \n" + str( params_rec).replace('{', '{\n ').replace( ',', ',\n ').replace('}', '\n}') + ",\nhighlighted = True)" return code else: raise PreventUpdate @app.callback(Output('execute-button', 'style'), [Input('interval-loading', 'n_intervals')]) def check_execution(n_intervals): button_style = { "background-color": "#008CBA", "border": "none", "color": "white", "padding": "15px 32px", "text-align": "center", "display": "inline-block", "font-size": 16, "margin": "4px 2px", "cursor": "pointer", "width": "150px", "border-radius": "5%" } if not self.running_experiment and not self.running_recommendation: return button_style if self.running_recommendation: button_style['visibility'] = "hidden" button_style["cursor"] = 'not-allowed' button_style['pointer-events'] = "none" return button_style button_style["cursor"] = 'not-allowed' button_style['pointer-events'] = "none" button_style["opacity"] = 0.5 return button_style # execute button handler app.callback(Output('output', 'value'), [Input('execute-button', 'n_clicks')], [State('sandbox', 'value')])(self.execute_code) self.app = app