@@ -3282,10 +3282,56 @@ def errorbar(self, x, y, yerr=None, xerr=None,
32823282 x = np .asarray (x , dtype = object )
32833283 if not isinstance (y , np .ndarray ):
32843284 y = np .asarray (y , dtype = object )
3285+
3286+ def _upcast_err (err ):
3287+ """
3288+ Safely handle tuple of containers that carry units.
3289+
3290+ If the units are carried on the values then casting to object
3291+ arrays preserves the units, but if the units are on the containers
3292+ this will not work.
3293+
3294+ This function covers the case where the input to the xerr/yerr is a
3295+ length 2 tuple of equal length ndarray-subclasses that carry the
3296+ unit information in the container.
3297+
3298+ We defer coercing the units to be consistent to the underlying unit
3299+ library (and implicitly the broadcasting).
3300+
3301+ If we do not have a tuple of nested numpy array (subclasses),
3302+ fallback to casting to an object array.
3303+
3304+ """
3305+
3306+ # we are here because we the container is not a numpy array, but it
3307+ # _is_ iterable (likely a list or a tuple but maybe something more
3308+ # exotic)
3309+
3310+ if (
3311+ # make sure it is not a scalar
3312+ np .iterable (err ) and
3313+ # and it is not empty
3314+ len (err ) > 0 and
3315+ # and the first element is an array sub-class use
3316+ # safe_first_element because getitem is index-first not
3317+ # location first on pandas objects so err[0] almost always
3318+ # fails.
3319+ isinstance (cbook .safe_first_element (err ), np .ndarray )
3320+ ):
3321+ # grab the type of the first element, we will try to promote
3322+ # the outer container to match the inner container
3323+ atype = type (cbook .safe_first_element (err ))
3324+ # you can not directly pass data to the init of `np.ndarray`
3325+ if atype is np .ndarray :
3326+ return np .asarray (err , dtype = object )
3327+ # but you can for unyt and astropy uints
3328+ return atype (err )
3329+ return np .asarray (err , dtype = object )
3330+
32853331 if xerr is not None and not isinstance (xerr , np .ndarray ):
3286- xerr = np . asarray (xerr , dtype = object )
3332+ xerr = _upcast_err (xerr )
32873333 if yerr is not None and not isinstance (yerr , np .ndarray ):
3288- yerr = np . asarray (yerr , dtype = object )
3334+ yerr = _upcast_err (yerr )
32893335 x , y = np .atleast_1d (x , y ) # Make sure all the args are iterable.
32903336 if len (x ) != len (y ):
32913337 raise ValueError ("'x' and 'y' must have the same size" )
0 commit comments