1

I'm trying to plot four stacked bar charts on the same plot using Python's matplotlib library.

For each observation (obs1, obs2, obs3, obs4), I want to view the quantity of each component (c1, c2, c3, c4, c5, c6) using a stacked bar chart. This is the code I have written:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

data = np.array([[-904., 97., 59., 5., 252., 138.], [-603., 65., 0., 29., 0., 0.], [-571., -27., 0., -28., 0., 0.], [-80., 40., 0., -9., 0., 0.]])

data2 = pd.DataFrame(data=data)
data2.index = ['obs1', 'obs2', 'obs3', 'obs4']
data2.columns = ['c1', 'c2', 'c3', 'c4', 'c5', 'c6']

ind = np.arange(4)
width = 0.4

p1 = plt.bar(ind, data2['c1'], width)
p2 = plt.bar(ind, data2['c2'], width)
p3 = plt.bar(ind, data2['c3'], width)
p4 = plt.bar(ind, data2['c4'], width)
p5 = plt.bar(ind, data2['c5'], width)
p6 = plt.bar(ind, data2['c6'], width)

plt.legend((p1[0], p2[0], p3[0], p4[0], p5[0], p6[0]), tuple(data2.columns), bbox_to_anchor = (1.05, 1), loc = 'upper left', borderaxespad = 0.)

For clarity, this is the DataFrame (used to produce the plot):

print(data2)
         c1    c2    c3    c4     c5     c6
obs1 -904.0  97.0  59.0   5.0  252.0  138.0
obs2 -603.0  65.0   0.0  29.0    0.0    0.0
obs3 -571.0 -27.0   0.0 -28.0    0.0    0.0
obs4  -80.0  40.0   0.0  -9.0    0.0    0.0

This is the plot:

enter image description here

Note on the plot, the bar for obs1 is at x=0, the bar for obs2 is at x=1, and so on.

However, there are two problems:

  1. obs1 has a value of 252 for component 5, but the height of component 5 (in purple) is substantially below 252. How can I fix this?

  2. obs3 has a value of -27 for component 2, but this is not shown on the plot at all. How can I solve this?

Thanks.

1 Answer 1

4

This is because when you plot, the y-value reference is taken from y=0, thus the purple bar for obs1 component 5 actually spanned from y=0 to y=252, and it got blocked by bar for component 6 (plotted later) due to the sequential nature matplotlib plots the patches of bars.

Similary, obs3 component 2 is not shown for the same reason.

To get what you want, a stacked bar chart, you can simply plot using pandas plotting interface:

fig, ax = plt.subplots(1,1,figsize=(6,4))

data2.plot(kind='bar', stacked=True, ax=ax)

ax.set_xticklabels(ax.get_xticklabels(), rotation=0)

plt.show()

which gives you exactly what you want:

enter image description here

On a side note, I would suggest to plot a separate bar chart for each component, as they are of very different scale, this would make the component level comparison across observations much clearer:

fig, ax = plt.subplots(1, 6, figsize=(20,4))

for index, col in enumerate(data2.columns):
    data2[col].plot(kind='bar', ax=ax[index], color=f'C{index}', title=f'{col}')
    ax[index].grid(True)
    ax[index].set_xticklabels(ax[index].get_xticklabels(), rotation=0)

plt.show()

which gives you:

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.