Select data to update from one plot to update multiple plots, with dropdown filter. Strange behaviour

I am trying to adapt the final plotly dash example on this page to my dataset and to include a dropdown filter. The idea is that I can select data on any of the three graphs and it will be highlighted on the others, with the dropdown providing a general filter for the dataasets.

Dataset structure:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 38124 entries, 0 to 38123
Data columns (total 9 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   Col1    38124 non-null  float64
 1   Col2    38124 non-null  float64
 2   Col3    38124 non-null  float64
 3   Col4    38124 non-null  float64
 4   Col5    38124 non-null  float64
 5   Col6    38124 non-null  float64
 6   Col7    38124 non-null  float64
 7   Col8    38124 non-null  int64  
 8   Col9    38124 non-null  float64
dtypes: float64(8), int64(1)
memory usage: 2.6 MB

When I just substituted my dataset into the example I could get the output I expected. However, when I start to include filtering based on Col2 in a dropdown, the behaviour of the output becomes quite strange. All of the data displays like it is unselected, then when I try to select data nothing happens.

My aim is that I will be able to filter the dataset on Col2 using the dropdown, and then have the behaviour demonstrated in the example. Any thoughts would be welcome.

Code below:

# Build App
app = JupyterDash(__name__)
app.layout = html.Div([
    html.Div([
            dcc.Dropdown(
                id='dropdown', clearable=False, multi=True,
                value=df['Col2'].unique(), options=[
                    {'label': f'{int(c)} bin', 'value': c}
                    for c in np.sort(df['Col2'].unique())
                ])
    ], style={'width': '30%',}),
    
    html.Div([
            dcc.Graph(id='graph1')
    ], style={'width': '33%', 'display': 'inline-block',}),
    html.Div([
            dcc.Graph(id='graph2')
    ], style={'width': '33%', 'display': 'inline-block',}),
    html.Div([
            dcc.Graph(id='graph3')
    ], style={'width': '33%', 'display': 'inline-block',}),       
], style={'background-color': 'white'})

# Define plotting function
def get_figure(df, xcol, ycol, selectedpoints, selectedpoints_local):
    if selectedpoints_local and selectedpoints_local['range']:
        ranges = selectedpoints_local['range']
        selection_bounds = {'x0': ranges['x'][0], 'x1': ranges['x'][1],
                            'y0': ranges['y'][0], 'y1': ranges['y'][1]}
    else:
        selection_bounds = {'x0': np.min(df[xcol]), 'x1': np.max(df[xcol]),
                            'y0': np.min(df[ycol]), 'y1': np.max(df[ycol])}


    fig = px.scatter(df, x=df[xcol], y=df[ycol])

    fig.update_traces(selectedpoints=selectedpoints,
                        customdata=df.index,
                      mode='markers',  
                      unselected={'marker': { 'opacity': 0.2 }})
                      
    fig.update_layout(margin={'l': 20, 'r': 0, 'b': 15, 't': 5}, dragmode='select', hovermode=False)
    
    fig.add_shape(dict({'type': 'rect',
                        'line': { 'width': 1, 'dash': 'dot', 'color': 'darkgrey' } },
                       **selection_bounds))
    return fig

# Define callback
@app.callback(
    Output('graph1', 'figure'),
    Output('graph2', 'figure'),
    Output('graph3', 'figure'),

    [Input('dropdown', 'value'), Input('graph1', 'selectedData'),],
    [Input('dropdown', 'value'), Input('graph2', 'selectedData'),],
    [Input('dropdown', 'value'), Input('graph3', 'selectedData'),],
)
def callback(dd1, selection1, dd2, selection2, dd3, selection3,):
    df_graph = df[(df['Col2'].isin(dd1)) & (df['Col1'] >= 40) & (df['Col1'] <= 65)]
    selectedpoints = df_graph.index
    trigger = callback_context.triggered[0]['prop_id'].split('.')[0]
    if trigger == 'dropdown': # introduced this to 'reset' the selection everytime a new dropdown selection is made 
        selection1 = None
        selection2 = None
        selection3 = None
    for selected_data in [selection1, selection2, selection3]:
        if selected_data and selected_data['points']:
            selectedpoints = np.intersect1d(selectedpoints,
                [p['customdata'] for p in selected_data['points']])
    return [get_figure(df_graph, "Col1", "Col3", selectedpoints, selection1),
            get_figure(df_graph, "Col4", "Col3", selectedpoints, selection2),
            get_figure(df_graph, "Col5", "Col3", selectedpoints, selection3,)]
    
app.run_server(mode='external')

Hi,

It could be unrelated, but you reference two dataframes in the mask where you define df_graph. You can check if this dataframe is empty.

Thank you for flagging that, unfortunately this is not the source of the error. I have updated the code in my original post to reflect the correct df references.