How to make bar chart that shows percent change with fainter color on same bar in python

I have the following dataframe that shows dollar cost associated with each color hat:

      Hat     Dollars
----------------------
0    Blue          33
1   Green          42
2     Red          54 

And so the blue hat costs $33, the green hat costs $42, and the red hat costs $54.

I can plot this as a bar chart using this simple code with seaborn:

dataplot = sns.barplot(x = 'Hat',
            y = 'Dollars',
            data = df,hue="Hat")
plt.gca().set_xticklabels([])
plt.ylabel("Dollars", fontsize=15)
plt.xlabel("Hat", fontsize=0)
plt.legend(title="Hat Costs")

Now, let’s say because of inflation the price of hats goes up the next year, and so the next year’s hat costs are represented in this dataframe:

      Hat     Dollar
---------------------
0    Blue         33
1   Green         42
2     Red         54 

What I want to do is take my first bar chart showing hat costs, and then insert the new year’s hat costs into the first chart so that there are still only three bars, one for each color, but the new amount is shown as an extension of the original bar, either going up or down, but with the new area marked by the same color faded, or if that is not doable, filled with faint diagonal lines. How can I modify the code to my original bar chart to incorporate the new values for each of the original bars to be displayed on the original bar?

The best solution is to use matplotlib, which has a functionality called hatch which you can use to customize the plot to your liking.

Option 1:

This is best if inflation is all positive or all negative, as in the case of the ‘Green’ hat the shading might be misleading

data = pd.DataFrame({'Hat': ['Blue', 'Green', 'Red'], 'Dollars': [33,42,54], 'Dollars2': [35, 10, 70]})
lightcolors = ['lightblue', 'lightgreen','lightcoral' ]
fig = plt.figure()
ax1 = fig.add_subplot()
ax1.bar(range(1, len(data) + 1), data['Dollars'], color = data['Hat'])
ax1.bar(range(1, len(data) + 1), data['Dollars2'] - data['Dollars'], bottom=data['Dollars'], color = lightcolors, hatch="//")
plt.xticks(range(1, len(data) + 1), data['Hat'])
plt.show()

enter image description here

Option 2:

Using light-green or light-red to show increase or decrease in price:

data = pd.DataFrame({'Hat': ['Blue', 'Green', 'Red'], 'Dollars': [33,42,54], 'Dollars2': [35, 10, 70]})
lightcolors = ['lightblue', 'lightgreen','lightcoral' ]
delta = list(data['Dollars2'] - data['Dollars'])
lightcolors = ['lightcoral' if x <0 else 'lightgreen' for x in delta]
fig = plt.figure()
ax1 = fig.add_subplot()
ax1.bar(range(1, len(data) + 1), data['Dollars'])
ax1.bar(range(1, len(data) + 1), delta, bottom=data['Dollars'], color = lightcolors)
plt.xticks(range(1, len(data) + 1), data['Hat'])
plt.show()

enter image description here

Option 3:

If you really need to use seaborn here, you can explore the stack class in seaborn.objects

data = pd.DataFrame({'Hat': ['Blue', 'Green', 'Red'], 'Dollars': [33,42,54], 'Dollars2': [35, 50, 70]})
import seaborn.objects as so
df = pd.melt(data, id_vars="Hat", value_vars=['Dollars', 'Dollars2'])
(
    so.Plot(df, x="Hat", y='value', alpha="variable", color="Hat")
    .add(so.Bars())
)

enter image description here

Leave a Comment