Patch() .. Does it work with dcc.graph ( with multiple lines )

Hello all,

I build a dropdown and create a callback to change the dcc.graph using Patch() that represent a multi[le line
( data frame is not available to share, and it represent simply Roads (which it’s the values of dropdown)
and each road have many Sites that have a traffic
So, I need when the user select one road
the dcc.graph represent the traffic on each sites of that selected road.

That the code I wrote but no changes.

def update_org_site_ob(selected_road):
    print(selected_road)
    if selected_road is None:
        selected_road = ["Beheira"]

df = org_mo_traffic_ob_per_site[org_mo_traffic_ob_per_site['Road_Name'].isin(selected_road)]
    org_mo_per_site_paragraph = Patch()
    org_mo_per_site_paragraph['layout']['data']['y'] = df['Site'].values

return org_mo_per_site_paragraph

Can anyone help me please?

1 Like

Hi @DoaaElbanaa Patch() actually works as expected.

Here I change the y coordinates of trace 4 (and the color):

import dash
from dash import Input, Output, html, dcc, Patch
import plotly.graph_objects as go
import numpy as np
import random

# generate some data
TRACES = 7
DATAPOINTS = 10

# create figure
figure = go.Figure(layout={'width': 1000, 'height': 800})
for idx in range(TRACES):
    figure.add_scatter(
        x=np.arange(DATAPOINTS),
        y=np.arange(DATAPOINTS) + 10 * idx,
        mode='markers',
        marker={'color': 'crimson', 'size': 10},
        name=idx
    )

app = dash.Dash(__name__)
app.layout = html.Div(
    [
        html.Div(
            [
                html.Button(id='btn', children='reset')
            ],
            style={'width': '10%'}
        ),
        html.Div([
            dcc.Graph(
                id='graph_post',
                figure=figure,
            )
        ]),
    ]
)


@app.callback(
    Output('graph_post', 'figure'),
    Input('btn', 'n_clicks'),
    prevent_initial_call=True
)
def update(_):
    # Creating a Patch object
    patched_figure = Patch()

    # change datapoints of trace 4
    patched_figure["data"][4]['y'] = np.random.randint(40, 45, 10)

    # change color for better visibility
    patched_figure["data"][4].update({"marker": {'color': 'blue', 'size': 10}})

    return patched_figure


if __name__ == '__main__':
    app.run(debug=True, port=8051)

Do you want to change several traces ? This makes me think you do.

[quote=“DoaaElbanaa, post:1, topic:75603”][‘data’][‘y’] = df[‘Site’].values`
[/quote]

Thanks for your response is appreciated,
I have a graph that represent a trend of traffic in each site in a certain road

there is a dropdown to choose a road, then that reflect in the graph a traffic in each sites that covers the selected road.

@AIMPED

This is my code for ( a datepicker, dropdown and graph ) then you will find the code of callback

dbc.Col(
                    dcc.DatePickerRange(
                        id='org-mt-voice-per-site-date-picker',  # ID to be used for callback
                        calendar_orientation='horizontal',  # vertical or horizontal
                        day_size=39,  # size of calendar image. Default is 39
                        end_date_placeholder_text="End Date",  # text that appears when no end date chosen
                        with_portal=False,  # if True calendar will open in a full screen overlay portal
                        first_day_of_week=0,  # Display of calendar when open (0 = Sunday)
                        reopen_calendar_on_clear=True,
                        is_RTL=False,  # True or False for direction of calendar
                        clearable=True,  # whether or not the user can clear the dropdown
                        number_of_months_shown=1,  # number of months shown when calendar is open
                        min_date_allowed=org_mt_traffic_ob_per_road['date'].min(),
                        # minimum date allowed on the DatePickerRange component
                        max_date_allowed=org_mt_traffic_ob_per_road['date'].max(),
                        initial_visible_month=org_mt_traffic_ob_per_road['date'].min(),
                        display_format='MMM Do, YY',
                        month_format='MMMM, YYYY',
                        persistence=True,
                        persisted_props=['start_date'],
                        # persistence_type='session',

                        updatemode='bothdates',
                        # className='bg-opacity-50 p-2 m-1 bg-primary'

                    ),

                ),
                dbc.Col(
                    dcc.Dropdown(
                        id="dropdown-sites-mt-traffic",
                        options=[
                            {'label': i, 'value': i} for i in org_mt_roads
                        ],
                        multi=True,
                        placeholder="Select Road",

                    ),

                ),

                dcc.Graph(id='org-mt-per-site-paragraph',
                          figure=px.line(data_frame=org_mt_traffic_ob_per_site, x='date', y="Duration_Min",
                                         color='Site', title="ORG MT Voice Traffic Per Site - Min/day", markers=True,
                                         ),
                          responsive=True, style={'display': 'block', 'margin-top': '3rem', 'width': '58rem',
                                                  'margin-right': '2rem', 'border': 'solid black'},

                          ),

            ]),

@app.callback(
    Output(component_id="org-mt-per-site-paragraph", component_property='figure'),
    Input(component_id="dropdown-sites-mt-traffic", component_property="value"),
    prevent_inital_call=True

)
def update_org_mt_site_ob(selected_road):
    print(selected_road)
    if selected_road is None:
        selected_road = ["Beheira"]

    df = org_mt_traffic_ob_per_site[org_mt_traffic_ob_per_site['Road_Name'].isin(selected_road)]
    print(df.head())
    org_mt_per_site_paragraph = Patch()
    org_mt_per_site_paragraph['layout']['color'] = df['Site'].values

    return org_mt_per_site_paragraph

@AIMPED

Can you help me? Sorry for bothering you

HI @DoaaElbanaa.

It’s pretty hard to help you because I don’t fully understand what you want to change with the Patch(). Could you post the full code+data?

A quick sidenote:
You are using plotly.epress which under the hood uses plotly.graph_objects. px does a lot of things for you such as grouping data, creating different traces, legend entries…but in the end, the plotly.graph_objects figure object is created.

When you are using the Patch() you have to find the right way to interact with this figure object. You could do so by converting your figure object into a dictionary via fig.to_dict() and inspect the dictionary. Once you found the item you would like to modify, you have to set up the Patch() according to the dictionary structure.

Back to your example.

The layout does not have a color parameter, that is why this does not work:

https://plotly.com/python-api-reference/generated/plotly.graph_objects.Layout.html#plotly.graph_objects.Layout

I assume you have more than one entry in the Site column of your DataFrame org_mt_traffic_ob_per_site therefore you will find more than one trace in the figure dictionary. If you want to change the line color of the single traces, you will have to do something like this:

patched = Patch()
for idx, color in zip([0, 1, 2], ['red', 'green', 'blue']):
    patched['data'][idx]['line']['color'] = color

which would change the line color of the first three traces .

I hope this makes sense.