Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Interactive Graphing & 'customdata' in callbacks

Hi Dash Community,

I’m trying to add interactivity to my dashboard following the code examples given here: (https://dash.plot.ly/interactive-graphing). In the “Update Graphs on Hover” section the callbacks use this syntax to grab custom data defined in the figure for a callback update, country_name = hoverData[‘points’][0][‘customdata’]. I’m trying to adapt this for use in clickData using the same syntax. However, I keep getting a type error that says: “TypeError: string indices must be integers”. To me that would indicate that after [‘points’] all further sub-indexing would have to be integers. But that’s not the way the example code is doing things. Without being able to access that ‘customdata’ property I can’t update my figure properly. Best I can come up with is that there something about the ‘customdata’ property that I’m not using properly. But I haven’t been able to find any documentation to validate that hunch. Thoughts? Any assistance would be greatly appreciated.

-cyranothebard

Hi @cyranothebard, below is the code of the callbacks adapted for clickData. I had to test whether clickData is None and in this case return dash.no_update, otherwise I also had indexing problems (because None cannot be indexed). I hope the code below also works for you

@app.callback(
    dash.dependencies.Output('x-time-series', 'figure'),
    [dash.dependencies.Input('crossfilter-indicator-scatter', 'clickData'),
     dash.dependencies.Input('crossfilter-xaxis-column', 'value'),
     dash.dependencies.Input('crossfilter-xaxis-type', 'value')])
def update_y_timeseries(clickData, xaxis_column_name, axis_type):
    if not clickData:
        return dash.no_update
    country_name = clickData['points'][0]['customdata']
    dff = df[df['Country Name'] == country_name]
    dff = dff[dff['Indicator Name'] == xaxis_column_name]
    title = '<b>{}</b><br>{}'.format(country_name, xaxis_column_name)
    return create_time_series(dff, axis_type, title)
    

@app.callback(
    dash.dependencies.Output('y-time-series', 'figure'),
    [dash.dependencies.Input('crossfilter-indicator-scatter', 'clickData'),
     dash.dependencies.Input('crossfilter-yaxis-column', 'value'),
     dash.dependencies.Input('crossfilter-yaxis-type', 'value')])
def update_x_timeseries(clickData, yaxis_column_name, axis_type):
    if not clickData:
        return dash.no_update
    dff = df[df['Country Name'] == clickData['points'][0]['customdata']]
    dff = dff[dff['Indicator Name'] == yaxis_column_name]
    return create_time_series(dff, axis_type, yaxis_column_name)

Hi @Emmanuelle!

Thanks for responding. I appreciate your suggestion about the dash.no_update needing to be added. That makes a lot of sense and I’ve adjusted my update function to reflect that. However, I believe I’ve got a more fundamental issue that must be resolved first. My customdata is a string, a label for one of the series in my stacked bar plot. I’ve currently got a json dump attached to my graph to show the results of my clickData to help troubleshoot. It seems my customdata string is being indexed by PointNumber or PointIndex. I can’t troubleshoot my update function if the input to that function isn’t properly formatted. I’ve included screenshots of my dashboard and the relevant functions below. If I can disconnect my customdata formatting from PointNumber/PointIndex and get the indexing to work then I think I’ll be able to get the update functions working. Maybe I’m missing something about the nature of customdata indexing behavior or something…Thanks again for your help!

I don’t think the problem is with customdata, but with clickData['points']['x']: you need clickData['points'][0]['x'] instead. Don’t hesitate to add a lot of print statements to debug this kind of problems :-).

Ok. But I still have to make sure the string is getting passed properly from customdata. Currently it’s still getting split up only returning the letter at the index given by pointNumber/pointIndex as shown in the top pic in the json. Do you know if there’s a connection between those keys that I can disable or if maybe I need to change the format of my customdata value?