Skip to content

Commit

Permalink
Merge pull request #2452 from larrybradley/limitfix
Browse files Browse the repository at this point in the history
Fixed issues with errorbar limits
  • Loading branch information
tacaswell committed Apr 4, 2014
2 parents f93ab9b + 7cc983d commit 9f28318
Show file tree
Hide file tree
Showing 8 changed files with 2,240 additions and 90 deletions.
4 changes: 4 additions & 0 deletions doc/api/api_changes.rst
Expand Up @@ -47,6 +47,10 @@ original location:
- mstream -> `from matplotlib import stream as mstream`
- mtable -> `from matplotlib import table as mtable`

* The :func:`~matplotlib.pyplot.errorbar` method has been changed such that
the upper and lower limits (*lolims*, *uplims*, *xlolims*, *xuplims*) now
point in the correct direction.

* The Sphinx extensions `ipython_directive` and
`ipython_console_highlighting` have been moved to the IPython
project itself. While they remain in matplotlib for this release,
Expand Down
5 changes: 5 additions & 0 deletions doc/users/whats_new.rst
Expand Up @@ -139,6 +139,11 @@ specify wedgeprops = {'linewidth':3} to specify the width of the borders of
the wedges in the pie. For more properties that the user can specify, look at
the docs for the wedge and text objects.

Fixed the direction of errorbar upper/lower limits
``````````````````````````````````````````````````
Larry Bradley fixed the :func:`~matplotlib.pyplot.errorbar` method such
that the upper and lower limits (*lolims*, *uplims*, *xlolims*,
*xuplims*) now point in the correct direction.

Date handling
-------------
Expand Down
53 changes: 53 additions & 0 deletions examples/statistics/errorbar_limits.py
@@ -0,0 +1,53 @@
"""
Demo of the errorbar function, including upper and lower limits
"""
import numpy as np
import matplotlib.pyplot as plt

# example data
x = np.arange(0.5, 5.5, 0.5)
y = np.exp(-x)
xerr = 0.1
yerr = 0.2
ls = 'dotted'

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

# standard error bars
plt.errorbar(x, y, xerr=xerr, yerr=yerr, ls=ls, color='blue')

# including upper limits
uplims = np.zeros(x.shape)
uplims[[1, 5, 9]] = True
plt.errorbar(x, y+0.5, xerr=xerr, yerr=yerr, uplims=uplims, ls=ls,
color='green')

# including lower limits
lolims = np.zeros(x.shape)
lolims[[2, 4, 8]] = True
plt.errorbar(x, y+1.0, xerr=xerr, yerr=yerr, lolims=lolims, ls=ls,
color='red')

# including upper and lower limits
plt.errorbar(x, y+1.5, marker='o', ms=8, xerr=xerr, yerr=yerr,
lolims=lolims, uplims=uplims, ls=ls, color='magenta')

# including xlower and xupper limits
xerr = 0.2
yerr = np.zeros(x.shape) + 0.2
yerr[[3, 6]] = 0.3
xlolims = lolims
xuplims = uplims
lolims = np.zeros(x.shape)
uplims = np.zeros(x.shape)
lolims[[6]] = True
uplims[[3]] = True
plt.errorbar(x, y+2.1, marker='o', ms=8, xerr=xerr, yerr=yerr,
xlolims=xlolims, xuplims=xuplims, uplims=uplims, lolims=lolims,
ls='none', mec='blue', capsize=0, color='cyan')

ax.set_xlim((0, 5.5))
ax.set_title('Errorbar upper and lower limits')
plt.show()

193 changes: 103 additions & 90 deletions lib/matplotlib/axes/_axes.py
Expand Up @@ -2602,7 +2602,9 @@ def errorbar(self, x, y, yerr=None, xerr=None,
These arguments can be used to indicate that a value gives
only upper/lower limits. In that case a caret symbol is
used to indicate this. lims-arguments may be of the same
type as *xerr* and *yerr*.
type as *xerr* and *yerr*. To use limits with inverted
axes, :meth:`set_xlim` or :meth:`set_ylim` must be called
before :meth:`errorbar`.
*errorevery*: positive integer
subsamples the errorbars. e.g., if everyerror=5, errorbars for
Expand Down Expand Up @@ -2682,16 +2684,12 @@ def errorbar(self, x, y, yerr=None, xerr=None,
if elinewidth:
lines_kw['linewidth'] = elinewidth
else:
if 'linewidth' in kwargs:
lines_kw['linewidth'] = kwargs['linewidth']
if 'lw' in kwargs:
lines_kw['lw'] = kwargs['lw']
if 'transform' in kwargs:
lines_kw['transform'] = kwargs['transform']
if 'alpha' in kwargs:
lines_kw['alpha'] = kwargs['alpha']
if 'zorder' in kwargs:
lines_kw['zorder'] = kwargs['zorder']
for key in ('linewidth', 'lw'):
if key in kwargs:
lines_kw[key] = kwargs[key]
for key in ('transform', 'alpha', 'zorder'):
if key in kwargs:
lines_kw[key] = kwargs[key]

# arrays fine here, they are booleans and hence not units
if not iterable(lolims):
Expand Down Expand Up @@ -2727,29 +2725,21 @@ def xywhere(xs, ys, mask):
ys = [thisy for thisy, b in zip(ys, mask) if b]
return xs, ys

plot_kw = {'label': '_nolegend_'}
if capsize > 0:
plot_kw = {
'ms': 2 * capsize,
'label': '_nolegend_'}
if capthick is not None:
# 'mew' has higher priority, I believe,
# if both 'mew' and 'markeredgewidth' exists.
# So, save capthick to markeredgewidth so that
# explicitly setting mew or markeredgewidth will
# over-write capthick.
plot_kw['markeredgewidth'] = capthick
# For backwards-compat, allow explicit setting of
# 'mew' or 'markeredgewidth' to over-ride capthick.
if 'markeredgewidth' in kwargs:
plot_kw['markeredgewidth'] = kwargs['markeredgewidth']
if 'mew' in kwargs:
plot_kw['mew'] = kwargs['mew']
if 'transform' in kwargs:
plot_kw['transform'] = kwargs['transform']
if 'alpha' in kwargs:
plot_kw['alpha'] = kwargs['alpha']
if 'zorder' in kwargs:
plot_kw['zorder'] = kwargs['zorder']
plot_kw['ms'] = 2. * capsize
if capthick is not None:
# 'mew' has higher priority, I believe,
# if both 'mew' and 'markeredgewidth' exists.
# So, save capthick to markeredgewidth so that
# explicitly setting mew or markeredgewidth will
# over-write capthick.
plot_kw['markeredgewidth'] = capthick
# For backwards-compat, allow explicit setting of
# 'mew' or 'markeredgewidth' to over-ride capthick.
for key in ('markeredgewidth', 'mew', 'transform', 'alpha', 'zorder'):
if key in kwargs:
plot_kw[key] = kwargs[key]

if xerr is not None:
if (iterable(xerr) and len(xerr) == 2 and
Expand All @@ -2766,38 +2756,48 @@ def xywhere(xs, ys, mask):
right = [thisx + thiserr for (thisx, thiserr)
in cbook.safezip(x, xerr)]

yo, _ = xywhere(y, right, everymask)
lo, ro = xywhere(left, right, everymask)
barcols.append(self.hlines(yo, lo, ro, **lines_kw))
if capsize > 0:
if xlolims.any():
# can't use numpy logical indexing since left and
# y are lists
leftlo, ylo = xywhere(left, y, xlolims & everymask)

caplines.extend(
self.plot(leftlo, ylo, ls='None',
marker=mlines.CARETLEFT, **plot_kw))
xlolims = ~xlolims
leftlo, ylo = xywhere(left, y, xlolims & everymask)
caplines.extend(self.plot(leftlo, ylo, 'k|', **plot_kw))
# select points without upper/lower limits in x and
# draw normal errorbars for these points
noxlims = ~(xlolims | xuplims)
if noxlims.any():
yo, _ = xywhere(y, right, noxlims & everymask)
lo, ro = xywhere(left, right, noxlims & everymask)
barcols.append(self.hlines(yo, lo, ro, **lines_kw))
if capsize > 0:
caplines.extend(self.plot(lo, yo, 'k|', **plot_kw))
caplines.extend(self.plot(ro, yo, 'k|', **plot_kw))

if xlolims.any():
yo, _ = xywhere(y, right, xlolims & everymask)
lo, ro = xywhere(x, right, xlolims & everymask)
barcols.append(self.hlines(yo, lo, ro, **lines_kw))
rightup, yup = xywhere(right, y, xlolims & everymask)
if self.xaxis_inverted():
marker = mlines.CARETLEFT
else:

leftlo, ylo = xywhere(left, y, everymask)
caplines.extend(self.plot(leftlo, ylo, 'k|', **plot_kw))

if xuplims.any():

rightup, yup = xywhere(right, y, xuplims & everymask)
caplines.extend(
self.plot(rightup, yup, ls='None',
marker=mlines.CARETRIGHT, **plot_kw))
xuplims = ~xuplims
rightup, yup = xywhere(right, y, xuplims & everymask)
caplines.extend(self.plot(rightup, yup, 'k|', **plot_kw))
marker = mlines.CARETRIGHT
caplines.extend(
self.plot(rightup, yup, ls='None', marker=marker,
**plot_kw))
if capsize > 0:
xlo, ylo = xywhere(x, y, xlolims & everymask)
caplines.extend(self.plot(xlo, ylo, 'k|', **plot_kw))

if xuplims.any():
yo, _ = xywhere(y, right, xuplims & everymask)
lo, ro = xywhere(left, x, xuplims & everymask)
barcols.append(self.hlines(yo, lo, ro, **lines_kw))
leftlo, ylo = xywhere(left, y, xuplims & everymask)
if self.xaxis_inverted():
marker = mlines.CARETRIGHT
else:
rightup, yup = xywhere(right, y, everymask)
caplines.extend(self.plot(rightup, yup, 'k|', **plot_kw))
marker = mlines.CARETLEFT
caplines.extend(
self.plot(leftlo, ylo, ls='None', marker=marker,
**plot_kw))
if capsize > 0:
xup, yup = xywhere(x, y, xuplims & everymask)
caplines.extend(self.plot(xup, yup, 'k|', **plot_kw))

if yerr is not None:
if (iterable(yerr) and len(yerr) == 2 and
Expand All @@ -2814,35 +2814,48 @@ def xywhere(xs, ys, mask):
upper = [thisy + thiserr for (thisy, thiserr)
in cbook.safezip(y, yerr)]

xo, _ = xywhere(x, lower, everymask)
lo, uo = xywhere(lower, upper, everymask)
barcols.append(self.vlines(xo, lo, uo, **lines_kw))
if capsize > 0:

if lolims.any():
xlo, lowerlo = xywhere(x, lower, lolims & everymask)
caplines.extend(
self.plot(xlo, lowerlo, ls='None',
marker=mlines.CARETDOWN, **plot_kw))
lolims = ~lolims
xlo, lowerlo = xywhere(x, lower, lolims & everymask)
caplines.extend(self.plot(xlo, lowerlo, 'k_', **plot_kw))
# select points without upper/lower limits in y and
# draw normal errorbars for these points
noylims = ~(lolims | uplims)
if noylims.any():
xo, _ = xywhere(x, lower, noylims & everymask)
lo, uo = xywhere(lower, upper, noylims & everymask)
barcols.append(self.vlines(xo, lo, uo, **lines_kw))
if capsize > 0:
caplines.extend(self.plot(xo, lo, 'k_', **plot_kw))
caplines.extend(self.plot(xo, uo, 'k_', **plot_kw))

if lolims.any():
xo, _ = xywhere(x, lower, lolims & everymask)
lo, uo = xywhere(y, upper, lolims & everymask)
barcols.append(self.vlines(xo, lo, uo, **lines_kw))
xup, upperup = xywhere(x, upper, lolims & everymask)
if self.yaxis_inverted():
marker = mlines.CARETDOWN
else:
xlo, lowerlo = xywhere(x, lower, everymask)
caplines.extend(self.plot(xlo, lowerlo, 'k_', **plot_kw))

if uplims.any():
xup, upperup = xywhere(x, upper, uplims & everymask)

caplines.extend(
self.plot(xup, upperup, ls='None',
marker=mlines.CARETUP, **plot_kw))
uplims = ~uplims
xup, upperup = xywhere(x, upper, uplims & everymask)
caplines.extend(self.plot(xup, upperup, 'k_', **plot_kw))
marker = mlines.CARETUP
caplines.extend(
self.plot(xup, upperup, ls='None', marker=marker,
**plot_kw))
if capsize > 0:
xlo, ylo = xywhere(x, y, lolims & everymask)
caplines.extend(self.plot(xlo, ylo, 'k_', **plot_kw))

if uplims.any():
xo, _ = xywhere(x, lower, uplims & everymask)
lo, uo = xywhere(lower, y, uplims & everymask)
barcols.append(self.vlines(xo, lo, uo, **lines_kw))
xlo, lowerlo = xywhere(x, lower, uplims & everymask)
if self.yaxis_inverted():
marker = mlines.CARETUP
else:
xup, upperup = xywhere(x, upper, everymask)
caplines.extend(self.plot(xup, upperup, 'k_', **plot_kw))
marker = mlines.CARETDOWN
caplines.extend(
self.plot(xlo, lowerlo, ls='None', marker=marker,
**plot_kw))
if capsize > 0:
xup, yup = xywhere(x, y, uplims & everymask)
caplines.extend(self.plot(xup, yup, 'k_', **plot_kw))

if not barsabove and fmt is not None:
l0, = self.plot(x, y, fmt, **kwargs)
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.

0 comments on commit 9f28318

Please sign in to comment.