Dash Crossfilter Scatter Hover Data and Custom Data do not Match Plot

Hi, I am trying to modify the code in the ‘Update Graphs on Hover’ section here: Part 3. Interactive Graphing and Crossfiltering | Dash for Python Documentation | Plotly. However, the hover data displayed on my plot, as well as the customdata do not match what was plotted. I strongly feel there must be some indexing going on that I do not understand. The blob_df generated should look like this:

. Notice in particular that the train_val column is filled with str. However, hovering over the data we can see that the ‘train_val’ hover data seems to be populated by int.

You can observe the same thing if you monitor my_demo_log.txt while hovering over various points – the X, y values do not even match. What am I missing that will get my hover and custom data index properly?

Thank you

from dash import Dash, html, dcc, Input, Output
import pandas as pd
import plotly.express as px
import joblib as jb
import numpy as np
from sklearn.datasets import make_blobs

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

app = Dash(__name__, external_stylesheets=external_stylesheets)

np.random.seed(42)


b = make_blobs(n_samples = 200, random_state=42)
blob_df = pd.DataFrame(b[0], columns = ['X', 'y'])
blob_df['class'] = b[1]
blob_df['site'] = np.random.randint(0, 1, len(blob_df))
blob_df.loc[:150, 'train_val'] = 'train'
blob_df.loc[150:, 'train_val'] = 'val'
symbol_color_cols = []
for i in range(3):
    new_col = f'predicted_class_v{i}'
    blob_df[new_col] = blob_df['class'].copy()
    alter_idx = np.random.randint(0, 200, 50)
    alter_vals = np.random.randint(0, 2, 50)
    blob_df.loc[alter_idx, new_col] = alter_vals
    symbol_color_cols.append(new_col)
symbol_color_cols = symbol_color_cols + ['class']
blob_df['info0'] = np.arange(0, 200, 1)
blob_df['info2'] = (blob_df['info0']) * 10


app.layout = html.Div([
    html.Div([
       
        dcc.RadioItems(
            symbol_color_cols,
            symbol_color_cols[0],
            id='symbol_col',
            labelStyle={'display': 'inline-block', 'marginTop': '5px'}
        )
    ],
    style={'width': '49%', 'display': 'inline-block'}),
    html.Div([
       
        dcc.RadioItems(
            symbol_color_cols,
            symbol_color_cols[1],
            id='color_col',
            labelStyle={'display': 'inline-block', 'marginTop': '5px'}
        )
    ],
    style={'width': '49%', 'display': 'inline-block', 'float':'right'}),

    html.Div([
            dcc.Graph(
                id='umap-scatter',
                #hoverData={'points': [{'customdata': None}]}
            )
        ], #style={'width': '100%', 'height':'75%', 'display': 'inline-block', 'padding': '0 20'}),
            style={'width': '100%', 'display': 'inline-block', }),
    html.Div([
            dcc.Graph(
                id='dummy-div',
                #hoverData={'points': [{'customdata': 'Japan'}]}
            )
        ], #style={'width': '100%', 'height':'75%', 'display': 'inline-block', 'padding': '0 20'}),
            style={'width': '100%', 'display': 'inline-block', }),


])

@app.callback(
    Output('umap-scatter', 'figure'), 
    Input('symbol_col', 'value'), 
    Input('color_col', 'value'))
def update_umap_scatter(symbol_col, color_col):
    #plot_me = blob_df.reset_index(drop = True)
    #hover_dat = plot_me.copy()
    fig = px.scatter(data_frame=blob_df,
                    color_discrete_map={'0':'deepskyblue', '1':'olive', '2':'coral',},
                    symbol_map={'0':'circle', '1':'hourglass', '2':'star'},
                    x ='X', 
                    facet_row='site', facet_col='train_val', y = 'y',
                    color = color_col, symbol=symbol_col, hover_data=list(blob_df.columns)
                    )
    fig.update_traces(customdata=blob_df.copy())
    #fig.update_traces(hover_data=list(hover_dat.columns))
    #fig.update_traces(hovertemplate = f'hover_data_0=%{customdata[0]}<br>label=%{customdata[1]}<extra></extra>')
    fig.update_layout(height=800,
        legend=dict(
        
        yanchor="top",
        y=0.99,
        xanchor="left",
        x=-.1
    ))
    return fig

@app.callback(
        Output('dummy-div', 'figure'), 
        Input('umap-scatter', 'hoverData'),
)
def log_hoverdata(hoverData, ):
    hdp = hoverData['points']
    with open('my_demo_log.txt', 'w') as f:
        f.write(str(hdp))

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