Black Lives Matter. Please consider donating to Black Girls Code today.

[Solution] Persistent click events

Here is a solution for appending multiple click events in a hidden div. The current list of events is accessed through State, and then updated with the most recent click event Input.

import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import json
import copy
import pandas as pd

def generate_table(dataframe, max_rows=10, show_index = True):
    if show_index:
        return html.Table(
            # Header
            [html.Tr([html.Th(dataframe.index.name)] + [html.Th(col) for col in dataframe.columns])] +

            # Body
            [html.Tr([html.Td(dataframe.index[i])] + [
                html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
            ]) for i in range(min(len(dataframe), max_rows))]
        )
    else:
        return html.Table(
            # Header
            [html.Tr([html.Th(col) for col in dataframe.columns])] +

            # Body
            [html.Tr([
                html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
            ]) for i in range(min(len(dataframe), max_rows))]
        )

app = dash.Dash()

FIGURE = {
    'data': [{
        'x': [1, 2, 3],
        'y': [4, 3, 6],
        'mode': 'markers',
        'marker': {
            'size': 12
        }
    }],
    'layout': {
        'xaxis': {},
        'yaxis': {},
    }
}
description = '''
Try clicking on different points. The table updates
with each clicked data point. 

Appending is accomplished by storing
click events in a hidden div, which is accessed through a State variable:

'''
app.layout = html.Div([
    html.H3('Persistent click events'),
    dcc.Markdown(description),

    dcc.Graph(
        id='my-graph',
        figure=FIGURE
    ),
    html.Div(id = 'selected-data'),
    html.Div(id = 'hidden-div', style = {'display': 'none'}),
])

@app.callback(
    Output('hidden-div', 'children'),
    [Input('my-graph', 'clickData')],
    [State('hidden-div', 'children')])
def get_selected_data(clickData, previous):
    if clickData is not None:
        result = clickData['points']
        if previous:
            previous_list = json.loads(previous)
            if previous_list is not None:
                result = previous_list + result
        return json.dumps(result)

@app.callback(
    Output('selected-data', 'children'),
    [Input('hidden-div', 'children')]
    )
def display_selected_data(points):
    if points:
        result = json.loads(points)
        if result is not None:
            return generate_table(pd.DataFrame(result))




app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

if __name__ == '__main__':
    app.run_server(debug=True)
4 Likes

This is really great! Also stay tuned for native persistent clicks here: https://github.com/plotly/plotly.js/issues/2143 and upcoming multiple selection regions here: https://github.com/plotly/plotly.js/pull/2140

This i great I have a stacked column chart and am using this to filter data by the XAxis position of the click but I’m wondering could the click event identify the actual element in the stacked column that was clicked.