# matplotlib/matplotlib

### Subversion checkout URL

You can clone with
or
.

# Add new plot style: stackplot#819

Closed
wants to merge 13 commits into from
+783 −2

### 7 participants

Collaborator

There is also an example so you can try out the pull request. Sample output from this code is provided below:

Feedback is greatly appreciated, as always.

Collaborator

Hooray, only two commits this time!

+1

commented on the diff
lib/matplotlib/stackplot.py
 ((6 lines not shown)) +(http://stackoverflow.com/users/66549/doug) + +""" +import numpy as np +import matplotlib + +__all__ = ['stackplot'] + + +def stackplot(axes, x, y): + """Draws a stacked area plot. + + Parameters + ---------- + *x* : 1d array of dimension N + *y* : 2d array of dimension MxN
 Owner mdboom added a note Apr 13, 2012 We should probably clarify here what's in the comment below: that the data is not "pre-stacked". It might also be nice for y to be either a 2d array of MxN, or a variable number of y arguments (which would be stacked implicitly here). to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/stackplot.py
 ((26 lines not shown)) + element in the stacked area plot. + """ + + y = np.atleast_2d(y) + + # Assume data passed has not been 'stacked', so stack it here. + y_stack = np.cumsum(y, axis=0) + + r = [] + + # Color between x = 0 and the first array. + r.append(axes.fill_between(x, 0, y_stack[0,:], facecolor=axes._get_lines.color_cycle.next())) + + # Color between array i-1 and array i + for i in xrange(len(y)-1): + r.append(axes.fill_between(x, y_stack[i-1,:], y_stack[i,:], facecolor=axes._get_lines.color_cycle.next()))
 Owner mdboom added a note Apr 13, 2012 A nice bonus might be the ability to pass in a kwarg with a list of colors if the user wants to override the color defaults. to join this conversation on GitHub. Already have an account? Sign in to comment
Owner

This is great! Barring my minor comments, I think this is good to go. (And I think the color thing could be done as a second step if necessary -- my other comments are more important, IMHO).

Collaborator

Thanks for your feedback @mdboom. GitHub is great for code review and feedback. I love it.

None of these most recent commits include the `colors` keyword argument functionality you mentioned. I figured I could do that at a later time.

Owner

I think this is ready to merge. Will leave it up for a few more days in case others would like to comment.

Collaborator

pyplot.py needs update, as well as some docs (front page, what's new and API changes). I haven't looked over the docstrings yet.

Collaborator

I've been trying to figure out what @WeatherGod means by 'pyplot.py needs an update'. I think I figured it out.

I add `stackplot` to the `_plot_commands` variable and run `boilerplate.py`. Then I tested the `stackplot` function using `pylab`. I get the following error:

`'NoneType' object has no attribute 'pop'`.

I then spent an hour trying figure out what was going wrong. Long story short:

1) stackplot has no argument `**kwargs`;
2) as a result, `boilerplate.py` adds the line: `hold = None.pop('hold', None)` to the `stackplot` method in `pyplot.py`.

How should I deal with this? Deleting it manually is not a solution because any time anybody else runs `boilerplate` the same thing will happen. Maybe I should just add a `**kwargs` argument and pass them to all the called `Axes.fill_between` methods in `stackplot`. The bonus there is that `stackplot` would then support things like `alpha`, `linewidth` and `facecolor`. Also, I plan to add support for custom coloring, so it will inevitably be added in the future.

Owner

This perhaps should be re-evaluated in relation to the related PR #847.

The example should be converted into a unit test.

Other than that, this looks generally good to me.

Collaborator

It does appear to need a rebase at the very least. Most likely due to changes in pyplot.py?

Collaborator

You mean you want me to rebase against current master? I can do that. Are there any changes you wish me to make before I rebase?

Collaborator

Changes before rebasing would only complicate things. There still remains discussion regarding design decisions, but at least we would have a working branch to refer to in this manner.

Collaborator

I've rebased against master.

Collaborator

@dmcdougall: Unfortunately this will need rebasing again due to some changes to the boilerplate script. It is possible that you will get conflicts there and in the actual pyplot file. The good news is that you can now simply run boilerplate.py and it automatically updates pyplot for you.

Once you have done that, and added the example code as a simple unit test, I will merge the PR. Great work!

 dmcdougall `Added new plot style: stackplot.` ```Stackplot adds the feature request in issue #359 (matplotlib#359) and borrows heavily from Doug Y'barbo's stackoverflow answer (http://stackoverflow.com/questions/2225995/how-can-i-create-stacked-line-graph-with-matplotlib).``` `914385a` dmcdougall `Added stackplot example.` `4557573` dmcdougall `Make docstring more helpful.` ```The data *y* is assumed to be unstacked. This is now explicitly said in the docstring for the paramater *y*.``` `ff8ecde` dmcdougall `Make stackplot take an arbitrary number of args.` ```stackplot now supports taking either an MxN array of data, stacking along axis=0, or an arbitrary number of 1xN arrays, stacking them in the order passed. No checks are done for the case when no the number of args is zero. An exception should probably be raised here. Updated docstring to explain new call signatures.``` `8bbac65` dmcdougall `Updated stackplot example.` `Stackplot example now reflects usage of variadic calling signature.` `6674548` dmcdougall `Update changelog to include stackplot.` `3e8fe6e` dmcdougall `Stackplot now supports the same keyword aargs as matplotlib.Axes.fill…` ```…_between(). This is a measure to make boilerplate.py not produce a pyplot.py file with syntax errors. It's also a sensible course of action considering new stackplot features will almost certainly require keyword arguments anyway.``` `38a903f` dmcdougall `Fixed an issue where stackplot didn't fill stacked data in correct or…` `…der.` `91a233a` dmcdougall `Added stackplot to list of pyplot commands.` ```pyplot.py now contains the necessary information to make stackplot work inside of pyplot.``` `7b93874` dmcdougall `Added support for custom colour cycle.` ```New keyword argument 'colors' can be passed to allow custom colouring of the stacked areas in a stacked area plot.``` `a66ca21` dmcdougall `Add stackplot to list of plotting commands.` `a3a35fb`
Collaborator

@pelson Thanks for the feedback. I've rebased and saw a conflict in `boilerplate.py`. I fixed everything. I'm currently at a conference stuck behind a router that blocks all ports except 80 and 443. I will push the changes as soon as I am behind a reasonable router.

Collaborator

Aha! I ninja pushed through a proxy. All sorted now!

was assigned
Collaborator

@dmcdougall: Ideally, I would just like to get a unittest added and then I can press the big green merge button ;-)

 dmcdougall `Added stackplot unit test.` ```Test images added. Unit test writted and unit test added to default tests in __init__.py``` `0fd841c`
Collaborator

Done. Let me know if I messed anything up. I followed the guidelines here.

Thanks.

Collaborator

Don't think you need the `stackplot_test_image_pdf.png` file.

 dmcdougall `Removed superfluous file.` `cd629e5`
Collaborator

I have no idea why that was there; the test produced it. Maybe because I am using the pdf backend by default? Anyway, it's gone.

Collaborator

So the tests, by default, produce a png, a svg and a pdf, but in order to do the test comparison they are rasterised into `<fname>_svg.png` and `<fname>_pdf.png`, the latter two don't need to be in the baseline directory. Will merge in 24 hrs.

referenced this pull request from a commit in pelson/matplotlib
 pelson `Merged #819: dmcdougall's stackplot` `5675ffa`
Collaborator

I merged this manually to mpl. I moved your test into the test_axes module and squashed the commits into one (see 5675ffa).

Thanks for all your work (and patience) on this PR.

closed this
referenced this pull request
Closed

### new plot style: stackplot #359

Is there a way to remove the black lines between the polygons?

Oh, yeah, this will do it:

``````fbk = {'lw':0.0, 'edgecolor':None}
plt.stackplot(x, y.T, **fbk)
``````

Stackplot currently takes Y in a transposed format.. should that be fixed?

Well transposed or not depends on the layout of your data. This is probably not the best place to discuss such changes. Comments on an old closed issue/PR are likely to be lost. If you want to suggest changes please either use the mailing list or create a new open issue/PR

referenced this pull request
Open

### Stackplot takes a transposed Y matrix #4952

Ok, done: #4952

Commits on Jun 19, 2012
1. dmcdougall authored
```Stackplot adds the feature request in issue #359
(matplotlib#359) and borrows
heavily from Doug Y'barbo's stackoverflow answer
(http://stackoverflow.com/questions/2225995/how-can-i-create-stacked-line-graph-with-matplotlib).```
2. dmcdougall authored
3. dmcdougall authored
```The data *y* is assumed to be unstacked. This is now explicitly said in
the docstring for the paramater *y*.```
4. dmcdougall authored
```stackplot now supports taking either an MxN array of data, stacking
along axis=0, or an arbitrary number of 1xN arrays, stacking them in the
order passed.

No checks are done for the case when no the number of args is zero. An
exception should probably be raised here.

Updated docstring to explain new call signatures.```
5. dmcdougall authored
`Stackplot example now reflects usage of variadic calling signature.`
6. dmcdougall authored
7. dmcdougall authored
```…_between().

This is a measure to make boilerplate.py not produce a pyplot.py file
with syntax errors. It's also a sensible course of action considering
new stackplot features will almost certainly require keyword arguments
anyway.```
8. dmcdougall authored
`…der.`
9. dmcdougall authored
```pyplot.py now contains the necessary information to make stackplot work
inside of pyplot.```
10. dmcdougall authored
```New keyword argument 'colors' can be passed to allow custom colouring of
the stacked areas in a stacked area plot.```
11. dmcdougall authored
Commits on Jul 5, 2012
1. dmcdougall authored
```Test images added. Unit test writted and unit test added to default
tests in __init__.py```
Commits on Jul 6, 2012
1. dmcdougall authored
3  CHANGELOG
 @@ -32,6 +32,9 @@ the linear portion relative to the logarithmic portion to be adjusted. - MGD +2012-04-14 Added new plot style: stackplot. This new feature supports stacked + area plots. - Damon McDougall + 2012-04-06 When path clipping changes a LINETO to a MOVETO, it also changes any CLOSEPOLY command to a LINETO to the initial point. This fixes a problem with pdf and svg where the
2  boilerplate.py
 @@ -69,7 +69,6 @@ def %(func)s(%(argspec)s): return %(ret)s """ - # Used for colormap functions CMAP_TEMPLATE = AUTOGEN_MSG + """ def {name}(): @@ -131,6 +130,7 @@ def boilerplate_gen(): 'semilogy', 'specgram', #'spy', + 'stackplot', 'stem', 'step', 'streamplot',
18 examples/pylab_examples/stackplot_demo.py
 @@ -0,0 +1,18 @@ +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) + +y1, y2, y3 = fnx(), fnx(), fnx() + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.stackplot(x, y) +plt.show() + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.stackplot(x, y1, y2, y3) +plt.show()
3  lib/matplotlib/__init__.py
 @@ -992,7 +992,8 @@ def tk_window_focus(): 'matplotlib.tests.test_text', 'matplotlib.tests.test_tightlayout', 'matplotlib.tests.test_delaunay', - 'matplotlib.tests.test_legend' + 'matplotlib.tests.test_legend', + 'matplotlib.tests.test_stackplot' ] def test(verbosity=1):
5 lib/matplotlib/axes.py
 @@ -29,6 +29,7 @@ import matplotlib.spines as mspines import matplotlib.quiver as mquiver import matplotlib.scale as mscale +import matplotlib.stackplot as mstack import matplotlib.streamplot as mstream import matplotlib.table as mtable import matplotlib.text as mtext @@ -6408,6 +6409,10 @@ def quiver(self, *args, **kw): return q quiver.__doc__ = mquiver.Quiver.quiver_doc + def stackplot(self, x, *args, **kwargs): + return mstack.stackplot(self, x, *args, **kwargs) + stackplot.__doc__ = mstack.stackplot.__doc__ + def streamplot(self, x, y, u, v, density=1, linewidth=None, color=None, cmap=None, norm=None, arrowsize=1, arrowstyle='-|>', minlength=0.1):
19 lib/matplotlib/pyplot.py
 @@ -1616,6 +1616,7 @@ def plotting(): until they have been closed; in interactive mode, show generally has no effect. specgram a spectrogram plot + stackplot make a stacked plot stem make a stem plot subplot make a subplot (numrows, numcols, axesnum) table add a table to the axes @@ -2960,6 +2961,24 @@ def specgram(x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost +@autogen_docstring(Axes.stackplot) +def stackplot(x, *args, **kwargs): + ax = gca() + # allow callers to override the hold state by passing hold=True|False + washold = ax.ishold() + hold = kwargs.pop('hold', None) + if hold is not None: + ax.hold(hold) + try: + ret = ax.stackplot(x, *args, **kwargs) + draw_if_interactive() + finally: + ax.hold(washold) + + return ret + +# This function was autogenerated by boilerplate.py. Do not edit as +# changes will be lost @autogen_docstring(Axes.stem) def stem(x, y, linefmt='b-', markerfmt='bo', basefmt='r-', bottom=None, label=None, hold=None):
60 lib/matplotlib/stackplot.py
 @@ -0,0 +1,60 @@ +""" +Stacked area plot for 1D arrays inspired by Douglas Y'barbo's stackoverflow +answer: +http://stackoverflow.com/questions/2225995/how-can-i-create-stacked-line-graph-with-matplotlib + +(http://stackoverflow.com/users/66549/doug) + +""" +import numpy as np +import matplotlib + +__all__ = ['stackplot'] + + +def stackplot(axes, x, *args, **kwargs): + """Draws a stacked area plot. + + Parameters + ---------- + *x* : 1d array of dimension N + *y* : 2d array of dimension MxN, OR any number 1d arrays each of dimension Owner mdboom added a note Apr 13, 2012 We should probably clarify here what's in the comment below: that the data is not "pre-stacked". It might also be nice for y to be either a 2d array of MxN, or a variable number of y arguments (which would be stacked implicitly here). to join this conversation on GitHub. Already have an account? Sign in to comment + 1xN. The data is assumed to be unstacked. Each of the following + calls is legal: + + stackplot(x, y) # where y is MxN + staclplot(x, y1, y2, y3, y4) # where y1, y2, y3, y4, are all 1xNm + + Keyword arguments: + *colors* : A list or tuple of colors. These will be cycled through and + used to colour the stacked areas. + All other keyword arguments are passed to + :func:`~matplotlib.Axes.fill_between` + + Returns + ------- + *r* : A list of :class:`~matplotlib.collections.PolyCollection`, one for + each element in the stacked area plot. + """ + + if len(args) == 1: + y = np.atleast_2d(*args) + elif len(args) > 1: + y = np.row_stack(args) + + colors = kwargs.pop('colors', None) + if colors is not None: + axes.set_color_cycle(colors) + + # Assume data passed has not been 'stacked', so stack it here. + y_stack = np.cumsum(y, axis=0) + + r = [] + + # Color between x = 0 and the first array. + r.append(axes.fill_between(x, 0, y_stack[0,:], facecolor=axes._get_lines.color_cycle.next(), **kwargs)) + + # Color between array i-1 and array i + for i in xrange(len(y)-1): + r.append(axes.fill_between(x, y_stack[i,:], y_stack[i+1,:], facecolor=axes._get_lines.color_cycle.next(), **kwargs)) + return r
BIN  lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.pdf
Binary file not shown
BIN  lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.png