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

Skip to content

Commit 8e569e9

Browse files
authored
Merge pull request #15037 from anntzer/simplify-errorbar
Simplifications to errorbar().
2 parents 90200c6 + c24b1af commit 8e569e9

File tree

1 file changed

+78
-89
lines changed

1 file changed

+78
-89
lines changed

lib/matplotlib/axes/_axes.py

Lines changed: 78 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,10 +3199,13 @@ def errorbar(self, x, y, yerr=None, xerr=None,
31993199
32003200
lolims, uplims, xlolims, xuplims : bool, default: False
32013201
These arguments can be used to indicate that a value gives only
3202-
upper/lower limits. In that case a caret symbol is used to
3203-
indicate this. *lims*-arguments may be of the same type as *xerr*
3204-
and *yerr*. To use limits with inverted axes, `~.Axes.set_xlim`
3205-
or `~.Axes.set_ylim` must be called before :meth:`errorbar`.
3202+
upper/lower limits. In that case a caret symbol is used to
3203+
indicate this. *lims*-arguments may be scalars, or array-likes of
3204+
the same length as *xerr* and *yerr*. To use limits with inverted
3205+
axes, `~.Axes.set_xlim` or `~.Axes.set_ylim` must be called before
3206+
:meth:`errorbar`. Note the tricky parameter names: setting e.g.
3207+
*lolims* to True means that the y-value is a *lower* limit of the
3208+
True value, so, only an *upward*-pointing arrow will be drawn!
32063209
32073210
errorevery : int or (int, int), default: 1
32083211
draws error bars on a subset of the data. *errorevery* =N draws
@@ -3296,6 +3299,9 @@ def errorbar(self, x, y, yerr=None, xerr=None,
32963299
if not np.iterable(y):
32973300
y = [y]
32983301

3302+
if len(x) != len(y):
3303+
raise ValueError("'x' and 'y' must have the same size")
3304+
32993305
if xerr is not None:
33003306
if not np.iterable(xerr):
33013307
xerr = [xerr] * len(x)
@@ -3368,22 +3374,29 @@ def errorbar(self, x, y, yerr=None, xerr=None,
33683374
everymask = np.zeros(len(x), bool)
33693375
everymask[offset::errorevery] = True
33703376

3371-
def xywhere(xs, ys, mask):
3372-
"""
3373-
Return xs[mask], ys[mask] where mask is True but xs and
3374-
ys are not arrays.
3375-
"""
3376-
assert len(xs) == len(ys)
3377-
assert len(xs) == len(mask)
3378-
xs = [thisx for thisx, b in zip(xs, mask) if b]
3379-
ys = [thisy for thisy, b in zip(ys, mask) if b]
3380-
return xs, ys
3377+
def apply_mask(arrays, mask):
3378+
# Return, for each array in *arrays*, the elements for which *mask*
3379+
# is True, without using fancy indexing.
3380+
return [[*itertools.compress(array, mask)] for array in arrays]
33813381

3382-
def extract_err(name, err, data):
3382+
def extract_err(name, err, data, lolims, uplims):
33833383
"""
3384-
Private function to parse *err* and subtract/add it to *data*.
3385-
3386-
Both *err* and *data* are already iterables at this point.
3384+
Private function to compute error bars.
3385+
3386+
Parameters
3387+
----------
3388+
name : {'x', 'y'}
3389+
Name used in the error message.
3390+
err : array-like
3391+
xerr or yerr from errorbar().
3392+
data : array-like
3393+
x or y from errorbar().
3394+
lolims : array-like
3395+
Error is only applied on **upper** side when this is True. See
3396+
the note in the main docstring about this parameter's name.
3397+
uplims : array-like
3398+
Error is only applied on **lower** side when this is True. See
3399+
the note in the main docstring about this parameter's name.
33873400
"""
33883401
try: # Asymmetric error: pair of 1D iterables.
33893402
a, b = err
@@ -3400,116 +3413,92 @@ def extract_err(name, err, data):
34003413
raise ValueError(
34013414
f"The lengths of the data ({len(data)}) and the "
34023415
f"error {len(e)} do not match")
3403-
low = [v - e for v, e in zip(data, a)]
3404-
high = [v + e for v, e in zip(data, b)]
3416+
low = [v if lo else v - e for v, e, lo in zip(data, a, lolims)]
3417+
high = [v if up else v + e for v, e, up in zip(data, b, uplims)]
34053418
return low, high
34063419

34073420
if xerr is not None:
3408-
left, right = extract_err('x', xerr, x)
3421+
left, right = extract_err('x', xerr, x, xlolims, xuplims)
3422+
barcols.append(self.hlines(
3423+
*apply_mask([y, left, right], everymask), **eb_lines_style))
34093424
# select points without upper/lower limits in x and
34103425
# draw normal errorbars for these points
34113426
noxlims = ~(xlolims | xuplims)
3412-
if noxlims.any() or len(noxlims) == 0:
3413-
yo, _ = xywhere(y, right, noxlims & everymask)
3414-
lo, ro = xywhere(left, right, noxlims & everymask)
3415-
barcols.append(self.hlines(yo, lo, ro, **eb_lines_style))
3416-
if capsize > 0:
3417-
caplines.append(mlines.Line2D(lo, yo, marker='|',
3418-
**eb_cap_style))
3419-
caplines.append(mlines.Line2D(ro, yo, marker='|',
3420-
**eb_cap_style))
3421-
3427+
if noxlims.any() and capsize > 0:
3428+
yo, lo, ro = apply_mask([y, left, right], noxlims & everymask)
3429+
caplines.extend([
3430+
mlines.Line2D(lo, yo, marker='|', **eb_cap_style),
3431+
mlines.Line2D(ro, yo, marker='|', **eb_cap_style)])
34223432
if xlolims.any():
3423-
yo, _ = xywhere(y, right, xlolims & everymask)
3424-
lo, ro = xywhere(x, right, xlolims & everymask)
3425-
barcols.append(self.hlines(yo, lo, ro, **eb_lines_style))
3426-
rightup, yup = xywhere(right, y, xlolims & everymask)
3433+
xo, yo, lo, ro = apply_mask([x, y, left, right],
3434+
xlolims & everymask)
34273435
if self.xaxis_inverted():
34283436
marker = mlines.CARETLEFTBASE
34293437
else:
34303438
marker = mlines.CARETRIGHTBASE
3431-
caplines.append(
3432-
mlines.Line2D(rightup, yup, ls='None', marker=marker,
3433-
**eb_cap_style))
3439+
caplines.append(mlines.Line2D(
3440+
ro, yo, ls='None', marker=marker, **eb_cap_style))
34343441
if capsize > 0:
3435-
xlo, ylo = xywhere(x, y, xlolims & everymask)
3436-
caplines.append(mlines.Line2D(xlo, ylo, marker='|',
3437-
**eb_cap_style))
3438-
3442+
caplines.append(mlines.Line2D(
3443+
xo, yo, marker='|', **eb_cap_style))
34393444
if xuplims.any():
3440-
yo, _ = xywhere(y, right, xuplims & everymask)
3441-
lo, ro = xywhere(left, x, xuplims & everymask)
3442-
barcols.append(self.hlines(yo, lo, ro, **eb_lines_style))
3443-
leftlo, ylo = xywhere(left, y, xuplims & everymask)
3445+
xo, yo, lo, ro = apply_mask([x, y, left, right],
3446+
xuplims & everymask)
34443447
if self.xaxis_inverted():
34453448
marker = mlines.CARETRIGHTBASE
34463449
else:
34473450
marker = mlines.CARETLEFTBASE
3448-
caplines.append(
3449-
mlines.Line2D(leftlo, ylo, ls='None', marker=marker,
3450-
**eb_cap_style))
3451+
caplines.append(mlines.Line2D(
3452+
lo, yo, ls='None', marker=marker, **eb_cap_style))
34513453
if capsize > 0:
3452-
xup, yup = xywhere(x, y, xuplims & everymask)
3453-
caplines.append(mlines.Line2D(xup, yup, marker='|',
3454-
**eb_cap_style))
3454+
caplines.append(mlines.Line2D(
3455+
xo, yo, marker='|', **eb_cap_style))
34553456

34563457
if yerr is not None:
3457-
lower, upper = extract_err('y', yerr, y)
3458+
lower, upper = extract_err('y', yerr, y, lolims, uplims)
3459+
barcols.append(self.vlines(
3460+
*apply_mask([x, lower, upper], everymask), **eb_lines_style))
34583461
# select points without upper/lower limits in y and
34593462
# draw normal errorbars for these points
34603463
noylims = ~(lolims | uplims)
3461-
if noylims.any() or len(noylims) == 0:
3462-
xo, _ = xywhere(x, lower, noylims & everymask)
3463-
lo, uo = xywhere(lower, upper, noylims & everymask)
3464-
barcols.append(self.vlines(xo, lo, uo, **eb_lines_style))
3465-
if capsize > 0:
3466-
caplines.append(mlines.Line2D(xo, lo, marker='_',
3467-
**eb_cap_style))
3468-
caplines.append(mlines.Line2D(xo, uo, marker='_',
3469-
**eb_cap_style))
3470-
3464+
if noylims.any() and capsize > 0:
3465+
xo, lo, uo = apply_mask([x, lower, upper], noylims & everymask)
3466+
caplines.extend([
3467+
mlines.Line2D(xo, lo, marker='_', **eb_cap_style),
3468+
mlines.Line2D(xo, uo, marker='_', **eb_cap_style)])
34713469
if lolims.any():
3472-
xo, _ = xywhere(x, lower, lolims & everymask)
3473-
lo, uo = xywhere(y, upper, lolims & everymask)
3474-
barcols.append(self.vlines(xo, lo, uo, **eb_lines_style))
3475-
xup, upperup = xywhere(x, upper, lolims & everymask)
3470+
xo, yo, lo, uo = apply_mask([x, y, lower, upper],
3471+
lolims & everymask)
34763472
if self.yaxis_inverted():
34773473
marker = mlines.CARETDOWNBASE
34783474
else:
34793475
marker = mlines.CARETUPBASE
3480-
caplines.append(
3481-
mlines.Line2D(xup, upperup, ls='None', marker=marker,
3482-
**eb_cap_style))
3476+
caplines.append(mlines.Line2D(
3477+
xo, uo, ls='None', marker=marker, **eb_cap_style))
34833478
if capsize > 0:
3484-
xlo, ylo = xywhere(x, y, lolims & everymask)
3485-
caplines.append(mlines.Line2D(xlo, ylo, marker='_',
3486-
**eb_cap_style))
3487-
3479+
caplines.append(mlines.Line2D(
3480+
xo, yo, marker='_', **eb_cap_style))
34883481
if uplims.any():
3489-
xo, _ = xywhere(x, lower, uplims & everymask)
3490-
lo, uo = xywhere(lower, y, uplims & everymask)
3491-
barcols.append(self.vlines(xo, lo, uo, **eb_lines_style))
3492-
xlo, lowerlo = xywhere(x, lower, uplims & everymask)
3482+
xo, yo, lo, uo = apply_mask([x, y, lower, upper],
3483+
uplims & everymask)
34933484
if self.yaxis_inverted():
34943485
marker = mlines.CARETUPBASE
34953486
else:
34963487
marker = mlines.CARETDOWNBASE
3497-
caplines.append(
3498-
mlines.Line2D(xlo, lowerlo, ls='None', marker=marker,
3499-
**eb_cap_style))
3488+
caplines.append(mlines.Line2D(
3489+
xo, lo, ls='None', marker=marker, **eb_cap_style))
35003490
if capsize > 0:
3501-
xup, yup = xywhere(x, y, uplims & everymask)
3502-
caplines.append(mlines.Line2D(xup, yup, marker='_',
3503-
**eb_cap_style))
3491+
caplines.append(mlines.Line2D(
3492+
xo, yo, marker='_', **eb_cap_style))
3493+
35043494
for l in caplines:
35053495
self.add_line(l)
35063496

35073497
self._request_autoscale_view()
3508-
errorbar_container = ErrorbarContainer((data_line, tuple(caplines),
3509-
tuple(barcols)),
3510-
has_xerr=(xerr is not None),
3511-
has_yerr=(yerr is not None),
3512-
label=label)
3498+
errorbar_container = ErrorbarContainer(
3499+
(data_line, tuple(caplines), tuple(barcols)),
3500+
has_xerr=(xerr is not None), has_yerr=(yerr is not None),
3501+
label=label)
35133502
self.containers.append(errorbar_container)
35143503

35153504
return errorbar_container # (l0, caplines, barcols)

0 commit comments

Comments
 (0)