Hello everyone,
I have a dashboard with cross-filtering. The issue I am facing is the following:
- I filter chart A
- I filter chart B
- I have a button which resets all the filters, i.e. sets selectedpoints for both charts to None
Everything up to here works just fine.
When I reapply the filter on either of those charts, the other filter gets applied as well. I checked and the “selectedData” callback returns points for both charts, eventhough it has previously been set to None.
My code is below:
import dash
import dash_table
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import datetime
from dash.dependencies import Input, Output
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
total_clicks = 0 # keep track of total clicks
df = pd.read_csv('data.csv').reset_index(drop=True)
df['published']= pd.to_datetime(df['published'])
styles = {
'pre': {
'border': 'thin lightgrey solid',
'overflowX': 'scroll'
}
}
selections = {
'sel1' : {'name' : 'crossfilter-error-bar-filetype', 'sort' : True, 'prev' : None, 'field' : 'file_type', 'axis' : 'y', 'data' : 'x', 'orientation' : 'h', 'type' : 'bar'},
'sel2' : {'name' : 'crossfilter-error-bar-entity', 'sort' : True, 'prev' : None, 'field' : 'entity_type', 'axis' : 'y', 'data' : 'x', 'orientation' : 'h', 'type' : 'bar'},
'sel3' : {'name' : 'crossfilter-error-bar-operation', 'sort' : True, 'prev' : None, 'field' : 'action', 'axis' : 'y', 'data' : 'x', 'orientation' : 'h', 'type' : 'bar'},
'sel4' : {'name' : 'crossfilter-error-bar-reason', 'sort' : True, 'prev' : None, 'field' : 'error_type', 'axis' : 'y', 'data' : 'x', 'orientation' : 'h', 'type' : 'bar'},
'sel5' : {'name' : 'crossfilter-error-pie-attribute', 'sort' : True, 'prev' : None, 'field' : 'error_attribute', 'axis' : 'x', 'data' : 'y', 'orientation' : 'v', 'type' : 'bar'},
'sel6' : {'name' : 'crossfilter-error-pie-file', 'sort' : True, 'prev' : None, 'field' : 'filename', 'axis' : 'x', 'data' : 'y', 'orientation' : 'v', 'type' : 'bar'},
'sel7' : {'name' : 'crossfilter-error-line-time', 'sort' : False,'prev' : None, 'field' : 'published', 'axis' : 'x', 'data' : 'y', 'orientation' : 'v', 'type' : 'scatter'}
}
app.layout = html.Div([
#Row 1 - Input
html.Div(html.Button('Reset selections', id='reset'), style={'width': '20%', 'display': 'inline-block'}),
html.Div([html.Label('Password')], style={'width': '10%', 'display': 'inline-block', 'textAlign': 'center'}),
html.Div([dcc.Input(id='PassInput',type='password')],style={'width': '68%', 'display': 'inline-block'}),
#Row 2 - Horisontal bars
html.Div([dcc.Graph(id='crossfilter-error-bar-filetype' , style={'height': 150},)],style={'width': '24%', 'display': 'inline-block'}),
html.Div([dcc.Graph(id='crossfilter-error-bar-entity' , style={'height': 150},)],style={'width': '25%', 'display': 'inline-block'}),
html.Div([dcc.Graph(id='crossfilter-error-bar-operation', style={'height': 150},)],style={'width': '24%', 'display': 'inline-block'}),
html.Div([dcc.Graph(id='crossfilter-error-bar-reason' , style={'height': 150},)],style={'width': '25%', 'display': 'inline-block'}),
#Row 3 - Vertical bars
html.Div([dcc.Graph(id='crossfilter-error-pie-attribute', style={'height': 200},)],style={'width': '49%', 'display': 'inline-block'}),
html.Div([dcc.Graph(id='crossfilter-error-pie-file' , style={'height': 200},)],style={'width': '49%', 'display': 'inline-block'}),
#Row 4 - Time chart
html.Div([dcc.Graph(id='crossfilter-error-line-time' , style={'height': 300},)],style={'width': '98%', 'display': 'inline-block'}),
#Row 5 - Data table
html.Div([dash_table.DataTable(id='data_table',
columns=[{"name": i, "id": i} for i in df.columns],
style_table={'overflowX': 'scroll','overflowY': 'scroll','maxHeight': '600px',},
fixed_rows={ 'headers': True, 'data': 0 })],style={'width': '98%', 'display': 'inline-block'}),
])
@app.callback(
[Output('crossfilter-error-bar-filetype', 'figure'),
Output('crossfilter-error-bar-entity', 'figure'),
Output('crossfilter-error-bar-operation', 'figure'),
Output('crossfilter-error-bar-reason', 'figure'),
Output('crossfilter-error-pie-attribute', 'figure'),
Output('crossfilter-error-pie-file', 'figure'),
Output('crossfilter-error-line-time', 'figure'),
Output('data_table', 'data'),
],
[Input('reset', 'n_clicks'),
Input('crossfilter-error-bar-filetype', 'selectedData'),
Input('crossfilter-error-bar-entity', 'selectedData'),
Input('crossfilter-error-bar-operation', 'selectedData'),
Input('crossfilter-error-bar-reason', 'selectedData'),
Input('crossfilter-error-pie-attribute', 'selectedData'),
Input('crossfilter-error-pie-file', 'selectedData'),
Input('crossfilter-error-line-time', 'selectedData'),
])
def display_click_data(n_clicks, *local_selection):
global total_clicks
sub = df.copy()
if n_clicks and n_clicks > total_clicks:
local_selection = [None for k in local_selection]
total_clicks = n_clicks
else:
for idx, item in enumerate(selections):
if local_selection[idx] and local_selection[idx]['points']:
axis = selections.get(item).get('axis')
field = selections.get(item).get('field')
sub = sub[sub[field].isin([p[axis] for p in local_selection[idx]['points']])]
return [generate_chart(sub.index, 'sel1', local_selection[0]),
generate_chart(sub.index, 'sel2', local_selection[1]),
generate_chart(sub.index, 'sel3', local_selection[2]),
generate_chart(sub.index, 'sel4', local_selection[3]),
generate_chart(sub.index, 'sel5', local_selection[4]),
generate_chart(sub.index, 'sel6', local_selection[5]),
generate_chart(sub.index, 'sel7', local_selection[6]),
dt_table(sub.index, None)]
def generate_chart(filter, id, selectedpoints):
grp = df[df.index.isin(filter)]
grp = grp.groupby(selections.get(id).get('field'))[selections.get(id).get('field')].count()
if selections.get(id).get('sort'):
grp = grp.sort_values()
chart = {
"data": [{"type": selections.get(id).get('type'),
'orientation': selections.get(id).get('orientation'),
selections.get(id).get('data'): grp.values,
selections.get(id).get('axis'): grp.index,
'selectedpoints': selectedpoints
}],
"layout": {"title": {"text" : selections.get(id).get('field')},
'xaxis' : {"type" : "log"},
'clickmode': 'select+event',
'dragmode': 'select+event',
"margin": {"l": 100, "r": 50, "b": 50, "t": 50, "pad": 4},
"xaxis" : {"showticklabels" : False}}
}
return chart
def dt_table(filter, selected):
grp = df[df.index.isin(filter)]
return grp.to_dict('records')
if __name__ == '__main__':
app.run_server(debug=True)