More effective way to highlight barchart?

Hello fellow seniors around the world who love Dash Plotly,
I also love Plotly Dash.

Recently, I have been creating pages using graph callbacks, and I realized a few things:

  1. You can select by clicking on the bar of the bar chart.
  2. You can select by dragging the bar of the bar chart.
  3. You can select multiple bars by clicking them together with the Control key (using extension).
  4. You cannot select multiple bars by dragging them with the Control key.
  5. You can draw a bar chart without Plotly in the graph element.

I was surprised because number 5 was something I learned recently.

Now, I want to create a function so that when I click on the graph, only the selected bar is displayed in red. Initially, when a callback occurred, a new figure was created and returned. Since the data does not change, this method seems inefficient. Is there perhaps an easier and more effective way?

Hi @nicobockko

You can use Patch to update more efficiently. Here’s an example


from dash import Dash, html, dcc, Input, Output, Patch, callback
import plotly.express as px

import random

app = Dash(__name__)

# Creating some starter x and y data
x_values = [2019, 2020, 2021, 2022, 2023]
y_values = [random.randrange(1, 30, 1) for i in range(5)]

fig = px.bar(x=x_values, y=y_values)

app.layout = html.Div(
    [
        html.Div("Updating Selected Bar Color"),
        dcc.Graph(figure=fig, id="example-graph"),
    ]
)


@callback(
    Output("example-graph", "figure"),
    Input("example-graph", "clickData"),
    prevent_initial_call=True,
)
def add_data_to_fig(data):
    selected_bar = data["points"][0]["x"]
    patched_figure = Patch()
    updated_markers = [
        "red" if selected_bar == x else "blue" for x in x_values
    ]
    patched_figure['data'][0]['marker']['color'] = updated_markers
    return patched_figure


if __name__ == "__main__":
    app.run(debug=True)



hellow Marrie
I’m so happy because of your reply!!!
It is my honor!!

i hava another Question i need your insight!

if I make two graphs
and then only one highlighted a bar
how about you for a better way?

My code is like this and works
but I think is not clean code

from dash import Dash, html, dcc, Input, Output, Patch, callback
import plotly.express as px

import random

app = Dash(__name__)

# Creating some starter x and y data
x_values = [2019, 2020, 2021, 2022, 2023]
y_values = [random.randrange(1, 30, 1) for i in range(5)]

fig = px.bar(x=x_values, y=y_values)
fig2 = px.bar(x=x_values, y=y_values) # for fig2

app.layout = html.Div(
    [
        html.Div("Updating Selected Bar Color"),
        dcc.Graph(figure=fig, id="example-graph"),
        dcc.Graph(figure=fig2, id="example-graph2"), # for fig2

    ]
)

@callback(
    Output("example-graph", "figure",allow_duplicate=True),
    Output("example-graph2", "figure",allow_duplicate=True),  # for fig2
    Input("example-graph", "clickData"),
    prevent_initial_call=True,
)
def add_data_to_fig(data):
    selected_bar = data["points"][0]["x"]
    patched_figure = Patch()
    patched_figure2 = Patch()  # for fig2

    updated_markers = [
        "red" if selected_bar == x else "blue" for x in x_values
    ]
    updated_markers2 = [  # for fig2
        "blue" for x in x_values
    ]
    patched_figure['data'][0]['marker']['color'] = updated_markers
    patched_figure2['data'][0]['marker']['color'] = updated_markers2 # for fig2
    return patched_figure,patched_figure2


@callback(
    Output("example-graph2", "figure",allow_duplicate=True),  # for fig2
    Output("example-graph", "figure",allow_duplicate=True),
    Input("example-graph2", "clickData"),
    prevent_initial_call=True,
)
def add_data_to_fig(data):
    selected_bar = data["points"][0]["x"]
    patched_figure = Patch()
    patched_figure2 = Patch()  # for fig2

    updated_markers = [
        "red" if selected_bar == x else "blue" for x in x_values
    ]
    updated_markers2 = [  # for fig2
        "blue" for x in x_values
    ]
    patched_figure['data'][0]['marker']['color'] = updated_markers
    patched_figure2['data'][0]['marker']['color'] = updated_markers2  # for fig2
    return patched_figure, patched_figure2


if __name__ == "__main__":
    app.run(debug=True)



Hi @nicobockko

There are lots of different ways you can do this. I see your code works - but you could reduce the number of times the figures are updating by combining the callbacks.

Here’s an example:

from dash import Dash, html, dcc, Input, Output, Patch, callback, ctx
import plotly.express as px

import random

app = Dash(__name__)

# Creating some starter x and y data
x_values = [2019, 2020, 2021, 2022, 2023]
y_values = [random.randrange(1, 30, 1) for i in range(5)]

fig = px.bar(x=x_values, y=y_values)
fig2 = px.bar(x=x_values, y=y_values) # for fig2

app.layout = html.Div(
    [
        html.Div("Updating Selected Bar Color"),
        dcc.Graph(figure=fig, id="example-graph"),
        dcc.Graph(figure=fig2, id="example-graph2"), # for fig2

    ]
)

def update_selected_bar_colors(data):
    selected_bar = data["points"][0]["x"]
    patched_figure = Patch()
    updated_markers = [
        "red" if selected_bar == x else "blue" for x in x_values
    ]
    patched_figure['data'][0]['marker']['color'] = updated_markers
    return patched_figure

def reset_bar_color():
    patched_figure = Patch()
    patched_figure['data'][0]['marker']['color']= ["blue" for x in x_values]
    return patched_figure



@callback(
    Output("example-graph", "figure"),
    Output("example-graph2", "figure"),
    Input("example-graph", "clickData"),
    Input("example-graph2", "clickData"),
    prevent_initial_call=True,
)
def add_data_to_fig(data, data2):
    if ctx.triggered_id == "example-graph":
        patched_figure = update_selected_bar_colors(data)
        patched_figure2 = reset_bar_color()
    else:
        patched_figure = reset_bar_color()
        patched_figure2 = update_selected_bar_colors(data2)

    return patched_figure,patched_figure2



if __name__ == "__main__":
    app.run(debug=True)

1 Like

Thanks!!!

Could we think about it deeper??

I’d like to do with stacked bar chart

but I couldn’t have any clue…

I could get infomation which i clicked! like this (‘curveNumber’, ‘x’)
But!!! how can I highlight it at this case??
Could you give me advice again please?

{‘points’: [{‘curveNumber’: 2, ‘pointNumber’: 2, ‘pointIndex’: 2, ‘x’: ‘Canada’, ‘y’: 12, ‘label’: ‘Canada’, ‘value’: 12, ‘bbox’: {‘x0’: 740.4, ‘x1’: 988.93, ‘y0’: 223.66, ‘y1’: 223.66}}]}

from dash import Dash, html, dcc, Input, Output, Patch, callback
import plotly.graph_objects as go

import random

app = Dash(__name__)

# Creating some starter x and y data
long_df = px.data.medals_long()
# go방식
trace_gold = go.Bar(
    x=long_df[long_df['medal'] == 'gold']['nation'],
    y=long_df[long_df['medal'] == 'gold']['count'],
    name='Gold',
    marker=dict(color='gold')
)

trace_silver = go.Bar(
    x=long_df[long_df['medal'] == 'silver']['nation'],
    y=long_df[long_df['medal'] == 'silver']['count'],
    name='Silver',
    marker=dict(color='silver')
)

trace_bronze = go.Bar(
    x=long_df[long_df['medal'] == 'bronze']['nation'],
    y=long_df[long_df['medal'] == 'bronze']['count'],
    name='Bronze',
    marker=dict(color='#CD7F32')  # Bronze color
)

# Create a stacked bar plot
fig = go.Figure(data=[trace_gold, trace_silver, trace_bronze])

# Update the layout for stacking bars
fig.update_layout(
    barmode='stack',  # Stack bars
    title='Stacked Bar Plot of Medal Counts by Nation',
    xaxis=dict(title='Nation'),
    yaxis=dict(title='Count')
)

app.layout = html.Div(
    [
        html.Div("Updating Selected Bar Color"),
        dcc.Graph(figure=fig, id="example-graph"),
    ]
)


@callback(
    Output("example-graph", "figure"),
    Input("example-graph", "clickData"),
    prevent_initial_call=True,
)
def add_data_to_fig(data):
    print(data)
    patched_figure = Patch()
    return patched_figure


if __name__ == "__main__":
    app.run(debug=True)

When you update the figure with the Patch, you are updating the just certain parts of the Figure Object. You can find a lot of good infomation about that in the Plotly docs here:

1 Like

I TOTALLY UNDERSTAND!! Thanks!!!

I will study how to select multiple bars with (CRTL + Click ) or (Drag)