The Python Oracle

How can I change the column colors of a stacked pyplot chart to indicate whether another column is true or false?

Become part of the top 3% of the developers by applying to Toptal https://topt.al/25cXVn

--

Music by Eric Matyas
https://www.soundimage.org
Track title: Over a Mysterious Island Looping

--

Chapters
00:00 Question
01:58 Accepted answer (Score 2)
02:19 Answer 2 (Score 2)
03:34 Thank you

--

Full question
https://stackoverflow.com/questions/6514...

Question links:
[image]: https://i.stack.imgur.com/tvKjQ.png
[Color matplotlib bar chart based on value]: https://stackoverflow.com/questions/3347...

Accepted answer links:
[image]: https://i.stack.imgur.com/cOlVi.png

Answer 2 links:
[image]: https://i.stack.imgur.com/RqUyj.png

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #pandas #matplotlib #colors #barchart

#avk47



ACCEPTED ANSWER

Score 2


There may be a better approach, but here is one using a loop:

for idx, row in df.iterrows():
    color = ['tab:blue', 'tab:orange'] if row['restricted'] else ['tab:blue', 'tab:red']
    plt.bar(row['Country'], row['V1%'], color=color[0])
    plt.bar(row['Country'], row['V2%'], bottom=row['V1%'], color=color[1])

Output:

enter image description here




ANSWER 2

Score 1


Probably this is not the most beautiful approach, but it works. I'm using the keyword argument color from the plot method. As argument, we can you a dictionary based on the 'restricted' condition. I've use some buint-in colors defined in matplotlib colormaps, but you can use the colors of your choice, of course:

from matplotlib import cm

palette1 = cm.get_cmap('autumn', 2)
palette2 = cm.get_cmap('winter', 2)

colors = {
    'V1': [palette1(0) if restricted else palette2(0) for restricted in df['restricted']],
    'V2': [palette1(1) if restricted else palette2(1) for restricted in df['restricted']]
}

xx = df.plot(kind="bar", x='Country', stacked=True, color=colors, legend=False, figsize=(20, 10))

Since this messes up the default legend, I've tried making one (not the prettiest, though):

from matplotlib.lines import Line2D

custom_legend = [
    Line2D([0], [0], color=palette1(0), lw=3),
    Line2D([0], [0], color=palette1(1), lw=3),
    Line2D([0], [0], color=palette2(0), lw=3),
    Line2D([0], [0], color=palette2(1), lw=3),
]

plt.legend(custom_legend, ['V1 (Restricted)', 
                           'V2 (Restricted)', 
                           'V1 (Non-Restricted)', 
                           'V2 (Non-Restricted'])

plt.show()

This gives us the following plot as output:

enter image description here