1

I have some data that is broken down by day. For each day, I have a datapoint at the start and end of the day, each with a value between 0 and 100. I need to display this data as a grouped bar plot with the days on the x axis, values on the y axis and the bars colors are determined by their values. For each day, the left bar needs to have the corresponding start value, and the right bar displays the day's end value. The legend however needs to display information on the color rather than the trace The plot basically needs to look like this but the legend needs to display "green", "amber", "red" instead of "start", "end".

I need the plot to look like this but with a legend describing the colors rather than the traces

Here is some code to reproduce the plot:

x = ["day"+str(i) for i in range(1,8)]
starts = [10, 50, 70, 75, 20, 50, 90]
ends = [95, 5, 80, 20, 50, 10, 75]
starts_colors = ['green', 'orange', 'red', 'red', 'green', 'orange', 'red']
ends_colors = ['red', 'green', 'red', 'green', 'orange', 'green', 'red']

And here is the code I have for the plot above.

layout = go.Layout(showlegend=True) 
fig = go.Figure(layout=layout)
fig.add_trace(go.Bar(x=x, y=starts, name = 'start', marker=dict(color=starts_colors)))
fig.add_trace(go.Bar(x=x, y=ends, name = 'end', marker=dict(color=ends_colors)))
fig.show()

If I rearrange the data into 3 traces (one for each color) with the corresponding values in starts and ends, I end up with gaps between the bars. For example "day1" would have a gap in the middle because there is no orange bar for "day1".

This seems like a simple problem but I'm at a loss as to how to get it to work the way I'm supposed to.

1 Answer 1

4
  • this creates exactly the graph you requested
  • start by putting your sample data into a dataframe to open up Plotly Express
  • start by updating traces to use colors columns
  • adding legend is done. Really is not a functional legend as it cannot be used for filtering the figure, will just show unique colors used in figure. This is achieved by adding additional small traces
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import numpy as np

df = pd.DataFrame(
    {
        "day": ["day" + str(i) for i in range(1, 8)],
        "starts": [10, 50, 70, 75, 20, 50, 90],
        "ends": [95, 5, 80, 20, 50, 10, 75],
        "starts_colors": ["green", "orange", "red", "red", "green", "orange", "red"],
        "ends_colors": ["red", "green", "red", "green", "orange", "green", "red"],
    }
)

# build figure, hover_data / customdata is used to hold colors
fig = px.bar(
    df,
    x="day",
    y=["starts", "ends"],
    barmode="group",
    hover_data={"starts_colors":False, "ends_colors":False},
)

# update colors of bars
fig.plotly_update(
    data=[
        t.update(marker_color=[c[i] for c in t.customdata])
        for i, t in enumerate(fig.data)
    ]
)

# just for display purpose, create traces so that legend contains colors.  does not connect with
# bars
fig.update_traces(showlegend=False).add_traces(
    [
        go.Bar(name=c, x=[fig.data[0].x[0]], marker_color=c, showlegend=True)
        for c in np.unique(df.loc[:,["starts_colors","ends_colors"]].values.ravel())
    ]
)

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.