dcc.Graph(id='fig'), dcc.Location(id='url'), html.Div(id='empty', style={'display': 'none'}), ], style={ 'position': 'absolute', 'top': '15vh', 'left': '10vw', 'width': '80vw', 'height': '60vh' }) app.clientside_callback(""" function(path) { return String(window.innerWidth) + ',' + String(window.innerHeight); } """, Output('empty', 'children'), [Input('url', 'pathname')], prevent_initial_call=True) @app.callback(Output('fig', 'figure'), [Input('empty', 'children')], prevent_initial_call=True) def draw_on_reload(c): plot_data = {} for team in teams: team_data = SignupData.objects.filter(team=team) d = datetime.date(2020, 9, 20) accd = [] while d <= datetime.date.today():
], className='bar_card') ], md=9) ], className=''), dcc.Location(id='url'), html.Div('', id='empty', style={'display': 'none'}) ], className='dashboard_container', id='team_container') app.clientside_callback( """ function(path) { console.log(path) return path+',' + String(window.innerWidth) + ',' + String(window.innerHeight); } """, Output('empty', 'children'), [Input('url', 'pathname')]) @app.callback([ Output('team_thumbnail', 'children'), Output('team_datatable', 'children'), Output('team_map', 'figure'), Output('bar1', 'children'), Output('bar2', 'children'), Output('bar3', 'children'), ], [Input('empty', 'children')], prevent_initial_call=True) def on_page_load(init_info):
class AnalysisApp: def __init__(self, dfs_path=os.path.join('static', 'dfs'), title='Analysis Dashboard', app_name='app', callback_side='backend'): """ callback_side='client' is not implemented for multiple outputs yet in dash """ if DEBUG: print('AnalysisApp init') self.dfs_path = dfs_path self.title = title self.callback_side = callback_side self.app_name = app_name self.template = self.CHART_FONT = self.opacity = None self.get_style() # Create Dahs App self.app = DjangoDash('analysis_app', add_bootstrap_links=True, suppress_callback_exceptions=True) # self.app.css.append_css({'external_url': 'https://codepen.io/amyoshino/pen/jzXypZ.css'}) # external_js = ["https://code.jquery.com/jquery-3.2.1.min.js", "https://codepen.io/bcd/pen/YaXojL.js"] # for js in external_js: self.app.scripts.append_script({"external_url": js}) # Instantiate components empty self.input_components, self.div_charts, self.div_tables, self.function_outputs = [], [], [], [] self.main_inputs, self.inputs_as_output, self.function_inputs, self.parameter_inputs = [], [], [], [] # Read Data self.read_data() if DEBUG: print(' -> Data Read') # Initialize Components self.read_input_configuration() self.create_input_components() self.create_output_components() self.update_inputs() # self.update_output() # Create App Layout self.app.layout = html.Div([ html.H2(self.title), dcc.Dropdown(id='test', options=[{ 'label': 'chart1', 'value': 'chart1' }, { 'label': 'chart2', 'value': 'chart2' }, { 'label': 'San Francisco', 'value': 'SF' }], placeholder="Select a city", multi=True), self.input_components, self.div_charts, self.div_tables, ], className="principal") # self.app.config.suppress_callback_exceptions = True # Cache # self.cache = Cache(self.app.server, config={ # # try 'filesystem' if you don't want to setup redis # 'CACHE_TYPE': 'filesystem', # 'CACHE_DIR': 'cache-directory' # }) # self.cache.memoize(timeout=5)(self.update_output) # Associate callbacks if self.callback_side == 'backend': self.app.callback( inputs=self.main_inputs, output=self.inputs_as_output, )(self.update_inputs) self.app.callback( inputs=self.function_inputs + [Input('correlation_chart', 'selectedData')], output=self.function_outputs, )(self.update_output) self.app.callback(output=[ Output('chart1', component_property='style'), Output('chart2', component_property='style') ], inputs=[Input('test', 'value')])(self.hide_charts) elif self.callback_side == 'client': ip = ','.join(self.parameter_inputs) self.app.clientside_callback( f""" function({ip}) {{ return update_inputs({ip}); }} """, output=self.inputs_as_output, inputs=self.main_inputs, ) # (self.update_inputs) self.app.clientside_callback( f""" function({ip}) {{ return update_output({ip}); }} """, output=self.function_outputs, inputs=self.function_inputs, ) # (self.update_output) if DEBUG: print(' -> Layout & Callbacks Ready') def hide_charts(self, show_charts): print('@@@@@@@@@@@@@@@@') print(show_charts) retorno = [] for chart_name in ['chart1', 'chart2']: if chart_name in show_charts: retorno.append({'display': 'block'}) else: retorno.append({'display': 'none'}) return retorno def get_style(self): conf_path = os.path.join('static', 'analysis_app', 'conf_files', f'{self.app_name}.txt') with open(conf_path) as json_file: json_conf = json.load(json_file, encoding='cp1252') self.charts = json_conf['charts'] self.tables = json_conf['tables'] self.template = json_conf['style']['template'] self.CHART_FONT = json_conf['style']['chart_font'] self.opacity = json_conf['style']['opacity'] if DEBUG: print(' -> Style Ready', self.template) @try_catch def get_csv(self, df_name='test_df.csv', path='static/dfs/'): """ Returns a pandas dataframe from a csv """ self.df = pd.read_csv(os.path.join(path, df_name)) @try_catch def read_data(self, dataframe_name=None): # Read data self.dataframes = [df_name for df_name in os.listdir(self.dfs_path)] if dataframe_name is None: dataframe_name = self.dataframes[0] self.get_csv(dataframe_name) self.columns_str = self.df.select_dtypes(include='object').columns self.columns_numeric = self.df.select_dtypes( include=['float64', 'int']).columns @try_catch def get_component(self, i, v): """ Generates de dcc component based on the attributes passed """ if v['control_type'] == 'dropdown': return html.P( dcc.Dropdown( options=[{ 'label': x, 'value': x } for x in v['data']], value=v['data'][0], className=v['className'], id=f'{i}', persistence=True, persistence_type='local', # local|memory clearable=True, searchable=True, placeholder=f"Select a {i}", disabled=False, )) elif v['control_type'] == 'slider': return html.P( dcc.RangeSlider( id=f'{i}', min=v['data']['min'], max=v['data']['max'], step=v['data']['step'], value=v['data']['value'], ), ) @try_catch def read_input_configuration(self, input_f_path=''): # TODO: read from file # Create the Inputs from Configuration self.inputs_conf = { 'dataframe': { 'property': 'value', 'control_type': 'dropdown', 'data': self.dataframes, 'className': 'col-6', 'main_control': True }, 'categorical': { 'property': 'value', 'control_type': 'dropdown', 'data': self.columns_str, 'className': 'col-6', 'main_control': False }, 'numerical': { 'property': 'value', 'control_type': 'dropdown', 'data': self.columns_numeric, 'className': 'col-6', 'main_control': False }, } if DEBUG: print(' -> Input Configuration Ready') @try_catch def save_input_config(self, input_f_path=''): # TODO: pass @try_catch def create_input_components(self): self.input_components = html.Div(className='row', id='controls_div', children=[]) self.main_inputs, self.inputs_as_output, self.function_inputs = [], [], [ ] # Restart Components self.parameter_inputs = [] for i, v in self.inputs_conf.items(): self.input_components.children.append( html.Div(className='col', children=[self.get_component(i, v)]), ) if v['main_control']: self.main_inputs.append(Input(i, v['property'])) else: self.parameter_inputs.append(i) self.parameter_inputs.append(f'{i}_selected_data') self.function_inputs.append(Input(i, v['property'])) # self.function_inputs.append(Input(i, 'selectedData')) self.inputs_as_output.append(Output(i, 'options')) self.inputs_as_output.append(Output(i, v['property'])) if DEBUG: print(' -> Input Components Ready') @try_catch def create_output_components(self): self.function_outputs = [] self.div_charts = html.Div(className='row', id='charts_div', children=[]) new_row = "row" for chart_name in self.charts: self.div_charts.children.append( html.Div([ html.Div([ dcc.Graph(id=chart_name, style={}), ], className="col card", id=f'{chart_name}_div'), ], className=f"{new_row}")) self.function_outputs.append(Output(chart_name, 'figure')) self.div_tables = html.Div(className='row', id='tables_div', children=[]) for table_name in self.tables: self.div_tables.children.append( html.Div(id=f'{table_name}', className='col card')) self.function_outputs.append(Output(table_name, 'children')) if DEBUG: print(' -> Output Components Ready') @try_catch def update_inputs(self, dataframe_name='test_df.csv'): # self.parameter_inputs """ Update the values of the Input Controls """ self.read_data(dataframe_name=dataframe_name) return [{'label': col, 'value': col} for col in self.columns_str], self.columns_str[0], \ [{'label': col, 'value': col} for col in self.columns_numeric], self.columns_numeric[0] @try_catch def get_boxplot(self, categorical_column, variable_column, df): try: names = self.df[categorical_column].unique() data = [ go.Box( # marker=dict(color=COLORS[provider], opacity=self.opacity, name=name, x=df[df[categorical_column] == name][categorical_column], y=df[df[categorical_column] == name][variable_column]) for name in names ] layout = { 'legend_orientation': 'h', 'title': go.layout.Title(text=f"Distribution of {variable_column}", ), 'template': self.template } except Exception as e: print(str(e)) data, layout = [], {} return go.Figure(data=data, layout=layout) @try_catch def get_histogram(self, categorical_column, variable_column, df, x_name='sepal_length', y_name='petal_length'): '''try: names = df[categorical_column].unique() data = [ dict( type='scatter', mode='markers', x=name_df[x_name], y=name_df[y_name], name=name, ) for name_df, name in [(df[df[categorical_column] == name], name) for name in names] ] layout = { 'title': go.layout.Title(text=f"{y_name} vs {x_name}", font=CHART_FONT), 'xaxis': go.layout.XAxis( title=go.layout.xaxis.Title(text=x_name, font=CHART_FONT)), 'yaxis': go.layout.YAxis( title=go.layout.yaxis.Title(text=y_name, font=CHART_FONT)), 'template': template, } except: data, layout = [], {} return go.Figure(data=data, layout=layout)''' return px.histogram( df, x=variable_column, y=variable_column, color=categorical_column, marginal="box", # or violin, rug hover_data=self.df.columns, template=self.template) @try_catch def get_null_map(self, df, columns_numeric): layout = { 'legend_orientation': 'h', 'title': go.layout.Title(text=f"Null Distribution", ), 'template': self.template } return go.Figure(data=go.Heatmap( z=self.df[columns_numeric].isnull().astype(int).to_numpy()), layout=layout) @try_catch def generate_correlation_chart(self, categorical_column, **kwargs): index_vals = self.df[categorical_column].astype('category').cat.codes fig = go.Figure(data=go.Splom( dimensions=[ dict(label=c, values=self.df[c]) for c in self.columns_numeric ], text=self.df[categorical_column], marker=dict( color=index_vals, showscale=False, # colors encode categorical variables line_color='white', line_width=0.5))) fig.update_layout(title='Correlations', template=self.template) # ,width=600, height=600, return fig @try_catch def generate_outlayers(self, categorical_column): # def get_outlayers(self, param='Total Unsuccessful', date=None, dataframe=None): D = [] for category in self.df[categorical_column].unique(): specific_df = self.df[self.df[categorical_column] == category] for feature in self.columns_numeric: specific_df['measuring'] = specific_df[feature] qv1 = specific_df[feature].quantile(0.25) qv3 = specific_df[feature].quantile(0.75) qv_limit = 1.5 * (qv3 - qv1) un_outliers_mask = (specific_df[feature] > qv3 + qv_limit) | ( specific_df[feature] < qv1 - qv_limit) un_outliers_data = specific_df[feature][un_outliers_mask] un_outliers_name = specific_df[un_outliers_mask] if un_outliers_data.shape[0] > 0: for i in [{ 'feature': feature, 'category': category, 'value': val } for val in un_outliers_data]: D.append(i) return pd.DataFrame(D) @try_catch # categorical_column, variable_column #### def update_output(self, categorical_column, variable_column, selected_data): if selected_data is None: self.selected_df = self.df else: selected_points = [ p['pointNumber'] for p in selected_data['points'] ] self.selected_df = self.df[self.df.index.isin(selected_points)] print(f'LENGTH OF DATAFRAME: ') print(self.selected_df.shape) outlayers = self.generate_outlayers(categorical_column) kwargs = { 'categorical_column': categorical_column, 'variable_column': variable_column, 'df': self.selected_df } output_generators = OrderedDict({ 'chart1': { 'function': self.get_boxplot, 'kwargs': kwargs }, 'chart2': { 'function': self.get_histogram, 'kwargs': kwargs }, 'correlation_chart': { 'function': self.generate_correlation_chart, 'kwargs': kwargs }, 'get_null_map': { 'function': self.get_null_map, 'kwargs': { 'df': self.df, 'columns_numeric': self.columns_numeric } }, 'table1': { 'function': generate_table_simple, 'kwargs': { 'dataframe': self.df.describe().round(1) } }, 'outlayers_table': { 'function': generate_table_simple, 'kwargs': { 'dataframe': outlayers } }, 'full_Table': { 'function': generate_table_simple, 'kwargs': { 'dataframe': self.df } }, }) return [ values['function'](**values['kwargs']) for out_name, values in output_generators.items() if out_name in self.charts + self.tables ] @try_catch def get_app(self): return self.app
class Graphs: def __init__(self, app_name, graph_title, graph_id, slider_id, top_bool, app_input_state_list, graph_color='Crimson', time_scale='12-m', anime_name="default"): self.jikan = Jikan() self.app_name = app_name self.graph_title = graph_title self.graph_id = graph_id self.slider_id = slider_id self.top_bool = top_bool self.app_input_state_list = app_input_state_list self.graph_color = graph_color self.time_scale = time_scale self.anime_name = anime_name self.app = DjangoDash(app_name, external_stylesheets=external_stylesheets) self.app.layout = html.Div([ html.H1(graph_title), #html.Button("Custom export", id="export_table", **{"data-dummy": ""}), self.return_graph( ), # dcc.Graph(id=graph_id, animate=True, style={"backgroundColor": "#1a2d46", 'color': '#ffffff'}) # html.Button("Custom export", id="export_table", **{"data-dummy": ""}), # dcc.Slider( # id=slider_id, # marks={i: '{}'.format(i) for i in range(20)}, # max=20, # value=2, # step=1, # updatemode='drag', # min=0, # ), ]) self.app.clientside_callback( """ function(n_clicks) { if (n_clicks > 0) document.querySelector("#topanime a.modebar-btn").click() return "" } """, Output("export_table", "data-dummy"), [Input("export_table", "n_clicks")]) @self.app.callback(Output(graph_id, 'figure'), app_input_state_list) def display_value(value): trendshow = TrendReq(hl='en-US', tz=360) kw_list = [] if top_bool: for k in range(0, 5): kw_list.append(self.get_top_anime_names(k, 'tv')) else: kw_list.append(self.search_anime(anime_name)) kw_group = list(zip(*[iter(kw_list)] * 1)) kw_grplist = [list(x) for x in kw_group] dic = {} i = 0 for kw in kw_grplist: trendshow.build_payload(kw, timeframe='today 1-w', geo='') dic[i] = trendshow.interest_over_time() i += 1 trendframe = pd.concat(dic, axis=1) trendframe.columns = trendframe.columns.droplevel(0) trendframe = trendframe.drop('isPartial', axis=1) trace = [ go.Scatter(x=trendframe.index, y=trendframe[col], name=col) for col in trendframe.columns ] layout = dict(paper_bgcolor='#27293d', plot_bgcolor='rgba(0,0,0,0)', font=dict(color='white'), showlegend=True) return {'data': trace, 'layout': layout} def get_top_anime_names(self, rank: int, subtype: str): top_anime = self.jikan.top(type='anime', page=1, subtype=subtype) time.sleep(0.5) return top_anime["top"][rank]["title"] def search_anime(self, anime_name): search = self.jikan.search('anime', anime_name) time.sleep(0.5) return search["results"][0]["title"] def return_graph(self): trendshow = TrendReq(hl='en-US', tz=360) kw_list = [] if self.top_bool: for k in range(0, 5): kw_list.append(self.get_top_anime_names(k, 'tv')) else: kw_list.append(self.search_anime(self.anime_name)) kw_group = list(zip(*[iter(kw_list)] * 1)) kw_grplist = [list(x) for x in kw_group] dic = {} i = 0 for kw in kw_grplist: trendshow.build_payload(kw, timeframe='today ' + self.time_scale, geo='') dic[i] = trendshow.interest_over_time() i += 1 trendframe = pd.concat(dic, axis=1) trendframe.columns = trendframe.columns.droplevel(0) trendframe = trendframe.drop('isPartial', axis=1) fig = { 'data': [ go.Scatter(x=trendframe.index, y=trendframe[col], name=col, line=dict(color=self.graph_color)) for col in trendframe.columns ], 'layout': dict( #legend=dict(font=dict(color='#7f7f7f')), paper_bgcolor='#27293d', plot_bgcolor='rgba(0,0,0,0)', font=dict(color='white'), showlegend=True) } return dcc.Graph(id=self.graph_id, figure=fig) def return_layout(self): return self.app.layout