Bring Drag & Drop to Dash with Dashboard Engine. 💫 Learn how at our next webinar!

Parsing output from one subplot to update second subplot in dash

Hi all, thanks to the developers for this amazing and easy-to-use package!

I am hoping to solicit ideas on how to implement a certain application in dash python using Plotly mixed_subplots. Below is a screen grab of my start point. On the left I have a go.Scattergeo plot with locations on a map and on the right I have a correlation go.Heatmap between the pairs of the locations on the left.

I’m trying to implement an app in which the user selects a pair of locations from the left side and this will zoom/scale the correlation heatmap to the spot/element which contains the pair of locations (or even simply, place the x & y spikes on the corresponding element in the heatmap without zooming).

How do I go about taking in as input a click from my Scattergeo plot and updating the Heatmap based on that?

Below is the code I’ve used to create the mixed_subplots with my attempt to implement the appropriate dash callback (to even just print out the corresponding locations being clicked on the left), but I’m completely lost. I’m not sure if I’m even using the right objects for a task like this…

# making a subplots object
bigfig = make_subplots(rows=1, cols=2, specs=[[{"type": "scattergeo"}, {"type": "xy"}]], column_widths=[0.6,0.4])

# creating scattergeo plot
bigfig.add_trace(go.Scattergeo(lat=rescoord[:,1], lon=rescoord[:,0], opacity=0.8, textfont={'family':'Arial'}), row=1, col=1)
bigfig.update_traces(marker=dict(color=['olivedrab']*111, 
size=8.*np.sqrt(sp_graph.n_samples_per_obs_node_permuted), 
line=dict(color='black', width=0.5)))
bigfig.update_layout(autosize=True, clickmode='event')
bigfig.update_geos(resolution=50,coastlinecolor='#9fa0a4',landcolor='#cccccc',fitbounds='locations', projection={'type':'robinson'}, center={'lat':np.median(rescoord[:,1]),'lon':np.median(rescoord[:,0])})

# creating heatmap plot
bigfig.add_trace(go.Heatmap(z=resmat, colorscale='balance', showscale=True, zmid=0), row=1, col=2)
bigfig.update_layout(font_family='Arial')
bigfig.update_xaxes(showspikes=True)
bigfig.update_yaxes(showspikes=True)

# defining app layout
app.layout = html.Div([
    dcc.Graph(id='locs',figure=bigfig, style={'width': 1600, 'height': 800})
])

# my attempt at trying to extract the clicks...
@app.callback(Output('locs', 'children'), Input('trace0', 'value'), Input('trace1', 'value'))
def on_click(x):
    if trace0 is None & trace1 is None:
        raise PreventUpdate
    elif trace0 is None:
        return 'The {} gives {} value...'.format(trace0,resmat[trace0,:])
    else:
        return 'The {} gives {} value...'.format(trace0,resmat[trace1,:])

app.run_server()

Hi!

I echo your words about Dash! :smiley: It has also a great documentation with some nice examples, so I will first point you out to the part about Interactive Graphing.

To trigger click events in dcc.Graph, one has to use the clickData property of it, so in your case this would be Input("locs", "clickData"). However, since you want to select multiple points on click (not one at each time), you should probably use selectedData instead with the layout.clickmode = 'event+select' option (more info in the docs!).

To rewrite your heatmap using this info, you must take a look on how clickData/selectedData is structured. Here is the documentation for Plotly.js about it and it should be straightforward to “translate” it into Python.

There is a caveat for your case though: since you have a subplot Figure, both of your graphs are in the same “figure” object as different traces, so I would recommend you to decouple them by using two dcc.Graph components. That way you can target Output("heatmap-id", "figure") in the callback without updating the scatterMap.

Hope that this helps and please follow up if you have further questions! :smiley: