Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stacked kwarg to hist and implement stacked hists for step histtype #847

Merged
merged 6 commits into from Sep 10, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions doc/users/whats_new.rst
Expand Up @@ -127,6 +127,17 @@ local intensity of the vector field.

.. plot:: mpl_examples/pylab_examples/streamplot_demo.py


New hist functionality
----------------------

Nic Eggert added a new `stacked` kwarg to :meth:`~matplotlib.pyplot.hist` that
allows creation of stacked histograms using any of the histogram types.
Previously, this functionality was only available by using the `barstacked`
histogram type. Now, when `stacked=True` is passed to the function, any of the
histogram types can be stacked. The `barstacked` histogram type retains its
previous functionality for backwards compatibility.

Updated shipped dependencies
----------------------------

Expand Down
14 changes: 13 additions & 1 deletion examples/pylab_examples/histogram_demo_extended.py
Expand Up @@ -82,7 +82,19 @@
#
P.figure()

n, bins, patches = P.hist(x, 10, normed=1, histtype='barstacked')
n, bins, patches = P.hist(x, 10, normed=1, histtype='bar', stacked=True)

P.show()

#
# we can also stack using the step histtype
#

P.figure()

n, bins, patches = P.hist(x, 10, histtype='step', stacked=True, fill=True)

P.show()

#
# finally: make a multiple-histogram of data-sets with different length
Expand Down
37 changes: 26 additions & 11 deletions lib/matplotlib/axes.py
Expand Up @@ -7728,7 +7728,7 @@ def get_shared_y_axes(self):
def hist(self, x, bins=10, range=None, normed=False, weights=None,
cumulative=False, bottom=None, histtype='bar', align='mid',
orientation='vertical', rwidth=None, log=False,
color=None, label=None,
color=None, label=None, stacked=False,
**kwargs):
"""
Plot a histogram.
Expand All @@ -7738,7 +7738,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
hist(x, bins=10, range=None, normed=False, weights=None,
cumulative=False, bottom=None, histtype='bar', align='mid',
orientation='vertical', rwidth=None, log=False,
color=None, label=None,
color=None, label=None, stacked=False,
**kwargs)

Compute and draw the histogram of *x*. The return value is a
Expand Down Expand Up @@ -7862,6 +7862,11 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
ax.hist(12+3*np.random.randn(1000), label='women', alpha=0.5)
ax.legend()

*stacked*:
If *True*, multiple data are stacked on top of each other
If *False* multiple data are aranged side by side if
histtype is 'bar' or on top of each other if histtype is 'step'

.

kwargs are used to update the properties of the
Expand Down Expand Up @@ -7901,6 +7906,9 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
'hist now uses the rwidth to give relative width '
'and not absolute width')

if histtype == 'barstacked' and not stacked:
stacked=True

# Massage 'x' for processing.
# NOTE: Be sure any changes here is also done below to 'weights'
if isinstance(x, np.ndarray) or not iterable(x[0]):
Expand Down Expand Up @@ -7986,13 +7994,21 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
hist_kwargs['new'] = True

n = []
for i in xrange(nx):
mlast = bottom
# reversed order is necessary so when stacking histogram, first dataset is on top
# if histogram isn't stacked, this doesn't make any difference
for i in reversed(xrange(nx)):
# this will automatically overwrite bins,
# so that each histogram uses the same bins
m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs)
if mlast is None:
mlast = np.zeros(len(bins)-1, np.int)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a thought... are we guaranteed that bins will have a non-zero length? If not, then it would be a good idea to catch the length-zero case and raise a descriptive exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bins argument to np.histogram takes either the number of bins or an array of bin edges.

I just played around a little, and I don't think it's possible for np.histogram to return a zero-length array of bin edges. It raises an exception if one tries to set bins=0

In fact, the only way I can get it to return anything less than a length-2 array is by explicitly passing only one bin edge. This will obviously result in some strange behavior, but that's a pretty edge case. If np.histogram doesn't raise an exception for that, I don't think we should, either.

if normed:
db = np.diff(bins)
m = (m.astype(float) / db) / m.sum()
if stacked:
m += mlast
mlast[:] = m
n.append(m)

if cumulative:
Expand All @@ -8005,6 +8021,8 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
else:
n = [m[slc].cumsum()[slc] for m in n]

n.reverse() # put them back in the right order

patches = []

if histtype.startswith('bar'):
Expand All @@ -8017,7 +8035,7 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
else:
dr = 1.0

if histtype=='bar':
if histtype=='bar' and not stacked:
width = dr*totwidth/nx
dw = width

Expand All @@ -8026,10 +8044,9 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
else:
boffset = 0.0
stacked = False
elif histtype=='barstacked':
elif histtype=='barstacked' or stacked:
width = dr*totwidth
boffset, dw = 0.0, 0.0
stacked = True

if align == 'mid' or align == 'edge':
boffset += 0.5*totwidth
Expand All @@ -8042,14 +8059,10 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
_barfunc = self.bar

for m, c in zip(n, color):
patch = _barfunc(bins[:-1]+boffset, m, width, bottom,
patch = _barfunc(bins[:-1]+boffset, m, width,
align='center', log=log,
color=c)
patches.append(patch)
if stacked:
if bottom is None:
bottom = 0.0
bottom += m
boffset += dw

elif histtype.startswith('step'):
Expand All @@ -8072,6 +8085,8 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
else: # orientation == 'vertical'
self.set_yscale('log')

# If fill kwarg is set, it will be passed to the patch collection,
# overriding this
fill = (histtype == 'stepfilled')

for m, c in zip(n, color):
Expand Down
3 changes: 2 additions & 1 deletion lib/matplotlib/pyplot.py
Expand Up @@ -2642,7 +2642,8 @@ def hexbin(x, y, C=None, gridsize=100, bins=None, xscale='linear',
@_autogen_docstring(Axes.hist)
def hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False,
bottom=None, histtype='bar', align='mid', orientation='vertical',
rwidth=None, log=False, color=None, label=None, hold=None, **kwargs):
rwidth=None, log=False, color=None, label=None, stacked=False,
hold=None, **kwargs):
ax = gca()
# allow callers to override the hold state by passing hold=True|False
washold = ax.ishold()
Expand Down
Binary file not shown.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.