The Python Oracle

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

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------

Take control of your privacy with Proton's trusted, Swiss-based, secure services.
Choose what you need and safeguard your digital life:
Mail: https://go.getproton.me/SH1CU
VPN: https://go.getproton.me/SH1DI
Password Manager: https://go.getproton.me/SH1DJ
Drive: https://go.getproton.me/SH1CT


Music by Eric Matyas
https://www.soundimage.org
Track title: Magical Minnie Puzzles

--

Chapters
00:00 How Can I Change The Column Colors Of A Stacked Pyplot Chart To Indicate Whether Another Column Is T
01:37 Accepted Answer Score 2
01:53 Answer 2 Score 1
02:40 Thank you

--

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

--

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