Skip to content

Commit 597d2ef

Browse files
committed
Merge pull request #5593 from tacaswell/fix_errorbar_cycleing
ENH: errorbar color cycle clean up
2 parents 98a2e64 + 2338e2e commit 597d2ef

File tree

1 file changed

+113
-95
lines changed

1 file changed

+113
-95
lines changed

lib/matplotlib/axes/_axes.py

+113-95
Original file line numberDiff line numberDiff line change
@@ -2830,6 +2830,8 @@ def errorbar(self, x, y, yerr=None, xerr=None,
28302830
.. plot:: mpl_examples/statistics/errorbar_demo.py
28312831
28322832
"""
2833+
kwargs = cbook.normalize_kwargs(kwargs, _alias_map)
2834+
kwargs.setdefault('zorder', 2)
28332835

28342836
if errorevery < 1:
28352837
raise ValueError(
@@ -2843,15 +2845,32 @@ def errorbar(self, x, y, yerr=None, xerr=None,
28432845

28442846
if fmt is None:
28452847
fmt = 'none'
2846-
msg = ('Use of None object as fmt keyword argument to '
2847-
+ 'suppress plotting of data values is deprecated '
2848-
+ 'since 1.4; use the string "none" instead.')
2848+
msg = ('Use of None object as fmt keyword argument to ' +
2849+
'suppress plotting of data values is deprecated ' +
2850+
'since 1.4; use the string "none" instead.')
28492851
warnings.warn(msg, mplDeprecation, stacklevel=1)
28502852

28512853
plot_line = (fmt.lower() != 'none')
2852-
28532854
label = kwargs.pop("label", None)
28542855

2856+
fmt_style_kwargs = {k: v for k, v in
2857+
zip(('linestyle', 'marker', 'color'),
2858+
_process_plot_format(fmt)) if v is not None}
2859+
2860+
if ('color' in kwargs or 'color' in fmt_style_kwargs or
2861+
ecolor is not None):
2862+
base_style = {}
2863+
if 'color' in kwargs:
2864+
base_style['color'] = kwargs.pop('color')
2865+
else:
2866+
base_style = six.next(self._get_lines.prop_cycler)
2867+
2868+
base_style['label'] = '_nolegend_'
2869+
base_style.update(fmt_style_kwargs)
2870+
if 'color' not in base_style:
2871+
base_style['color'] = 'C0'
2872+
if ecolor is None:
2873+
ecolor = base_style['color']
28552874
# make sure all the args are iterable; use lists not arrays to
28562875
# preserve units
28572876
if not iterable(x):
@@ -2868,47 +2887,69 @@ def errorbar(self, x, y, yerr=None, xerr=None,
28682887
if not iterable(yerr):
28692888
yerr = [yerr] * len(y)
28702889

2871-
l0 = None
2890+
# make the style dict for the 'normal' plot line
2891+
plot_line_style = dict(base_style)
2892+
plot_line_style.update(**kwargs)
2893+
if barsabove:
2894+
plot_line_style['zorder'] = kwargs['zorder'] - .1
2895+
else:
2896+
plot_line_style['zorder'] = kwargs['zorder'] + .1
28722897

2873-
# Instead of using zorder, the line plot is being added
2874-
# either here, or after all the errorbar plot elements.
2875-
if barsabove and plot_line:
2876-
l0, = self.plot(x, y, fmt, label="_nolegend_", **kwargs)
2898+
# make the style dict for the line collections (the bars)
2899+
eb_lines_style = dict(base_style)
2900+
eb_lines_style.pop('marker', None)
2901+
eb_lines_style.pop('linestyle', None)
2902+
eb_lines_style['color'] = ecolor
28772903

2878-
barcols = []
2879-
caplines = []
2880-
2881-
lines_kw = {'label': '_nolegend_'}
28822904
if elinewidth:
2883-
lines_kw['linewidth'] = elinewidth
2884-
else:
2885-
for key in ('linewidth', 'lw'):
2886-
if key in kwargs:
2887-
lines_kw[key] = kwargs[key]
2905+
eb_lines_style['linewidth'] = elinewidth
2906+
elif 'linewidth' in kwargs:
2907+
eb_lines_style['linewidth'] = kwargs['linewidth']
2908+
28882909
for key in ('transform', 'alpha', 'zorder', 'rasterized'):
28892910
if key in kwargs:
2890-
lines_kw[key] = kwargs[key]
2911+
eb_lines_style[key] = kwargs[key]
2912+
2913+
# set up cap style dictionary
2914+
eb_cap_style = dict(base_style)
2915+
# eject any marker information from format string
2916+
eb_cap_style.pop('marker', None)
2917+
eb_cap_style.pop('ls', None)
2918+
eb_cap_style['linestyle'] = 'none'
2919+
if capsize is None:
2920+
capsize = rcParams["errorbar.capsize"]
2921+
if capsize > 0:
2922+
eb_cap_style['markersize'] = 2. * capsize
2923+
if capthick is not None:
2924+
eb_cap_style['markeredgewidth'] = capthick
28912925

2892-
# arrays fine here, they are booleans and hence not units
2893-
if not iterable(lolims):
2894-
lolims = np.asarray([lolims] * len(x), bool)
2895-
else:
2896-
lolims = np.asarray(lolims, bool)
2926+
# For backwards-compat, allow explicit setting of
2927+
# 'markeredgewidth' to over-ride capthick.
2928+
for key in ('markeredgewidth', 'transform', 'alpha',
2929+
'zorder', 'rasterized'):
2930+
if key in kwargs:
2931+
eb_cap_style[key] = kwargs[key]
2932+
eb_cap_style['color'] = ecolor
28972933

2898-
if not iterable(uplims):
2899-
uplims = np.array([uplims] * len(x), bool)
2900-
else:
2901-
uplims = np.asarray(uplims, bool)
2934+
data_line = None
2935+
if plot_line:
2936+
data_line = mlines.Line2D(x, y, **plot_line_style)
2937+
self.add_line(data_line)
29022938

2903-
if not iterable(xlolims):
2904-
xlolims = np.array([xlolims] * len(x), bool)
2905-
else:
2906-
xlolims = np.asarray(xlolims, bool)
2939+
barcols = []
2940+
caplines = []
29072941

2908-
if not iterable(xuplims):
2909-
xuplims = np.array([xuplims] * len(x), bool)
2910-
else:
2911-
xuplims = np.asarray(xuplims, bool)
2942+
# arrays fine here, they are booleans and hence not units
2943+
def _bool_asarray_helper(d, expected):
2944+
if not iterable(d):
2945+
return np.asarray([d] * expected, bool)
2946+
else:
2947+
return np.asarray(d, bool)
2948+
2949+
lolims = _bool_asarray_helper(lolims, len(x))
2950+
uplims = _bool_asarray_helper(uplims, len(x))
2951+
xlolims = _bool_asarray_helper(xlolims, len(x))
2952+
xuplims = _bool_asarray_helper(xuplims, len(x))
29122953

29132954
everymask = np.arange(len(x)) % errorevery == 0
29142955

@@ -2923,25 +2964,6 @@ def xywhere(xs, ys, mask):
29232964
ys = [thisy for thisy, b in zip(ys, mask) if b]
29242965
return xs, ys
29252966

2926-
plot_kw = {'label': '_nolegend_'}
2927-
if capsize is None:
2928-
capsize = rcParams["errorbar.capsize"]
2929-
if capsize > 0:
2930-
plot_kw['ms'] = 2. * capsize
2931-
if capthick is not None:
2932-
# 'mew' has higher priority, I believe,
2933-
# if both 'mew' and 'markeredgewidth' exists.
2934-
# So, save capthick to markeredgewidth so that
2935-
# explicitly setting mew or markeredgewidth will
2936-
# over-write capthick.
2937-
plot_kw['markeredgewidth'] = capthick
2938-
# For backwards-compat, allow explicit setting of
2939-
# 'mew' or 'markeredgewidth' to over-ride capthick.
2940-
for key in ('markeredgewidth', 'mew', 'transform', 'alpha',
2941-
'zorder', 'rasterized'):
2942-
if key in kwargs:
2943-
plot_kw[key] = kwargs[key]
2944-
29452967
def extract_err(err, data):
29462968
'''private function to compute error bars
29472969
@@ -2986,42 +3008,46 @@ def extract_err(err, data):
29863008
if noxlims.any():
29873009
yo, _ = xywhere(y, right, noxlims & everymask)
29883010
lo, ro = xywhere(left, right, noxlims & everymask)
2989-
barcols.append(self.hlines(yo, lo, ro, **lines_kw))
3011+
barcols.append(self.hlines(yo, lo, ro, **eb_lines_style))
29903012
if capsize > 0:
2991-
caplines.extend(self.plot(lo, yo, 'k|', **plot_kw))
2992-
caplines.extend(self.plot(ro, yo, 'k|', **plot_kw))
3013+
caplines.append(mlines.Line2D(lo, yo, marker='|',
3014+
**eb_cap_style))
3015+
caplines.append(mlines.Line2D(ro, yo, marker='|',
3016+
**eb_cap_style))
29933017

29943018
if xlolims.any():
29953019
yo, _ = xywhere(y, right, xlolims & everymask)
29963020
lo, ro = xywhere(x, right, xlolims & everymask)
2997-
barcols.append(self.hlines(yo, lo, ro, **lines_kw))
3021+
barcols.append(self.hlines(yo, lo, ro, **eb_lines_style))
29983022
rightup, yup = xywhere(right, y, xlolims & everymask)
29993023
if self.xaxis_inverted():
30003024
marker = mlines.CARETLEFTBASE
30013025
else:
30023026
marker = mlines.CARETRIGHTBASE
3003-
caplines.extend(
3004-
self.plot(rightup, yup, ls='None', marker=marker,
3005-
**plot_kw))
3027+
caplines.append(
3028+
mlines.Line2D(rightup, yup, ls='None', marker=marker,
3029+
**eb_cap_style))
30063030
if capsize > 0:
30073031
xlo, ylo = xywhere(x, y, xlolims & everymask)
3008-
caplines.extend(self.plot(xlo, ylo, 'k|', **plot_kw))
3032+
caplines.append(mlines.Line2D(xlo, ylo, marker='|',
3033+
**eb_cap_style))
30093034

30103035
if xuplims.any():
30113036
yo, _ = xywhere(y, right, xuplims & everymask)
30123037
lo, ro = xywhere(left, x, xuplims & everymask)
3013-
barcols.append(self.hlines(yo, lo, ro, **lines_kw))
3038+
barcols.append(self.hlines(yo, lo, ro, **eb_lines_style))
30143039
leftlo, ylo = xywhere(left, y, xuplims & everymask)
30153040
if self.xaxis_inverted():
30163041
marker = mlines.CARETRIGHTBASE
30173042
else:
30183043
marker = mlines.CARETLEFTBASE
3019-
caplines.extend(
3020-
self.plot(leftlo, ylo, ls='None', marker=marker,
3021-
**plot_kw))
3044+
caplines.append(
3045+
mlines.Line2D(leftlo, ylo, ls='None', marker=marker,
3046+
**eb_cap_style))
30223047
if capsize > 0:
30233048
xup, yup = xywhere(x, y, xuplims & everymask)
3024-
caplines.extend(self.plot(xup, yup, 'k|', **plot_kw))
3049+
caplines.append(mlines.Line2D(xup, yup, marker='|',
3050+
**eb_cap_style))
30253051

30263052
if yerr is not None:
30273053
lower, upper = extract_err(yerr, y)
@@ -3031,61 +3057,53 @@ def extract_err(err, data):
30313057
if noylims.any():
30323058
xo, _ = xywhere(x, lower, noylims & everymask)
30333059
lo, uo = xywhere(lower, upper, noylims & everymask)
3034-
barcols.append(self.vlines(xo, lo, uo, **lines_kw))
3060+
barcols.append(self.vlines(xo, lo, uo, **eb_lines_style))
30353061
if capsize > 0:
3036-
caplines.extend(self.plot(xo, lo, 'k_', **plot_kw))
3037-
caplines.extend(self.plot(xo, uo, 'k_', **plot_kw))
3062+
caplines.append(mlines.Line2D(xo, lo, marker='_',
3063+
**eb_cap_style))
3064+
caplines.append(mlines.Line2D(xo, uo, marker='_',
3065+
**eb_cap_style))
30383066

30393067
if lolims.any():
30403068
xo, _ = xywhere(x, lower, lolims & everymask)
30413069
lo, uo = xywhere(y, upper, lolims & everymask)
3042-
barcols.append(self.vlines(xo, lo, uo, **lines_kw))
3070+
barcols.append(self.vlines(xo, lo, uo, **eb_lines_style))
30433071
xup, upperup = xywhere(x, upper, lolims & everymask)
30443072
if self.yaxis_inverted():
30453073
marker = mlines.CARETDOWNBASE
30463074
else:
30473075
marker = mlines.CARETUPBASE
3048-
caplines.extend(
3049-
self.plot(xup, upperup, ls='None', marker=marker,
3050-
**plot_kw))
3076+
caplines.append(
3077+
mlines.Line2D(xup, upperup, ls='None', marker=marker,
3078+
**eb_cap_style))
30513079
if capsize > 0:
30523080
xlo, ylo = xywhere(x, y, lolims & everymask)
3053-
caplines.extend(self.plot(xlo, ylo, 'k_', **plot_kw))
3081+
caplines.append(mlines.Line2D(xlo, ylo, marker='_',
3082+
**eb_cap_style))
30543083

30553084
if uplims.any():
30563085
xo, _ = xywhere(x, lower, uplims & everymask)
30573086
lo, uo = xywhere(lower, y, uplims & everymask)
3058-
barcols.append(self.vlines(xo, lo, uo, **lines_kw))
3087+
barcols.append(self.vlines(xo, lo, uo, **eb_lines_style))
30593088
xlo, lowerlo = xywhere(x, lower, uplims & everymask)
30603089
if self.yaxis_inverted():
30613090
marker = mlines.CARETUPBASE
30623091
else:
30633092
marker = mlines.CARETDOWNBASE
3064-
caplines.extend(
3065-
self.plot(xlo, lowerlo, ls='None', marker=marker,
3066-
**plot_kw))
3093+
caplines.append(
3094+
mlines.Line2D(xlo, lowerlo, ls='None', marker=marker,
3095+
**eb_cap_style))
30673096
if capsize > 0:
30683097
xup, yup = xywhere(x, y, uplims & everymask)
3069-
caplines.extend(self.plot(xup, yup, 'k_', **plot_kw))
3070-
3071-
if not barsabove and plot_line:
3072-
l0, = self.plot(x, y, fmt, label='_nolegend_', **kwargs)
3073-
3074-
if ecolor is None:
3075-
if l0 is None:
3076-
ecolor = self._get_lines.get_next_color()
3077-
else:
3078-
ecolor = l0.get_color()
3079-
3080-
for l in barcols:
3081-
l.set_color(ecolor)
3098+
caplines.append(mlines.Line2D(xup, yup, marker='_',
3099+
**eb_cap_style))
30823100
for l in caplines:
3083-
l.set_color(ecolor)
3101+
self.add_line(l)
30843102

30853103
self.autoscale_view()
30863104
self._hold = holdstate
30873105

3088-
errorbar_container = ErrorbarContainer((l0, tuple(caplines),
3106+
errorbar_container = ErrorbarContainer((data_line, tuple(caplines),
30893107
tuple(barcols)),
30903108
has_xerr=(xerr is not None),
30913109
has_yerr=(yerr is not None),

0 commit comments

Comments
 (0)