From e078f918c9625d29e1e65964315aa23602de5ecd Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 27 Aug 2017 18:58:19 -0400 Subject: [PATCH 1/7] API: change signature of bar and barh Change the documented first position argument to x and y for bar and barh respectively but still support passing in left and bottom as keyword arguments. closes #7954 closes #8327 closes #8527 closes #8882 --- doc/api/api_changes/2017-08-27-TAC.rst | 22 ++ doc/users/dflt_style_changes.rst | 2 + examples/pie_and_polar_charts/nested_pie.py | 6 +- lib/matplotlib/axes/_axes.py | 247 ++++++++++++++------ lib/matplotlib/pyplot.py | 13 +- lib/matplotlib/tests/test_axes.py | 32 +++ lib/matplotlib/tests/test_pickle.py | 2 +- 7 files changed, 241 insertions(+), 83 deletions(-) create mode 100644 doc/api/api_changes/2017-08-27-TAC.rst diff --git a/doc/api/api_changes/2017-08-27-TAC.rst b/doc/api/api_changes/2017-08-27-TAC.rst new file mode 100644 index 000000000000..82f709169eb8 --- /dev/null +++ b/doc/api/api_changes/2017-08-27-TAC.rst @@ -0,0 +1,22 @@ +Change to signatures of :meth:`~matplotlib.axes.Axes.bar` & :meth:`~matplotlib.axes.Axes.barh` +---------------------------------------------------------------------------------------------- + +For 2.0 the :ref:`default value of *align* ` changed to +``'center'``. However this caused the signature of +:meth:`~matplotlib.axes.Axes.bar` and +:meth:`~matplotlib.axes.Axes.barh` to be misleading as the first parameters were +still *left* and *bottom* respectively:: + + bar(left, height, *, align='center', **kwargs) + barh(bottom, width, *, align='center', **kwargs) + +despite behaving as the center in both cases. The methods now take ``*args, **kwargs`` +is input and are documented to have the primary signatures of:: + + bar(x, height, *, align='center', **kwargs) + barh(y, width, *, align='center', **kwargs) + +Passing *left* and *bottom* as keyword arguments to +:meth:`~matplotlib.axes.Axes.bar` and +:meth:`~matplotlib.axes.Axes.barh` respectively will warn. +Support will be removed in Matplotlib 3.0. diff --git a/doc/users/dflt_style_changes.rst b/doc/users/dflt_style_changes.rst index 2035b71773a5..06984253e72b 100644 --- a/doc/users/dflt_style_changes.rst +++ b/doc/users/dflt_style_changes.rst @@ -599,6 +599,8 @@ The default value of the ``linecolor`` kwarg for `~matplotlib.Axes.hexbin` has changed from ``'none'`` to ``'face'``. If 'none' is now supplied, no line edges are drawn around the hexagons. +.. _barbarh_align: + ``bar`` and ``barh`` -------------------- diff --git a/examples/pie_and_polar_charts/nested_pie.py b/examples/pie_and_polar_charts/nested_pie.py index 5355bd615611..7dd77a1f531d 100644 --- a/examples/pie_and_polar_charts/nested_pie.py +++ b/examples/pie_and_polar_charts/nested_pie.py @@ -44,17 +44,17 @@ left_middle = np.arange(0.0, 2 * np.pi, 2 * np.pi / 12) left_outer = np.arange(0.0, 2 * np.pi, 2 * np.pi / 9) -ax.bar(left=left_inner, +ax.bar(x=left_inner, width=2 * np.pi / 6, bottom=0, color='C0', linewidth=2, edgecolor='w', height=np.zeros_like(left_inner) + 5) -ax.bar(left=left_middle, +ax.bar(x=left_middle, width=2 * np.pi / 12, bottom=5, color='C1', linewidth=2, edgecolor='w', height=np.zeros_like(left_middle) + 2) -ax.bar(left=left_outer, +ax.bar(x=left_outer, width=2 * np.pi / 9, bottom=7, color='C2', linewidth=2, edgecolor='w', height=np.zeros_like(left_outer) + 3) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 15ba96030a89..bcbfae8837ab 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -1868,25 +1868,49 @@ def step(self, x, y, *args, **kwargs): return self.plot(x, y, *args, **kwargs) - @_preprocess_data(replace_names=["left", "height", "width", "bottom", + @_preprocess_data(replace_names=["x", "left", + "height", "width", + "y", "bottom", "color", "edgecolor", "linewidth", "tick_label", "xerr", "yerr", "ecolor"], - label_namer=None) + label_namer=None, + replace_all_args=True + ) @docstring.dedent_interpd - def bar(self, left, height, width=0.8, bottom=None, **kwargs): + def bar(self, *args, **kwargs): """ Make a bar plot. - Make a bar plot with rectangles bounded by: + Call signatures:: + + bar(x, height, *, align='center', **kwargs) + bar(x, height, width, *, align='center', **kwargs) + bar(x, height, width, bottom, *, align='center', **kwargs) + + Make a bar plot with rectangles bounded by + + .. math:: + + (x - width/2, x + width/2, bottom, bottom + height) + + (left, right, bottom and top edges) by default. *x*, + *height*, *width*, and *bottom* can be either scalars or + sequences. - `left`, `left` + `width`, `bottom`, `bottom` + `height` - (left, right, bottom and top edges) + The *align* and *orientation* kwargs control the interpretation of *x* + and *bottom* + + The *align* keyword-only argument controls if *x* is interpreted + as the center or the left edge of the rectangle. Parameters ---------- - left : sequence of scalars - the x coordinates of the left sides of the bars + x : sequence of scalars + the x coordinates of the bars. + + *align* controls if *x* is the bar center (default) or + left edge. height : scalar or sequence of scalars the height(s) of the bars @@ -1899,6 +1923,21 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): the y coordinate(s) of the bars default: None + align : {'center', 'edge'}, optional, default: 'center' + If 'center', interpret the *x* argument as the coordinates + of the centers of the bars. If 'edge', aligns bars by + their left edges + + To align the bars on the right edge pass a negative + *width* and ``align='edge'`` + + Returns + ------- + bars : matplotlib.container.BarContainer + Container with all of the bars + errorbars + + Other Parameters + ---------------- color : scalar or array-like, optional the colors of the bar faces @@ -1935,24 +1974,20 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): dictionary of kwargs to be passed to errorbar method. *ecolor* and *capsize* may be specified here rather than as independent kwargs. - align : {'center', 'edge'}, optional, default: 'center' - If 'edge', aligns bars by their left edges (for vertical bars) and - by their bottom edges (for horizontal bars). If 'center', interpret - the `left` argument as the coordinates of the centers of the bars. - To align on the align bars on the right edge pass a negative - `width`. - - orientation : {'vertical', 'horizontal'}, optional - The orientation of the bars. - log : boolean, optional If true, sets the axis to be log scale. default: False - Returns - ------- - bars : matplotlib.container.BarContainer - Container with all of the bars + errorbars + orientation : {'vertical', 'horizontal'}, optional + + This is for internal use, please do not directly use this, + call `barh` instead. + + The orientation of the bars. + + See also + -------- + barh: Plot a horizontal bar plot. Notes ----- @@ -1968,11 +2003,34 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): %(Rectangle)s - See also - -------- - barh: Plot a horizontal bar plot. """ kwargs = cbook.normalize_kwargs(kwargs, mpatches._patch_alias_map) + + matchers = [ + (lambda x, height, width=0.8, bottom=None, **kwargs: + (False, x, height, width, bottom, kwargs)), + (lambda left, height, width=0.8, bottom=None, **kwargs: + (True, left, height, width, bottom, kwargs)), + ] + exps = [] + for matcher in matchers: + try: + dp, x, height, width, y, kwargs = matcher(*args, **kwargs) + except TypeError as e: + # This can only come from a no-match as there is + # no other logic in the matchers. + exps.append(e) + else: + break + else: + raise exps[0] + # if we matched the second-case, then the user passed in + # left=val as a kwarg which we want to deprecate + if dp: + warnings.warn( + "The *left* kwarg to `bar` is deprecated use *x* instead. " + "Support for *left* will be removed in Matplotlib 3.0", + mplDeprecation, stacklevel=2) if not self._hold: self.cla() color = kwargs.pop('color', None) @@ -2002,38 +2060,38 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): label = kwargs.pop('label', '') tick_labels = kwargs.pop('tick_label', None) - _left = left - _bottom = bottom - left, height, width, bottom = np.broadcast_arrays( + _x = x + _y = y + x, height, width, y, linewidth = np.broadcast_arrays( # Make args iterable too. - np.atleast_1d(left), height, width, bottom) + np.atleast_1d(x), height, width, y, linewidth) adjust_ylim = False adjust_xlim = False if orientation == 'vertical': - self._process_unit_info(xdata=left, ydata=height, kwargs=kwargs) + self._process_unit_info(xdata=x, ydata=height, kwargs=kwargs) if log: self.set_yscale('log', nonposy='clip') - # size width and bottom according to length of left - if _bottom is None: + # size width and y according to length of x + if _y is None: if self.get_yscale() == 'log': adjust_ylim = True - bottom = np.zeros_like(bottom) + y = np.zeros_like(y) tick_label_axis = self.xaxis - tick_label_position = left + tick_label_position = x elif orientation == 'horizontal': - self._process_unit_info(xdata=width, ydata=bottom, kwargs=kwargs) + self._process_unit_info(xdata=width, ydata=y, kwargs=kwargs) if log: self.set_xscale('log', nonposx='clip') - # size left and height according to length of bottom - if _left is None: + # size x and height according to length of y + if _x is None: if self.get_xscale() == 'log': adjust_xlim = True - left = np.zeros_like(left) + x = np.zeros_like(x) tick_label_axis = self.yaxis - tick_label_position = bottom + tick_label_position = y else: raise ValueError('invalid orientation: %s' % orientation) @@ -2051,24 +2109,30 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): # lets do some conversions now since some types cannot be # subtracted uniformly if self.xaxis is not None: - left = self.convert_xunits(left) + x = self.convert_xunits(x) width = self.convert_xunits(width) if xerr is not None: xerr = self.convert_xunits(xerr) if self.yaxis is not None: - bottom = self.convert_yunits(bottom) + y = self.convert_yunits(y) height = self.convert_yunits(height) if yerr is not None: yerr = self.convert_yunits(yerr) + # We will now resolve the alignment and really have + # left, bottom, width, height vectors if align == 'center': if orientation == 'vertical': - left = left - width / 2 + left = x - width / 2 + bottom = y elif orientation == 'horizontal': - bottom = bottom - height / 2 - - elif align != 'edge': + bottom = y - height / 2 + left = x + elif align == 'edge': + left = x + bottom = y + else: raise ValueError('invalid alignment: %s' % align) patches = [] @@ -2096,18 +2160,17 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): if xerr is not None or yerr is not None: if orientation == 'vertical': # using list comps rather than arrays to preserve unit info - x = [l + 0.5 * w for l, w in zip(left, width)] - y = [b + h for b, h in zip(bottom, height)] + ex = [l + 0.5 * w for l, w in zip(left, width)] + ey = [b + h for b, h in zip(bottom, height)] elif orientation == 'horizontal': # using list comps rather than arrays to preserve unit info - x = [l + w for l, w in zip(left, width)] - y = [b + 0.5 * h for b, h in zip(bottom, height)] + ex = [l + w for l, w in zip(left, width)] + ey = [b + 0.5 * h for b, h in zip(bottom, height)] - if "label" not in error_kw: - error_kw["label"] = '_nolegend_' + error_kw.setdefault("label", '_nolegend_') - errorbar = self.errorbar(x, y, + errorbar = self.errorbar(ex, ey, yerr=yerr, xerr=xerr, fmt='none', **error_kw) else: @@ -2143,23 +2206,37 @@ def bar(self, left, height, width=0.8, bottom=None, **kwargs): return bar_container @docstring.dedent_interpd - def barh(self, bottom, width, height=0.8, left=None, **kwargs): + def barh(self, *args, **kwargs): """ Make a horizontal bar plot. - Make a horizontal bar plot with rectangles bounded by: + Call signatures:: + + bar(y, width, *, align='center', **kwargs) + bar(y, width, height, *, align='center', **kwargs) + bar(y, width, height, left, *, align='center', **kwargs) + + Make a horizontal bar plot with rectangles by default bounded by + + .. math:: + + (left, left + width, y - height/2, y + height/2) + + (left, right, bottom and top edges) by default. *y*, *width*, + *height*, and *left* can be either scalars or sequences. - `left`, `left` + `width`, `bottom`, `bottom` + `height` - (left, right, bottom and top edges) + The *align* keyword-only argument controls if *y* is interpreted + as the center or the bottom edge of the rectangle. - `bottom`, `width`, `height`, and `left` can be either scalars - or sequences Parameters ---------- - bottom : scalar or array-like + y : scalar or array-like the y coordinate(s) of the bars + *align* controls if *y* is the bar center (default) + or bottom edge. + width : scalar or array-like the width(s) of the bars @@ -2169,6 +2246,14 @@ def barh(self, bottom, width, height=0.8, left=None, **kwargs): left : sequence of scalars the x coordinates of the left sides of the bars + align : {'center', 'edge'}, optional, default: 'center' + If 'center', interpret the *y* argument as the coordinates + of the centers of the bars. If 'edge', aligns bars by + their bottom edges + + To align the bars on the top edge pass a negative + *height* and ``align='edge'`` + Returns ------- `matplotlib.patches.Rectangle` instances. @@ -2206,16 +2291,13 @@ def barh(self, bottom, width, height=0.8, left=None, **kwargs): dictionary of kwargs to be passed to errorbar method. `ecolor` and `capsize` may be specified here rather than as independent kwargs. - align : {'center', 'edge'}, optional, default: 'center' - If 'edge', aligns bars by their left edges (for vertical - bars) and by their bottom edges (for horizontal bars). If - 'center', interpret the `bottom` argument as the - coordinates of the centers of the bars. To align on the - align bars on the top edge pass a negative 'height'. - log : boolean, optional, default: False If true, sets the axis to be log scale + See also + -------- + bar: Plot a vertical bar plot. + Notes ----- The optional arguments `color`, `edgecolor`, `linewidth`, @@ -2230,13 +2312,34 @@ def barh(self, bottom, width, height=0.8, left=None, **kwargs): %(Rectangle)s - See also - -------- - bar: Plot a vertical bar plot. """ - - patches = self.bar(left=left, height=height, width=width, - bottom=bottom, orientation='horizontal', **kwargs) + matchers = [ + (lambda y, width, height=0.8, left=None, **kwargs: + (False, y, width, height, left, kwargs)), + (lambda bottom, width, height=0.8, left=None, **kwargs: + (True, bottom, width, height, left, kwargs)), + ] + excs = [] + for matcher in matchers: + try: + dp, y, width, height, left, kwargs = matcher(*args, **kwargs) + except TypeError as e: + # This can only come from a no-match as there is + # no other logic in the matchers. + excs.append(e) + else: + break + else: + raise excs[0] + + if dp: + warnings.warn( + "The *bottom* kwarg to `barh` is deprecated use *y* instead. " + "Support for *bottom* will be removed in Matplotlib 3.0", + mplDeprecation, stacklevel=2) + kwargs.setdefault('orientation', 'horizontal') + patches = self.bar(x=left, height=height, width=width, + bottom=y, **kwargs) return patches @_preprocess_data(label_namer=None) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 85b5ea47b657..6a8151889a49 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2622,20 +2622,19 @@ def axvspan(xmin, xmax, ymin=0, ymax=1, hold=None, **kwargs): # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @_autogen_docstring(Axes.bar) -def bar(left, height, width=0.8, bottom=None, hold=None, data=None, **kwargs): +def bar(*args, **kwargs): ax = gca() # Deprecated: allow callers to override the hold state # by passing hold=True|False washold = ax._hold - + hold = kwargs.pop('hold', None) if hold is not None: ax._hold = hold from matplotlib.cbook import mplDeprecation warnings.warn("The 'hold' keyword argument is deprecated since 2.0.", mplDeprecation) try: - ret = ax.bar(left, height, width=width, bottom=bottom, data=data, - **kwargs) + ret = ax.bar(*args, **kwargs) finally: ax._hold = washold @@ -2644,19 +2643,19 @@ def bar(left, height, width=0.8, bottom=None, hold=None, data=None, **kwargs): # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @_autogen_docstring(Axes.barh) -def barh(bottom, width, height=0.8, left=None, hold=None, **kwargs): +def barh(*args, **kwargs): ax = gca() # Deprecated: allow callers to override the hold state # by passing hold=True|False washold = ax._hold - + hold = kwargs.pop('hold', None) if hold is not None: ax._hold = hold from matplotlib.cbook import mplDeprecation warnings.warn("The 'hold' keyword argument is deprecated since 2.0.", mplDeprecation) try: - ret = ax.barh(bottom, width, height=height, left=left, **kwargs) + ret = ax.barh(*args, **kwargs) finally: ax._hold = washold diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 7a0e8f326fc2..1d0aeee0a8e5 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -5266,6 +5266,38 @@ def test_twinx_knows_limits(): assert((xtwin.viewLim.intervalx == ax2.viewLim.intervalx).all()) +@pytest.mark.style('mpl20') +@pytest.mark.parametrize('args, kwargs, warning_count', + [((1, 1), {'width': 1, 'bottom': 1}, 0), + ((1, ), {'height': 1, 'bottom': 1}, 0), + ((), {'x': 1, 'height': 1}, 0), + ((), {'left': 1, 'height': 1}, 1)]) +def test_bar_signature(args, kwargs, warning_count): + fig, ax = plt.subplots() + with warnings.catch_warnings(record=True) as w: + r, = ax.bar(*args, **kwargs) + + assert r.get_width() == kwargs.get('width', 0.8) + assert r.get_y() == kwargs.get('bottom', 0) + assert len(w) == warning_count + + +@pytest.mark.style('mpl20') +@pytest.mark.parametrize('args, kwargs, warning_count', + [((1, 1), {'height': 1, 'left': 1}, 0), + ((1, ), {'width': 1, 'left': 1}, 0), + ((), {'y': 1, 'width': 1}, 0), + ((), {'bottom': 1, 'width': 1}, 1)]) +def test_barh_signature(args, kwargs, warning_count): + fig, ax = plt.subplots() + with warnings.catch_warnings(record=True) as w: + r, = ax.barh(*args, **kwargs) + + assert r.get_height() == kwargs.get('height', 0.8) + assert r.get_x() == kwargs.get('left', 0) + assert len(w) == warning_count + + def test_zero_linewidth(): # Check that setting a zero linewidth doesn't error plt.plot([0, 1], [0, 1], ls='--', lw=0) diff --git a/lib/matplotlib/tests/test_pickle.py b/lib/matplotlib/tests/test_pickle.py index de3b30cb5966..6d8d8f0f73ee 100644 --- a/lib/matplotlib/tests/test_pickle.py +++ b/lib/matplotlib/tests/test_pickle.py @@ -31,7 +31,7 @@ def test_simple(): # pickle.dump(ax, BytesIO(), pickle.HIGHEST_PROTOCOL) plt.figure() - plt.bar(left=np.arange(10), height=np.arange(10)) + plt.bar(x=np.arange(10), height=np.arange(10)) pickle.dump(plt.gca(), BytesIO(), pickle.HIGHEST_PROTOCOL) fig = plt.figure() From 5546eeefa8bcf8463646ad43f01d01ecd110e217 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 27 Aug 2017 19:02:16 -0400 Subject: [PATCH 2/7] MNT: update pyplot.hist for changes to Axes.hist This change is from #8993 --- lib/matplotlib/pyplot.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 6a8151889a49..7b46dc3179d4 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2992,10 +2992,10 @@ def hexbin(x, y, C=None, gridsize=100, bins=None, xscale='linear', # This function was autogenerated by boilerplate.py. Do not edit as # changes will be lost @_autogen_docstring(Axes.hist) -def hist(x, bins=None, range=None, normed=False, weights=None, cumulative=False, +def hist(x, bins=None, range=None, density=None, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, - hold=None, data=None, **kwargs): + normed=None, hold=None, data=None, **kwargs): ax = gca() # Deprecated: allow callers to override the hold state # by passing hold=True|False @@ -3007,11 +3007,11 @@ def hist(x, bins=None, range=None, normed=False, weights=None, cumulative=False, warnings.warn("The 'hold' keyword argument is deprecated since 2.0.", mplDeprecation) try: - ret = ax.hist(x, bins=bins, range=range, normed=normed, + ret = ax.hist(x, bins=bins, range=range, density=density, weights=weights, cumulative=cumulative, bottom=bottom, histtype=histtype, align=align, orientation=orientation, rwidth=rwidth, log=log, color=color, label=label, - stacked=stacked, data=data, **kwargs) + stacked=stacked, normed=normed, data=data, **kwargs) finally: ax._hold = washold From 5bb1c8a94401c196215252b17cdaaef7015988fa Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 27 Aug 2017 19:03:35 -0400 Subject: [PATCH 3/7] STY: whitespace fixes --- lib/matplotlib/__init__.py | 2 +- lib/matplotlib/testing/determinism.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 1b8870f3a573..c025444e8780 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1463,7 +1463,7 @@ def _replacer(data, key): def _preprocess_data(replace_names=None, replace_all_args=False, - label_namer=None, positional_parameter_names=None): + label_namer=None, positional_parameter_names=None): """ A decorator to add a 'data' kwarg to any a function. The signature of the input function must include the ax argument at the first position :: diff --git a/lib/matplotlib/testing/determinism.py b/lib/matplotlib/testing/determinism.py index 972df062075e..aca4572b2e5b 100644 --- a/lib/matplotlib/testing/determinism.py +++ b/lib/matplotlib/testing/determinism.py @@ -43,8 +43,8 @@ def _determinism_save(objects='mhi', format="pdf", usetex=False): if 'h' in objects: # also use different hatch patterns ax2 = fig.add_subplot(1, 6, 2) - bars = ax2.bar(range(1, 5), range(1, 5)) + \ - ax2.bar(range(1, 5), [6] * 4, bottom=range(1, 5)) + bars = (ax2.bar(range(1, 5), range(1, 5)) + + ax2.bar(range(1, 5), [6] * 4, bottom=range(1, 5))) ax2.set_xticks([1.5, 2.5, 3.5, 4.5]) patterns = ('-', '+', 'x', '\\', '*', 'o', 'O', '.') From 89c6a77a982493529cddd6ab90846c11636a662e Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 27 Aug 2017 23:17:32 -0400 Subject: [PATCH 4/7] DOC: tweak markup a bit --- lib/matplotlib/axes/_axes.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index bcbfae8837ab..5806a353a82e 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -1991,11 +1991,11 @@ def bar(self, *args, **kwargs): Notes ----- - The optional arguments `color`, `edgecolor`, `linewidth`, - `xerr`, and `yerr` can be either scalars or sequences of + The optional arguments *color*, *edgecolor*, *linewidth*, + *xerr*, and *yerr* can be either scalars or sequences of length equal to the number of bars. This enables you to use bar as the basis for stacked bar charts, or candlestick plots. - Detail: `xerr` and `yerr` are passed directly to + Detail: *xerr* and *yerr* are passed directly to :meth:`errorbar`, so they can also have shape 2xN for independent specification of lower and upper errors. @@ -2300,11 +2300,11 @@ def barh(self, *args, **kwargs): Notes ----- - The optional arguments `color`, `edgecolor`, `linewidth`, - `xerr`, and `yerr` can be either scalars or sequences of + The optional arguments *color*, *edgecolor*, *linewidth*, + *xerr*, and *yerr* can be either scalars or sequences of length equal to the number of bars. This enables you to use bar as the basis for stacked bar charts, or candlestick plots. - Detail: `xerr` and `yerr` are passed directly to + Detail: *xerr* and *yerr* are passed directly to :meth:`errorbar`, so they can also have shape 2xN for independent specification of lower and upper errors. From dd9c7b178e88ad862d24375bbaa5a15a56b02721 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sun, 27 Aug 2017 23:17:39 -0400 Subject: [PATCH 5/7] FIX: bug in docs inserted by _preprocess_data --- lib/matplotlib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index c025444e8780..00488a134097 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1720,7 +1720,7 @@ def inner(ax, *args, **kwargs): if len(replace_names) != 0: _repl = "* All arguments with the following names: '{names}'." if replace_all_args: - _repl += "\n* All positional arguments." + _repl += "\n * All positional arguments." _repl = _repl.format(names="', '".join(sorted(replace_names))) inner.__doc__ = (pre_doc + _DATA_DOC_APPENDIX.format(replaced=_repl)) From 80355e03d64e82b0d57fddd3c1e1e1756336092b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 28 Aug 2017 15:20:27 -0400 Subject: [PATCH 6/7] DOC: add comment about use of lambdas to unpack args/kwrags credit goes to @anntzer --- lib/matplotlib/axes/_axes.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 5806a353a82e..cfe861ca7299 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2005,7 +2005,8 @@ def bar(self, *args, **kwargs): """ kwargs = cbook.normalize_kwargs(kwargs, mpatches._patch_alias_map) - + # this is using the lambdas to do the arg/kwarg unpacking rather + # than trying to re-implement all of that logic our selves. matchers = [ (lambda x, height, width=0.8, bottom=None, **kwargs: (False, x, height, width, bottom, kwargs)), @@ -2313,6 +2314,8 @@ def barh(self, *args, **kwargs): %(Rectangle)s """ + # this is using the lambdas to do the arg/kwarg unpacking rather + # than trying to re-implement all of that logic our selves. matchers = [ (lambda y, width, height=0.8, left=None, **kwargs: (False, y, width, height, left, kwargs)), From 7e1a65d2adb5e41e6f449560803916eff9260082 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Mon, 28 Aug 2017 15:21:04 -0400 Subject: [PATCH 7/7] MNT: re-organize to simplify handling `None` as input --- lib/matplotlib/axes/_axes.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index cfe861ca7299..402382587ccf 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -2061,23 +2061,29 @@ def bar(self, *args, **kwargs): label = kwargs.pop('label', '') tick_labels = kwargs.pop('tick_label', None) - _x = x - _y = y + adjust_ylim = False + adjust_xlim = False + + if orientation == 'vertical': + if y is None: + if self.get_yscale() == 'log': + adjust_ylim = True + y = 0 + + elif orientation == 'horizontal': + if x is None: + if self.get_xscale() == 'log': + adjust_xlim = True + x = 0 + x, height, width, y, linewidth = np.broadcast_arrays( # Make args iterable too. np.atleast_1d(x), height, width, y, linewidth) - adjust_ylim = False - adjust_xlim = False if orientation == 'vertical': self._process_unit_info(xdata=x, ydata=height, kwargs=kwargs) if log: self.set_yscale('log', nonposy='clip') - # size width and y according to length of x - if _y is None: - if self.get_yscale() == 'log': - adjust_ylim = True - y = np.zeros_like(y) tick_label_axis = self.xaxis tick_label_position = x @@ -2085,11 +2091,6 @@ def bar(self, *args, **kwargs): self._process_unit_info(xdata=width, ydata=y, kwargs=kwargs) if log: self.set_xscale('log', nonposx='clip') - # size x and height according to length of y - if _x is None: - if self.get_xscale() == 'log': - adjust_xlim = True - x = np.zeros_like(x) tick_label_axis = self.yaxis tick_label_position = y