diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 3f040410d58c..2a22dbc898d4 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -39,7 +39,8 @@ import matplotlib.transforms as mtransforms import matplotlib.tri as mtri from matplotlib.cbook import ( - _backports, mplDeprecation, STEP_LOOKUP_MAP, iterable, safe_first_element) + _backports, mplDeprecation, warn_deprecated, + STEP_LOOKUP_MAP, iterable, safe_first_element) from matplotlib.container import BarContainer, ErrorbarContainer, StemContainer from matplotlib.axes._base import _AxesBase, _process_plot_format @@ -2394,27 +2395,109 @@ def stem(self, *args, **kwargs): """ Create a stem plot. - Call signatures:: + A stem plot plots vertical lines at each *x* location from the baseline + to *y*, and places a marker there. + + Call signature:: + + stem([x,] y, linefmt=None, markerfmt=None, basefmt=None) + + The x-positions are optional. The formats may be provided either as + positional or as keyword-arguments. + + Parameters + ---------- + x : array-like, optional + The x-positions of the stems. Default: (0, 1, ..., len(y) - 1). + + y : array-like + The y-values of the stem heads. + + linefmt : str, optional + A string defining the properties of the vertical lines. Usually, + this will be a color or a color and a linestyle: + + ========= ============= + Character Line Style + ========= ============= + ``'-'`` solid line + ``'--'`` dashed line + ``'-.'`` dash-dot line + ``':'`` dotted line + ========= ============= + + Default: 'C0-', i.e. solid line with the first color of the color + cycle. - stem(y, linefmt='b-', markerfmt='bo', basefmt='r-') - stem(x, y, linefmt='b-', markerfmt='bo', basefmt='r-') + Note: While it is technically possible to specify valid formats + other than color or color and linestyle (e.g. 'rx' or '-.'), this + is beyond the intention of the method and will most likely not + result in a reasonable reasonable plot. - A stem plot plots vertical lines (using *linefmt*) at each *x* - location from the baseline to *y*, and places a marker there - using *markerfmt*. A horizontal line at 0 is plotted using - *basefmt*. + markerfmt : str, optional + A string defining the properties of the markers at the stem heads. + Default: 'C0o', i.e. filled circles with the first color of the + color cycle. - If no *x* values are provided, the default is (0, 1, ..., len(y) - 1) + basefmt : str, optional + A format string defining the properties of the baseline. + + Default: 'C3-' ('C2-' in classic mode). + + bottom : float, optional, default: 0 + The y-position of the baseline. + + label : str, optional, default: None + The label to use for the stems in legends. + + + Other Parameters + ---------------- + **kwargs + No other parameters are supported. They are currently ignored + silently for backward compatibility. This behavior is deprecated. + Future versions will not accept any other parameters and will + raise a TypeError instead. + + + Returns + ------- + :class:`~matplotlib.container.StemContainer` + The stemcontainer may be treated like a tuple + (*markerline*, *stemlines*, *baseline*) - Return value is a tuple (*markerline*, *stemlines*, - *baseline*). See :class:`~matplotlib.container.StemContainer` + + Notes + ----- .. seealso:: - This - `document `_ - for details. + The MATLAB function + `stem `_ + which inspired this method. """ + + # kwargs handling + # We would like to have a signature with explicit kewords: + # stem(*args, linefmt=None, markerfmt=None, basefmt=None, + # bottom=0, label=None) + # Unfortunately, this is not supported in Python 2.x. There, *args + # can only exist after keyword arguments. + linefmt = kwargs.pop('linefmt', None) + markerfmt = kwargs.pop('markerfmt', None) + basefmt = kwargs.pop('basefmt', None) + bottom = kwargs.pop('bottom', None) + if bottom is None: + bottom = 0 + label = kwargs.pop('label', None) + if kwargs: + warn_deprecated(since='2.2', + message="stem() got an unexpected keyword " + "argument '%s'. This will raise a " + "TypeError in future versions." % ( + next(k for k in kwargs), ) + ) + remember_hold = self._hold if not self._hold: self.cla() @@ -2434,11 +2517,10 @@ def stem(self, *args, **kwargs): second = np.arange(len(y)) x = second - # Popping some defaults - try: - linefmt = kwargs['linefmt'] - except KeyError: + # defaults for formats + if linefmt is None: try: + # fallback to positional argument linefmt = args[0] except IndexError: linecolor = 'C0' @@ -2449,10 +2531,10 @@ def stem(self, *args, **kwargs): _process_plot_format(linefmt) else: linestyle, linemarker, linecolor = _process_plot_format(linefmt) - try: - markerfmt = kwargs['markerfmt'] - except KeyError: + + if markerfmt is None: try: + # fallback to positional argument markerfmt = args[1] except IndexError: markercolor = 'C0' @@ -2464,10 +2546,10 @@ def stem(self, *args, **kwargs): else: markerstyle, markermarker, markercolor = \ _process_plot_format(markerfmt) - try: - basefmt = kwargs['basefmt'] - except KeyError: + + if basefmt is None: try: + # fallback to positional argument basefmt = args[2] except IndexError: if rcParams['_internal.classic_mode']: @@ -2482,15 +2564,9 @@ def stem(self, *args, **kwargs): else: basestyle, basemarker, basecolor = _process_plot_format(basefmt) - bottom = kwargs.pop('bottom', None) - label = kwargs.pop('label', None) - markerline, = self.plot(x, y, color=markercolor, linestyle=markerstyle, marker=markermarker, label="_nolegend_") - if bottom is None: - bottom = 0 - stemlines = [] for thisx, thisy in zip(x, y): l, = self.plot([thisx, thisx], [bottom, thisy], diff --git a/lib/matplotlib/container.py b/lib/matplotlib/container.py index c47c88f3e020..f96bf9f03f7f 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -10,6 +10,9 @@ class Container(tuple): """ Base class for containers. + + Containers are classes that collect semantically related Artists such as + the bars of a bar plot. """ def __repr__(self): @@ -107,6 +110,23 @@ def get_children(self): class BarContainer(Container): + """ + Container for the artists of bar plots (e.g. created by `.Axes.bar`). + + The container can be treated as a tuple of the *patches* themselves. + Additionally, you can access these and further parameters by the + attributes. + + Attributes + ---------- + patches : list of :class:`~matplotlib.patches.Rectangle` + The artists of the bars. + + errorbar : None or :class:`~matplotlib.container.ErrorbarContainer` + A container for the error bar artists if error bars are present. + *None* otherwise. + + """ def __init__(self, patches, errorbar=None, **kwargs): self.patches = patches @@ -115,8 +135,12 @@ def __init__(self, patches, errorbar=None, **kwargs): class ErrorbarContainer(Container): - ''' - Container for errobars. + """ + Container for the artists of error bars (e.g. created by `.Axes.errorbar`). + + The container can be treated as the *lines* tuple itself. + Additionally, you can access these and further parameters by the + attributes. Attributes ---------- @@ -132,7 +156,8 @@ class ErrorbarContainer(Container): has_xerr, has_yerr : bool ``True`` if the errorbar has x/y errors. - ''' + + """ def __init__(self, lines, has_xerr=False, has_yerr=False, **kwargs): self.lines = lines @@ -142,6 +167,24 @@ def __init__(self, lines, has_xerr=False, has_yerr=False, **kwargs): class StemContainer(Container): + """ + Container for the artists created in a :meth:`.Axes.stem` plot. + + The container can be treated like a namedtuple ``(markerline, stemlines, + baseline)``. + + Attributes + ---------- + markerline : :class:`~matplotlib.lines.Line2D` + The artist of the markers at the stem heads. + + stemlines : list of :class:`~matplotlib.lines.Line2D` + The artists of the vertical lines for all stems. + + baseline : :class:`~matplotlib.lines.Line2D` + The artist of the horizontal baseline. + + """ def __init__(self, markerline_stemlines_baseline, **kwargs): markerline, stemlines, baseline = markerline_stemlines_baseline