@@ -3409,116 +3409,66 @@ def errorbar(self, x, y, yerr=None, xerr=None,
3409
3409
barcols = []
3410
3410
caplines = []
3411
3411
3412
- # arrays fine here, they are booleans and hence not units
3413
- lolims = np .broadcast_to (lolims , len (x )).astype (bool )
3414
- uplims = np .broadcast_to (uplims , len (x )).astype (bool )
3415
- xlolims = np .broadcast_to (xlolims , len (x )).astype (bool )
3416
- xuplims = np .broadcast_to (xuplims , len (x )).astype (bool )
3417
-
3418
3412
# Vectorized fancy-indexer.
3419
3413
def apply_mask (arrays , mask ): return [array [mask ] for array in arrays ]
3420
3414
3421
- def extract_err (name , err , data , lolims , uplims ):
3422
- """
3423
- Private function to compute error bars.
3424
-
3425
- Parameters
3426
- ----------
3427
- name : {'x', 'y'}
3428
- Name used in the error message.
3429
- err : array-like
3430
- xerr or yerr from errorbar().
3431
- data : array-like
3432
- x or y from errorbar().
3433
- lolims : array-like
3434
- Error is only applied on **upper** side when this is True. See
3435
- the note in the main docstring about this parameter's name.
3436
- uplims : array-like
3437
- Error is only applied on **lower** side when this is True. See
3438
- the note in the main docstring about this parameter's name.
3439
- """
3415
+ # dep: dependent dataset, indep: independent dataset
3416
+ for (dep_axis , dep , err , lolims , uplims , indep , lines_func ,
3417
+ marker , lomarker , himarker ) in [
3418
+ ("x" , x , xerr , xlolims , xuplims , y , self .hlines ,
3419
+ "|" , mlines .CARETRIGHTBASE , mlines .CARETLEFTBASE ),
3420
+ ("y" , y , yerr , lolims , uplims , x , self .vlines ,
3421
+ "_" , mlines .CARETUPBASE , mlines .CARETDOWNBASE ),
3422
+ ]:
3423
+ if err is None :
3424
+ continue
3425
+ lolims = np .broadcast_to (lolims , len (dep )).astype (bool )
3426
+ uplims = np .broadcast_to (uplims , len (dep )).astype (bool )
3440
3427
try :
3441
- np .broadcast_to (err , (2 , len (data )))
3428
+ np .broadcast_to (err , (2 , len (dep )))
3442
3429
except ValueError :
3443
3430
raise ValueError (
3444
- f"'{ name } err' (shape: { np .shape (err )} ) must be a scalar "
3445
- f"or a 1D or (2, n) array-like whose shape matches "
3446
- f"'{ name } ' (shape: { np .shape (data )} )" ) from None
3431
+ f"'{ dep_axis } err' (shape: { np .shape (err )} ) must be a "
3432
+ f"scalar or a 1D or (2, n) array-like whose shape matches "
3433
+ f"'{ dep_axis } ' (shape: { np .shape (dep )} )" ) from None
3447
3434
# This is like
3448
- # low, high = np.broadcast_to(...)
3449
- # return data - low * ~lolims, data + high * ~uplims
3435
+ # elow, ehigh = np.broadcast_to(...)
3436
+ # return dep - elow * ~lolims, dep + ehigh * ~uplims
3450
3437
# except that broadcast_to would strip units.
3451
- return data + np .row_stack ([- (1 - lolims ), 1 - uplims ]) * err
3452
-
3453
- if xerr is not None :
3454
- left , right = extract_err ('x' , xerr , x , xlolims , xuplims )
3455
- barcols .append (self .hlines (
3456
- * apply_mask ([y , left , right ], everymask ), ** eb_lines_style ))
3457
- # select points without upper/lower limits in x and
3458
- # draw normal errorbars for these points
3459
- noxlims = ~ (xlolims | xuplims )
3460
- if noxlims .any () and capsize > 0 :
3461
- yo , lo , ro = apply_mask ([y , left , right ], noxlims & everymask )
3462
- caplines .extend ([
3463
- mlines .Line2D (lo , yo , marker = '|' , ** eb_cap_style ),
3464
- mlines .Line2D (ro , yo , marker = '|' , ** eb_cap_style )])
3465
- if xlolims .any ():
3466
- xo , yo , ro = apply_mask ([x , y , right ], xlolims & everymask )
3467
- if self .xaxis_inverted ():
3468
- marker = mlines .CARETLEFTBASE
3469
- else :
3470
- marker = mlines .CARETRIGHTBASE
3471
- caplines .append (mlines .Line2D (
3472
- ro , yo , ls = 'None' , marker = marker , ** eb_cap_style ))
3473
- if capsize > 0 :
3474
- caplines .append (mlines .Line2D (
3475
- xo , yo , marker = '|' , ** eb_cap_style ))
3476
- if xuplims .any ():
3477
- xo , yo , lo = apply_mask ([x , y , left ], xuplims & everymask )
3478
- if self .xaxis_inverted ():
3479
- marker = mlines .CARETRIGHTBASE
3480
- else :
3481
- marker = mlines .CARETLEFTBASE
3482
- caplines .append (mlines .Line2D (
3483
- lo , yo , ls = 'None' , marker = marker , ** eb_cap_style ))
3484
- if capsize > 0 :
3485
- caplines .append (mlines .Line2D (
3486
- xo , yo , marker = '|' , ** eb_cap_style ))
3487
-
3488
- if yerr is not None :
3489
- lower , upper = extract_err ('y' , yerr , y , lolims , uplims )
3490
- barcols .append (self .vlines (
3491
- * apply_mask ([x , lower , upper ], everymask ), ** eb_lines_style ))
3492
- # select points without upper/lower limits in y and
3493
- # draw normal errorbars for these points
3494
- noylims = ~ (lolims | uplims )
3495
- if noylims .any () and capsize > 0 :
3496
- xo , lo , uo = apply_mask ([x , lower , upper ], noylims & everymask )
3497
- caplines .extend ([
3498
- mlines .Line2D (xo , lo , marker = '_' , ** eb_cap_style ),
3499
- mlines .Line2D (xo , uo , marker = '_' , ** eb_cap_style )])
3500
- if lolims .any ():
3501
- xo , yo , uo = apply_mask ([x , y , upper ], lolims & everymask )
3502
- if self .yaxis_inverted ():
3503
- marker = mlines .CARETDOWNBASE
3504
- else :
3505
- marker = mlines .CARETUPBASE
3506
- caplines .append (mlines .Line2D (
3507
- xo , uo , ls = 'None' , marker = marker , ** eb_cap_style ))
3508
- if capsize > 0 :
3509
- caplines .append (mlines .Line2D (
3510
- xo , yo , marker = '_' , ** eb_cap_style ))
3511
- if uplims .any ():
3512
- xo , yo , lo = apply_mask ([x , y , lower ], uplims & everymask )
3513
- if self .yaxis_inverted ():
3514
- marker = mlines .CARETUPBASE
3515
- else :
3516
- marker = mlines .CARETDOWNBASE
3517
- caplines .append (mlines .Line2D (
3518
- xo , lo , ls = 'None' , marker = marker , ** eb_cap_style ))
3438
+ low , high = dep + np .row_stack ([- (1 - lolims ), 1 - uplims ]) * err
3439
+
3440
+ barcols .append (lines_func (
3441
+ * apply_mask ([indep , low , high ], everymask ), ** eb_lines_style ))
3442
+ # Normal errorbars for points without upper/lower limits.
3443
+ nolims = ~ (lolims | uplims )
3444
+ if nolims .any () and capsize > 0 :
3445
+ indep_masked , lo_masked , hi_masked = apply_mask (
3446
+ [indep , low , high ], nolims & everymask )
3447
+ for lh_masked in [lo_masked , hi_masked ]:
3448
+ # Since this has to work for x and y as dependent data, we
3449
+ # first set both x and y to the independent variable and
3450
+ # overwrite the respective dependent data in a second step.
3451
+ line = mlines .Line2D (indep_masked , indep_masked ,
3452
+ marker = marker , ** eb_cap_style )
3453
+ line .set (** {f"{ dep_axis } data" : lh_masked })
3454
+ caplines .append (line )
3455
+ for idx , (lims , hl ) in enumerate ([(lolims , high ), (uplims , low )]):
3456
+ if not lims .any ():
3457
+ continue
3458
+ hlmarker = (
3459
+ himarker
3460
+ if getattr (self , f"{ dep_axis } axis" ).get_inverted () ^ idx
3461
+ else lomarker )
3462
+ x_masked , y_masked , hl_masked = apply_mask (
3463
+ [x , y , hl ], lims & everymask )
3464
+ # As above, we set the dependent data in a second step.
3465
+ line = mlines .Line2D (x_masked , y_masked ,
3466
+ marker = hlmarker , ** eb_cap_style )
3467
+ line .set (** {f"{ dep_axis } data" : hl_masked })
3468
+ caplines .append (line )
3519
3469
if capsize > 0 :
3520
3470
caplines .append (mlines .Line2D (
3521
- xo , yo , marker = '_' , ** eb_cap_style ))
3471
+ x_masked , y_masked , marker = marker , ** eb_cap_style ))
3522
3472
3523
3473
for l in caplines :
3524
3474
self .add_line (l )
0 commit comments