Search code examples
pythonplotlydata-visualizationbar-chartplotly-python

Plotly: Is there a way to choose which color line takes precedence in a stacked bar chart?


I am producing horizontal stacked bar charts via plotly graph objects in python, and have one issue that I can not figure out:

The lines at the right side of the positive bar are overridden by a negative line, even when the negative value is zero.

I would prefer for a blue line to surround the positive bars, and an orange line to surround the negative bars. This works as intended until a particular group has no negative value, then an orange line appears in the right side of the plot.

I have provided enough code to reproduce the attached image as an example, and have also provided a figure which highlights the problem area (the line circled should be blue when the value of "negative" is zero).

import plotly.graph_objects as go
import plotly.io as pio

pio.renderers.default='svg'

top_words = ['State', 'Opportunities', 'Information', 'Members', 'Enterprise', 'Affiliate', 'Networking', 'Common', 'Goals', 'Process', 'Monthly', 'Level']
neg_words = [0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0]
pos_words = [6, 5, 3, 3, 3, 3, 3, 1, 1, 2, 2, 2]

font_family = "sans-serif"
font_size = 17

fig5 = go.Figure()
fig5.add_bar(
    y=top_words,
    x=pos_words,
    name='Positive',
    orientation='h',
    marker=dict(
        color='rgba(105, 149, 183, .35)',
            line=dict(color='rgba(105, 149, 183, 1)', width=2)
    )
)
fig5.add_bar(
    y=top_words,
    x=neg_words,
    name='Negative',
    orientation='h',
    marker=dict(
        color='rgba(234, 115, 11, .35)',
        line=dict(color='rgba(234, 115, 11, 1)', width=2)
    )
)
fig5.update_layout(barmode='stack')
fig5.update_yaxes(autorange="reversed")
fig5.update_layout(
    autosize=False,
    height=800,
    width=650,
    template='none',
    yaxis=dict(
        tickfont_family=font_family,
        tickfont_size=font_size,
        tickfont_color="#4B4D4B"
    ),
    xaxis=dict(
        tickfont_family=font_family,
        tickfont_size=font_size,
        tickfont_color="#4B4D4B"
    ),
    legend=dict(
        font_size=font_size,
        font_family=font_family
    ),
    margin_pad=10,
    margin=dict(l=135, r=0, t=20, b=45)
)
fig5.update_xaxes(showline=True, linewidth=.2, linecolor='lightgray', mirror=True)

fig5.show()

Orange should be blue

Thank you in advance for the help, I really tried to figure this out on my own by reading plotly documentation and scouring through stack overflow, but could not find anything on this exact topic.


Solution

  • If instead of 0 you write float('nan') (or math.nan after importing math) you will not get a red line. I've adjusted this for the negative value of "Information" only to demonstrate:

    import plotly.graph_objects as go
    import plotly.io as pio
    
    pio.renderers.default='svg'
    
    top_words = ['State', 'Opportunities', 'Information', 'Members', 'Enterprise', 'Affiliate', 'Networking', 'Common', 'Goals', 'Process', 'Monthly', 'Level']
    neg_words = [0, 1, float("nan"), 0, 0, 0, 0, 1, 1, 0, 0, 0]
    pos_words = [6, 5, 3, 3, 3, 3, 3, 1, 1, 2, 2, 2]
    
    ... (rest stays the same)
    

    The output is:

    enter image description here