selectedData event not triggered on select

Hello

I have two graphs, both line graphs. X axis is date, Y axis is hours of day
Once i run code, i see both graphs as expected, here I have not selected any points on first graph (trend_grapgh).
Callback is triggered , i do see parameter values printed on console

Then i select section on trend graph and expect selection data to be sent to callback.
I dont see callback triggered , print of selection is still none
What am i missing here?

Code below:

import pandas as pd
import plotly.express as px
import dash
from dash import dcc,html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc

df = pd.read_csv ('TrendData.csv')

df['USER_EXTRACT_END_TIME'] = pd.to_datetime(df['USER_EXTRACT_END_TIME'], format='%H:%M:%S')
df['BATCH_END_TIME'] = pd.to_datetime(df['BATCH_END_TIME'], format='%H:%M:%S')
df['LAST_FILE_RECEIVED'] = pd.to_datetime(df['LAST_FILE_RECEIVED_HHMI'], format='%H:%M:%S')
df['COB_DT']=pd.to_datetime(df['COB_DT'], format='%d/%m/%Y')
df['Duration']= (df['BATCH_END_TIME']-df['LAST_FILE_RECEIVED']).astype('timedelta64[s]')/60
df['Weekday']=df['COB_DT'].dt.day_name()

app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
#app.config['suppress_callback_exceptions']=True

controls = dbc.Card(
    [
        html.Div(
            [
                dbc.Label("Product"),
                dcc.Dropdown(id='product_option',
                             options=[{'label': x, 'value': x} for x in df.sort_values('PRODUCT')['PRODUCT'].unique()],
                             value='Product1',
                             multi=False,
                             disabled=False,
                             clearable=True,
                             searchable=True,
                             placeholder='Choose Product...',
                             className='form-dropdown',
                             style={'width': "100%"},
                             persistence='string',
                             persistence_type='memory'),
            ]
        ),
        html.Div(
            [
                dbc.Label("Weekday"),
                dcc.Dropdown(id='weekday_option',
                             options=[{'label': x, 'value': x} for x in
                                      df.sort_values('Weekday')['Weekday'].unique()] + [
                                         {'label': 'All Weekdays', 'value': 'all_values'}],
                             value='all_values',
                             multi=False,
                             clearable=False,
                             style={'width': "100%"},
                             persistence='string',
                             persistence_type='session'),
            ]
        ),
    ],
    body=True,
    style={"width": "25rem"},
)


app.layout = dbc.Container(
[
    html.H1("Batch Process"),
    html.Hr(),
    dbc.Row(
        [
            dbc.Col(controls, width=3),
        ],
        align="start",
    ),
    dbc.Row(
        [
            dbc.Col(dcc.Graph(id='trend_graph'),
                              width="auto",
                              style={"height": "60%", "width": "80%"}),

        ],
        align="center",
    ),
    dbc.Row(
        [
            dbc.Col(dcc.Graph(id='duration_graph'),
                              width="auto",
                              style={"height": "60%", "width": "80%"}),
        ],
        align="center",
    ),
    html.Br(),
    html.Div(id='my-output'),
],
#fluid=True,
)

#---------------------------------------------------------------

def build_graph(dff,product, weekday):

    trendfig = px.line(dff,x='COB_DT', y=["USER_EXTRACT_END_TIME",
                                          "BATCH_END_TIME",
                                          "LAST_FILE_RECEIVED"]
                          )

    trendfig.update_layout(title={
        'text': "Batch Process Trend for Product "+product,
        'y':0.9,
        'x':0.5,
        'xanchor': 'center',
        'yanchor': 'top'},
        legend_title="Batch Status")

    durfig = px.line(dff, x='COB_DT', y=["Duration"])



    durfig.update_layout(title={
        'text': "Processing Time in Minutes for Product "+product,
        'y': 0.9,
        'x': 0.5,
        'xanchor': 'center',
        'yanchor': 'top'})

    trendfig.update_xaxes(
        title_text="COB Date",
        tickformat="%b\n%d")
    trendfig.update_yaxes(
        title_text="Time",
        tickformat="%H:%M")

    durfig.update_xaxes(
        title_text="COB Date",
        tickformat="%b\n%d")
    durfig.update_yaxes(
        title_text="Minutes",
        tickformat="%H:%M")



    return [trendfig,durfig]

@app.callback(
    [Output('trend_graph','figure'),
     Output('duration_graph', 'figure')],
    [Input('product_option','value'),
     Input('weekday_option','value'),
     Input('trend_graph', 'selectedData')]
)
def build_graph_callback(product, weekday,selection1):
    print(product)
    print(weekday)
    print(selection1)

    if weekday == 'all_values':
        dff = df[(df['PRODUCT'] == product)]
    else:
        dff=df[(df['PRODUCT']==product)&
               (df['Weekday']==weekday)]
    #print(dff[["LAST_FILE_RECEIVED","Duration"]])

    trendfig, durfig =  build_graph(dff,product,weekday)

    return [trendfig, durfig]


#---------------------------------------------------------------

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

Data:

"COB_DT","PRODUCT","FIRST_FILE_RECEIVED_HHMI","LAST_FILE_RECEIVED_HHMI","BATCH_END_TIME","USER_EXTRACT_END_TIME"
"01/12/2021","Product1","02:03:06","03:23:12","03:35:44","16:34:38"
"01/12/2021","Product2","06:04:08","15:41:57","16:12:11","16:34:38"
"01/12/2021","Product3","06:35:48","06:35:48","07:04:48","16:34:38"
"01/12/2021","Product4","12:00:49","15:54:02","16:16:01","16:34:38"
"01/12/2021","Product5","06:45:27","13:26:12","16:10:30","16:34:38"
"02/12/2021","Product1","01:49:04","02:07:06","02:38:38","18:00:13"
"02/12/2021","Product2","09:17:09","16:42:53","17:14:00","18:00:13"
"02/12/2021","Product3","06:39:54","06:39:54","06:55:05","18:00:13"
"02/12/2021","Product4","09:17:09","17:05:04","17:16:57","18:00:13"
"02/12/2021","Product5","06:44:09","15:06:03","17:45:05","18:00:13"
"03/12/2021","Product1","03:12:49","03:47:52","04:21:55","10:56:22"
"03/12/2021","Product2","02:27:20","06:57:48","08:03:43","10:56:22"
"03/12/2021","Product3","06:35:49","06:35:49","06:53:21","10:56:22"
"03/12/2021","Product4","02:27:20","10:25:12","10:41:41","10:56:22"
"03/12/2021","Product5","02:28:44","06:42:00","09:06:21","10:56:22"
"06/12/2021","Product1","01:40:47","02:20:50","02:50:43","18:20:16"
"06/12/2021","Product2","05:59:46","16:58:57","17:25:57","18:20:16"
"06/12/2021","Product3","10:22:37","10:22:37","10:42:12","18:20:16"
"06/12/2021","Product4","08:07:44","17:19:22","17:33:21","18:20:16"
"06/12/2021","Product5","06:43:11","14:51:31","18:05:40","18:20:16"
"07/12/2021","Product1","04:44:35","05:14:45","05:45:59","18:29:18"
"07/12/2021","Product2","01:54:40","17:42:03","18:13:40","18:29:18"
"07/12/2021","Product3","07:58:42","07:58:42","08:20:31","18:29:18"
"07/12/2021","Product4","01:54:40","17:57:20","18:08:22","18:29:18"
"07/12/2021","Product5","07:57:38","15:33:05","17:51:45","18:29:18"

Have you tried building trending and durfig normally in def_build_graph_callback?

This is:

durfig = px.line(dff, x='COB_DT', y=["Duration"])
# Styling 
trendfig = px.line(dff,x='COB_DT', y=["USER_EXTRACT_END_TIME",
                                      "BATCH_END_TIME",
                                      "LAST_FILE_RECEIVED"]
                      )
# Styling 

return trendfig, durfig

Hello
yes, tried building trending and durfigwithin callback
Dont see callback triggered when i select first (trend_graph)

Could you provide a dummy dataset, so I can test it on my side?

Data is provided within my initial post

You’re pointing to a CSV but there is no link to it.

@NAbraham :point_up_2:t3:

So I’ve came up with this

And here’s the code

# -*- coding: utf-8 -*-

# Import libraries

import time
import dash
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd

# import from dash
from dash import Input, Output, dcc, html  # please not the difference here

# Data Ingestion

df = pd.read_csv("TrendData.csv")

# Data Treatment

df["USER_EXTRACT_END_TIME"] = pd.to_datetime(
    df["USER_EXTRACT_END_TIME"], format="%H:%M:%S"
)
df["BATCH_END_TIME"] = pd.to_datetime(df["BATCH_END_TIME"], format="%H:%M:%S")
df["LAST_FILE_RECEIVED"] = pd.to_datetime(
    df["LAST_FILE_RECEIVED_HHMI"], format="%H:%M:%S"
)
df["COB_DT"] = pd.to_datetime(df["COB_DT"], format="%d/%m/%Y")
df["Duration"] = (df["BATCH_END_TIME"] - df["LAST_FILE_RECEIVED"]).astype(
    "timedelta64[s]"
) / 60
df["Weekday"] = df["COB_DT"].dt.day_name()


# Start app

app = dash.Dash(
    external_stylesheets=[dbc.themes.BOOTSTRAP],
    suppress_callback_exceptions=True,
    meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1"}],
)


controls = dbc.Card(
    [
        html.Div(
            [
                dbc.Label("Product"),
                dcc.Dropdown(
                    id="product_option",
                    options=[
                        {"label": x, "value": x}
                        for x in df.sort_values("PRODUCT")["PRODUCT"].unique()
                    ],
                    value="Product1",
                    multi=False,
                    disabled=False,
                    clearable=True,
                    searchable=True,
                    placeholder="Choose Product...",
                    className="form-dropdown",
                    style={"width": "100%"},
                    persistence="string",
                    persistence_type="memory",
                ),
            ]
        ),
        html.Div(
            [
                dbc.Label("Weekday"),
                dcc.Dropdown(
                    id="weekday_option",
                    options=[
                        {"label": x, "value": x}
                        for x in df.sort_values("Weekday")["Weekday"].unique()
                    ]
                    + [{"label": "All Weekdays", "value": "all_values"}],
                    value="all_values",
                    multi=False,
                    clearable=False,
                    style={"width": "100%"},
                    persistence="string",
                    persistence_type="session",
                ),
            ]
        ),
    ],
    body=True,
    style={"width": "25rem"},
)

app.layout = dbc.Container(
    [
        html.H1("Batch Process"),
        html.Hr(),
        dbc.Row(
            [
                dbc.Col(controls, width=3),
            ],
            align="start",
        ),
        dbc.Row(
            [
                dbc.Col(
                    dcc.Graph(id="trend_graph"),
                    width="auto",
                    style={"height": "60%", "width": "80%"},
                ),
            ],
            align="center",
        ),
        dbc.Row(
            [
                dbc.Col(
                    dcc.Graph(id="duration_graph"),
                    width="auto",
                    style={"height": "60%", "width": "80%"},
                ),
            ],
            align="center",
        ),
        html.Br(),
        html.Div(id="my-output"),
    ],
    # fluid=True,
)


@app.callback(
    [Output("trend_graph", "figure"), Output("duration_graph", "figure")],
    [
        Input("product_option", "value"),
        Input("weekday_option", "value"),
        Input("trend_graph", "selectedData"),
    ],
)
def build_graph_callback(product, weekday, selection1):
    print(product)
    print(weekday)
    print(selection1)

    if weekday == "all_values":
        dff = df[(df["PRODUCT"] == product)]
    else:
        dff = df[(df["PRODUCT"] == product) & (df["Weekday"] == weekday)]
    # print(dff[["LAST_FILE_RECEIVED","Duration"]])

    # trendfig, durfig =  build_graph(dff,product,weekday) #

    trendfig = px.line(
        dff,
        x="COB_DT",
        y=["USER_EXTRACT_END_TIME", "BATCH_END_TIME", "LAST_FILE_RECEIVED"],
    )

    durfig = px.line(dff, x="COB_DT", y=["Duration"])

    return [trendfig, durfig]


# ---------------------------------------------------------------

if __name__ == "__main__":
    app.run_server(debug=True, port=8800)
1 Like

Hello

Since sample data contains data for 1 week, you need All weekdays option to get a line chart.
Do you see callback triggered , as i dont see it

@NAbraham I was looking at your code and I see two def but only one callback.

I also don’t see where you define selectedData

If you modify and do something like this

def build_graph_callback(product, weekday, selection1):
    selection1 = [product,weekday]
    print(product)
    print(weekday)
    print(selection1)

then the return on the console is

Product1
Friday
['Product1', 'Friday']

    LAST_FILE_RECEIVED  Duration
10 1900-01-01 03:47:52     34.05

selectedData is used to build interactive charts
Part 4. Interactive Graphing and Crossfiltering | Dash for Python Documentation | Plotly

Could you try to use px.scatter instead of px.line? I don’t think selections work with “pure” line plots…

1 Like

px.scatter option did not trigger callback

Must be missing something here!

That’s odd…

One suggestions to help debugging: isolate selectedData in a simple callback and see if it gets triggered. Like:

@app.callback(
    Output('selected-data', 'children'),
    Input('basic-interactions', 'selectedData'))
def display_selected_data(selectedData):
    return json.dumps(selectedData, indent=2)

How are you making the selections? By clicking on the points or using box/lasso selection? I still can’t figure out how any of these approaches wouldn’t work in a scatter plot. :frowning_face:

Tried as suggested, dont see any callback called when i select box on first graph

Ok, I thought it would be easier to try your code out… So I took your example and switched the first plot to px.scatter and the selections work as expected: the callback gets triggered with a box selection. Because you are updating the same figure in the callback output, then the selection disappears, but I can see the selectedData in the terminal and so on…

If you tried the scatterplot selection by clicking in the points, then you have to enable selections on click via clickmode:

trendfig.update_layout(clickmode='event+select')

You can find more information about it in the reference page. Here is the relevant part:

clickmode – Determines the mode of single click interactions. “event” is the default value and emits the plotly_click event. In addition this mode emits the plotly_selected event in drag modes “lasso” and “select”, but with no event data attached (kept for compatibility reasons). The “select” flag enables selecting single data points via click. This mode also supports persistent selections, meaning that pressing Shift while clicking, adds to / subtracts from an existing selection. “select” with hovermode : “x” can be confusing, consider explicitly setting hovermode : “closest” when using this feature. Selection events are sent accordingly as long as “event” flag is set as well. When the “event” flag is missing, plotly_click and plotly_selected events are not fired

Hope this clarifies your issue with selectedData.

Tired your option trendfig.update_layout(clickmode=‘event+select’)
Don’t see any callback yet,

trendfig.update_layout(title={
‘text’: "Batch Process Trend for Product "+product,
‘y’:0.9,
‘x’:0.5,
‘xanchor’: ‘center’,
‘yanchor’: ‘top’},
legend_title=“Batch Status”,
clickmode=‘event+select’)

Can you provide your code

import pandas as pd
import plotly.express as px
import dash
from dash import dcc,html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc

df = pd.read_csv ('test.csv')

df['USER_EXTRACT_END_TIME'] = pd.to_datetime(df['USER_EXTRACT_END_TIME'], format='%H:%M:%S')
df['BATCH_END_TIME'] = pd.to_datetime(df['BATCH_END_TIME'], format='%H:%M:%S')
df['LAST_FILE_RECEIVED'] = pd.to_datetime(df['LAST_FILE_RECEIVED_HHMI'], format='%H:%M:%S')
df['COB_DT']=pd.to_datetime(df['COB_DT'], format='%d/%m/%Y')
df['Duration']= (df['BATCH_END_TIME']-df['LAST_FILE_RECEIVED']).astype('timedelta64[s]')/60
df['Weekday']=df['COB_DT'].dt.day_name()

app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP])
#app.config['suppress_callback_exceptions']=True

controls = dbc.Card(
    [
        html.Div(
            [
                dbc.Label("Product"),
                dcc.Dropdown(id='product_option',
                             options=[{'label': x, 'value': x} for x in df.sort_values('PRODUCT')['PRODUCT'].unique()],
                             value='Product1',
                             multi=False,
                             disabled=False,
                             clearable=True,
                             searchable=True,
                             placeholder='Choose Product...',
                             className='form-dropdown',
                             style={'width': "100%"},
                             persistence='string',
                             persistence_type='memory'),
            ]
        ),
        html.Div(
            [
                dbc.Label("Weekday"),
                dcc.Dropdown(id='weekday_option',
                             options=[{'label': x, 'value': x} for x in
                                      df.sort_values('Weekday')['Weekday'].unique()] + [
                                         {'label': 'All Weekdays', 'value': 'all_values'}],
                             value='all_values',
                             multi=False,
                             clearable=False,
                             style={'width': "100%"},
                             persistence='string',
                             persistence_type='session'),
            ]
        ),
    ],
    body=True,
    style={"width": "25rem"},
)


app.layout = dbc.Container(
[
    html.H1("Batch Process"),
    html.Hr(),
    dbc.Row(
        [
            dbc.Col(controls, width=3),
        ],
        align="start",
    ),
    dbc.Row(
        [
            dbc.Col(dcc.Graph(id='trend_graph'),
                              width="auto",
                              style={"height": "60%", "width": "80%"}),

        ],
        align="center",
    ),
    dbc.Row(
        [
            dbc.Col(dcc.Graph(id='duration_graph'),
                              width="auto",
                              style={"height": "60%", "width": "80%"}),
        ],
        align="center",
    ),
    html.Br(),
    html.Div(id='my-output'),
],
#fluid=True,
)

#---------------------------------------------------------------

def build_graph(dff,product, weekday):

    trendfig = px.scatter(dff,x='COB_DT', y=["USER_EXTRACT_END_TIME",
                                          "BATCH_END_TIME",
                                          "LAST_FILE_RECEIVED"]
                          )

    trendfig.update_layout(title={
        'text': "Batch Process Trend for Product "+product,
        'y':0.9,
        'x':0.5,
        'xanchor': 'center',
        'yanchor': 'top'},
        legend_title="Batch Status",
    )

    trendfig.update_layout(
        clickmode='event+select'
    )
    

    durfig = px.line(dff, x='COB_DT', y=["Duration"])



    durfig.update_layout(title={
        'text': "Processing Time in Minutes for Product "+product,
        'y': 0.9,
        'x': 0.5,
        'xanchor': 'center',
        'yanchor': 'top'})

    trendfig.update_xaxes(
        title_text="COB Date",
        tickformat="%b\n%d")
    trendfig.update_yaxes(
        title_text="Time",
        tickformat="%H:%M")

    durfig.update_xaxes(
        title_text="COB Date",
        tickformat="%b\n%d")
    durfig.update_yaxes(
        title_text="Minutes",
        tickformat="%H:%M")



    return [trendfig,durfig]

@app.callback(
    [Output('trend_graph','figure'),
     Output('duration_graph', 'figure')],
    [Input('product_option','value'),
     Input('weekday_option','value'),
     Input('trend_graph', 'selectedData')]
)
def build_graph_callback(product, weekday,selection1):
    print(product)
    print(weekday)
    print(selection1)

    if weekday == 'all_values':
        dff = df[(df['PRODUCT'] == product)]
    else:
        dff=df[(df['PRODUCT']==product)&
               (df['Weekday']==weekday)]
    #print(dff[["LAST_FILE_RECEIVED","Duration"]])

    trendfig, durfig =  build_graph(dff,product,weekday)

    return [trendfig, durfig]


#---------------------------------------------------------------

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