Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Added ability to offset errorbars when using errorevery. #6280

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

Merged
merged 11 commits into from
Apr 28, 2019
Merged
10 changes: 10 additions & 0 deletions doc/users/next_whats_new/errorbar_offsets.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Errorbar plots can shift which points have error bars
-----------------------------------------------------

Previously, `plt.errorbar()` accepted a kwarg `errorevery` such that the
command `plt.errorbar(x, y, yerr, errorevery=6)` would add error bars to
datapoints `x[::6], y[::6]`.

`errorbar()` now also accepts a tuple for `errorevery` such that
`plt.errorbar(x, y, yerr, errorevery=(start, N))` adds error bars to points
`x[start::N], y[start::N]`.
26 changes: 16 additions & 10 deletions examples/lines_bars_and_markers/errorbar_subsample.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,29 @@

# example data
x = np.arange(0.1, 4, 0.1)
y = np.exp(-x)
y1 = np.exp(-1.0 * x)
y2 = np.exp(-0.5 * x)

# example variable error bar values
yerr = 0.1 + 0.1 * np.sqrt(x)
y1err = 0.1 + 0.1 * np.sqrt(x)
y2err = 0.1 + 0.1 * np.sqrt(x/2)


# Now switch to a more OO interface to exercise more features.
fig, axs = plt.subplots(nrows=1, ncols=2, sharex=True)
ax = axs[0]
ax.errorbar(x, y, yerr=yerr)
ax.set_title('all errorbars')
fig, (ax_l, ax_c, ax_r) = plt.subplots(nrows=1, ncols=3,
sharex=True, figsize=(12, 6))

ax = axs[1]
ax.errorbar(x, y, yerr=yerr, errorevery=5)
ax.set_title('only every 5th errorbar')
ax_l.set_title('all errorbars')
ax_l.errorbar(x, y1, yerr=y1err)
ax_l.errorbar(x, y2, yerr=y2err)

ax_c.set_title('only every 6th errorbar')
ax_c.errorbar(x, y1, yerr=y1err, errorevery=6)
ax_c.errorbar(x, y2, yerr=y2err, errorevery=6)

fig.suptitle('Errorbar subsampling for better appearance')
ax_r.set_title('second series shifted by 3')
ax_r.errorbar(x, y1, yerr=y1err, errorevery=(0, 6))
ax_r.errorbar(x, y2, yerr=y2err, errorevery=(3, 6))

fig.suptitle('Errorbar subsampling for better appearance')
plt.show()
27 changes: 20 additions & 7 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3143,10 +3143,14 @@ def errorbar(self, x, y, yerr=None, xerr=None,
and *yerr*. To use limits with inverted axes, :meth:`set_xlim`
or :meth:`set_ylim` must be called before :meth:`errorbar`.

errorevery : positive integer, optional, default: 1
Subsamples the errorbars. e.g., if errorevery=5, errorbars for
every 5-th datapoint will be plotted. The data plot itself still
shows all data points.
errorevery : int or (int, int), optional, default: 1
draws error bars on a subset of the data. *errorevery* =N draws
error bars on the points (x[::N], y[::N]).
*errorevery* =(start, N) draws error bars on the points
(x[start::N], y[start::N]). e.g. errorevery=(6, 3)
adds error bars to the data at (x[6], x[9], x[12], x[15], ...).
Used to avoid overlapping error bars when two series share x-axis
values.

Returns
-------
Expand Down Expand Up @@ -3191,9 +3195,17 @@ def errorbar(self, x, y, yerr=None, xerr=None,
kwargs = {k: v for k, v in kwargs.items() if v is not None}
kwargs.setdefault('zorder', 2)

if errorevery < 1:
try:
offset, errorevery = errorevery
except TypeError:
offset = 0

if errorevery < 1 or int(errorevery) != errorevery:
raise ValueError(
'errorevery must be positive integer or tuple of integers')
if int(offset) != offset:
raise ValueError(
'errorevery has to be a strictly positive integer')
'errorevery\'s starting index must be an integer')

self._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)

Expand Down Expand Up @@ -3302,7 +3314,8 @@ def errorbar(self, x, y, yerr=None, xerr=None,
xlolims = np.broadcast_to(xlolims, len(x)).astype(bool)
xuplims = np.broadcast_to(xuplims, len(x)).astype(bool)

everymask = np.arange(len(x)) % errorevery == 0
everymask = np.zeros(len(x), bool)
everymask[offset::errorevery] = True

def xywhere(xs, ys, mask):
"""
Expand Down
23 changes: 23 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2945,6 +2945,29 @@ def test_errorbar_with_prop_cycle():
ax.errorbar(x=[2, 4, 10], y=[6, 4, 2], yerr=0.5)


@check_figures_equal()
def test_errorbar_offsets(fig_test, fig_ref):
x = np.linspace(0, 1, 15)
y = x * (1-x)
yerr = y/6

ax_ref = fig_ref.subplots()
ax_test = fig_test.subplots()

for color, shift in zip('rgbk', [0, 0, 2, 7]):
y += .02

# Using feature in question
ax_test.errorbar(x, y, yerr, errorevery=(shift, 4),
capsize=4, c=color)

# Using manual errorbars
# n.b. errorbar draws the main plot at z=2.1 by default
ax_ref.plot(x, y, c=color, zorder=2.1)
ax_ref.errorbar(x[shift::4], y[shift::4], yerr[shift::4],
capsize=4, c=color, fmt='none')


@image_comparison(baseline_images=['hist_stacked_stepfilled',
'hist_stacked_stepfilled'])
def test_hist_stacked_stepfilled():
Expand Down