Olga
Olga

Reputation: 31

Dash Plotly: Highlighting point on the graph

I was googl'ing around trying to find solution for the following question (no luck so far). I am using Plotly Dash callback in order to build a graph:

@app.callback(
    Output("graph", "figure"),
    [Input("some-input", "value")],
    [State("some-state", "value")])
def build_graph(input_value, state_value):
    // computing data for graph_figure
    return graph_figure

Now, I want to have another callback which will highlight a specific point on the graph (or add/remove a point) based on some input condition. I struggle to figure out what to use for Output in this case? Because I cannot output graph.figure again (Dash does not allow output to the same component from different callbacks). And re-drawing entire graph seems to be inefficient.

I will appreciate any suggestions.

Upvotes: 1

Views: 2779

Answers (1)

Philipp
Philipp

Reputation: 1391

It is possible to change the layout of your graph without redrawing the whole graph by using this library: https://github.com/jimmybow/mydcc

There is an example how to use it here: https://github.com/jimmybow/mydcc#3-mydccrelayout-

I have prepared a small example that adds an annotation on button click. Don't forget to pip install mydcc beforehand. I had to add a cache - in form of an invisible div - to preserve the old annotations when adding a new one.

import dash
import dash_core_components as dcc
import dash_html_components as html
import mydcc
import random
import json

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)


initial_layout = {'title': 'Dash Data Visualization'}

app.layout = html.Div(children=[
    html.H1(children='Hello Dash'),

    html.Div(children='''
        Dash: A web application framework for Python.
    '''),

    dcc.Graph(
        id='example-graph',
        figure={
            'data': [{'x': [1, 2, 3], 'y': [4, 1, 2], 'name': 'Test'}],
            'layout': initial_layout
        }
    ),
    mydcc.Relayout(id="rrr", aim='example-graph'),
    html.Button('Add random annotation', id='button'),
    html.Div(id='user-cache', style={'display': 'none'},
             children=json.dumps(initial_layout)),
])

@app.callback(
    [dash.dependencies.Output('rrr', 'layout'),
     dash.dependencies.Output('user-cache', 'children')],
    [dash.dependencies.Input('button', 'n_clicks')],
    [dash.dependencies.State('user-cache', 'children')])
def update_graph_annotations(n_clicks, layout):
    if n_clicks is not None:
        layout = json.loads(layout)
        if not 'annotations' in layout:
            layout['annotations'] = []
        layout['annotations'].append(dict(
            x=random.uniform(0, 1) * 2 + 1,
            y=random.uniform(0, 1) * 2 + 1,
            xref="x",
            yref="y",
            text="Annotation" + str(n_clicks),
            showarrow=True
        ))
        return layout, json.dumps(layout)
    return dash.no_update, dash.no_update




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

Upvotes: 1

Related Questions