diff --git a/CHANGELOG b/CHANGELOG index bfe878021a4c..f590d9b11fb8 100644 --- a/CHANGELOG +++ b/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 diff --git a/boilerplate.py b/boilerplate.py index 2426c0864b6f..b1a430a0f98f 100644 --- a/boilerplate.py +++ b/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', diff --git a/examples/pylab_examples/stackplot_demo.py b/examples/pylab_examples/stackplot_demo.py new file mode 100644 index 000000000000..0148dd8430a9 --- /dev/null +++ b/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() diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 0c4583f465f0..b9578b89d4e7 100644 --- a/lib/matplotlib/__init__.py +++ b/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): diff --git a/lib/matplotlib/axes.py b/lib/matplotlib/axes.py index d2dec622cd80..26d9405d71f3 100644 --- a/lib/matplotlib/axes.py +++ b/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): diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 229355bab969..08b769271827 100644 --- a/lib/matplotlib/pyplot.py +++ b/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 @@ -2958,6 +2959,24 @@ def specgram(x, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, sci(ret[-1]) return ret +# 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) diff --git a/lib/matplotlib/stackplot.py b/lib/matplotlib/stackplot.py new file mode 100644 index 000000000000..255c8e2fb1b8 --- /dev/null +++ b/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 + 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 diff --git a/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.pdf b/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.pdf new file mode 100644 index 000000000000..b922c19f06a6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.png b/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.png new file mode 100644 index 000000000000..a9812530c71c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.svg b/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.svg new file mode 100644 index 000000000000..ae64951b8022 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_stackplot/stackplot_test_image.svg @@ -0,0 +1,661 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/test_stackplot.py b/lib/matplotlib/tests/test_stackplot.py new file mode 100644 index 000000000000..9c437595a6e7 --- /dev/null +++ b/lib/matplotlib/tests/test_stackplot.py @@ -0,0 +1,14 @@ +import numpy as np +import matplotlib +from matplotlib.testing.decorators import image_comparison +import matplotlib.pyplot as plt + +@image_comparison(baseline_images=['stackplot_test_image']) +def test_stackplot(): + fig = plt.figure() + x = np.linspace(0, 10, 10) + y1 = 1.0 * x + y2 = 2.0 * x + 1 + y3 = 3.0 * x + 2 + ax = fig.add_subplot(1, 1, 1) + ax.stackplot(x, y1, y2, y3)