3

I'm trying to create a bar plot where just one of the bars is stacked. I'm trying it out with a MultiIndex, but not sure if this would be the best approach. Here's a quick example of how the dataframe looks like:

df = pd.DataFrame({'case 1': [-12, 0, 0, 0, 7, -5], 
                   'case 2': [0, -5, -3, -4, 9, -3]},
                   index=pd.MultiIndex.from_arrays([['investment', 'investment', 'investment', 
                                                     'investment', 'profit', 'difference'], 
                                                    list('gabc  ')],
                                                   names=['one', 'two']))

                    case 1  case 2
one        two                
investment g       -12       0
           a         0      -5
           b         0      -3
           c         0      -4
profit               7       9
difference          -5      -3

df.plot(kind='bar', stacked=True, rot=0)

I want just that the data on 'investments' 'a', 'b' and 'c' are combined on a stacked bar. I feel I may be close to a solution, but I'm completely stuck on this, and I'm not sure using a MultiIndex is the best way to do this.

Here's how I want it to look like: A bar plot where just one bar is stacked

Would someone have an idea on how to achieve this? Thanks!

1 Answer 1

3

It's tricky to stack only one bar using pandas. Here's a little bit of a hack, we'll reshape the DataFrame and then loop over the cases and plot each with a different edge alignment, due to the sign of width (works since there are only 2 cases). Since 'case 2' is the one that get's split, we'll supply a list of colors to cycle through as a kwarg when we plot that subset.

We need to manually construct the legend after because it's a mess otherwise.

import matplotlib.pyplot as plt
from matplotlib.patches import Patch

s = (df.unstack(-1).stack(0).rename_axis(index=[None, None], columns=None)
       .reindex(['investment', 'profit', 'difference'], level=0))
#                          a    b    c     g
#investment case 1  NaN  0.0  0.0  0.0 -12.0
#           case 2  NaN -5.0 -3.0 -4.0   0.0
#profit     case 1  7.0  NaN  NaN  NaN   NaN
#           case 2  9.0  NaN  NaN  NaN   NaN
#difference case 1 -5.0  NaN  NaN  NaN   NaN
#           case 2 -3.0  NaN  NaN  NaN   NaN  

kwargs = {'case 1': {'width': -0.2, 'color': 'white'}, 
          'case 2': {'width': 0.2, 'color': ['black', '#ffa500', '#00daff', 'red']}}

fig, ax = plt.subplots()
for c in ['case 1', 'case 2']:
    s.xs(c, level=1).plot(kind='bar', stacked=True, ec='k', ax=ax, align='edge',
                          legend=False, rot=0, **kwargs[c])

legend_elements = [Patch(facecolor='white', edgecolor='k', label='case 1'),
                   Patch(facecolor='black', edgecolor='k', label='case 2')]    

ax.legend(handles=legend_elements)
ax.set_ylim(ax.get_ylim()[0]*1.05, ax.get_ylim()[1]*1.05)
plt.show()

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.