1
votes

So, I want to create a bar chart with Plotly.express in Python 3.9. I created the following table with pandas:

      idx  cat1  cat2  cat3   cat4
0       A  0.98  0.93  0.550  1.00
1       B  0.92  0.80  0.865  1.00
2       C  0.91  0.87  0.955  0.96

and I have the following code:

 # df is the pandas table
fig = px.bar(df,
        x = 'idx',
        y=['cat1', 'cat2', 'cat3', 'cat4']
    )

colors = ['#dc1a22', ] * 12
colors[2] = '#000000'
fig.update_traces(marker_color = colors, marker_line_color='rgb(8,48,107)',
                  marker_line_width=1.5, opacity=0.6)
    
fig.update_layout(barmode='group')

I want to color all bars in all groups in #dc1a22 except the one at third position (colors[2]).

The reality is, that all bars in the first and second group are in #dc1a22 and all bars in the third group are in #000000.

Is there a possibility to color a single bar in a grouped chart?

Might be important: In the future I am trying to color the bars depending on their values.

(0-0.5 -> red, 0.5-0.9 -> yellow, 0.9-1 -> green)

1
No because in this example is the barmode not set to "group". Therefore I am ending up with the same result as in my question.HoffErik-JohnerInst

1 Answers

2
votes

What you can do is add the traces one at a time using a loop, and passing a list of colors and a list of the corresponding column names to each go.bar object. Unfortunately, the default width of the bars will need to be reset, and in grouped mode, the bars are plotted in overlay mode (meaning if you set the width of each bar without changing the offset, they will overlap).

So the offset also needs to be adjusted to make sure the bars are centered nicely around each idx category on the x-axis. With a bar width of 0.2, setting the offset for each of the four bars to [-0.4, -0.2, 0, 0.2], respectively works. This can probably be generalized for any width.

import numpy as np
import pandas as pd
import plotly.graph_objs as go

## recreate the data
df = pd.DataFrame({'idx':['A','B','C'], 'cat1':[0.98,0.92,0.91], 'cat2':[0.93,0.80,0.87], 'cat3':[0.55,0.865,0.955], 'cat4':[1,1,0.96]})

fig = go.Figure()
indexes = ['A','B','C']
groups = ['cat1','cat2','cat3','cat4']
colors = ['#dc1a22','#dc1a22','#000000','#dc1a22']

## this can be generalized a bit better
width = 0.2
offset = [-0.4,-0.2,0,0.2]

for i in indexes:
    for g, c, o in zip(groups, colors, offset):
            fig.add_trace(
                go.Bar(x=df['idx'], y=df[g], marker_color=c, width=width, offset=o)
            )

fig.update_traces(
    marker_line_color='rgb(8,48,107)',
    marker_line_width=1.5, 
    opacity=0.6
)

fig.update_layout(
    xaxis_title='idx',
    yaxis_title='value',
    barmode='group', 
    showlegend=False
)

fig.show()

enter image description here