Search code examples
pythonplotlyplotly-python

Plotly express barmode overlay legend does not match bar/marker opacity


I'm making facet bar plots using plotly express and overlaying the bars. The graphs look as I want them to, but the legend colors don't match the overlay opacity shown in the graphs. That is, the colors in the graph are somewhat transparent and the colors in the legend are completely opaque. I understand that the parts that are overlapping are a different color, but the non-overlapping also doesn't match the legend

import pandas
import plotly.express as px

df = pandas.DataFrame({'group':['first', 'first', 'second', 'second', 'comb', 'comb', ],'month':[1,2,1,2,1,2],
'prop1':[.3,.4,0,0,.3,.4],
'prop2':[0,0,.5,.3,.5,.3]})

fig = px.bar(df, x="month", y=["prop1", "prop2"],
             barmode="overlay", facet_col='group', facet_col_wrap=3)            
fig.show()

enter image description here


Solution

  • As far as I've tried, the transparency doesn't seem to change to the color of the legend in the bar graph overlay mode. So I reproduced the equivalent graph with a graph object. The graph object can specify transparency in the graph specification. I specified opacity=0.5 for each of the subplot configurations and a single legend item that overlaps with the addition of the subplot title.

    import plotly.graph_objects as go
    from plotly.subplots import make_subplots
    import plotly.express as px
    
    colors = px.colors.qualitative.Plotly
    
    fig = make_subplots(rows=1, cols=3, subplot_titles=['group=first','group=second','group=comb'])
    
    for i,gr in enumerate(df['group'].unique()):
        dff = df.query('group == @gr')
        fig.add_trace(go.Bar(x=dff['month'],
                             y=dff['prop1'],
                             name='prop1',
                             marker=dict(color=colors[0]),
                             opacity=0.5), 
                      row=1, col=i+1)
        fig.add_trace(go.Bar(x=dff['month'],
                             y=dff['prop2'],
                             name='prop2',
                             marker=dict(color=colors[1]),
                             opacity=0.5),
                      row=1, col=i+1)
    
    fig.update_layout(barmode='overlay')
    
    names = set()
    fig.for_each_trace(
        lambda trace:
            trace.update(showlegend=False)
            if (trace.name in names) else names.add(trace.name))
    
    fig.show()
    

    enter image description here