Python – How to get mouse drawing graph data in Dash

How to get mouse drawing graph data in Dash… here is a solution to the problem.

How to get mouse drawing graph data in Dash

So I have this simple python dash application where I laid out a graphic and a button.
My goal: when I press the button, I want to retrieve the shape that has been drawn.

import plotly.graph_objects as go
import dash
from dash import html, dcc, Input, Output, State

app = dash. Dash(__name__)
fig = go. Figure()

app.layout = html. Div([
                        dcc.Graph(id = "graph-pic", className="graph-pic", figure=fig, config={'modeBarButtonsToAdd':['drawrect', 'eraseshape']}),
                        .html. Button("Shape count", id = "shape-count-button")
                    ])
        
fig.add_shape(editable=True, x0=-1, x1=0, y0=2, y1=3, xref='x', yref='y')

@app.callback(
    Output("graph-pic", "figure"),
    Input("shape-count-button", "n_clicks")
)
def on_shape_count_button_pressed(n_clicks):
    trigger_id = dash.callback_context.triggered_id

if trigger_id == "shape-count-button":
        print("Shape count: " + str(len(fig.layout.shapes)))
        print(fig.layout.shapes)
    
return dash.no_update

if __name__ == "__main__":
    app.run_server()

Dash app
When I press the button, it only prints the first shape I added through the code… Instead of the shape I drew on the graph using the Draw Rectangle tool.

Output:

Shape count: 1
(layout. Shape({
    'editable': True, 'x0': -1, 'x1': 0, 'xref': 'x', 'y0': 2, 'y1': 3, 'yref': 'y'
}),)

Any tips would be appreciated!

Solution

You should use relayout_data to detect all drawn shapes on the graph, and then you can parse the required data as you do:

import dash
import json
import plotly.graph_objects as go
from dash import html, dcc, Input, Output, State

app = dash. Dash(__name__)
fig = go. Figure()

app.layout = html. Div([
                        dcc.Graph(id = "graph-pic", className="graph-pic", figure=fig, config={'modeBarButtonsToAdd':['drawrect', 'eraseshape']}),
                        .html. Button("Shape count", id = "shape-count-button"),
                        .html. Div(id="text")
                    ])
        
fig.add_shape(editable=True, x0=-1, x1=0, y0=2, y1=3, xref='x', yref='y')

@app.callback(
    Output("text", "children"),
    Input("shape-count-button", "n_clicks"),
    Input("graph-pic", "relayoutData"),
)
def on_shape_count_button_pressed(n_clicks, relayout_data):
    
trigger_id = dash.callback_context.triggered_id

if trigger_id == "shape-count-button":
        text_lst = "Shape count: " + str(len(fig.layout.shapes))
        text_lst += str(fig.layout.shapes)
        
if "shapes" in relayout_data:
            text_lst += json.dumps(relayout_data["shapes"], indent=2)
            
return text_lst
    
return dash.no_update

if __name__ == "__main__":
    app.run_server()

Output
enter image description here

Related Problems and Solutions