8

I was wondering how to create a 100 % stacked area chart in matplotlib. At the matplotlib page I couldn't find an example for it.

Somebody here can show me how to achieve that?

sodd
  • 12,482
  • 3
  • 54
  • 62
Thomas Becker
  • 471
  • 3
  • 8
  • 16
  • 3
    How about this [example](http://matplotlib.org/examples/pylab_examples/stackplot_demo.html)? –  Jun 01 '13 at 17:56
  • 1
    Have you tried anything? You will typically get a better response on SO if you have mostly working code. As it stands this question reads and 'please do my work for me'. The example @LogicalKnight pointed to is a good start and gets you 95% of the way there. – tacaswell Jun 01 '13 at 19:37

1 Answers1

22

A simple way to achieve this is to make sure that for every x-value, the y-values sum to 100.

I assume that you have the y-values organized in an array as in the example below, i.e.

y = np.array([[17, 19,  5, 16, 22, 20,  9, 31, 39,  8],
              [46, 18, 37, 27, 29,  6,  5, 23, 22,  5],
              [15, 46, 33, 36, 11, 13, 39, 17, 49, 17]])

To make sure the column totals are 100, you have to divide the y array by its column sums, and then multiply by 100. This makes the y-values span from 0 to 100, making the "unit" of the y-axis percent. If you instead want the values of the y-axis to span the interval from 0 to 1, don't multiply by 100.

Even if you don't have the y-values organized in one array as above, the principle is the same; the corresponding elements in each array consisting of y-values (e.g. y1, y2 etc.) should sum to 100 (or 1).

The below code is a modified version of the example @LogicalKnight linked to in his comment.

import numpy as np
from matplotlib import pyplot as plt

fnx = lambda : np.random.randint(5, 50, 10)
y = np.row_stack((fnx(), fnx(), fnx()))
x = np.arange(10)

# Make new array consisting of fractions of column-totals,
# using .astype(float) to avoid integer division
percent = y /  y.sum(axis=0).astype(float) * 100 

fig = plt.figure()
ax = fig.add_subplot(111)

ax.stackplot(x, percent)
ax.set_title('100 % stacked area chart')
ax.set_ylabel('Percent (%)')
ax.margins(0, 0) # Set margins to avoid "whitespace"

plt.show()

This gives the output shown below.

enter image description here

sodd
  • 12,482
  • 3
  • 54
  • 62
  • Thanks a lot for the proper help! I'm currently fighting a bit with mpl 1.2.1 and numpy to plot the data in the first place, and haven't had time to look at this issue again. Hence, I'm really happy to get this nice piece of code! Cheers Thomas – Thomas Becker Jun 04 '13 at 07:06
  • I've tried this method for producing a stack chart myself just now, and an exception is being thrown every time I try to call stackplot `Traceback (most recent call last): File "", line 1, in ax.stackplot(pressures) AttributeError: 'AxesSubplot' object has no attribute 'stackplot'` – Magic_Matt_Man Jul 14 '14 at 12:14
  • 1
    @Magic_Matt_Man What versions of Python and Matplotlib are you using? – sodd Jul 14 '14 at 12:31
  • Python 2.7.3 and MPL 1.1.1rc on an Ubuntu Linux 64-bit distribution. – Magic_Matt_Man Jul 14 '14 at 12:49
  • 1
    @Magic_Matt_Man You should update your Matplotlib to a more recent version, then the code above will work. I don't believe `stackplot` was included in the 1.1.1rc-release. – sodd Jul 14 '14 at 12:55
  • @nordev Ok now I have the module working properly. Basic examples run just fine. Now I just need to figure out the syntax for my application... Thanks! – Magic_Matt_Man Jul 14 '14 at 13:28