Coverage for /usr/lib/python3/dist-packages/matplotlib/axes/_axes.py: 14%
2244 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1import functools
2import itertools
3import logging
4import math
5from numbers import Integral, Number
7import numpy as np
8from numpy import ma
10import matplotlib as mpl
11import matplotlib.category # Register category unit converter as side-effect.
12import matplotlib.cbook as cbook
13import matplotlib.collections as mcoll
14import matplotlib.colors as mcolors
15import matplotlib.contour as mcontour
16import matplotlib.dates # noqa # Register date unit converter as side-effect.
17import matplotlib.image as mimage
18import matplotlib.legend as mlegend
19import matplotlib.lines as mlines
20import matplotlib.markers as mmarkers
21import matplotlib.mlab as mlab
22import matplotlib.patches as mpatches
23import matplotlib.path as mpath
24import matplotlib.quiver as mquiver
25import matplotlib.stackplot as mstack
26import matplotlib.streamplot as mstream
27import matplotlib.table as mtable
28import matplotlib.text as mtext
29import matplotlib.ticker as mticker
30import matplotlib.transforms as mtransforms
31import matplotlib.tri as mtri
32import matplotlib.units as munits
33from matplotlib import _api, _docstring, _preprocess_data
34from matplotlib.axes._base import (
35 _AxesBase, _TransformedBoundsLocator, _process_plot_format)
36from matplotlib.axes._secondary_axes import SecondaryAxis
37from matplotlib.container import BarContainer, ErrorbarContainer, StemContainer
39_log = logging.getLogger(__name__)
42# The axes module contains all the wrappers to plotting functions.
43# All the other methods should go in the _AxesBase class.
46@_docstring.interpd
47class Axes(_AxesBase):
48 """
49 The `Axes` contains most of the figure elements: `~.axis.Axis`,
50 `~.axis.Tick`, `~.lines.Line2D`, `~.text.Text`, `~.patches.Polygon`, etc.,
51 and sets the coordinate system.
53 The `Axes` instance supports callbacks through a callbacks attribute which
54 is a `~.cbook.CallbackRegistry` instance. The events you can connect to
55 are 'xlim_changed' and 'ylim_changed' and the callback will be called with
56 func(*ax*) where *ax* is the `Axes` instance.
58 .. note::
60 As a user, you do not instantiate Axes directly, but use Axes creation
61 methods instead; e.g. from `.pyplot` or `.Figure`:
62 `~.pyplot.subplots`, `~.pyplot.subplot_mosaic` or `.Figure.add_axes`.
64 Attributes
65 ----------
66 dataLim : `.Bbox`
67 The bounding box enclosing all data displayed in the Axes.
68 viewLim : `.Bbox`
69 The view limits in data coordinates.
71 """
72 ### Labelling, legend and texts
74 def get_title(self, loc="center"):
75 """
76 Get an Axes title.
78 Get one of the three available Axes titles. The available titles
79 are positioned above the Axes in the center, flush with the left
80 edge, and flush with the right edge.
82 Parameters
83 ----------
84 loc : {'center', 'left', 'right'}, str, default: 'center'
85 Which title to return.
87 Returns
88 -------
89 str
90 The title text string.
92 """
93 titles = {'left': self._left_title,
94 'center': self.title,
95 'right': self._right_title}
96 title = _api.check_getitem(titles, loc=loc.lower())
97 return title.get_text()
99 def set_title(self, label, fontdict=None, loc=None, pad=None, *, y=None,
100 **kwargs):
101 """
102 Set a title for the Axes.
104 Set one of the three available Axes titles. The available titles
105 are positioned above the Axes in the center, flush with the left
106 edge, and flush with the right edge.
108 Parameters
109 ----------
110 label : str
111 Text to use for the title
113 fontdict : dict
114 A dictionary controlling the appearance of the title text,
115 the default *fontdict* is::
117 {'fontsize': rcParams['axes.titlesize'],
118 'fontweight': rcParams['axes.titleweight'],
119 'color': rcParams['axes.titlecolor'],
120 'verticalalignment': 'baseline',
121 'horizontalalignment': loc}
123 loc : {'center', 'left', 'right'}, default: :rc:`axes.titlelocation`
124 Which title to set.
126 y : float, default: :rc:`axes.titley`
127 Vertical Axes location for the title (1.0 is the top). If
128 None (the default) and :rc:`axes.titley` is also None, y is
129 determined automatically to avoid decorators on the Axes.
131 pad : float, default: :rc:`axes.titlepad`
132 The offset of the title from the top of the Axes, in points.
134 Returns
135 -------
136 `.Text`
137 The matplotlib text instance representing the title
139 Other Parameters
140 ----------------
141 **kwargs : `.Text` properties
142 Other keyword arguments are text properties, see `.Text` for a list
143 of valid text properties.
144 """
145 if loc is None:
146 loc = mpl.rcParams['axes.titlelocation']
148 if y is None:
149 y = mpl.rcParams['axes.titley']
150 if y is None:
151 y = 1.0
152 else:
153 self._autotitlepos = False
154 kwargs['y'] = y
156 titles = {'left': self._left_title,
157 'center': self.title,
158 'right': self._right_title}
159 title = _api.check_getitem(titles, loc=loc.lower())
160 default = {
161 'fontsize': mpl.rcParams['axes.titlesize'],
162 'fontweight': mpl.rcParams['axes.titleweight'],
163 'verticalalignment': 'baseline',
164 'horizontalalignment': loc.lower()}
165 titlecolor = mpl.rcParams['axes.titlecolor']
166 if not cbook._str_lower_equal(titlecolor, 'auto'):
167 default["color"] = titlecolor
168 if pad is None:
169 pad = mpl.rcParams['axes.titlepad']
170 self._set_title_offset_trans(float(pad))
171 title.set_text(label)
172 title.update(default)
173 if fontdict is not None:
174 title.update(fontdict)
175 title._internal_update(kwargs)
176 return title
178 def get_legend_handles_labels(self, legend_handler_map=None):
179 """
180 Return handles and labels for legend
182 ``ax.legend()`` is equivalent to ::
184 h, l = ax.get_legend_handles_labels()
185 ax.legend(h, l)
186 """
187 # pass through to legend.
188 handles, labels = mlegend._get_legend_handles_labels(
189 [self], legend_handler_map)
190 return handles, labels
192 @_docstring.dedent_interpd
193 def legend(self, *args, **kwargs):
194 """
195 Place a legend on the Axes.
197 Call signatures::
199 legend()
200 legend(handles, labels)
201 legend(handles=handles)
202 legend(labels)
204 The call signatures correspond to the following different ways to use
205 this method:
207 **1. Automatic detection of elements to be shown in the legend**
209 The elements to be added to the legend are automatically determined,
210 when you do not pass in any extra arguments.
212 In this case, the labels are taken from the artist. You can specify
213 them either at artist creation or by calling the
214 :meth:`~.Artist.set_label` method on the artist::
216 ax.plot([1, 2, 3], label='Inline label')
217 ax.legend()
219 or::
221 line, = ax.plot([1, 2, 3])
222 line.set_label('Label via method')
223 ax.legend()
225 .. note::
226 Specific artists can be excluded from the automatic legend element
227 selection by using a label starting with an underscore, "_".
228 A string starting with an underscore is the default label for all
229 artists, so calling `.Axes.legend` without any arguments and
230 without setting the labels manually will result in no legend being
231 drawn.
234 **2. Explicitly listing the artists and labels in the legend**
236 For full control of which artists have a legend entry, it is possible
237 to pass an iterable of legend artists followed by an iterable of
238 legend labels respectively::
240 ax.legend([line1, line2, line3], ['label1', 'label2', 'label3'])
243 **3. Explicitly listing the artists in the legend**
245 This is similar to 2, but the labels are taken from the artists'
246 label properties. Example::
248 line1, = ax.plot([1, 2, 3], label='label1')
249 line2, = ax.plot([1, 2, 3], label='label2')
250 ax.legend(handles=[line1, line2])
253 **4. Labeling existing plot elements**
255 .. admonition:: Discouraged
257 This call signature is discouraged, because the relation between
258 plot elements and labels is only implicit by their order and can
259 easily be mixed up.
261 To make a legend for all artists on an Axes, call this function with
262 an iterable of strings, one for each legend item. For example::
264 ax.plot([1, 2, 3])
265 ax.plot([5, 6, 7])
266 ax.legend(['First line', 'Second line'])
269 Parameters
270 ----------
271 handles : sequence of `.Artist`, optional
272 A list of Artists (lines, patches) to be added to the legend.
273 Use this together with *labels*, if you need full control on what
274 is shown in the legend and the automatic mechanism described above
275 is not sufficient.
277 The length of handles and labels should be the same in this
278 case. If they are not, they are truncated to the smaller length.
280 labels : list of str, optional
281 A list of labels to show next to the artists.
282 Use this together with *handles*, if you need full control on what
283 is shown in the legend and the automatic mechanism described above
284 is not sufficient.
286 Returns
287 -------
288 `~matplotlib.legend.Legend`
290 Other Parameters
291 ----------------
292 %(_legend_kw_doc)s
294 See Also
295 --------
296 .Figure.legend
298 Notes
299 -----
300 Some artists are not supported by this function. See
301 :doc:`/tutorials/intermediate/legend_guide` for details.
303 Examples
304 --------
305 .. plot:: gallery/text_labels_and_annotations/legend.py
306 """
307 handles, labels, extra_args, kwargs = mlegend._parse_legend_args(
308 [self],
309 *args,
310 **kwargs)
311 if len(extra_args):
312 raise TypeError('legend only accepts two non-keyword arguments')
313 self.legend_ = mlegend.Legend(self, handles, labels, **kwargs)
314 self.legend_._remove_method = self._remove_legend
315 return self.legend_
317 def _remove_legend(self, legend):
318 self.legend_ = None
320 def inset_axes(self, bounds, *, transform=None, zorder=5, **kwargs):
321 """
322 Add a child inset Axes to this existing Axes.
324 Warnings
325 --------
326 This method is experimental as of 3.0, and the API may change.
328 Parameters
329 ----------
330 bounds : [x0, y0, width, height]
331 Lower-left corner of inset Axes, and its width and height.
333 transform : `.Transform`
334 Defaults to `ax.transAxes`, i.e. the units of *rect* are in
335 Axes-relative coordinates.
337 projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \
338'polar', 'rectilinear', str}, optional
339 The projection type of the inset `~.axes.Axes`. *str* is the name
340 of a custom projection, see `~matplotlib.projections`. The default
341 None results in a 'rectilinear' projection.
343 polar : bool, default: False
344 If True, equivalent to projection='polar'.
346 axes_class : subclass type of `~.axes.Axes`, optional
347 The `.axes.Axes` subclass that is instantiated. This parameter
348 is incompatible with *projection* and *polar*. See
349 :ref:`axisartist_users-guide-index` for examples.
351 zorder : number
352 Defaults to 5 (same as `.Axes.legend`). Adjust higher or lower
353 to change whether it is above or below data plotted on the
354 parent Axes.
356 **kwargs
357 Other keyword arguments are passed on to the inset Axes class.
359 Returns
360 -------
361 ax
362 The created `~.axes.Axes` instance.
364 Examples
365 --------
366 This example makes two inset Axes, the first is in Axes-relative
367 coordinates, and the second in data-coordinates::
369 fig, ax = plt.subplots()
370 ax.plot(range(10))
371 axin1 = ax.inset_axes([0.8, 0.1, 0.15, 0.15])
372 axin2 = ax.inset_axes(
373 [5, 7, 2.3, 2.3], transform=ax.transData)
375 """
376 if transform is None:
377 transform = self.transAxes
378 kwargs.setdefault('label', 'inset_axes')
380 # This puts the rectangle into figure-relative coordinates.
381 inset_locator = _TransformedBoundsLocator(bounds, transform)
382 bounds = inset_locator(self, None).bounds
383 projection_class, pkw = self.figure._process_projection_requirements(
384 bounds, **kwargs)
385 inset_ax = projection_class(self.figure, bounds, zorder=zorder, **pkw)
387 # this locator lets the axes move if in data coordinates.
388 # it gets called in `ax.apply_aspect() (of all places)
389 inset_ax.set_axes_locator(inset_locator)
391 self.add_child_axes(inset_ax)
393 return inset_ax
395 @_docstring.dedent_interpd
396 def indicate_inset(self, bounds, inset_ax=None, *, transform=None,
397 facecolor='none', edgecolor='0.5', alpha=0.5,
398 zorder=4.99, **kwargs):
399 """
400 Add an inset indicator to the Axes. This is a rectangle on the plot
401 at the position indicated by *bounds* that optionally has lines that
402 connect the rectangle to an inset Axes (`.Axes.inset_axes`).
404 Warnings
405 --------
406 This method is experimental as of 3.0, and the API may change.
408 Parameters
409 ----------
410 bounds : [x0, y0, width, height]
411 Lower-left corner of rectangle to be marked, and its width
412 and height.
414 inset_ax : `.Axes`
415 An optional inset Axes to draw connecting lines to. Two lines are
416 drawn connecting the indicator box to the inset Axes on corners
417 chosen so as to not overlap with the indicator box.
419 transform : `.Transform`
420 Transform for the rectangle coordinates. Defaults to
421 `ax.transAxes`, i.e. the units of *rect* are in Axes-relative
422 coordinates.
424 facecolor : color, default: 'none'
425 Facecolor of the rectangle.
427 edgecolor : color, default: '0.5'
428 Color of the rectangle and color of the connecting lines.
430 alpha : float, default: 0.5
431 Transparency of the rectangle and connector lines.
433 zorder : float, default: 4.99
434 Drawing order of the rectangle and connector lines. The default,
435 4.99, is just below the default level of inset Axes.
437 **kwargs
438 Other keyword arguments are passed on to the `.Rectangle` patch:
440 %(Rectangle:kwdoc)s
442 Returns
443 -------
444 rectangle_patch : `.patches.Rectangle`
445 The indicator frame.
447 connector_lines : 4-tuple of `.patches.ConnectionPatch`
448 The four connector lines connecting to (lower_left, upper_left,
449 lower_right upper_right) corners of *inset_ax*. Two lines are
450 set with visibility to *False*, but the user can set the
451 visibility to True if the automatic choice is not deemed correct.
453 """
454 # to make the axes connectors work, we need to apply the aspect to
455 # the parent axes.
456 self.apply_aspect()
458 if transform is None:
459 transform = self.transData
460 kwargs.setdefault('label', '_indicate_inset')
462 x, y, width, height = bounds
463 rectangle_patch = mpatches.Rectangle(
464 (x, y), width, height,
465 facecolor=facecolor, edgecolor=edgecolor, alpha=alpha,
466 zorder=zorder, transform=transform, **kwargs)
467 self.add_patch(rectangle_patch)
469 connects = []
471 if inset_ax is not None:
472 # connect the inset_axes to the rectangle
473 for xy_inset_ax in [(0, 0), (0, 1), (1, 0), (1, 1)]:
474 # inset_ax positions are in axes coordinates
475 # The 0, 1 values define the four edges if the inset_ax
476 # lower_left, upper_left, lower_right upper_right.
477 ex, ey = xy_inset_ax
478 if self.xaxis.get_inverted():
479 ex = 1 - ex
480 if self.yaxis.get_inverted():
481 ey = 1 - ey
482 xy_data = x + ex * width, y + ey * height
483 p = mpatches.ConnectionPatch(
484 xyA=xy_inset_ax, coordsA=inset_ax.transAxes,
485 xyB=xy_data, coordsB=self.transData,
486 arrowstyle="-", zorder=zorder,
487 edgecolor=edgecolor, alpha=alpha)
488 connects.append(p)
489 self.add_patch(p)
491 # decide which two of the lines to keep visible....
492 pos = inset_ax.get_position()
493 bboxins = pos.transformed(self.figure.transSubfigure)
494 rectbbox = mtransforms.Bbox.from_bounds(
495 *bounds
496 ).transformed(transform)
497 x0 = rectbbox.x0 < bboxins.x0
498 x1 = rectbbox.x1 < bboxins.x1
499 y0 = rectbbox.y0 < bboxins.y0
500 y1 = rectbbox.y1 < bboxins.y1
501 connects[0].set_visible(x0 ^ y0)
502 connects[1].set_visible(x0 == y1)
503 connects[2].set_visible(x1 == y0)
504 connects[3].set_visible(x1 ^ y1)
506 return rectangle_patch, tuple(connects) if connects else None
508 def indicate_inset_zoom(self, inset_ax, **kwargs):
509 """
510 Add an inset indicator rectangle to the Axes based on the axis
511 limits for an *inset_ax* and draw connectors between *inset_ax*
512 and the rectangle.
514 Warnings
515 --------
516 This method is experimental as of 3.0, and the API may change.
518 Parameters
519 ----------
520 inset_ax : `.Axes`
521 Inset Axes to draw connecting lines to. Two lines are
522 drawn connecting the indicator box to the inset Axes on corners
523 chosen so as to not overlap with the indicator box.
525 **kwargs
526 Other keyword arguments are passed on to `.Axes.indicate_inset`
528 Returns
529 -------
530 rectangle_patch : `.patches.Rectangle`
531 Rectangle artist.
533 connector_lines : 4-tuple of `.patches.ConnectionPatch`
534 Each of four connector lines coming from the rectangle drawn on
535 this axis, in the order lower left, upper left, lower right,
536 upper right.
537 Two are set with visibility to *False*, but the user can
538 set the visibility to *True* if the automatic choice is not deemed
539 correct.
540 """
542 xlim = inset_ax.get_xlim()
543 ylim = inset_ax.get_ylim()
544 rect = (xlim[0], ylim[0], xlim[1] - xlim[0], ylim[1] - ylim[0])
545 return self.indicate_inset(rect, inset_ax, **kwargs)
547 @_docstring.dedent_interpd
548 def secondary_xaxis(self, location, *, functions=None, **kwargs):
549 """
550 Add a second x-axis to this Axes.
552 For example if we want to have a second scale for the data plotted on
553 the xaxis.
555 %(_secax_docstring)s
557 Examples
558 --------
559 The main axis shows frequency, and the secondary axis shows period.
561 .. plot::
563 fig, ax = plt.subplots()
564 ax.loglog(range(1, 360, 5), range(1, 360, 5))
565 ax.set_xlabel('frequency [Hz]')
567 def invert(x):
568 # 1/x with special treatment of x == 0
569 x = np.array(x).astype(float)
570 near_zero = np.isclose(x, 0)
571 x[near_zero] = np.inf
572 x[~near_zero] = 1 / x[~near_zero]
573 return x
575 # the inverse of 1/x is itself
576 secax = ax.secondary_xaxis('top', functions=(invert, invert))
577 secax.set_xlabel('Period [s]')
578 plt.show()
579 """
580 if location in ['top', 'bottom'] or isinstance(location, Number):
581 secondary_ax = SecondaryAxis(self, 'x', location, functions,
582 **kwargs)
583 self.add_child_axes(secondary_ax)
584 return secondary_ax
585 else:
586 raise ValueError('secondary_xaxis location must be either '
587 'a float or "top"/"bottom"')
589 @_docstring.dedent_interpd
590 def secondary_yaxis(self, location, *, functions=None, **kwargs):
591 """
592 Add a second y-axis to this Axes.
594 For example if we want to have a second scale for the data plotted on
595 the yaxis.
597 %(_secax_docstring)s
599 Examples
600 --------
601 Add a secondary Axes that converts from radians to degrees
603 .. plot::
605 fig, ax = plt.subplots()
606 ax.plot(range(1, 360, 5), range(1, 360, 5))
607 ax.set_ylabel('degrees')
608 secax = ax.secondary_yaxis('right', functions=(np.deg2rad,
609 np.rad2deg))
610 secax.set_ylabel('radians')
611 """
612 if location in ['left', 'right'] or isinstance(location, Number):
613 secondary_ax = SecondaryAxis(self, 'y', location,
614 functions, **kwargs)
615 self.add_child_axes(secondary_ax)
616 return secondary_ax
617 else:
618 raise ValueError('secondary_yaxis location must be either '
619 'a float or "left"/"right"')
621 @_docstring.dedent_interpd
622 def text(self, x, y, s, fontdict=None, **kwargs):
623 """
624 Add text to the Axes.
626 Add the text *s* to the Axes at location *x*, *y* in data coordinates.
628 Parameters
629 ----------
630 x, y : float
631 The position to place the text. By default, this is in data
632 coordinates. The coordinate system can be changed using the
633 *transform* parameter.
635 s : str
636 The text.
638 fontdict : dict, default: None
639 A dictionary to override the default text properties. If fontdict
640 is None, the defaults are determined by `.rcParams`.
642 Returns
643 -------
644 `.Text`
645 The created `.Text` instance.
647 Other Parameters
648 ----------------
649 **kwargs : `~matplotlib.text.Text` properties.
650 Other miscellaneous text parameters.
652 %(Text:kwdoc)s
654 Examples
655 --------
656 Individual keyword arguments can be used to override any given
657 parameter::
659 >>> text(x, y, s, fontsize=12)
661 The default transform specifies that text is in data coords,
662 alternatively, you can specify text in axis coords ((0, 0) is
663 lower-left and (1, 1) is upper-right). The example below places
664 text in the center of the Axes::
666 >>> text(0.5, 0.5, 'matplotlib', horizontalalignment='center',
667 ... verticalalignment='center', transform=ax.transAxes)
669 You can put a rectangular box around the text instance (e.g., to
670 set a background color) by using the keyword *bbox*. *bbox* is
671 a dictionary of `~matplotlib.patches.Rectangle`
672 properties. For example::
674 >>> text(x, y, s, bbox=dict(facecolor='red', alpha=0.5))
675 """
676 effective_kwargs = {
677 'verticalalignment': 'baseline',
678 'horizontalalignment': 'left',
679 'transform': self.transData,
680 'clip_on': False,
681 **(fontdict if fontdict is not None else {}),
682 **kwargs,
683 }
684 t = mtext.Text(x, y, text=s, **effective_kwargs)
685 t.set_clip_path(self.patch)
686 self._add_text(t)
687 return t
689 @_docstring.dedent_interpd
690 def annotate(self, text, xy, xytext=None, xycoords='data', textcoords=None,
691 arrowprops=None, annotation_clip=None, **kwargs):
692 # Signature must match Annotation. This is verified in
693 # test_annotate_signature().
694 a = mtext.Annotation(text, xy, xytext=xytext, xycoords=xycoords,
695 textcoords=textcoords, arrowprops=arrowprops,
696 annotation_clip=annotation_clip, **kwargs)
697 a.set_transform(mtransforms.IdentityTransform())
698 if 'clip_on' in kwargs:
699 a.set_clip_path(self.patch)
700 self._add_text(a)
701 return a
702 annotate.__doc__ = mtext.Annotation.__init__.__doc__
703 #### Lines and spans
705 @_docstring.dedent_interpd
706 def axhline(self, y=0, xmin=0, xmax=1, **kwargs):
707 """
708 Add a horizontal line across the Axes.
710 Parameters
711 ----------
712 y : float, default: 0
713 y position in data coordinates of the horizontal line.
715 xmin : float, default: 0
716 Should be between 0 and 1, 0 being the far left of the plot, 1 the
717 far right of the plot.
719 xmax : float, default: 1
720 Should be between 0 and 1, 0 being the far left of the plot, 1 the
721 far right of the plot.
723 Returns
724 -------
725 `~matplotlib.lines.Line2D`
727 Other Parameters
728 ----------------
729 **kwargs
730 Valid keyword arguments are `.Line2D` properties, with the
731 exception of 'transform':
733 %(Line2D:kwdoc)s
735 See Also
736 --------
737 hlines : Add horizontal lines in data coordinates.
738 axhspan : Add a horizontal span (rectangle) across the axis.
739 axline : Add a line with an arbitrary slope.
741 Examples
742 --------
743 * draw a thick red hline at 'y' = 0 that spans the xrange::
745 >>> axhline(linewidth=4, color='r')
747 * draw a default hline at 'y' = 1 that spans the xrange::
749 >>> axhline(y=1)
751 * draw a default hline at 'y' = .5 that spans the middle half of
752 the xrange::
754 >>> axhline(y=.5, xmin=0.25, xmax=0.75)
755 """
756 self._check_no_units([xmin, xmax], ['xmin', 'xmax'])
757 if "transform" in kwargs:
758 raise ValueError("'transform' is not allowed as a keyword "
759 "argument; axhline generates its own transform.")
760 ymin, ymax = self.get_ybound()
762 # Strip away the units for comparison with non-unitized bounds.
763 yy, = self._process_unit_info([("y", y)], kwargs)
764 scaley = (yy < ymin) or (yy > ymax)
766 trans = self.get_yaxis_transform(which='grid')
767 l = mlines.Line2D([xmin, xmax], [y, y], transform=trans, **kwargs)
768 self.add_line(l)
769 if scaley:
770 self._request_autoscale_view("y")
771 return l
773 @_docstring.dedent_interpd
774 def axvline(self, x=0, ymin=0, ymax=1, **kwargs):
775 """
776 Add a vertical line across the Axes.
778 Parameters
779 ----------
780 x : float, default: 0
781 x position in data coordinates of the vertical line.
783 ymin : float, default: 0
784 Should be between 0 and 1, 0 being the bottom of the plot, 1 the
785 top of the plot.
787 ymax : float, default: 1
788 Should be between 0 and 1, 0 being the bottom of the plot, 1 the
789 top of the plot.
791 Returns
792 -------
793 `~matplotlib.lines.Line2D`
795 Other Parameters
796 ----------------
797 **kwargs
798 Valid keyword arguments are `.Line2D` properties, with the
799 exception of 'transform':
801 %(Line2D:kwdoc)s
803 See Also
804 --------
805 vlines : Add vertical lines in data coordinates.
806 axvspan : Add a vertical span (rectangle) across the axis.
807 axline : Add a line with an arbitrary slope.
809 Examples
810 --------
811 * draw a thick red vline at *x* = 0 that spans the yrange::
813 >>> axvline(linewidth=4, color='r')
815 * draw a default vline at *x* = 1 that spans the yrange::
817 >>> axvline(x=1)
819 * draw a default vline at *x* = .5 that spans the middle half of
820 the yrange::
822 >>> axvline(x=.5, ymin=0.25, ymax=0.75)
823 """
824 self._check_no_units([ymin, ymax], ['ymin', 'ymax'])
825 if "transform" in kwargs:
826 raise ValueError("'transform' is not allowed as a keyword "
827 "argument; axvline generates its own transform.")
828 xmin, xmax = self.get_xbound()
830 # Strip away the units for comparison with non-unitized bounds.
831 xx, = self._process_unit_info([("x", x)], kwargs)
832 scalex = (xx < xmin) or (xx > xmax)
834 trans = self.get_xaxis_transform(which='grid')
835 l = mlines.Line2D([x, x], [ymin, ymax], transform=trans, **kwargs)
836 self.add_line(l)
837 if scalex:
838 self._request_autoscale_view("x")
839 return l
841 @staticmethod
842 def _check_no_units(vals, names):
843 # Helper method to check that vals are not unitized
844 for val, name in zip(vals, names):
845 if not munits._is_natively_supported(val):
846 raise ValueError(f"{name} must be a single scalar value, "
847 f"but got {val}")
849 @_docstring.dedent_interpd
850 def axline(self, xy1, xy2=None, *, slope=None, **kwargs):
851 """
852 Add an infinitely long straight line.
854 The line can be defined either by two points *xy1* and *xy2*, or
855 by one point *xy1* and a *slope*.
857 This draws a straight line "on the screen", regardless of the x and y
858 scales, and is thus also suitable for drawing exponential decays in
859 semilog plots, power laws in loglog plots, etc. However, *slope*
860 should only be used with linear scales; It has no clear meaning for
861 all other scales, and thus the behavior is undefined. Please specify
862 the line using the points *xy1*, *xy2* for non-linear scales.
864 The *transform* keyword argument only applies to the points *xy1*,
865 *xy2*. The *slope* (if given) is always in data coordinates. This can
866 be used e.g. with ``ax.transAxes`` for drawing grid lines with a fixed
867 slope.
869 Parameters
870 ----------
871 xy1, xy2 : (float, float)
872 Points for the line to pass through.
873 Either *xy2* or *slope* has to be given.
874 slope : float, optional
875 The slope of the line. Either *xy2* or *slope* has to be given.
877 Returns
878 -------
879 `.Line2D`
881 Other Parameters
882 ----------------
883 **kwargs
884 Valid kwargs are `.Line2D` properties
886 %(Line2D:kwdoc)s
888 See Also
889 --------
890 axhline : for horizontal lines
891 axvline : for vertical lines
893 Examples
894 --------
895 Draw a thick red line passing through (0, 0) and (1, 1)::
897 >>> axline((0, 0), (1, 1), linewidth=4, color='r')
898 """
899 if slope is not None and (self.get_xscale() != 'linear' or
900 self.get_yscale() != 'linear'):
901 raise TypeError("'slope' cannot be used with non-linear scales")
903 datalim = [xy1] if xy2 is None else [xy1, xy2]
904 if "transform" in kwargs:
905 # if a transform is passed (i.e. line points not in data space),
906 # data limits should not be adjusted.
907 datalim = []
909 line = mlines._AxLine(xy1, xy2, slope, **kwargs)
910 # Like add_line, but correctly handling data limits.
911 self._set_artist_props(line)
912 if line.get_clip_path() is None:
913 line.set_clip_path(self.patch)
914 if not line.get_label():
915 line.set_label(f"_child{len(self._children)}")
916 self._children.append(line)
917 line._remove_method = self._children.remove
918 self.update_datalim(datalim)
920 self._request_autoscale_view()
921 return line
923 @_docstring.dedent_interpd
924 def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs):
925 """
926 Add a horizontal span (rectangle) across the Axes.
928 The rectangle spans from *ymin* to *ymax* vertically, and, by default,
929 the whole x-axis horizontally. The x-span can be set using *xmin*
930 (default: 0) and *xmax* (default: 1) which are in axis units; e.g.
931 ``xmin = 0.5`` always refers to the middle of the x-axis regardless of
932 the limits set by `~.Axes.set_xlim`.
934 Parameters
935 ----------
936 ymin : float
937 Lower y-coordinate of the span, in data units.
938 ymax : float
939 Upper y-coordinate of the span, in data units.
940 xmin : float, default: 0
941 Lower x-coordinate of the span, in x-axis (0-1) units.
942 xmax : float, default: 1
943 Upper x-coordinate of the span, in x-axis (0-1) units.
945 Returns
946 -------
947 `~matplotlib.patches.Polygon`
948 Horizontal span (rectangle) from (xmin, ymin) to (xmax, ymax).
950 Other Parameters
951 ----------------
952 **kwargs : `~matplotlib.patches.Polygon` properties
954 %(Polygon:kwdoc)s
956 See Also
957 --------
958 axvspan : Add a vertical span across the Axes.
959 """
960 # Strip units away.
961 self._check_no_units([xmin, xmax], ['xmin', 'xmax'])
962 (ymin, ymax), = self._process_unit_info([("y", [ymin, ymax])], kwargs)
964 verts = (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)
965 p = mpatches.Polygon(verts, **kwargs)
966 p.set_transform(self.get_yaxis_transform(which="grid"))
967 self.add_patch(p)
968 self._request_autoscale_view("y")
969 return p
971 @_docstring.dedent_interpd
972 def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs):
973 """
974 Add a vertical span (rectangle) across the Axes.
976 The rectangle spans from *xmin* to *xmax* horizontally, and, by
977 default, the whole y-axis vertically. The y-span can be set using
978 *ymin* (default: 0) and *ymax* (default: 1) which are in axis units;
979 e.g. ``ymin = 0.5`` always refers to the middle of the y-axis
980 regardless of the limits set by `~.Axes.set_ylim`.
982 Parameters
983 ----------
984 xmin : float
985 Lower x-coordinate of the span, in data units.
986 xmax : float
987 Upper x-coordinate of the span, in data units.
988 ymin : float, default: 0
989 Lower y-coordinate of the span, in y-axis units (0-1).
990 ymax : float, default: 1
991 Upper y-coordinate of the span, in y-axis units (0-1).
993 Returns
994 -------
995 `~matplotlib.patches.Polygon`
996 Vertical span (rectangle) from (xmin, ymin) to (xmax, ymax).
998 Other Parameters
999 ----------------
1000 **kwargs : `~matplotlib.patches.Polygon` properties
1002 %(Polygon:kwdoc)s
1004 See Also
1005 --------
1006 axhspan : Add a horizontal span across the Axes.
1008 Examples
1009 --------
1010 Draw a vertical, green, translucent rectangle from x = 1.25 to
1011 x = 1.55 that spans the yrange of the Axes.
1013 >>> axvspan(1.25, 1.55, facecolor='g', alpha=0.5)
1015 """
1016 # Strip units away.
1017 self._check_no_units([ymin, ymax], ['ymin', 'ymax'])
1018 (xmin, xmax), = self._process_unit_info([("x", [xmin, xmax])], kwargs)
1020 verts = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)]
1021 p = mpatches.Polygon(verts, **kwargs)
1022 p.set_transform(self.get_xaxis_transform(which="grid"))
1023 p.get_path()._interpolation_steps = 100
1024 self.add_patch(p)
1025 self._request_autoscale_view("x")
1026 return p
1028 @_preprocess_data(replace_names=["y", "xmin", "xmax", "colors"],
1029 label_namer="y")
1030 def hlines(self, y, xmin, xmax, colors=None, linestyles='solid',
1031 label='', **kwargs):
1032 """
1033 Plot horizontal lines at each *y* from *xmin* to *xmax*.
1035 Parameters
1036 ----------
1037 y : float or array-like
1038 y-indexes where to plot the lines.
1040 xmin, xmax : float or array-like
1041 Respective beginning and end of each line. If scalars are
1042 provided, all lines will have the same length.
1044 colors : list of colors, default: :rc:`lines.color`
1046 linestyles : {'solid', 'dashed', 'dashdot', 'dotted'}, optional
1048 label : str, default: ''
1050 Returns
1051 -------
1052 `~matplotlib.collections.LineCollection`
1054 Other Parameters
1055 ----------------
1056 data : indexable object, optional
1057 DATA_PARAMETER_PLACEHOLDER
1058 **kwargs : `~matplotlib.collections.LineCollection` properties.
1060 See Also
1061 --------
1062 vlines : vertical lines
1063 axhline : horizontal line across the Axes
1064 """
1066 # We do the conversion first since not all unitized data is uniform
1067 xmin, xmax, y = self._process_unit_info(
1068 [("x", xmin), ("x", xmax), ("y", y)], kwargs)
1070 if not np.iterable(y):
1071 y = [y]
1072 if not np.iterable(xmin):
1073 xmin = [xmin]
1074 if not np.iterable(xmax):
1075 xmax = [xmax]
1077 # Create and combine masked_arrays from input
1078 y, xmin, xmax = cbook._combine_masks(y, xmin, xmax)
1079 y = np.ravel(y)
1080 xmin = np.ravel(xmin)
1081 xmax = np.ravel(xmax)
1083 masked_verts = np.ma.empty((len(y), 2, 2))
1084 masked_verts[:, 0, 0] = xmin
1085 masked_verts[:, 0, 1] = y
1086 masked_verts[:, 1, 0] = xmax
1087 masked_verts[:, 1, 1] = y
1089 lines = mcoll.LineCollection(masked_verts, colors=colors,
1090 linestyles=linestyles, label=label)
1091 self.add_collection(lines, autolim=False)
1092 lines._internal_update(kwargs)
1094 if len(y) > 0:
1095 # Extreme values of xmin/xmax/y. Using masked_verts here handles
1096 # the case of y being a masked *object* array (as can be generated
1097 # e.g. by errorbar()), which would make nanmin/nanmax stumble.
1098 minx = np.nanmin(masked_verts[..., 0])
1099 maxx = np.nanmax(masked_verts[..., 0])
1100 miny = np.nanmin(masked_verts[..., 1])
1101 maxy = np.nanmax(masked_verts[..., 1])
1102 corners = (minx, miny), (maxx, maxy)
1103 self.update_datalim(corners)
1104 self._request_autoscale_view()
1106 return lines
1108 @_preprocess_data(replace_names=["x", "ymin", "ymax", "colors"],
1109 label_namer="x")
1110 def vlines(self, x, ymin, ymax, colors=None, linestyles='solid',
1111 label='', **kwargs):
1112 """
1113 Plot vertical lines at each *x* from *ymin* to *ymax*.
1115 Parameters
1116 ----------
1117 x : float or array-like
1118 x-indexes where to plot the lines.
1120 ymin, ymax : float or array-like
1121 Respective beginning and end of each line. If scalars are
1122 provided, all lines will have the same length.
1124 colors : list of colors, default: :rc:`lines.color`
1126 linestyles : {'solid', 'dashed', 'dashdot', 'dotted'}, optional
1128 label : str, default: ''
1130 Returns
1131 -------
1132 `~matplotlib.collections.LineCollection`
1134 Other Parameters
1135 ----------------
1136 data : indexable object, optional
1137 DATA_PARAMETER_PLACEHOLDER
1138 **kwargs : `~matplotlib.collections.LineCollection` properties.
1140 See Also
1141 --------
1142 hlines : horizontal lines
1143 axvline : vertical line across the Axes
1144 """
1146 # We do the conversion first since not all unitized data is uniform
1147 x, ymin, ymax = self._process_unit_info(
1148 [("x", x), ("y", ymin), ("y", ymax)], kwargs)
1150 if not np.iterable(x):
1151 x = [x]
1152 if not np.iterable(ymin):
1153 ymin = [ymin]
1154 if not np.iterable(ymax):
1155 ymax = [ymax]
1157 # Create and combine masked_arrays from input
1158 x, ymin, ymax = cbook._combine_masks(x, ymin, ymax)
1159 x = np.ravel(x)
1160 ymin = np.ravel(ymin)
1161 ymax = np.ravel(ymax)
1163 masked_verts = np.ma.empty((len(x), 2, 2))
1164 masked_verts[:, 0, 0] = x
1165 masked_verts[:, 0, 1] = ymin
1166 masked_verts[:, 1, 0] = x
1167 masked_verts[:, 1, 1] = ymax
1169 lines = mcoll.LineCollection(masked_verts, colors=colors,
1170 linestyles=linestyles, label=label)
1171 self.add_collection(lines, autolim=False)
1172 lines._internal_update(kwargs)
1174 if len(x) > 0:
1175 # Extreme values of x/ymin/ymax. Using masked_verts here handles
1176 # the case of x being a masked *object* array (as can be generated
1177 # e.g. by errorbar()), which would make nanmin/nanmax stumble.
1178 minx = np.nanmin(masked_verts[..., 0])
1179 maxx = np.nanmax(masked_verts[..., 0])
1180 miny = np.nanmin(masked_verts[..., 1])
1181 maxy = np.nanmax(masked_verts[..., 1])
1182 corners = (minx, miny), (maxx, maxy)
1183 self.update_datalim(corners)
1184 self._request_autoscale_view()
1186 return lines
1188 @_preprocess_data(replace_names=["positions", "lineoffsets",
1189 "linelengths", "linewidths",
1190 "colors", "linestyles"])
1191 @_docstring.dedent_interpd
1192 def eventplot(self, positions, orientation='horizontal', lineoffsets=1,
1193 linelengths=1, linewidths=None, colors=None,
1194 linestyles='solid', **kwargs):
1195 """
1196 Plot identical parallel lines at the given positions.
1198 This type of plot is commonly used in neuroscience for representing
1199 neural events, where it is usually called a spike raster, dot raster,
1200 or raster plot.
1202 However, it is useful in any situation where you wish to show the
1203 timing or position of multiple sets of discrete events, such as the
1204 arrival times of people to a business on each day of the month or the
1205 date of hurricanes each year of the last century.
1207 Parameters
1208 ----------
1209 positions : array-like or list of array-like
1210 A 1D array-like defines the positions of one sequence of events.
1212 Multiple groups of events may be passed as a list of array-likes.
1213 Each group can be styled independently by passing lists of values
1214 to *lineoffsets*, *linelengths*, *linewidths*, *colors* and
1215 *linestyles*.
1217 Note that *positions* can be a 2D array, but in practice different
1218 event groups usually have different counts so that one will use a
1219 list of different-length arrays rather than a 2D array.
1221 orientation : {'horizontal', 'vertical'}, default: 'horizontal'
1222 The direction of the event sequence:
1224 - 'horizontal': the events are arranged horizontally.
1225 The indicator lines are vertical.
1226 - 'vertical': the events are arranged vertically.
1227 The indicator lines are horizontal.
1229 lineoffsets : float or array-like, default: 1
1230 The offset of the center of the lines from the origin, in the
1231 direction orthogonal to *orientation*.
1233 If *positions* is 2D, this can be a sequence with length matching
1234 the length of *positions*.
1236 linelengths : float or array-like, default: 1
1237 The total height of the lines (i.e. the lines stretches from
1238 ``lineoffset - linelength/2`` to ``lineoffset + linelength/2``).
1240 If *positions* is 2D, this can be a sequence with length matching
1241 the length of *positions*.
1243 linewidths : float or array-like, default: :rc:`lines.linewidth`
1244 The line width(s) of the event lines, in points.
1246 If *positions* is 2D, this can be a sequence with length matching
1247 the length of *positions*.
1249 colors : color or list of colors, default: :rc:`lines.color`
1250 The color(s) of the event lines.
1252 If *positions* is 2D, this can be a sequence with length matching
1253 the length of *positions*.
1255 linestyles : str or tuple or list of such values, default: 'solid'
1256 Default is 'solid'. Valid strings are ['solid', 'dashed',
1257 'dashdot', 'dotted', '-', '--', '-.', ':']. Dash tuples
1258 should be of the form::
1260 (offset, onoffseq),
1262 where *onoffseq* is an even length tuple of on and off ink
1263 in points.
1265 If *positions* is 2D, this can be a sequence with length matching
1266 the length of *positions*.
1268 data : indexable object, optional
1269 DATA_PARAMETER_PLACEHOLDER
1271 **kwargs
1272 Other keyword arguments are line collection properties. See
1273 `.LineCollection` for a list of the valid properties.
1275 Returns
1276 -------
1277 list of `.EventCollection`
1278 The `.EventCollection` that were added.
1280 Notes
1281 -----
1282 For *linelengths*, *linewidths*, *colors*, and *linestyles*, if only
1283 a single value is given, that value is applied to all lines. If an
1284 array-like is given, it must have the same length as *positions*, and
1285 each value will be applied to the corresponding row of the array.
1287 Examples
1288 --------
1289 .. plot:: gallery/lines_bars_and_markers/eventplot_demo.py
1290 """
1292 lineoffsets, linelengths = self._process_unit_info(
1293 [("y", lineoffsets), ("y", linelengths)], kwargs)
1295 # fix positions, noting that it can be a list of lists:
1296 if not np.iterable(positions):
1297 positions = [positions]
1298 elif any(np.iterable(position) for position in positions):
1299 positions = [np.asanyarray(position) for position in positions]
1300 else:
1301 positions = [np.asanyarray(positions)]
1303 if len(positions) == 0:
1304 return []
1306 poss = []
1307 for position in positions:
1308 poss += self._process_unit_info([("x", position)], kwargs)
1309 positions = poss
1311 # prevent 'singular' keys from **kwargs dict from overriding the effect
1312 # of 'plural' keyword arguments (e.g. 'color' overriding 'colors')
1313 colors = cbook._local_over_kwdict(colors, kwargs, 'color')
1314 linewidths = cbook._local_over_kwdict(linewidths, kwargs, 'linewidth')
1315 linestyles = cbook._local_over_kwdict(linestyles, kwargs, 'linestyle')
1317 if not np.iterable(lineoffsets):
1318 lineoffsets = [lineoffsets]
1319 if not np.iterable(linelengths):
1320 linelengths = [linelengths]
1321 if not np.iterable(linewidths):
1322 linewidths = [linewidths]
1323 if not np.iterable(colors):
1324 colors = [colors]
1325 if hasattr(linestyles, 'lower') or not np.iterable(linestyles):
1326 linestyles = [linestyles]
1328 lineoffsets = np.asarray(lineoffsets)
1329 linelengths = np.asarray(linelengths)
1330 linewidths = np.asarray(linewidths)
1332 if len(lineoffsets) == 0:
1333 lineoffsets = [None]
1334 if len(linelengths) == 0:
1335 linelengths = [None]
1336 if len(linewidths) == 0:
1337 lineoffsets = [None]
1338 if len(linewidths) == 0:
1339 lineoffsets = [None]
1340 if len(colors) == 0:
1341 colors = [None]
1342 try:
1343 # Early conversion of the colors into RGBA values to take care
1344 # of cases like colors='0.5' or colors='C1'. (Issue #8193)
1345 colors = mcolors.to_rgba_array(colors)
1346 except ValueError:
1347 # Will fail if any element of *colors* is None. But as long
1348 # as len(colors) == 1 or len(positions), the rest of the
1349 # code should process *colors* properly.
1350 pass
1352 if len(lineoffsets) == 1 and len(positions) != 1:
1353 lineoffsets = np.tile(lineoffsets, len(positions))
1354 lineoffsets[0] = 0
1355 lineoffsets = np.cumsum(lineoffsets)
1356 if len(linelengths) == 1:
1357 linelengths = np.tile(linelengths, len(positions))
1358 if len(linewidths) == 1:
1359 linewidths = np.tile(linewidths, len(positions))
1360 if len(colors) == 1:
1361 colors = list(colors)
1362 colors = colors * len(positions)
1363 if len(linestyles) == 1:
1364 linestyles = [linestyles] * len(positions)
1366 if len(lineoffsets) != len(positions):
1367 raise ValueError('lineoffsets and positions are unequal sized '
1368 'sequences')
1369 if len(linelengths) != len(positions):
1370 raise ValueError('linelengths and positions are unequal sized '
1371 'sequences')
1372 if len(linewidths) != len(positions):
1373 raise ValueError('linewidths and positions are unequal sized '
1374 'sequences')
1375 if len(colors) != len(positions):
1376 raise ValueError('colors and positions are unequal sized '
1377 'sequences')
1378 if len(linestyles) != len(positions):
1379 raise ValueError('linestyles and positions are unequal sized '
1380 'sequences')
1382 colls = []
1383 for position, lineoffset, linelength, linewidth, color, linestyle in \
1384 zip(positions, lineoffsets, linelengths, linewidths,
1385 colors, linestyles):
1386 coll = mcoll.EventCollection(position,
1387 orientation=orientation,
1388 lineoffset=lineoffset,
1389 linelength=linelength,
1390 linewidth=linewidth,
1391 color=color,
1392 linestyle=linestyle)
1393 self.add_collection(coll, autolim=False)
1394 coll._internal_update(kwargs)
1395 colls.append(coll)
1397 if len(positions) > 0:
1398 # try to get min/max
1399 min_max = [(np.min(_p), np.max(_p)) for _p in positions
1400 if len(_p) > 0]
1401 # if we have any non-empty positions, try to autoscale
1402 if len(min_max) > 0:
1403 mins, maxes = zip(*min_max)
1404 minpos = np.min(mins)
1405 maxpos = np.max(maxes)
1407 minline = (lineoffsets - linelengths).min()
1408 maxline = (lineoffsets + linelengths).max()
1410 if orientation == "vertical":
1411 corners = (minline, minpos), (maxline, maxpos)
1412 else: # "horizontal"
1413 corners = (minpos, minline), (maxpos, maxline)
1414 self.update_datalim(corners)
1415 self._request_autoscale_view()
1417 return colls
1419 #### Basic plotting
1421 # Uses a custom implementation of data-kwarg handling in
1422 # _process_plot_var_args.
1423 @_docstring.dedent_interpd
1424 def plot(self, *args, scalex=True, scaley=True, data=None, **kwargs):
1425 """
1426 Plot y versus x as lines and/or markers.
1428 Call signatures::
1430 plot([x], y, [fmt], *, data=None, **kwargs)
1431 plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)
1433 The coordinates of the points or line nodes are given by *x*, *y*.
1435 The optional parameter *fmt* is a convenient way for defining basic
1436 formatting like color, marker and linestyle. It's a shortcut string
1437 notation described in the *Notes* section below.
1439 >>> plot(x, y) # plot x and y using default line style and color
1440 >>> plot(x, y, 'bo') # plot x and y using blue circle markers
1441 >>> plot(y) # plot y using x as index array 0..N-1
1442 >>> plot(y, 'r+') # ditto, but with red plusses
1444 You can use `.Line2D` properties as keyword arguments for more
1445 control on the appearance. Line properties and *fmt* can be mixed.
1446 The following two calls yield identical results:
1448 >>> plot(x, y, 'go--', linewidth=2, markersize=12)
1449 >>> plot(x, y, color='green', marker='o', linestyle='dashed',
1450 ... linewidth=2, markersize=12)
1452 When conflicting with *fmt*, keyword arguments take precedence.
1455 **Plotting labelled data**
1457 There's a convenient way for plotting objects with labelled data (i.e.
1458 data that can be accessed by index ``obj['y']``). Instead of giving
1459 the data in *x* and *y*, you can provide the object in the *data*
1460 parameter and just give the labels for *x* and *y*::
1462 >>> plot('xlabel', 'ylabel', data=obj)
1464 All indexable objects are supported. This could e.g. be a `dict`, a
1465 `pandas.DataFrame` or a structured numpy array.
1468 **Plotting multiple sets of data**
1470 There are various ways to plot multiple sets of data.
1472 - The most straight forward way is just to call `plot` multiple times.
1473 Example:
1475 >>> plot(x1, y1, 'bo')
1476 >>> plot(x2, y2, 'go')
1478 - If *x* and/or *y* are 2D arrays a separate data set will be drawn
1479 for every column. If both *x* and *y* are 2D, they must have the
1480 same shape. If only one of them is 2D with shape (N, m) the other
1481 must have length N and will be used for every data set m.
1483 Example:
1485 >>> x = [1, 2, 3]
1486 >>> y = np.array([[1, 2], [3, 4], [5, 6]])
1487 >>> plot(x, y)
1489 is equivalent to:
1491 >>> for col in range(y.shape[1]):
1492 ... plot(x, y[:, col])
1494 - The third way is to specify multiple sets of *[x]*, *y*, *[fmt]*
1495 groups::
1497 >>> plot(x1, y1, 'g^', x2, y2, 'g-')
1499 In this case, any additional keyword argument applies to all
1500 datasets. Also this syntax cannot be combined with the *data*
1501 parameter.
1503 By default, each line is assigned a different style specified by a
1504 'style cycle'. The *fmt* and line property parameters are only
1505 necessary if you want explicit deviations from these defaults.
1506 Alternatively, you can also change the style cycle using
1507 :rc:`axes.prop_cycle`.
1510 Parameters
1511 ----------
1512 x, y : array-like or scalar
1513 The horizontal / vertical coordinates of the data points.
1514 *x* values are optional and default to ``range(len(y))``.
1516 Commonly, these parameters are 1D arrays.
1518 They can also be scalars, or two-dimensional (in that case, the
1519 columns represent separate data sets).
1521 These arguments cannot be passed as keywords.
1523 fmt : str, optional
1524 A format string, e.g. 'ro' for red circles. See the *Notes*
1525 section for a full description of the format strings.
1527 Format strings are just an abbreviation for quickly setting
1528 basic line properties. All of these and more can also be
1529 controlled by keyword arguments.
1531 This argument cannot be passed as keyword.
1533 data : indexable object, optional
1534 An object with labelled data. If given, provide the label names to
1535 plot in *x* and *y*.
1537 .. note::
1538 Technically there's a slight ambiguity in calls where the
1539 second label is a valid *fmt*. ``plot('n', 'o', data=obj)``
1540 could be ``plt(x, y)`` or ``plt(y, fmt)``. In such cases,
1541 the former interpretation is chosen, but a warning is issued.
1542 You may suppress the warning by adding an empty format string
1543 ``plot('n', 'o', '', data=obj)``.
1545 Returns
1546 -------
1547 list of `.Line2D`
1548 A list of lines representing the plotted data.
1550 Other Parameters
1551 ----------------
1552 scalex, scaley : bool, default: True
1553 These parameters determine if the view limits are adapted to the
1554 data limits. The values are passed on to
1555 `~.axes.Axes.autoscale_view`.
1557 **kwargs : `.Line2D` properties, optional
1558 *kwargs* are used to specify properties like a line label (for
1559 auto legends), linewidth, antialiasing, marker face color.
1560 Example::
1562 >>> plot([1, 2, 3], [1, 2, 3], 'go-', label='line 1', linewidth=2)
1563 >>> plot([1, 2, 3], [1, 4, 9], 'rs', label='line 2')
1565 If you specify multiple lines with one plot call, the kwargs apply
1566 to all those lines. In case the label object is iterable, each
1567 element is used as labels for each set of data.
1569 Here is a list of available `.Line2D` properties:
1571 %(Line2D:kwdoc)s
1573 See Also
1574 --------
1575 scatter : XY scatter plot with markers of varying size and/or color (
1576 sometimes also called bubble chart).
1578 Notes
1579 -----
1580 **Format Strings**
1582 A format string consists of a part for color, marker and line::
1584 fmt = '[marker][line][color]'
1586 Each of them is optional. If not provided, the value from the style
1587 cycle is used. Exception: If ``line`` is given, but no ``marker``,
1588 the data will be a line without markers.
1590 Other combinations such as ``[color][marker][line]`` are also
1591 supported, but note that their parsing may be ambiguous.
1593 **Markers**
1595 ============= ===============================
1596 character description
1597 ============= ===============================
1598 ``'.'`` point marker
1599 ``','`` pixel marker
1600 ``'o'`` circle marker
1601 ``'v'`` triangle_down marker
1602 ``'^'`` triangle_up marker
1603 ``'<'`` triangle_left marker
1604 ``'>'`` triangle_right marker
1605 ``'1'`` tri_down marker
1606 ``'2'`` tri_up marker
1607 ``'3'`` tri_left marker
1608 ``'4'`` tri_right marker
1609 ``'8'`` octagon marker
1610 ``'s'`` square marker
1611 ``'p'`` pentagon marker
1612 ``'P'`` plus (filled) marker
1613 ``'*'`` star marker
1614 ``'h'`` hexagon1 marker
1615 ``'H'`` hexagon2 marker
1616 ``'+'`` plus marker
1617 ``'x'`` x marker
1618 ``'X'`` x (filled) marker
1619 ``'D'`` diamond marker
1620 ``'d'`` thin_diamond marker
1621 ``'|'`` vline marker
1622 ``'_'`` hline marker
1623 ============= ===============================
1625 **Line Styles**
1627 ============= ===============================
1628 character description
1629 ============= ===============================
1630 ``'-'`` solid line style
1631 ``'--'`` dashed line style
1632 ``'-.'`` dash-dot line style
1633 ``':'`` dotted line style
1634 ============= ===============================
1636 Example format strings::
1638 'b' # blue markers with default shape
1639 'or' # red circles
1640 '-g' # green solid line
1641 '--' # dashed line with default color
1642 '^k:' # black triangle_up markers connected by a dotted line
1644 **Colors**
1646 The supported color abbreviations are the single letter codes
1648 ============= ===============================
1649 character color
1650 ============= ===============================
1651 ``'b'`` blue
1652 ``'g'`` green
1653 ``'r'`` red
1654 ``'c'`` cyan
1655 ``'m'`` magenta
1656 ``'y'`` yellow
1657 ``'k'`` black
1658 ``'w'`` white
1659 ============= ===============================
1661 and the ``'CN'`` colors that index into the default property cycle.
1663 If the color is the only part of the format string, you can
1664 additionally use any `matplotlib.colors` spec, e.g. full names
1665 (``'green'``) or hex strings (``'#008000'``).
1666 """
1667 kwargs = cbook.normalize_kwargs(kwargs, mlines.Line2D)
1668 lines = [*self._get_lines(*args, data=data, **kwargs)]
1669 for line in lines:
1670 self.add_line(line)
1671 if scalex:
1672 self._request_autoscale_view("x")
1673 if scaley:
1674 self._request_autoscale_view("y")
1675 return lines
1677 @_preprocess_data(replace_names=["x", "y"], label_namer="y")
1678 @_docstring.dedent_interpd
1679 def plot_date(self, x, y, fmt='o', tz=None, xdate=True, ydate=False,
1680 **kwargs):
1681 """
1682 [*Discouraged*] Plot coercing the axis to treat floats as dates.
1684 .. admonition:: Discouraged
1686 This method exists for historic reasons and will be deprecated in
1687 the future.
1689 - ``datetime``-like data should directly be plotted using
1690 `~.Axes.plot`.
1691 - If you need to plot plain numeric data as :ref:`date-format` or
1692 need to set a timezone, call ``ax.xaxis.axis_date`` /
1693 ``ax.yaxis.axis_date`` before `~.Axes.plot`. See
1694 `.Axis.axis_date`.
1696 Similar to `.plot`, this plots *y* vs. *x* as lines or markers.
1697 However, the axis labels are formatted as dates depending on *xdate*
1698 and *ydate*. Note that `.plot` will work with `datetime` and
1699 `numpy.datetime64` objects without resorting to this method.
1701 Parameters
1702 ----------
1703 x, y : array-like
1704 The coordinates of the data points. If *xdate* or *ydate* is
1705 *True*, the respective values *x* or *y* are interpreted as
1706 :ref:`Matplotlib dates <date-format>`.
1708 fmt : str, optional
1709 The plot format string. For details, see the corresponding
1710 parameter in `.plot`.
1712 tz : timezone string or `datetime.tzinfo`, default: :rc:`timezone`
1713 The time zone to use in labeling dates.
1715 xdate : bool, default: True
1716 If *True*, the *x*-axis will be interpreted as Matplotlib dates.
1718 ydate : bool, default: False
1719 If *True*, the *y*-axis will be interpreted as Matplotlib dates.
1721 Returns
1722 -------
1723 list of `.Line2D`
1724 Objects representing the plotted data.
1726 Other Parameters
1727 ----------------
1728 data : indexable object, optional
1729 DATA_PARAMETER_PLACEHOLDER
1730 **kwargs
1731 Keyword arguments control the `.Line2D` properties:
1733 %(Line2D:kwdoc)s
1735 See Also
1736 --------
1737 matplotlib.dates : Helper functions on dates.
1738 matplotlib.dates.date2num : Convert dates to num.
1739 matplotlib.dates.num2date : Convert num to dates.
1740 matplotlib.dates.drange : Create an equally spaced sequence of dates.
1742 Notes
1743 -----
1744 If you are using custom date tickers and formatters, it may be
1745 necessary to set the formatters/locators after the call to
1746 `.plot_date`. `.plot_date` will set the default tick locator to
1747 `.AutoDateLocator` (if the tick locator is not already set to a
1748 `.DateLocator` instance) and the default tick formatter to
1749 `.AutoDateFormatter` (if the tick formatter is not already set to a
1750 `.DateFormatter` instance).
1751 """
1752 if xdate:
1753 self.xaxis_date(tz)
1754 if ydate:
1755 self.yaxis_date(tz)
1756 return self.plot(x, y, fmt, **kwargs)
1758 # @_preprocess_data() # let 'plot' do the unpacking..
1759 @_docstring.dedent_interpd
1760 def loglog(self, *args, **kwargs):
1761 """
1762 Make a plot with log scaling on both the x and y axis.
1764 Call signatures::
1766 loglog([x], y, [fmt], data=None, **kwargs)
1767 loglog([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)
1769 This is just a thin wrapper around `.plot` which additionally changes
1770 both the x-axis and the y-axis to log scaling. All of the concepts and
1771 parameters of plot can be used here as well.
1773 The additional parameters *base*, *subs* and *nonpositive* control the
1774 x/y-axis properties. They are just forwarded to `.Axes.set_xscale` and
1775 `.Axes.set_yscale`. To use different properties on the x-axis and the
1776 y-axis, use e.g.
1777 ``ax.set_xscale("log", base=10); ax.set_yscale("log", base=2)``.
1779 Parameters
1780 ----------
1781 base : float, default: 10
1782 Base of the logarithm.
1784 subs : sequence, optional
1785 The location of the minor ticks. If *None*, reasonable locations
1786 are automatically chosen depending on the number of decades in the
1787 plot. See `.Axes.set_xscale`/`.Axes.set_yscale` for details.
1789 nonpositive : {'mask', 'clip'}, default: 'mask'
1790 Non-positive values can be masked as invalid, or clipped to a very
1791 small positive number.
1793 **kwargs
1794 All parameters supported by `.plot`.
1796 Returns
1797 -------
1798 list of `.Line2D`
1799 Objects representing the plotted data.
1800 """
1801 dx = {k: v for k, v in kwargs.items()
1802 if k in ['base', 'subs', 'nonpositive',
1803 'basex', 'subsx', 'nonposx']}
1804 self.set_xscale('log', **dx)
1805 dy = {k: v for k, v in kwargs.items()
1806 if k in ['base', 'subs', 'nonpositive',
1807 'basey', 'subsy', 'nonposy']}
1808 self.set_yscale('log', **dy)
1809 return self.plot(
1810 *args, **{k: v for k, v in kwargs.items() if k not in {*dx, *dy}})
1812 # @_preprocess_data() # let 'plot' do the unpacking..
1813 @_docstring.dedent_interpd
1814 def semilogx(self, *args, **kwargs):
1815 """
1816 Make a plot with log scaling on the x axis.
1818 Call signatures::
1820 semilogx([x], y, [fmt], data=None, **kwargs)
1821 semilogx([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)
1823 This is just a thin wrapper around `.plot` which additionally changes
1824 the x-axis to log scaling. All of the concepts and parameters of plot
1825 can be used here as well.
1827 The additional parameters *base*, *subs*, and *nonpositive* control the
1828 x-axis properties. They are just forwarded to `.Axes.set_xscale`.
1830 Parameters
1831 ----------
1832 base : float, default: 10
1833 Base of the x logarithm.
1835 subs : array-like, optional
1836 The location of the minor xticks. If *None*, reasonable locations
1837 are automatically chosen depending on the number of decades in the
1838 plot. See `.Axes.set_xscale` for details.
1840 nonpositive : {'mask', 'clip'}, default: 'mask'
1841 Non-positive values in x can be masked as invalid, or clipped to a
1842 very small positive number.
1844 **kwargs
1845 All parameters supported by `.plot`.
1847 Returns
1848 -------
1849 list of `.Line2D`
1850 Objects representing the plotted data.
1851 """
1852 d = {k: v for k, v in kwargs.items()
1853 if k in ['base', 'subs', 'nonpositive',
1854 'basex', 'subsx', 'nonposx']}
1855 self.set_xscale('log', **d)
1856 return self.plot(
1857 *args, **{k: v for k, v in kwargs.items() if k not in d})
1859 # @_preprocess_data() # let 'plot' do the unpacking..
1860 @_docstring.dedent_interpd
1861 def semilogy(self, *args, **kwargs):
1862 """
1863 Make a plot with log scaling on the y axis.
1865 Call signatures::
1867 semilogy([x], y, [fmt], data=None, **kwargs)
1868 semilogy([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)
1870 This is just a thin wrapper around `.plot` which additionally changes
1871 the y-axis to log scaling. All of the concepts and parameters of plot
1872 can be used here as well.
1874 The additional parameters *base*, *subs*, and *nonpositive* control the
1875 y-axis properties. They are just forwarded to `.Axes.set_yscale`.
1877 Parameters
1878 ----------
1879 base : float, default: 10
1880 Base of the y logarithm.
1882 subs : array-like, optional
1883 The location of the minor yticks. If *None*, reasonable locations
1884 are automatically chosen depending on the number of decades in the
1885 plot. See `.Axes.set_yscale` for details.
1887 nonpositive : {'mask', 'clip'}, default: 'mask'
1888 Non-positive values in y can be masked as invalid, or clipped to a
1889 very small positive number.
1891 **kwargs
1892 All parameters supported by `.plot`.
1894 Returns
1895 -------
1896 list of `.Line2D`
1897 Objects representing the plotted data.
1898 """
1899 d = {k: v for k, v in kwargs.items()
1900 if k in ['base', 'subs', 'nonpositive',
1901 'basey', 'subsy', 'nonposy']}
1902 self.set_yscale('log', **d)
1903 return self.plot(
1904 *args, **{k: v for k, v in kwargs.items() if k not in d})
1906 @_preprocess_data(replace_names=["x"], label_namer="x")
1907 def acorr(self, x, **kwargs):
1908 """
1909 Plot the autocorrelation of *x*.
1911 Parameters
1912 ----------
1913 x : array-like
1915 detrend : callable, default: `.mlab.detrend_none` (no detrending)
1916 A detrending function applied to *x*. It must have the
1917 signature ::
1919 detrend(x: np.ndarray) -> np.ndarray
1921 normed : bool, default: True
1922 If ``True``, input vectors are normalised to unit length.
1924 usevlines : bool, default: True
1925 Determines the plot style.
1927 If ``True``, vertical lines are plotted from 0 to the acorr value
1928 using `.Axes.vlines`. Additionally, a horizontal line is plotted
1929 at y=0 using `.Axes.axhline`.
1931 If ``False``, markers are plotted at the acorr values using
1932 `.Axes.plot`.
1934 maxlags : int, default: 10
1935 Number of lags to show. If ``None``, will return all
1936 ``2 * len(x) - 1`` lags.
1938 Returns
1939 -------
1940 lags : array (length ``2*maxlags+1``)
1941 The lag vector.
1942 c : array (length ``2*maxlags+1``)
1943 The auto correlation vector.
1944 line : `.LineCollection` or `.Line2D`
1945 `.Artist` added to the Axes of the correlation:
1947 - `.LineCollection` if *usevlines* is True.
1948 - `.Line2D` if *usevlines* is False.
1949 b : `.Line2D` or None
1950 Horizontal line at 0 if *usevlines* is True
1951 None *usevlines* is False.
1953 Other Parameters
1954 ----------------
1955 linestyle : `.Line2D` property, optional
1956 The linestyle for plotting the data points.
1957 Only used if *usevlines* is ``False``.
1959 marker : str, default: 'o'
1960 The marker for plotting the data points.
1961 Only used if *usevlines* is ``False``.
1963 data : indexable object, optional
1964 DATA_PARAMETER_PLACEHOLDER
1966 **kwargs
1967 Additional parameters are passed to `.Axes.vlines` and
1968 `.Axes.axhline` if *usevlines* is ``True``; otherwise they are
1969 passed to `.Axes.plot`.
1971 Notes
1972 -----
1973 The cross correlation is performed with `numpy.correlate` with
1974 ``mode = "full"``.
1975 """
1976 return self.xcorr(x, x, **kwargs)
1978 @_preprocess_data(replace_names=["x", "y"], label_namer="y")
1979 def xcorr(self, x, y, normed=True, detrend=mlab.detrend_none,
1980 usevlines=True, maxlags=10, **kwargs):
1981 r"""
1982 Plot the cross correlation between *x* and *y*.
1984 The correlation with lag k is defined as
1985 :math:`\sum_n x[n+k] \cdot y^*[n]`, where :math:`y^*` is the complex
1986 conjugate of :math:`y`.
1988 Parameters
1989 ----------
1990 x, y : array-like of length n
1992 detrend : callable, default: `.mlab.detrend_none` (no detrending)
1993 A detrending function applied to *x* and *y*. It must have the
1994 signature ::
1996 detrend(x: np.ndarray) -> np.ndarray
1998 normed : bool, default: True
1999 If ``True``, input vectors are normalised to unit length.
2001 usevlines : bool, default: True
2002 Determines the plot style.
2004 If ``True``, vertical lines are plotted from 0 to the xcorr value
2005 using `.Axes.vlines`. Additionally, a horizontal line is plotted
2006 at y=0 using `.Axes.axhline`.
2008 If ``False``, markers are plotted at the xcorr values using
2009 `.Axes.plot`.
2011 maxlags : int, default: 10
2012 Number of lags to show. If None, will return all ``2 * len(x) - 1``
2013 lags.
2015 Returns
2016 -------
2017 lags : array (length ``2*maxlags+1``)
2018 The lag vector.
2019 c : array (length ``2*maxlags+1``)
2020 The auto correlation vector.
2021 line : `.LineCollection` or `.Line2D`
2022 `.Artist` added to the Axes of the correlation:
2024 - `.LineCollection` if *usevlines* is True.
2025 - `.Line2D` if *usevlines* is False.
2026 b : `.Line2D` or None
2027 Horizontal line at 0 if *usevlines* is True
2028 None *usevlines* is False.
2030 Other Parameters
2031 ----------------
2032 linestyle : `.Line2D` property, optional
2033 The linestyle for plotting the data points.
2034 Only used if *usevlines* is ``False``.
2036 marker : str, default: 'o'
2037 The marker for plotting the data points.
2038 Only used if *usevlines* is ``False``.
2040 data : indexable object, optional
2041 DATA_PARAMETER_PLACEHOLDER
2043 **kwargs
2044 Additional parameters are passed to `.Axes.vlines` and
2045 `.Axes.axhline` if *usevlines* is ``True``; otherwise they are
2046 passed to `.Axes.plot`.
2048 Notes
2049 -----
2050 The cross correlation is performed with `numpy.correlate` with
2051 ``mode = "full"``.
2052 """
2053 Nx = len(x)
2054 if Nx != len(y):
2055 raise ValueError('x and y must be equal length')
2057 x = detrend(np.asarray(x))
2058 y = detrend(np.asarray(y))
2060 correls = np.correlate(x, y, mode="full")
2062 if normed:
2063 correls /= np.sqrt(np.dot(x, x) * np.dot(y, y))
2065 if maxlags is None:
2066 maxlags = Nx - 1
2068 if maxlags >= Nx or maxlags < 1:
2069 raise ValueError('maxlags must be None or strictly '
2070 'positive < %d' % Nx)
2072 lags = np.arange(-maxlags, maxlags + 1)
2073 correls = correls[Nx - 1 - maxlags:Nx + maxlags]
2075 if usevlines:
2076 a = self.vlines(lags, [0], correls, **kwargs)
2077 # Make label empty so only vertical lines get a legend entry
2078 kwargs.pop('label', '')
2079 b = self.axhline(**kwargs)
2080 else:
2081 kwargs.setdefault('marker', 'o')
2082 kwargs.setdefault('linestyle', 'None')
2083 a, = self.plot(lags, correls, **kwargs)
2084 b = None
2085 return lags, correls, a, b
2087 #### Specialized plotting
2089 # @_preprocess_data() # let 'plot' do the unpacking..
2090 def step(self, x, y, *args, where='pre', data=None, **kwargs):
2091 """
2092 Make a step plot.
2094 Call signatures::
2096 step(x, y, [fmt], *, data=None, where='pre', **kwargs)
2097 step(x, y, [fmt], x2, y2, [fmt2], ..., *, where='pre', **kwargs)
2099 This is just a thin wrapper around `.plot` which changes some
2100 formatting options. Most of the concepts and parameters of plot can be
2101 used here as well.
2103 .. note::
2105 This method uses a standard plot with a step drawstyle: The *x*
2106 values are the reference positions and steps extend left/right/both
2107 directions depending on *where*.
2109 For the common case where you know the values and edges of the
2110 steps, use `~.Axes.stairs` instead.
2112 Parameters
2113 ----------
2114 x : array-like
2115 1D sequence of x positions. It is assumed, but not checked, that
2116 it is uniformly increasing.
2118 y : array-like
2119 1D sequence of y levels.
2121 fmt : str, optional
2122 A format string, e.g. 'g' for a green line. See `.plot` for a more
2123 detailed description.
2125 Note: While full format strings are accepted, it is recommended to
2126 only specify the color. Line styles are currently ignored (use
2127 the keyword argument *linestyle* instead). Markers are accepted
2128 and plotted on the given positions, however, this is a rarely
2129 needed feature for step plots.
2131 where : {'pre', 'post', 'mid'}, default: 'pre'
2132 Define where the steps should be placed:
2134 - 'pre': The y value is continued constantly to the left from
2135 every *x* position, i.e. the interval ``(x[i-1], x[i]]`` has the
2136 value ``y[i]``.
2137 - 'post': The y value is continued constantly to the right from
2138 every *x* position, i.e. the interval ``[x[i], x[i+1])`` has the
2139 value ``y[i]``.
2140 - 'mid': Steps occur half-way between the *x* positions.
2142 data : indexable object, optional
2143 An object with labelled data. If given, provide the label names to
2144 plot in *x* and *y*.
2146 **kwargs
2147 Additional parameters are the same as those for `.plot`.
2149 Returns
2150 -------
2151 list of `.Line2D`
2152 Objects representing the plotted data.
2153 """
2154 _api.check_in_list(('pre', 'post', 'mid'), where=where)
2155 kwargs['drawstyle'] = 'steps-' + where
2156 return self.plot(x, y, *args, data=data, **kwargs)
2158 @staticmethod
2159 def _convert_dx(dx, x0, xconv, convert):
2160 """
2161 Small helper to do logic of width conversion flexibly.
2163 *dx* and *x0* have units, but *xconv* has already been converted
2164 to unitless (and is an ndarray). This allows the *dx* to have units
2165 that are different from *x0*, but are still accepted by the
2166 ``__add__`` operator of *x0*.
2167 """
2169 # x should be an array...
2170 assert type(xconv) is np.ndarray
2172 if xconv.size == 0:
2173 # xconv has already been converted, but maybe empty...
2174 return convert(dx)
2176 try:
2177 # attempt to add the width to x0; this works for
2178 # datetime+timedelta, for instance
2180 # only use the first element of x and x0. This saves
2181 # having to be sure addition works across the whole
2182 # vector. This is particularly an issue if
2183 # x0 and dx are lists so x0 + dx just concatenates the lists.
2184 # We can't just cast x0 and dx to numpy arrays because that
2185 # removes the units from unit packages like `pint` that
2186 # wrap numpy arrays.
2187 try:
2188 x0 = cbook._safe_first_finite(x0)
2189 except (TypeError, IndexError, KeyError):
2190 pass
2191 except StopIteration:
2192 # this means we found no finite element, fall back to first
2193 # element unconditionally
2194 x0 = cbook.safe_first_element(x0)
2196 try:
2197 x = cbook._safe_first_finite(xconv)
2198 except (TypeError, IndexError, KeyError):
2199 x = xconv
2200 except StopIteration:
2201 # this means we found no finite element, fall back to first
2202 # element unconditionally
2203 x = cbook.safe_first_element(xconv)
2205 delist = False
2206 if not np.iterable(dx):
2207 dx = [dx]
2208 delist = True
2209 dx = [convert(x0 + ddx) - x for ddx in dx]
2210 if delist:
2211 dx = dx[0]
2212 except (ValueError, TypeError, AttributeError):
2213 # if the above fails (for any reason) just fallback to what
2214 # we do by default and convert dx by itself.
2215 dx = convert(dx)
2216 return dx
2218 @_preprocess_data()
2219 @_docstring.dedent_interpd
2220 def bar(self, x, height, width=0.8, bottom=None, *, align="center",
2221 **kwargs):
2222 r"""
2223 Make a bar plot.
2225 The bars are positioned at *x* with the given *align*\ment. Their
2226 dimensions are given by *height* and *width*. The vertical baseline
2227 is *bottom* (default 0).
2229 Many parameters can take either a single value applying to all bars
2230 or a sequence of values, one for each bar.
2232 Parameters
2233 ----------
2234 x : float or array-like
2235 The x coordinates of the bars. See also *align* for the
2236 alignment of the bars to the coordinates.
2238 height : float or array-like
2239 The height(s) of the bars.
2241 width : float or array-like, default: 0.8
2242 The width(s) of the bars.
2244 bottom : float or array-like, default: 0
2245 The y coordinate(s) of the bottom side(s) of the bars.
2247 align : {'center', 'edge'}, default: 'center'
2248 Alignment of the bars to the *x* coordinates:
2250 - 'center': Center the base on the *x* positions.
2251 - 'edge': Align the left edges of the bars with the *x* positions.
2253 To align the bars on the right edge pass a negative *width* and
2254 ``align='edge'``.
2256 Returns
2257 -------
2258 `.BarContainer`
2259 Container with all the bars and optionally errorbars.
2261 Other Parameters
2262 ----------------
2263 color : color or list of color, optional
2264 The colors of the bar faces.
2266 edgecolor : color or list of color, optional
2267 The colors of the bar edges.
2269 linewidth : float or array-like, optional
2270 Width of the bar edge(s). If 0, don't draw edges.
2272 tick_label : str or list of str, optional
2273 The tick labels of the bars.
2274 Default: None (Use default numeric labels.)
2276 label : str or list of str, optional
2277 A single label is attached to the resulting `.BarContainer` as a
2278 label for the whole dataset.
2279 If a list is provided, it must be the same length as *x* and
2280 labels the individual bars. Repeated labels are not de-duplicated
2281 and will cause repeated label entries, so this is best used when
2282 bars also differ in style (e.g., by passing a list to *color*.)
2284 xerr, yerr : float or array-like of shape(N,) or shape(2, N), optional
2285 If not *None*, add horizontal / vertical errorbars to the bar tips.
2286 The values are +/- sizes relative to the data:
2288 - scalar: symmetric +/- values for all bars
2289 - shape(N,): symmetric +/- values for each bar
2290 - shape(2, N): Separate - and + values for each bar. First row
2291 contains the lower errors, the second row contains the upper
2292 errors.
2293 - *None*: No errorbar. (Default)
2295 See :doc:`/gallery/statistics/errorbar_features` for an example on
2296 the usage of *xerr* and *yerr*.
2298 ecolor : color or list of color, default: 'black'
2299 The line color of the errorbars.
2301 capsize : float, default: :rc:`errorbar.capsize`
2302 The length of the error bar caps in points.
2304 error_kw : dict, optional
2305 Dictionary of keyword arguments to be passed to the
2306 `~.Axes.errorbar` method. Values of *ecolor* or *capsize* defined
2307 here take precedence over the independent keyword arguments.
2309 log : bool, default: False
2310 If *True*, set the y-axis to be log scale.
2312 data : indexable object, optional
2313 DATA_PARAMETER_PLACEHOLDER
2315 **kwargs : `.Rectangle` properties
2317 %(Rectangle:kwdoc)s
2319 See Also
2320 --------
2321 barh : Plot a horizontal bar plot.
2323 Notes
2324 -----
2325 Stacked bars can be achieved by passing individual *bottom* values per
2326 bar. See :doc:`/gallery/lines_bars_and_markers/bar_stacked`.
2327 """
2328 kwargs = cbook.normalize_kwargs(kwargs, mpatches.Patch)
2329 color = kwargs.pop('color', None)
2330 if color is None:
2331 color = self._get_patches_for_fill.get_next_color()
2332 edgecolor = kwargs.pop('edgecolor', None)
2333 linewidth = kwargs.pop('linewidth', None)
2334 hatch = kwargs.pop('hatch', None)
2336 # Because xerr and yerr will be passed to errorbar, most dimension
2337 # checking and processing will be left to the errorbar method.
2338 xerr = kwargs.pop('xerr', None)
2339 yerr = kwargs.pop('yerr', None)
2340 error_kw = kwargs.pop('error_kw', {})
2341 ezorder = error_kw.pop('zorder', None)
2342 if ezorder is None:
2343 ezorder = kwargs.get('zorder', None)
2344 if ezorder is not None:
2345 # If using the bar zorder, increment slightly to make sure
2346 # errorbars are drawn on top of bars
2347 ezorder += 0.01
2348 error_kw.setdefault('zorder', ezorder)
2349 ecolor = kwargs.pop('ecolor', 'k')
2350 capsize = kwargs.pop('capsize', mpl.rcParams["errorbar.capsize"])
2351 error_kw.setdefault('ecolor', ecolor)
2352 error_kw.setdefault('capsize', capsize)
2354 # The keyword argument *orientation* is used by barh() to defer all
2355 # logic and drawing to bar(). It is considered internal and is
2356 # intentionally not mentioned in the docstring.
2357 orientation = kwargs.pop('orientation', 'vertical')
2358 _api.check_in_list(['vertical', 'horizontal'], orientation=orientation)
2359 log = kwargs.pop('log', False)
2360 label = kwargs.pop('label', '')
2361 tick_labels = kwargs.pop('tick_label', None)
2363 y = bottom # Matches barh call signature.
2364 if orientation == 'vertical':
2365 if y is None:
2366 y = 0
2367 else: # horizontal
2368 if x is None:
2369 x = 0
2371 if orientation == 'vertical':
2372 self._process_unit_info(
2373 [("x", x), ("y", height)], kwargs, convert=False)
2374 if log:
2375 self.set_yscale('log', nonpositive='clip')
2376 else: # horizontal
2377 self._process_unit_info(
2378 [("x", width), ("y", y)], kwargs, convert=False)
2379 if log:
2380 self.set_xscale('log', nonpositive='clip')
2382 # lets do some conversions now since some types cannot be
2383 # subtracted uniformly
2384 if self.xaxis is not None:
2385 x0 = x
2386 x = np.asarray(self.convert_xunits(x))
2387 width = self._convert_dx(width, x0, x, self.convert_xunits)
2388 if xerr is not None:
2389 xerr = self._convert_dx(xerr, x0, x, self.convert_xunits)
2390 if self.yaxis is not None:
2391 y0 = y
2392 y = np.asarray(self.convert_yunits(y))
2393 height = self._convert_dx(height, y0, y, self.convert_yunits)
2394 if yerr is not None:
2395 yerr = self._convert_dx(yerr, y0, y, self.convert_yunits)
2397 x, height, width, y, linewidth, hatch = np.broadcast_arrays(
2398 # Make args iterable too.
2399 np.atleast_1d(x), height, width, y, linewidth, hatch)
2401 # Now that units have been converted, set the tick locations.
2402 if orientation == 'vertical':
2403 tick_label_axis = self.xaxis
2404 tick_label_position = x
2405 else: # horizontal
2406 tick_label_axis = self.yaxis
2407 tick_label_position = y
2409 if not isinstance(label, str) and np.iterable(label):
2410 bar_container_label = '_nolegend_'
2411 patch_labels = label
2412 else:
2413 bar_container_label = label
2414 patch_labels = ['_nolegend_'] * len(x)
2415 if len(patch_labels) != len(x):
2416 raise ValueError(f'number of labels ({len(patch_labels)}) '
2417 f'does not match number of bars ({len(x)}).')
2419 linewidth = itertools.cycle(np.atleast_1d(linewidth))
2420 hatch = itertools.cycle(np.atleast_1d(hatch))
2421 color = itertools.chain(itertools.cycle(mcolors.to_rgba_array(color)),
2422 # Fallback if color == "none".
2423 itertools.repeat('none'))
2424 if edgecolor is None:
2425 edgecolor = itertools.repeat(None)
2426 else:
2427 edgecolor = itertools.chain(
2428 itertools.cycle(mcolors.to_rgba_array(edgecolor)),
2429 # Fallback if edgecolor == "none".
2430 itertools.repeat('none'))
2432 # We will now resolve the alignment and really have
2433 # left, bottom, width, height vectors
2434 _api.check_in_list(['center', 'edge'], align=align)
2435 if align == 'center':
2436 if orientation == 'vertical':
2437 try:
2438 left = x - width / 2
2439 except TypeError as e:
2440 raise TypeError(f'the dtypes of parameters x ({x.dtype}) '
2441 f'and width ({width.dtype}) '
2442 f'are incompatible') from e
2443 bottom = y
2444 else: # horizontal
2445 try:
2446 bottom = y - height / 2
2447 except TypeError as e:
2448 raise TypeError(f'the dtypes of parameters y ({y.dtype}) '
2449 f'and height ({height.dtype}) '
2450 f'are incompatible') from e
2451 left = x
2452 else: # edge
2453 left = x
2454 bottom = y
2456 patches = []
2457 args = zip(left, bottom, width, height, color, edgecolor, linewidth,
2458 hatch, patch_labels)
2459 for l, b, w, h, c, e, lw, htch, lbl in args:
2460 r = mpatches.Rectangle(
2461 xy=(l, b), width=w, height=h,
2462 facecolor=c,
2463 edgecolor=e,
2464 linewidth=lw,
2465 label=lbl,
2466 hatch=htch,
2467 )
2468 r._internal_update(kwargs)
2469 r.get_path()._interpolation_steps = 100
2470 if orientation == 'vertical':
2471 r.sticky_edges.y.append(b)
2472 else: # horizontal
2473 r.sticky_edges.x.append(l)
2474 self.add_patch(r)
2475 patches.append(r)
2477 if xerr is not None or yerr is not None:
2478 if orientation == 'vertical':
2479 # using list comps rather than arrays to preserve unit info
2480 ex = [l + 0.5 * w for l, w in zip(left, width)]
2481 ey = [b + h for b, h in zip(bottom, height)]
2483 else: # horizontal
2484 # using list comps rather than arrays to preserve unit info
2485 ex = [l + w for l, w in zip(left, width)]
2486 ey = [b + 0.5 * h for b, h in zip(bottom, height)]
2488 error_kw.setdefault("label", '_nolegend_')
2490 errorbar = self.errorbar(ex, ey,
2491 yerr=yerr, xerr=xerr,
2492 fmt='none', **error_kw)
2493 else:
2494 errorbar = None
2496 self._request_autoscale_view()
2498 if orientation == 'vertical':
2499 datavalues = height
2500 else: # horizontal
2501 datavalues = width
2503 bar_container = BarContainer(patches, errorbar, datavalues=datavalues,
2504 orientation=orientation,
2505 label=bar_container_label)
2506 self.add_container(bar_container)
2508 if tick_labels is not None:
2509 tick_labels = np.broadcast_to(tick_labels, len(patches))
2510 tick_label_axis.set_ticks(tick_label_position)
2511 tick_label_axis.set_ticklabels(tick_labels)
2513 return bar_container
2515 # @_preprocess_data() # let 'bar' do the unpacking..
2516 @_docstring.dedent_interpd
2517 def barh(self, y, width, height=0.8, left=None, *, align="center",
2518 data=None, **kwargs):
2519 r"""
2520 Make a horizontal bar plot.
2522 The bars are positioned at *y* with the given *align*\ment. Their
2523 dimensions are given by *width* and *height*. The horizontal baseline
2524 is *left* (default 0).
2526 Many parameters can take either a single value applying to all bars
2527 or a sequence of values, one for each bar.
2529 Parameters
2530 ----------
2531 y : float or array-like
2532 The y coordinates of the bars. See also *align* for the
2533 alignment of the bars to the coordinates.
2535 width : float or array-like
2536 The width(s) of the bars.
2538 height : float or array-like, default: 0.8
2539 The heights of the bars.
2541 left : float or array-like, default: 0
2542 The x coordinates of the left side(s) of the bars.
2544 align : {'center', 'edge'}, default: 'center'
2545 Alignment of the base to the *y* coordinates*:
2547 - 'center': Center the bars on the *y* positions.
2548 - 'edge': Align the bottom edges of the bars with the *y*
2549 positions.
2551 To align the bars on the top edge pass a negative *height* and
2552 ``align='edge'``.
2554 Returns
2555 -------
2556 `.BarContainer`
2557 Container with all the bars and optionally errorbars.
2559 Other Parameters
2560 ----------------
2561 color : color or list of color, optional
2562 The colors of the bar faces.
2564 edgecolor : color or list of color, optional
2565 The colors of the bar edges.
2567 linewidth : float or array-like, optional
2568 Width of the bar edge(s). If 0, don't draw edges.
2570 tick_label : str or list of str, optional
2571 The tick labels of the bars.
2572 Default: None (Use default numeric labels.)
2574 label : str or list of str, optional
2575 A single label is attached to the resulting `.BarContainer` as a
2576 label for the whole dataset.
2577 If a list is provided, it must be the same length as *y* and
2578 labels the individual bars. Repeated labels are not de-duplicated
2579 and will cause repeated label entries, so this is best used when
2580 bars also differ in style (e.g., by passing a list to *color*.)
2582 xerr, yerr : float or array-like of shape(N,) or shape(2, N), optional
2583 If not *None*, add horizontal / vertical errorbars to the bar tips.
2584 The values are +/- sizes relative to the data:
2586 - scalar: symmetric +/- values for all bars
2587 - shape(N,): symmetric +/- values for each bar
2588 - shape(2, N): Separate - and + values for each bar. First row
2589 contains the lower errors, the second row contains the upper
2590 errors.
2591 - *None*: No errorbar. (default)
2593 See :doc:`/gallery/statistics/errorbar_features` for an example on
2594 the usage of *xerr* and *yerr*.
2596 ecolor : color or list of color, default: 'black'
2597 The line color of the errorbars.
2599 capsize : float, default: :rc:`errorbar.capsize`
2600 The length of the error bar caps in points.
2602 error_kw : dict, optional
2603 Dictionary of keyword arguments to be passed to the
2604 `~.Axes.errorbar` method. Values of *ecolor* or *capsize* defined
2605 here take precedence over the independent keyword arguments.
2607 log : bool, default: False
2608 If ``True``, set the x-axis to be log scale.
2610 data : indexable object, optional
2611 If given, all parameters also accept a string ``s``, which is
2612 interpreted as ``data[s]`` (unless this raises an exception).
2614 **kwargs : `.Rectangle` properties
2616 %(Rectangle:kwdoc)s
2618 See Also
2619 --------
2620 bar : Plot a vertical bar plot.
2622 Notes
2623 -----
2624 Stacked bars can be achieved by passing individual *left* values per
2625 bar. See
2626 :doc:`/gallery/lines_bars_and_markers/horizontal_barchart_distribution`.
2627 """
2628 kwargs.setdefault('orientation', 'horizontal')
2629 patches = self.bar(x=left, height=height, width=width, bottom=y,
2630 align=align, data=data, **kwargs)
2631 return patches
2633 def bar_label(self, container, labels=None, *, fmt="%g", label_type="edge",
2634 padding=0, **kwargs):
2635 """
2636 Label a bar plot.
2638 Adds labels to bars in the given `.BarContainer`.
2639 You may need to adjust the axis limits to fit the labels.
2641 Parameters
2642 ----------
2643 container : `.BarContainer`
2644 Container with all the bars and optionally errorbars, likely
2645 returned from `.bar` or `.barh`.
2647 labels : array-like, optional
2648 A list of label texts, that should be displayed. If not given, the
2649 label texts will be the data values formatted with *fmt*.
2651 fmt : str, default: '%g'
2652 A format string for the label.
2654 label_type : {'edge', 'center'}, default: 'edge'
2655 The label type. Possible values:
2657 - 'edge': label placed at the end-point of the bar segment, and the
2658 value displayed will be the position of that end-point.
2659 - 'center': label placed in the center of the bar segment, and the
2660 value displayed will be the length of that segment.
2661 (useful for stacked bars, i.e.,
2662 :doc:`/gallery/lines_bars_and_markers/bar_label_demo`)
2664 padding : float, default: 0
2665 Distance of label from the end of the bar, in points.
2667 **kwargs
2668 Any remaining keyword arguments are passed through to
2669 `.Axes.annotate`. The alignment parameters (
2670 *horizontalalignment* / *ha*, *verticalalignment* / *va*) are
2671 not supported because the labels are automatically aligned to
2672 the bars.
2674 Returns
2675 -------
2676 list of `.Text`
2677 A list of `.Text` instances for the labels.
2678 """
2679 for key in ['horizontalalignment', 'ha', 'verticalalignment', 'va']:
2680 if key in kwargs:
2681 raise ValueError(
2682 f"Passing {key!r} to bar_label() is not supported.")
2684 a, b = self.yaxis.get_view_interval()
2685 y_inverted = a > b
2686 c, d = self.xaxis.get_view_interval()
2687 x_inverted = c > d
2689 # want to know whether to put label on positive or negative direction
2690 # cannot use np.sign here because it will return 0 if x == 0
2691 def sign(x):
2692 return 1 if x >= 0 else -1
2694 _api.check_in_list(['edge', 'center'], label_type=label_type)
2696 bars = container.patches
2697 errorbar = container.errorbar
2698 datavalues = container.datavalues
2699 orientation = container.orientation
2701 if errorbar:
2702 # check "ErrorbarContainer" for the definition of these elements
2703 lines = errorbar.lines # attribute of "ErrorbarContainer" (tuple)
2704 barlinecols = lines[2] # 0: data_line, 1: caplines, 2: barlinecols
2705 barlinecol = barlinecols[0] # the "LineCollection" of error bars
2706 errs = barlinecol.get_segments()
2707 else:
2708 errs = []
2710 if labels is None:
2711 labels = []
2713 annotations = []
2715 for bar, err, dat, lbl in itertools.zip_longest(
2716 bars, errs, datavalues, labels
2717 ):
2718 (x0, y0), (x1, y1) = bar.get_bbox().get_points()
2719 xc, yc = (x0 + x1) / 2, (y0 + y1) / 2
2721 if orientation == "vertical":
2722 extrema = max(y0, y1) if dat >= 0 else min(y0, y1)
2723 length = abs(y0 - y1)
2724 else: # horizontal
2725 extrema = max(x0, x1) if dat >= 0 else min(x0, x1)
2726 length = abs(x0 - x1)
2728 if err is None or np.size(err) == 0:
2729 endpt = extrema
2730 elif orientation == "vertical":
2731 endpt = err[:, 1].max() if dat >= 0 else err[:, 1].min()
2732 else: # horizontal
2733 endpt = err[:, 0].max() if dat >= 0 else err[:, 0].min()
2735 if label_type == "center":
2736 value = sign(dat) * length
2737 else: # edge
2738 value = extrema
2740 if label_type == "center":
2741 xy = xc, yc
2742 else: # edge
2743 if orientation == "vertical":
2744 xy = xc, endpt
2745 else: # horizontal
2746 xy = endpt, yc
2748 if orientation == "vertical":
2749 y_direction = -1 if y_inverted else 1
2750 xytext = 0, y_direction * sign(dat) * padding
2751 else: # horizontal
2752 x_direction = -1 if x_inverted else 1
2753 xytext = x_direction * sign(dat) * padding, 0
2755 if label_type == "center":
2756 ha, va = "center", "center"
2757 else: # edge
2758 if orientation == "vertical":
2759 ha = 'center'
2760 if y_inverted:
2761 va = 'top' if dat > 0 else 'bottom' # also handles NaN
2762 else:
2763 va = 'top' if dat < 0 else 'bottom' # also handles NaN
2764 else: # horizontal
2765 if x_inverted:
2766 ha = 'right' if dat > 0 else 'left' # also handles NaN
2767 else:
2768 ha = 'right' if dat < 0 else 'left' # also handles NaN
2769 va = 'center'
2771 if np.isnan(dat):
2772 lbl = ''
2774 annotation = self.annotate(fmt % value if lbl is None else lbl,
2775 xy, xytext, textcoords="offset points",
2776 ha=ha, va=va, **kwargs)
2777 annotations.append(annotation)
2779 return annotations
2781 @_preprocess_data()
2782 @_docstring.dedent_interpd
2783 def broken_barh(self, xranges, yrange, **kwargs):
2784 """
2785 Plot a horizontal sequence of rectangles.
2787 A rectangle is drawn for each element of *xranges*. All rectangles
2788 have the same vertical position and size defined by *yrange*.
2790 This is a convenience function for instantiating a
2791 `.BrokenBarHCollection`, adding it to the Axes and autoscaling the
2792 view.
2794 Parameters
2795 ----------
2796 xranges : sequence of tuples (*xmin*, *xwidth*)
2797 The x-positions and extends of the rectangles. For each tuple
2798 (*xmin*, *xwidth*) a rectangle is drawn from *xmin* to *xmin* +
2799 *xwidth*.
2800 yrange : (*ymin*, *yheight*)
2801 The y-position and extend for all the rectangles.
2803 Returns
2804 -------
2805 `~.collections.BrokenBarHCollection`
2807 Other Parameters
2808 ----------------
2809 data : indexable object, optional
2810 DATA_PARAMETER_PLACEHOLDER
2811 **kwargs : `.BrokenBarHCollection` properties
2813 Each *kwarg* can be either a single argument applying to all
2814 rectangles, e.g.::
2816 facecolors='black'
2818 or a sequence of arguments over which is cycled, e.g.::
2820 facecolors=('black', 'blue')
2822 would create interleaving black and blue rectangles.
2824 Supported keywords:
2826 %(BrokenBarHCollection:kwdoc)s
2827 """
2828 # process the unit information
2829 if len(xranges):
2830 xdata = cbook._safe_first_finite(xranges)
2831 else:
2832 xdata = None
2833 if len(yrange):
2834 ydata = cbook._safe_first_finite(yrange)
2835 else:
2836 ydata = None
2837 self._process_unit_info(
2838 [("x", xdata), ("y", ydata)], kwargs, convert=False)
2839 xranges_conv = []
2840 for xr in xranges:
2841 if len(xr) != 2:
2842 raise ValueError('each range in xrange must be a sequence '
2843 'with two elements (i.e. an Nx2 array)')
2844 # convert the absolute values, not the x and dx...
2845 x_conv = np.asarray(self.convert_xunits(xr[0]))
2846 x1 = self._convert_dx(xr[1], xr[0], x_conv, self.convert_xunits)
2847 xranges_conv.append((x_conv, x1))
2849 yrange_conv = self.convert_yunits(yrange)
2851 col = mcoll.BrokenBarHCollection(xranges_conv, yrange_conv, **kwargs)
2852 self.add_collection(col, autolim=True)
2853 self._request_autoscale_view()
2855 return col
2857 @_preprocess_data()
2858 @_api.delete_parameter("3.6", "use_line_collection")
2859 def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None, bottom=0,
2860 label=None, use_line_collection=True, orientation='vertical'):
2861 """
2862 Create a stem plot.
2864 A stem plot draws lines perpendicular to a baseline at each location
2865 *locs* from the baseline to *heads*, and places a marker there. For
2866 vertical stem plots (the default), the *locs* are *x* positions, and
2867 the *heads* are *y* values. For horizontal stem plots, the *locs* are
2868 *y* positions, and the *heads* are *x* values.
2870 Call signature::
2872 stem([locs,] heads, linefmt=None, markerfmt=None, basefmt=None)
2874 The *locs*-positions are optional. The formats may be provided either
2875 as positional or as keyword-arguments.
2876 Passing *markerfmt* and *basefmt* positionally is deprecated since
2877 Matplotlib 3.5.
2879 Parameters
2880 ----------
2881 locs : array-like, default: (0, 1, ..., len(heads) - 1)
2882 For vertical stem plots, the x-positions of the stems.
2883 For horizontal stem plots, the y-positions of the stems.
2885 heads : array-like
2886 For vertical stem plots, the y-values of the stem heads.
2887 For horizontal stem plots, the x-values of the stem heads.
2889 linefmt : str, optional
2890 A string defining the color and/or linestyle of the vertical lines:
2892 ========= =============
2893 Character Line Style
2894 ========= =============
2895 ``'-'`` solid line
2896 ``'--'`` dashed line
2897 ``'-.'`` dash-dot line
2898 ``':'`` dotted line
2899 ========= =============
2901 Default: 'C0-', i.e. solid line with the first color of the color
2902 cycle.
2904 Note: Markers specified through this parameter (e.g. 'x') will be
2905 silently ignored (unless using ``use_line_collection=False``).
2906 Instead, markers should be specified using *markerfmt*.
2908 markerfmt : str, optional
2909 A string defining the color and/or shape of the markers at the stem
2910 heads. If the marker is not given, use the marker 'o', i.e. filled
2911 circles. If the color is not given, use the color from *linefmt*.
2913 basefmt : str, default: 'C3-' ('C2-' in classic mode)
2914 A format string defining the properties of the baseline.
2916 orientation : {'vertical', 'horizontal'}, default: 'vertical'
2917 If 'vertical', will produce a plot with stems oriented vertically,
2918 If 'horizontal', the stems will be oriented horizontally.
2920 bottom : float, default: 0
2921 The y/x-position of the baseline (depending on orientation).
2923 label : str, default: None
2924 The label to use for the stems in legends.
2926 use_line_collection : bool, default: True
2927 *Deprecated since 3.6*
2929 If ``True``, store and plot the stem lines as a
2930 `~.collections.LineCollection` instead of individual lines, which
2931 significantly increases performance. If ``False``, defaults to the
2932 old behavior of using a list of `.Line2D` objects.
2934 data : indexable object, optional
2935 DATA_PARAMETER_PLACEHOLDER
2937 Returns
2938 -------
2939 `.StemContainer`
2940 The container may be treated like a tuple
2941 (*markerline*, *stemlines*, *baseline*)
2943 Notes
2944 -----
2945 .. seealso::
2946 The MATLAB function
2947 `stem <https://www.mathworks.com/help/matlab/ref/stem.html>`_
2948 which inspired this method.
2949 """
2950 if not 1 <= len(args) <= 5:
2951 raise TypeError('stem expected between 1 and 5 positional '
2952 'arguments, got {}'.format(args))
2953 _api.check_in_list(['horizontal', 'vertical'], orientation=orientation)
2955 if len(args) == 1:
2956 heads, = args
2957 locs = np.arange(len(heads))
2958 args = ()
2959 elif isinstance(args[1], str):
2960 heads, *args = args
2961 locs = np.arange(len(heads))
2962 else:
2963 locs, heads, *args = args
2964 if len(args) > 1:
2965 _api.warn_deprecated(
2966 "3.5",
2967 message="Passing the markerfmt parameter positionally is "
2968 "deprecated since Matplotlib %(since)s; the "
2969 "parameter will become keyword-only %(removal)s.")
2971 if orientation == 'vertical':
2972 locs, heads = self._process_unit_info([("x", locs), ("y", heads)])
2973 else: # horizontal
2974 heads, locs = self._process_unit_info([("x", heads), ("y", locs)])
2976 # resolve line format
2977 if linefmt is None:
2978 linefmt = args[0] if len(args) > 0 else "C0-"
2979 linestyle, linemarker, linecolor = _process_plot_format(linefmt)
2981 # resolve marker format
2982 if markerfmt is None:
2983 # if not given as kwarg, check for positional or fall back to 'o'
2984 markerfmt = args[1] if len(args) > 1 else "o"
2985 if markerfmt == '':
2986 markerfmt = ' ' # = empty line style; '' would resolve rcParams
2987 markerstyle, markermarker, markercolor = \
2988 _process_plot_format(markerfmt)
2989 if markermarker is None:
2990 markermarker = 'o'
2991 if markerstyle is None:
2992 markerstyle = 'None'
2993 if markercolor is None:
2994 markercolor = linecolor
2996 # resolve baseline format
2997 if basefmt is None:
2998 basefmt = (args[2] if len(args) > 2 else
2999 "C2-" if mpl.rcParams["_internal.classic_mode"] else
3000 "C3-")
3001 basestyle, basemarker, basecolor = _process_plot_format(basefmt)
3003 # New behaviour in 3.1 is to use a LineCollection for the stemlines
3004 if use_line_collection:
3005 if linestyle is None:
3006 linestyle = mpl.rcParams['lines.linestyle']
3007 xlines = self.vlines if orientation == "vertical" else self.hlines
3008 stemlines = xlines(
3009 locs, bottom, heads,
3010 colors=linecolor, linestyles=linestyle, label="_nolegend_")
3011 # Old behaviour is to plot each of the lines individually
3012 else:
3013 stemlines = []
3014 for loc, head in zip(locs, heads):
3015 if orientation == 'horizontal':
3016 xs = [bottom, head]
3017 ys = [loc, loc]
3018 else:
3019 xs = [loc, loc]
3020 ys = [bottom, head]
3021 l, = self.plot(xs, ys,
3022 color=linecolor, linestyle=linestyle,
3023 marker=linemarker, label="_nolegend_")
3024 stemlines.append(l)
3026 if orientation == 'horizontal':
3027 marker_x = heads
3028 marker_y = locs
3029 baseline_x = [bottom, bottom]
3030 baseline_y = [np.min(locs), np.max(locs)]
3031 else:
3032 marker_x = locs
3033 marker_y = heads
3034 baseline_x = [np.min(locs), np.max(locs)]
3035 baseline_y = [bottom, bottom]
3037 markerline, = self.plot(marker_x, marker_y,
3038 color=markercolor, linestyle=markerstyle,
3039 marker=markermarker, label="_nolegend_")
3041 baseline, = self.plot(baseline_x, baseline_y,
3042 color=basecolor, linestyle=basestyle,
3043 marker=basemarker, label="_nolegend_")
3045 stem_container = StemContainer((markerline, stemlines, baseline),
3046 label=label)
3047 self.add_container(stem_container)
3048 return stem_container
3050 @_preprocess_data(replace_names=["x", "explode", "labels", "colors"])
3051 def pie(self, x, explode=None, labels=None, colors=None,
3052 autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1,
3053 startangle=0, radius=1, counterclock=True,
3054 wedgeprops=None, textprops=None, center=(0, 0),
3055 frame=False, rotatelabels=False, *, normalize=True):
3056 """
3057 Plot a pie chart.
3059 Make a pie chart of array *x*. The fractional area of each wedge is
3060 given by ``x/sum(x)``.
3062 The wedges are plotted counterclockwise, by default starting from the
3063 x-axis.
3065 Parameters
3066 ----------
3067 x : 1D array-like
3068 The wedge sizes.
3070 explode : array-like, default: None
3071 If not *None*, is a ``len(x)`` array which specifies the fraction
3072 of the radius with which to offset each wedge.
3074 labels : list, default: None
3075 A sequence of strings providing the labels for each wedge
3077 colors : array-like, default: None
3078 A sequence of colors through which the pie chart will cycle. If
3079 *None*, will use the colors in the currently active cycle.
3081 autopct : None or str or callable, default: None
3082 If not *None*, is a string or function used to label the wedges
3083 with their numeric value. The label will be placed inside the
3084 wedge. If it is a format string, the label will be ``fmt % pct``.
3085 If it is a function, it will be called.
3087 pctdistance : float, default: 0.6
3088 The ratio between the center of each pie slice and the start of
3089 the text generated by *autopct*. Ignored if *autopct* is *None*.
3091 shadow : bool, default: False
3092 Draw a shadow beneath the pie.
3094 normalize : bool, default: True
3095 When *True*, always make a full pie by normalizing x so that
3096 ``sum(x) == 1``. *False* makes a partial pie if ``sum(x) <= 1``
3097 and raises a `ValueError` for ``sum(x) > 1``.
3099 labeldistance : float or None, default: 1.1
3100 The radial distance at which the pie labels are drawn.
3101 If set to ``None``, label are not drawn, but are stored for use in
3102 ``legend()``
3104 startangle : float, default: 0 degrees
3105 The angle by which the start of the pie is rotated,
3106 counterclockwise from the x-axis.
3108 radius : float, default: 1
3109 The radius of the pie.
3111 counterclock : bool, default: True
3112 Specify fractions direction, clockwise or counterclockwise.
3114 wedgeprops : dict, default: None
3115 Dict of arguments passed to the wedge objects making the pie.
3116 For example, you can pass in ``wedgeprops = {'linewidth': 3}``
3117 to set the width of the wedge border lines equal to 3.
3118 For more details, look at the doc/arguments of the wedge object.
3119 By default ``clip_on=False``.
3121 textprops : dict, default: None
3122 Dict of arguments to pass to the text objects.
3124 center : (float, float), default: (0, 0)
3125 The coordinates of the center of the chart.
3127 frame : bool, default: False
3128 Plot Axes frame with the chart if true.
3130 rotatelabels : bool, default: False
3131 Rotate each label to the angle of the corresponding slice if true.
3133 data : indexable object, optional
3134 DATA_PARAMETER_PLACEHOLDER
3136 Returns
3137 -------
3138 patches : list
3139 A sequence of `matplotlib.patches.Wedge` instances
3141 texts : list
3142 A list of the label `.Text` instances.
3144 autotexts : list
3145 A list of `.Text` instances for the numeric labels. This will only
3146 be returned if the parameter *autopct* is not *None*.
3148 Notes
3149 -----
3150 The pie chart will probably look best if the figure and Axes are
3151 square, or the Axes aspect is equal.
3152 This method sets the aspect ratio of the axis to "equal".
3153 The Axes aspect ratio can be controlled with `.Axes.set_aspect`.
3154 """
3155 self.set_aspect('equal')
3156 # The use of float32 is "historical", but can't be changed without
3157 # regenerating the test baselines.
3158 x = np.asarray(x, np.float32)
3159 if x.ndim > 1:
3160 raise ValueError("x must be 1D")
3162 if np.any(x < 0):
3163 raise ValueError("Wedge sizes 'x' must be non negative values")
3165 sx = x.sum()
3167 if normalize:
3168 x = x / sx
3169 elif sx > 1:
3170 raise ValueError('Cannot plot an unnormalized pie with sum(x) > 1')
3171 if labels is None:
3172 labels = [''] * len(x)
3173 if explode is None:
3174 explode = [0] * len(x)
3175 if len(x) != len(labels):
3176 raise ValueError("'label' must be of length 'x'")
3177 if len(x) != len(explode):
3178 raise ValueError("'explode' must be of length 'x'")
3179 if colors is None:
3180 get_next_color = self._get_patches_for_fill.get_next_color
3181 else:
3182 color_cycle = itertools.cycle(colors)
3184 def get_next_color():
3185 return next(color_cycle)
3187 _api.check_isinstance(Number, radius=radius, startangle=startangle)
3188 if radius <= 0:
3189 raise ValueError(f'radius must be a positive number, not {radius}')
3191 # Starting theta1 is the start fraction of the circle
3192 theta1 = startangle / 360
3194 if wedgeprops is None:
3195 wedgeprops = {}
3196 if textprops is None:
3197 textprops = {}
3199 texts = []
3200 slices = []
3201 autotexts = []
3203 for frac, label, expl in zip(x, labels, explode):
3204 x, y = center
3205 theta2 = (theta1 + frac) if counterclock else (theta1 - frac)
3206 thetam = 2 * np.pi * 0.5 * (theta1 + theta2)
3207 x += expl * math.cos(thetam)
3208 y += expl * math.sin(thetam)
3210 w = mpatches.Wedge((x, y), radius, 360. * min(theta1, theta2),
3211 360. * max(theta1, theta2),
3212 facecolor=get_next_color(),
3213 clip_on=False,
3214 label=label)
3215 w.set(**wedgeprops)
3216 slices.append(w)
3217 self.add_patch(w)
3219 if shadow:
3220 # Make sure to add a shadow after the call to add_patch so the
3221 # figure and transform props will be set.
3222 shad = mpatches.Shadow(w, -0.02, -0.02, label='_nolegend_')
3223 self.add_patch(shad)
3225 if labeldistance is not None:
3226 xt = x + labeldistance * radius * math.cos(thetam)
3227 yt = y + labeldistance * radius * math.sin(thetam)
3228 label_alignment_h = 'left' if xt > 0 else 'right'
3229 label_alignment_v = 'center'
3230 label_rotation = 'horizontal'
3231 if rotatelabels:
3232 label_alignment_v = 'bottom' if yt > 0 else 'top'
3233 label_rotation = (np.rad2deg(thetam)
3234 + (0 if xt > 0 else 180))
3235 t = self.text(xt, yt, label,
3236 clip_on=False,
3237 horizontalalignment=label_alignment_h,
3238 verticalalignment=label_alignment_v,
3239 rotation=label_rotation,
3240 size=mpl.rcParams['xtick.labelsize'])
3241 t.set(**textprops)
3242 texts.append(t)
3244 if autopct is not None:
3245 xt = x + pctdistance * radius * math.cos(thetam)
3246 yt = y + pctdistance * radius * math.sin(thetam)
3247 if isinstance(autopct, str):
3248 s = autopct % (100. * frac)
3249 elif callable(autopct):
3250 s = autopct(100. * frac)
3251 else:
3252 raise TypeError(
3253 'autopct must be callable or a format string')
3254 t = self.text(xt, yt, s,
3255 clip_on=False,
3256 horizontalalignment='center',
3257 verticalalignment='center')
3258 t.set(**textprops)
3259 autotexts.append(t)
3261 theta1 = theta2
3263 if frame:
3264 self._request_autoscale_view()
3265 else:
3266 self.set(frame_on=False, xticks=[], yticks=[],
3267 xlim=(-1.25 + center[0], 1.25 + center[0]),
3268 ylim=(-1.25 + center[1], 1.25 + center[1]))
3270 if autopct is None:
3271 return slices, texts
3272 else:
3273 return slices, texts, autotexts
3275 @staticmethod
3276 def _errorevery_to_mask(x, errorevery):
3277 """
3278 Normalize `errorbar`'s *errorevery* to be a boolean mask for data *x*.
3280 This function is split out to be usable both by 2D and 3D errorbars.
3281 """
3282 if isinstance(errorevery, Integral):
3283 errorevery = (0, errorevery)
3284 if isinstance(errorevery, tuple):
3285 if (len(errorevery) == 2 and
3286 isinstance(errorevery[0], Integral) and
3287 isinstance(errorevery[1], Integral)):
3288 errorevery = slice(errorevery[0], None, errorevery[1])
3289 else:
3290 raise ValueError(
3291 f'{errorevery=!r} is a not a tuple of two integers')
3292 elif isinstance(errorevery, slice):
3293 pass
3294 elif not isinstance(errorevery, str) and np.iterable(errorevery):
3295 try:
3296 x[errorevery] # fancy indexing
3297 except (ValueError, IndexError) as err:
3298 raise ValueError(
3299 f"{errorevery=!r} is iterable but not a valid NumPy fancy "
3300 "index to match 'xerr'/'yerr'") from err
3301 else:
3302 raise ValueError(f"{errorevery=!r} is not a recognized value")
3303 everymask = np.zeros(len(x), bool)
3304 everymask[errorevery] = True
3305 return everymask
3307 @_preprocess_data(replace_names=["x", "y", "xerr", "yerr"],
3308 label_namer="y")
3309 @_docstring.dedent_interpd
3310 def errorbar(self, x, y, yerr=None, xerr=None,
3311 fmt='', ecolor=None, elinewidth=None, capsize=None,
3312 barsabove=False, lolims=False, uplims=False,
3313 xlolims=False, xuplims=False, errorevery=1, capthick=None,
3314 **kwargs):
3315 """
3316 Plot y versus x as lines and/or markers with attached errorbars.
3318 *x*, *y* define the data locations, *xerr*, *yerr* define the errorbar
3319 sizes. By default, this draws the data markers/lines as well the
3320 errorbars. Use fmt='none' to draw errorbars without any data markers.
3322 Parameters
3323 ----------
3324 x, y : float or array-like
3325 The data positions.
3327 xerr, yerr : float or array-like, shape(N,) or shape(2, N), optional
3328 The errorbar sizes:
3330 - scalar: Symmetric +/- values for all data points.
3331 - shape(N,): Symmetric +/-values for each data point.
3332 - shape(2, N): Separate - and + values for each bar. First row
3333 contains the lower errors, the second row contains the upper
3334 errors.
3335 - *None*: No errorbar.
3337 All values must be >= 0.
3339 See :doc:`/gallery/statistics/errorbar_features`
3340 for an example on the usage of ``xerr`` and ``yerr``.
3342 fmt : str, default: ''
3343 The format for the data points / data lines. See `.plot` for
3344 details.
3346 Use 'none' (case insensitive) to plot errorbars without any data
3347 markers.
3349 ecolor : color, default: None
3350 The color of the errorbar lines. If None, use the color of the
3351 line connecting the markers.
3353 elinewidth : float, default: None
3354 The linewidth of the errorbar lines. If None, the linewidth of
3355 the current style is used.
3357 capsize : float, default: :rc:`errorbar.capsize`
3358 The length of the error bar caps in points.
3360 capthick : float, default: None
3361 An alias to the keyword argument *markeredgewidth* (a.k.a. *mew*).
3362 This setting is a more sensible name for the property that
3363 controls the thickness of the error bar cap in points. For
3364 backwards compatibility, if *mew* or *markeredgewidth* are given,
3365 then they will over-ride *capthick*. This may change in future
3366 releases.
3368 barsabove : bool, default: False
3369 If True, will plot the errorbars above the plot
3370 symbols. Default is below.
3372 lolims, uplims, xlolims, xuplims : bool, default: False
3373 These arguments can be used to indicate that a value gives only
3374 upper/lower limits. In that case a caret symbol is used to
3375 indicate this. *lims*-arguments may be scalars, or array-likes of
3376 the same length as *xerr* and *yerr*. To use limits with inverted
3377 axes, `~.Axes.set_xlim` or `~.Axes.set_ylim` must be called before
3378 :meth:`errorbar`. Note the tricky parameter names: setting e.g.
3379 *lolims* to True means that the y-value is a *lower* limit of the
3380 True value, so, only an *upward*-pointing arrow will be drawn!
3382 errorevery : int or (int, int), default: 1
3383 draws error bars on a subset of the data. *errorevery* =N draws
3384 error bars on the points (x[::N], y[::N]).
3385 *errorevery* =(start, N) draws error bars on the points
3386 (x[start::N], y[start::N]). e.g. errorevery=(6, 3)
3387 adds error bars to the data at (x[6], x[9], x[12], x[15], ...).
3388 Used to avoid overlapping error bars when two series share x-axis
3389 values.
3391 Returns
3392 -------
3393 `.ErrorbarContainer`
3394 The container contains:
3396 - plotline: `.Line2D` instance of x, y plot markers and/or line.
3397 - caplines: A tuple of `.Line2D` instances of the error bar caps.
3398 - barlinecols: A tuple of `.LineCollection` with the horizontal and
3399 vertical error ranges.
3401 Other Parameters
3402 ----------------
3403 data : indexable object, optional
3404 DATA_PARAMETER_PLACEHOLDER
3406 **kwargs
3407 All other keyword arguments are passed on to the `~.Axes.plot` call
3408 drawing the markers. For example, this code makes big red squares
3409 with thick green edges::
3411 x, y, yerr = rand(3, 10)
3412 errorbar(x, y, yerr, marker='s', mfc='red',
3413 mec='green', ms=20, mew=4)
3415 where *mfc*, *mec*, *ms* and *mew* are aliases for the longer
3416 property names, *markerfacecolor*, *markeredgecolor*, *markersize*
3417 and *markeredgewidth*.
3419 Valid kwargs for the marker properties are:
3421 - *dashes*
3422 - *dash_capstyle*
3423 - *dash_joinstyle*
3424 - *drawstyle*
3425 - *fillstyle*
3426 - *linestyle*
3427 - *marker*
3428 - *markeredgecolor*
3429 - *markeredgewidth*
3430 - *markerfacecolor*
3431 - *markerfacecoloralt*
3432 - *markersize*
3433 - *markevery*
3434 - *solid_capstyle*
3435 - *solid_joinstyle*
3437 Refer to the corresponding `.Line2D` property for more details:
3439 %(Line2D:kwdoc)s
3440 """
3441 kwargs = cbook.normalize_kwargs(kwargs, mlines.Line2D)
3442 # Drop anything that comes in as None to use the default instead.
3443 kwargs = {k: v for k, v in kwargs.items() if v is not None}
3444 kwargs.setdefault('zorder', 2)
3446 # Casting to object arrays preserves units.
3447 if not isinstance(x, np.ndarray):
3448 x = np.asarray(x, dtype=object)
3449 if not isinstance(y, np.ndarray):
3450 y = np.asarray(y, dtype=object)
3452 def _upcast_err(err):
3453 """
3454 Safely handle tuple of containers that carry units.
3456 This function covers the case where the input to the xerr/yerr is a
3457 length 2 tuple of equal length ndarray-subclasses that carry the
3458 unit information in the container.
3460 If we have a tuple of nested numpy array (subclasses), we defer
3461 coercing the units to be consistent to the underlying unit
3462 library (and implicitly the broadcasting).
3464 Otherwise, fallback to casting to an object array.
3465 """
3467 if (
3468 # make sure it is not a scalar
3469 np.iterable(err) and
3470 # and it is not empty
3471 len(err) > 0 and
3472 # and the first element is an array sub-class use
3473 # safe_first_element because getitem is index-first not
3474 # location first on pandas objects so err[0] almost always
3475 # fails.
3476 isinstance(cbook._safe_first_finite(err), np.ndarray)
3477 ):
3478 # Get the type of the first element
3479 atype = type(cbook._safe_first_finite(err))
3480 # Promote the outer container to match the inner container
3481 if atype is np.ndarray:
3482 # Converts using np.asarray, because data cannot
3483 # be directly passed to init of np.ndarray
3484 return np.asarray(err, dtype=object)
3485 # If atype is not np.ndarray, directly pass data to init.
3486 # This works for types such as unyts and astropy units
3487 return atype(err)
3488 # Otherwise wrap it in an object array
3489 return np.asarray(err, dtype=object)
3491 if xerr is not None and not isinstance(xerr, np.ndarray):
3492 xerr = _upcast_err(xerr)
3493 if yerr is not None and not isinstance(yerr, np.ndarray):
3494 yerr = _upcast_err(yerr)
3495 x, y = np.atleast_1d(x, y) # Make sure all the args are iterable.
3496 if len(x) != len(y):
3497 raise ValueError("'x' and 'y' must have the same size")
3499 everymask = self._errorevery_to_mask(x, errorevery)
3501 label = kwargs.pop("label", None)
3502 kwargs['label'] = '_nolegend_'
3504 # Create the main line and determine overall kwargs for child artists.
3505 # We avoid calling self.plot() directly, or self._get_lines(), because
3506 # that would call self._process_unit_info again, and do other indirect
3507 # data processing.
3508 (data_line, base_style), = self._get_lines._plot_args(
3509 (x, y) if fmt == '' else (x, y, fmt), kwargs, return_kwargs=True)
3511 # Do this after creating `data_line` to avoid modifying `base_style`.
3512 if barsabove:
3513 data_line.set_zorder(kwargs['zorder'] - .1)
3514 else:
3515 data_line.set_zorder(kwargs['zorder'] + .1)
3517 # Add line to plot, or throw it away and use it to determine kwargs.
3518 if fmt.lower() != 'none':
3519 self.add_line(data_line)
3520 else:
3521 data_line = None
3522 # Remove alpha=0 color that _get_lines._plot_args returns for
3523 # 'none' format, and replace it with user-specified color, if
3524 # supplied.
3525 base_style.pop('color')
3526 if 'color' in kwargs:
3527 base_style['color'] = kwargs.pop('color')
3529 if 'color' not in base_style:
3530 base_style['color'] = 'C0'
3531 if ecolor is None:
3532 ecolor = base_style['color']
3534 # Eject any line-specific information from format string, as it's not
3535 # needed for bars or caps.
3536 for key in ['marker', 'markersize', 'markerfacecolor',
3537 'markerfacecoloralt',
3538 'markeredgewidth', 'markeredgecolor', 'markevery',
3539 'linestyle', 'fillstyle', 'drawstyle', 'dash_capstyle',
3540 'dash_joinstyle', 'solid_capstyle', 'solid_joinstyle',
3541 'dashes']:
3542 base_style.pop(key, None)
3544 # Make the style dict for the line collections (the bars).
3545 eb_lines_style = {**base_style, 'color': ecolor}
3547 if elinewidth is not None:
3548 eb_lines_style['linewidth'] = elinewidth
3549 elif 'linewidth' in kwargs:
3550 eb_lines_style['linewidth'] = kwargs['linewidth']
3552 for key in ('transform', 'alpha', 'zorder', 'rasterized'):
3553 if key in kwargs:
3554 eb_lines_style[key] = kwargs[key]
3556 # Make the style dict for caps (the "hats").
3557 eb_cap_style = {**base_style, 'linestyle': 'none'}
3558 if capsize is None:
3559 capsize = mpl.rcParams["errorbar.capsize"]
3560 if capsize > 0:
3561 eb_cap_style['markersize'] = 2. * capsize
3562 if capthick is not None:
3563 eb_cap_style['markeredgewidth'] = capthick
3565 # For backwards-compat, allow explicit setting of
3566 # 'markeredgewidth' to over-ride capthick.
3567 for key in ('markeredgewidth', 'transform', 'alpha',
3568 'zorder', 'rasterized'):
3569 if key in kwargs:
3570 eb_cap_style[key] = kwargs[key]
3571 eb_cap_style['color'] = ecolor
3573 barcols = []
3574 caplines = []
3576 # Vectorized fancy-indexer.
3577 def apply_mask(arrays, mask): return [array[mask] for array in arrays]
3579 # dep: dependent dataset, indep: independent dataset
3580 for (dep_axis, dep, err, lolims, uplims, indep, lines_func,
3581 marker, lomarker, himarker) in [
3582 ("x", x, xerr, xlolims, xuplims, y, self.hlines,
3583 "|", mlines.CARETRIGHTBASE, mlines.CARETLEFTBASE),
3584 ("y", y, yerr, lolims, uplims, x, self.vlines,
3585 "_", mlines.CARETUPBASE, mlines.CARETDOWNBASE),
3586 ]:
3587 if err is None:
3588 continue
3589 lolims = np.broadcast_to(lolims, len(dep)).astype(bool)
3590 uplims = np.broadcast_to(uplims, len(dep)).astype(bool)
3591 try:
3592 np.broadcast_to(err, (2, len(dep)))
3593 except ValueError:
3594 raise ValueError(
3595 f"'{dep_axis}err' (shape: {np.shape(err)}) must be a "
3596 f"scalar or a 1D or (2, n) array-like whose shape matches "
3597 f"'{dep_axis}' (shape: {np.shape(dep)})") from None
3598 res = np.zeros(err.shape, dtype=bool) # Default in case of nan
3599 if np.any(np.less(err, -err, out=res, where=(err == err))):
3600 # like err<0, but also works for timedelta and nan.
3601 raise ValueError(
3602 f"'{dep_axis}err' must not contain negative values")
3603 # This is like
3604 # elow, ehigh = np.broadcast_to(...)
3605 # return dep - elow * ~lolims, dep + ehigh * ~uplims
3606 # except that broadcast_to would strip units.
3607 low, high = dep + np.row_stack([-(1 - lolims), 1 - uplims]) * err
3609 barcols.append(lines_func(
3610 *apply_mask([indep, low, high], everymask), **eb_lines_style))
3611 # Normal errorbars for points without upper/lower limits.
3612 nolims = ~(lolims | uplims)
3613 if nolims.any() and capsize > 0:
3614 indep_masked, lo_masked, hi_masked = apply_mask(
3615 [indep, low, high], nolims & everymask)
3616 for lh_masked in [lo_masked, hi_masked]:
3617 # Since this has to work for x and y as dependent data, we
3618 # first set both x and y to the independent variable and
3619 # overwrite the respective dependent data in a second step.
3620 line = mlines.Line2D(indep_masked, indep_masked,
3621 marker=marker, **eb_cap_style)
3622 line.set(**{f"{dep_axis}data": lh_masked})
3623 caplines.append(line)
3624 for idx, (lims, hl) in enumerate([(lolims, high), (uplims, low)]):
3625 if not lims.any():
3626 continue
3627 hlmarker = (
3628 himarker
3629 if getattr(self, f"{dep_axis}axis").get_inverted() ^ idx
3630 else lomarker)
3631 x_masked, y_masked, hl_masked = apply_mask(
3632 [x, y, hl], lims & everymask)
3633 # As above, we set the dependent data in a second step.
3634 line = mlines.Line2D(x_masked, y_masked,
3635 marker=hlmarker, **eb_cap_style)
3636 line.set(**{f"{dep_axis}data": hl_masked})
3637 caplines.append(line)
3638 if capsize > 0:
3639 caplines.append(mlines.Line2D(
3640 x_masked, y_masked, marker=marker, **eb_cap_style))
3642 for l in caplines:
3643 self.add_line(l)
3645 self._request_autoscale_view()
3646 errorbar_container = ErrorbarContainer(
3647 (data_line, tuple(caplines), tuple(barcols)),
3648 has_xerr=(xerr is not None), has_yerr=(yerr is not None),
3649 label=label)
3650 self.containers.append(errorbar_container)
3652 return errorbar_container # (l0, caplines, barcols)
3654 @_preprocess_data()
3655 def boxplot(self, x, notch=None, sym=None, vert=None, whis=None,
3656 positions=None, widths=None, patch_artist=None,
3657 bootstrap=None, usermedians=None, conf_intervals=None,
3658 meanline=None, showmeans=None, showcaps=None,
3659 showbox=None, showfliers=None, boxprops=None,
3660 labels=None, flierprops=None, medianprops=None,
3661 meanprops=None, capprops=None, whiskerprops=None,
3662 manage_ticks=True, autorange=False, zorder=None,
3663 capwidths=None):
3664 """
3665 Draw a box and whisker plot.
3667 The box extends from the first quartile (Q1) to the third
3668 quartile (Q3) of the data, with a line at the median. The
3669 whiskers extend from the box by 1.5x the inter-quartile range
3670 (IQR). Flier points are those past the end of the whiskers.
3671 See https://en.wikipedia.org/wiki/Box_plot for reference.
3673 .. code-block:: none
3675 Q1-1.5IQR Q1 median Q3 Q3+1.5IQR
3676 |-----:-----|
3677 o |--------| : |--------| o o
3678 |-----:-----|
3679 flier <-----------> fliers
3680 IQR
3683 Parameters
3684 ----------
3685 x : Array or a sequence of vectors.
3686 The input data. If a 2D array, a boxplot is drawn for each column
3687 in *x*. If a sequence of 1D arrays, a boxplot is drawn for each
3688 array in *x*.
3690 notch : bool, default: False
3691 Whether to draw a notched boxplot (`True`), or a rectangular
3692 boxplot (`False`). The notches represent the confidence interval
3693 (CI) around the median. The documentation for *bootstrap*
3694 describes how the locations of the notches are computed by
3695 default, but their locations may also be overridden by setting the
3696 *conf_intervals* parameter.
3698 .. note::
3700 In cases where the values of the CI are less than the
3701 lower quartile or greater than the upper quartile, the
3702 notches will extend beyond the box, giving it a
3703 distinctive "flipped" appearance. This is expected
3704 behavior and consistent with other statistical
3705 visualization packages.
3707 sym : str, optional
3708 The default symbol for flier points. An empty string ('') hides
3709 the fliers. If `None`, then the fliers default to 'b+'. More
3710 control is provided by the *flierprops* parameter.
3712 vert : bool, default: True
3713 If `True`, draws vertical boxes.
3714 If `False`, draw horizontal boxes.
3716 whis : float or (float, float), default: 1.5
3717 The position of the whiskers.
3719 If a float, the lower whisker is at the lowest datum above
3720 ``Q1 - whis*(Q3-Q1)``, and the upper whisker at the highest datum
3721 below ``Q3 + whis*(Q3-Q1)``, where Q1 and Q3 are the first and
3722 third quartiles. The default value of ``whis = 1.5`` corresponds
3723 to Tukey's original definition of boxplots.
3725 If a pair of floats, they indicate the percentiles at which to
3726 draw the whiskers (e.g., (5, 95)). In particular, setting this to
3727 (0, 100) results in whiskers covering the whole range of the data.
3729 In the edge case where ``Q1 == Q3``, *whis* is automatically set
3730 to (0, 100) (cover the whole range of the data) if *autorange* is
3731 True.
3733 Beyond the whiskers, data are considered outliers and are plotted
3734 as individual points.
3736 bootstrap : int, optional
3737 Specifies whether to bootstrap the confidence intervals
3738 around the median for notched boxplots. If *bootstrap* is
3739 None, no bootstrapping is performed, and notches are
3740 calculated using a Gaussian-based asymptotic approximation
3741 (see McGill, R., Tukey, J.W., and Larsen, W.A., 1978, and
3742 Kendall and Stuart, 1967). Otherwise, bootstrap specifies
3743 the number of times to bootstrap the median to determine its
3744 95% confidence intervals. Values between 1000 and 10000 are
3745 recommended.
3747 usermedians : 1D array-like, optional
3748 A 1D array-like of length ``len(x)``. Each entry that is not
3749 `None` forces the value of the median for the corresponding
3750 dataset. For entries that are `None`, the medians are computed
3751 by Matplotlib as normal.
3753 conf_intervals : array-like, optional
3754 A 2D array-like of shape ``(len(x), 2)``. Each entry that is not
3755 None forces the location of the corresponding notch (which is
3756 only drawn if *notch* is `True`). For entries that are `None`,
3757 the notches are computed by the method specified by the other
3758 parameters (e.g., *bootstrap*).
3760 positions : array-like, optional
3761 The positions of the boxes. The ticks and limits are
3762 automatically set to match the positions. Defaults to
3763 ``range(1, N+1)`` where N is the number of boxes to be drawn.
3765 widths : float or array-like
3766 The widths of the boxes. The default is 0.5, or ``0.15*(distance
3767 between extreme positions)``, if that is smaller.
3769 patch_artist : bool, default: False
3770 If `False` produces boxes with the Line2D artist. Otherwise,
3771 boxes are drawn with Patch artists.
3773 labels : sequence, optional
3774 Labels for each dataset (one per dataset).
3776 manage_ticks : bool, default: True
3777 If True, the tick locations and labels will be adjusted to match
3778 the boxplot positions.
3780 autorange : bool, default: False
3781 When `True` and the data are distributed such that the 25th and
3782 75th percentiles are equal, *whis* is set to (0, 100) such
3783 that the whisker ends are at the minimum and maximum of the data.
3785 meanline : bool, default: False
3786 If `True` (and *showmeans* is `True`), will try to render the
3787 mean as a line spanning the full width of the box according to
3788 *meanprops* (see below). Not recommended if *shownotches* is also
3789 True. Otherwise, means will be shown as points.
3791 zorder : float, default: ``Line2D.zorder = 2``
3792 The zorder of the boxplot.
3794 Returns
3795 -------
3796 dict
3797 A dictionary mapping each component of the boxplot to a list
3798 of the `.Line2D` instances created. That dictionary has the
3799 following keys (assuming vertical boxplots):
3801 - ``boxes``: the main body of the boxplot showing the
3802 quartiles and the median's confidence intervals if
3803 enabled.
3805 - ``medians``: horizontal lines at the median of each box.
3807 - ``whiskers``: the vertical lines extending to the most
3808 extreme, non-outlier data points.
3810 - ``caps``: the horizontal lines at the ends of the
3811 whiskers.
3813 - ``fliers``: points representing data that extend beyond
3814 the whiskers (fliers).
3816 - ``means``: points or lines representing the means.
3818 Other Parameters
3819 ----------------
3820 showcaps : bool, default: True
3821 Show the caps on the ends of whiskers.
3822 showbox : bool, default: True
3823 Show the central box.
3824 showfliers : bool, default: True
3825 Show the outliers beyond the caps.
3826 showmeans : bool, default: False
3827 Show the arithmetic means.
3828 capprops : dict, default: None
3829 The style of the caps.
3830 capwidths : float or array, default: None
3831 The widths of the caps.
3832 boxprops : dict, default: None
3833 The style of the box.
3834 whiskerprops : dict, default: None
3835 The style of the whiskers.
3836 flierprops : dict, default: None
3837 The style of the fliers.
3838 medianprops : dict, default: None
3839 The style of the median.
3840 meanprops : dict, default: None
3841 The style of the mean.
3842 data : indexable object, optional
3843 DATA_PARAMETER_PLACEHOLDER
3845 See Also
3846 --------
3847 violinplot : Draw an estimate of the probability density function.
3848 """
3850 # Missing arguments default to rcParams.
3851 if whis is None:
3852 whis = mpl.rcParams['boxplot.whiskers']
3853 if bootstrap is None:
3854 bootstrap = mpl.rcParams['boxplot.bootstrap']
3856 bxpstats = cbook.boxplot_stats(x, whis=whis, bootstrap=bootstrap,
3857 labels=labels, autorange=autorange)
3858 if notch is None:
3859 notch = mpl.rcParams['boxplot.notch']
3860 if vert is None:
3861 vert = mpl.rcParams['boxplot.vertical']
3862 if patch_artist is None:
3863 patch_artist = mpl.rcParams['boxplot.patchartist']
3864 if meanline is None:
3865 meanline = mpl.rcParams['boxplot.meanline']
3866 if showmeans is None:
3867 showmeans = mpl.rcParams['boxplot.showmeans']
3868 if showcaps is None:
3869 showcaps = mpl.rcParams['boxplot.showcaps']
3870 if showbox is None:
3871 showbox = mpl.rcParams['boxplot.showbox']
3872 if showfliers is None:
3873 showfliers = mpl.rcParams['boxplot.showfliers']
3875 if boxprops is None:
3876 boxprops = {}
3877 if whiskerprops is None:
3878 whiskerprops = {}
3879 if capprops is None:
3880 capprops = {}
3881 if medianprops is None:
3882 medianprops = {}
3883 if meanprops is None:
3884 meanprops = {}
3885 if flierprops is None:
3886 flierprops = {}
3888 if patch_artist:
3889 boxprops['linestyle'] = 'solid' # Not consistent with bxp.
3890 if 'color' in boxprops:
3891 boxprops['edgecolor'] = boxprops.pop('color')
3893 # if non-default sym value, put it into the flier dictionary
3894 # the logic for providing the default symbol ('b+') now lives
3895 # in bxp in the initial value of flierkw
3896 # handle all of the *sym* related logic here so we only have to pass
3897 # on the flierprops dict.
3898 if sym is not None:
3899 # no-flier case, which should really be done with
3900 # 'showfliers=False' but none-the-less deal with it to keep back
3901 # compatibility
3902 if sym == '':
3903 # blow away existing dict and make one for invisible markers
3904 flierprops = dict(linestyle='none', marker='', color='none')
3905 # turn the fliers off just to be safe
3906 showfliers = False
3907 # now process the symbol string
3908 else:
3909 # process the symbol string
3910 # discarded linestyle
3911 _, marker, color = _process_plot_format(sym)
3912 # if we have a marker, use it
3913 if marker is not None:
3914 flierprops['marker'] = marker
3915 # if we have a color, use it
3916 if color is not None:
3917 # assume that if color is passed in the user want
3918 # filled symbol, if the users want more control use
3919 # flierprops
3920 flierprops['color'] = color
3921 flierprops['markerfacecolor'] = color
3922 flierprops['markeredgecolor'] = color
3924 # replace medians if necessary:
3925 if usermedians is not None:
3926 if (len(np.ravel(usermedians)) != len(bxpstats) or
3927 np.shape(usermedians)[0] != len(bxpstats)):
3928 raise ValueError(
3929 "'usermedians' and 'x' have different lengths")
3930 else:
3931 # reassign medians as necessary
3932 for stats, med in zip(bxpstats, usermedians):
3933 if med is not None:
3934 stats['med'] = med
3936 if conf_intervals is not None:
3937 if len(conf_intervals) != len(bxpstats):
3938 raise ValueError(
3939 "'conf_intervals' and 'x' have different lengths")
3940 else:
3941 for stats, ci in zip(bxpstats, conf_intervals):
3942 if ci is not None:
3943 if len(ci) != 2:
3944 raise ValueError('each confidence interval must '
3945 'have two values')
3946 else:
3947 if ci[0] is not None:
3948 stats['cilo'] = ci[0]
3949 if ci[1] is not None:
3950 stats['cihi'] = ci[1]
3952 artists = self.bxp(bxpstats, positions=positions, widths=widths,
3953 vert=vert, patch_artist=patch_artist,
3954 shownotches=notch, showmeans=showmeans,
3955 showcaps=showcaps, showbox=showbox,
3956 boxprops=boxprops, flierprops=flierprops,
3957 medianprops=medianprops, meanprops=meanprops,
3958 meanline=meanline, showfliers=showfliers,
3959 capprops=capprops, whiskerprops=whiskerprops,
3960 manage_ticks=manage_ticks, zorder=zorder,
3961 capwidths=capwidths)
3962 return artists
3964 def bxp(self, bxpstats, positions=None, widths=None, vert=True,
3965 patch_artist=False, shownotches=False, showmeans=False,
3966 showcaps=True, showbox=True, showfliers=True,
3967 boxprops=None, whiskerprops=None, flierprops=None,
3968 medianprops=None, capprops=None, meanprops=None,
3969 meanline=False, manage_ticks=True, zorder=None,
3970 capwidths=None):
3971 """
3972 Drawing function for box and whisker plots.
3974 Make a box and whisker plot for each column of *x* or each
3975 vector in sequence *x*. The box extends from the lower to
3976 upper quartile values of the data, with a line at the median.
3977 The whiskers extend from the box to show the range of the
3978 data. Flier points are those past the end of the whiskers.
3980 Parameters
3981 ----------
3982 bxpstats : list of dicts
3983 A list of dictionaries containing stats for each boxplot.
3984 Required keys are:
3986 - ``med``: Median (scalar).
3987 - ``q1``, ``q3``: First & third quartiles (scalars).
3988 - ``whislo``, ``whishi``: Lower & upper whisker positions (scalars).
3990 Optional keys are:
3992 - ``mean``: Mean (scalar). Needed if ``showmeans=True``.
3993 - ``fliers``: Data beyond the whiskers (array-like).
3994 Needed if ``showfliers=True``.
3995 - ``cilo``, ``cihi``: Lower & upper confidence intervals
3996 about the median. Needed if ``shownotches=True``.
3997 - ``label``: Name of the dataset (str). If available,
3998 this will be used a tick label for the boxplot
4000 positions : array-like, default: [1, 2, ..., n]
4001 The positions of the boxes. The ticks and limits
4002 are automatically set to match the positions.
4004 widths : float or array-like, default: None
4005 The widths of the boxes. The default is
4006 ``clip(0.15*(distance between extreme positions), 0.15, 0.5)``.
4008 capwidths : float or array-like, default: None
4009 Either a scalar or a vector and sets the width of each cap.
4010 The default is ``0.5*(with of the box)``, see *widths*.
4012 vert : bool, default: True
4013 If `True` (default), makes the boxes vertical.
4014 If `False`, makes horizontal boxes.
4016 patch_artist : bool, default: False
4017 If `False` produces boxes with the `.Line2D` artist.
4018 If `True` produces boxes with the `~matplotlib.patches.Patch` artist.
4020 shownotches, showmeans, showcaps, showbox, showfliers : bool
4021 Whether to draw the CI notches, the mean value (both default to
4022 False), the caps, the box, and the fliers (all three default to
4023 True).
4025 boxprops, whiskerprops, capprops, flierprops, medianprops, meanprops :\
4026 dict, optional
4027 Artist properties for the boxes, whiskers, caps, fliers, medians, and
4028 means.
4030 meanline : bool, default: False
4031 If `True` (and *showmeans* is `True`), will try to render the mean
4032 as a line spanning the full width of the box according to
4033 *meanprops*. Not recommended if *shownotches* is also True.
4034 Otherwise, means will be shown as points.
4036 manage_ticks : bool, default: True
4037 If True, the tick locations and labels will be adjusted to match the
4038 boxplot positions.
4040 zorder : float, default: ``Line2D.zorder = 2``
4041 The zorder of the resulting boxplot.
4043 Returns
4044 -------
4045 dict
4046 A dictionary mapping each component of the boxplot to a list
4047 of the `.Line2D` instances created. That dictionary has the
4048 following keys (assuming vertical boxplots):
4050 - ``boxes``: main bodies of the boxplot showing the quartiles, and
4051 the median's confidence intervals if enabled.
4052 - ``medians``: horizontal lines at the median of each box.
4053 - ``whiskers``: vertical lines up to the last non-outlier data.
4054 - ``caps``: horizontal lines at the ends of the whiskers.
4055 - ``fliers``: points representing data beyond the whiskers (fliers).
4056 - ``means``: points or lines representing the means.
4058 Examples
4059 --------
4060 .. plot:: gallery/statistics/bxp.py
4061 """
4063 # lists of artists to be output
4064 whiskers = []
4065 caps = []
4066 boxes = []
4067 medians = []
4068 means = []
4069 fliers = []
4071 # empty list of xticklabels
4072 datalabels = []
4074 # Use default zorder if none specified
4075 if zorder is None:
4076 zorder = mlines.Line2D.zorder
4078 zdelta = 0.1
4080 def merge_kw_rc(subkey, explicit, zdelta=0, usemarker=True):
4081 d = {k.split('.')[-1]: v for k, v in mpl.rcParams.items()
4082 if k.startswith(f'boxplot.{subkey}props')}
4083 d['zorder'] = zorder + zdelta
4084 if not usemarker:
4085 d['marker'] = ''
4086 d.update(cbook.normalize_kwargs(explicit, mlines.Line2D))
4087 return d
4089 box_kw = {
4090 'linestyle': mpl.rcParams['boxplot.boxprops.linestyle'],
4091 'linewidth': mpl.rcParams['boxplot.boxprops.linewidth'],
4092 'edgecolor': mpl.rcParams['boxplot.boxprops.color'],
4093 'facecolor': ('white' if mpl.rcParams['_internal.classic_mode']
4094 else mpl.rcParams['patch.facecolor']),
4095 'zorder': zorder,
4096 **cbook.normalize_kwargs(boxprops, mpatches.PathPatch)
4097 } if patch_artist else merge_kw_rc('box', boxprops, usemarker=False)
4098 whisker_kw = merge_kw_rc('whisker', whiskerprops, usemarker=False)
4099 cap_kw = merge_kw_rc('cap', capprops, usemarker=False)
4100 flier_kw = merge_kw_rc('flier', flierprops)
4101 median_kw = merge_kw_rc('median', medianprops, zdelta, usemarker=False)
4102 mean_kw = merge_kw_rc('mean', meanprops, zdelta)
4103 removed_prop = 'marker' if meanline else 'linestyle'
4104 # Only remove the property if it's not set explicitly as a parameter.
4105 if meanprops is None or removed_prop not in meanprops:
4106 mean_kw[removed_prop] = ''
4108 # vertical or horizontal plot?
4109 maybe_swap = slice(None) if vert else slice(None, None, -1)
4111 def do_plot(xs, ys, **kwargs):
4112 return self.plot(*[xs, ys][maybe_swap], **kwargs)[0]
4114 def do_patch(xs, ys, **kwargs):
4115 path = mpath.Path._create_closed(
4116 np.column_stack([xs, ys][maybe_swap]))
4117 patch = mpatches.PathPatch(path, **kwargs)
4118 self.add_artist(patch)
4119 return patch
4121 # input validation
4122 N = len(bxpstats)
4123 datashape_message = ("List of boxplot statistics and `{0}` "
4124 "values must have same the length")
4125 # check position
4126 if positions is None:
4127 positions = list(range(1, N + 1))
4128 elif len(positions) != N:
4129 raise ValueError(datashape_message.format("positions"))
4131 positions = np.array(positions)
4132 if len(positions) > 0 and not isinstance(positions[0], Number):
4133 raise TypeError("positions should be an iterable of numbers")
4135 # width
4136 if widths is None:
4137 widths = [np.clip(0.15 * np.ptp(positions), 0.15, 0.5)] * N
4138 elif np.isscalar(widths):
4139 widths = [widths] * N
4140 elif len(widths) != N:
4141 raise ValueError(datashape_message.format("widths"))
4143 # capwidth
4144 if capwidths is None:
4145 capwidths = 0.5 * np.array(widths)
4146 elif np.isscalar(capwidths):
4147 capwidths = [capwidths] * N
4148 elif len(capwidths) != N:
4149 raise ValueError(datashape_message.format("capwidths"))
4151 for pos, width, stats, capwidth in zip(positions, widths, bxpstats,
4152 capwidths):
4153 # try to find a new label
4154 datalabels.append(stats.get('label', pos))
4156 # whisker coords
4157 whis_x = [pos, pos]
4158 whislo_y = [stats['q1'], stats['whislo']]
4159 whishi_y = [stats['q3'], stats['whishi']]
4160 # cap coords
4161 cap_left = pos - capwidth * 0.5
4162 cap_right = pos + capwidth * 0.5
4163 cap_x = [cap_left, cap_right]
4164 cap_lo = np.full(2, stats['whislo'])
4165 cap_hi = np.full(2, stats['whishi'])
4166 # box and median coords
4167 box_left = pos - width * 0.5
4168 box_right = pos + width * 0.5
4169 med_y = [stats['med'], stats['med']]
4170 # notched boxes
4171 if shownotches:
4172 notch_left = pos - width * 0.25
4173 notch_right = pos + width * 0.25
4174 box_x = [box_left, box_right, box_right, notch_right,
4175 box_right, box_right, box_left, box_left, notch_left,
4176 box_left, box_left]
4177 box_y = [stats['q1'], stats['q1'], stats['cilo'],
4178 stats['med'], stats['cihi'], stats['q3'],
4179 stats['q3'], stats['cihi'], stats['med'],
4180 stats['cilo'], stats['q1']]
4181 med_x = [notch_left, notch_right]
4182 # plain boxes
4183 else:
4184 box_x = [box_left, box_right, box_right, box_left, box_left]
4185 box_y = [stats['q1'], stats['q1'], stats['q3'], stats['q3'],
4186 stats['q1']]
4187 med_x = [box_left, box_right]
4189 # maybe draw the box
4190 if showbox:
4191 do_box = do_patch if patch_artist else do_plot
4192 boxes.append(do_box(box_x, box_y, **box_kw))
4193 # draw the whiskers
4194 whiskers.append(do_plot(whis_x, whislo_y, **whisker_kw))
4195 whiskers.append(do_plot(whis_x, whishi_y, **whisker_kw))
4196 # maybe draw the caps
4197 if showcaps:
4198 caps.append(do_plot(cap_x, cap_lo, **cap_kw))
4199 caps.append(do_plot(cap_x, cap_hi, **cap_kw))
4200 # draw the medians
4201 medians.append(do_plot(med_x, med_y, **median_kw))
4202 # maybe draw the means
4203 if showmeans:
4204 if meanline:
4205 means.append(do_plot(
4206 [box_left, box_right], [stats['mean'], stats['mean']],
4207 **mean_kw
4208 ))
4209 else:
4210 means.append(do_plot([pos], [stats['mean']], **mean_kw))
4211 # maybe draw the fliers
4212 if showfliers:
4213 flier_x = np.full(len(stats['fliers']), pos, dtype=np.float64)
4214 flier_y = stats['fliers']
4215 fliers.append(do_plot(flier_x, flier_y, **flier_kw))
4217 if manage_ticks:
4218 axis_name = "x" if vert else "y"
4219 interval = getattr(self.dataLim, f"interval{axis_name}")
4220 axis = getattr(self, f"{axis_name}axis")
4221 positions = axis.convert_units(positions)
4222 # The 0.5 additional padding ensures reasonable-looking boxes
4223 # even when drawing a single box. We set the sticky edge to
4224 # prevent margins expansion, in order to match old behavior (back
4225 # when separate calls to boxplot() would completely reset the axis
4226 # limits regardless of what was drawn before). The sticky edges
4227 # are attached to the median lines, as they are always present.
4228 interval[:] = (min(interval[0], min(positions) - .5),
4229 max(interval[1], max(positions) + .5))
4230 for median, position in zip(medians, positions):
4231 getattr(median.sticky_edges, axis_name).extend(
4232 [position - .5, position + .5])
4233 # Modified from Axis.set_ticks and Axis.set_ticklabels.
4234 locator = axis.get_major_locator()
4235 if not isinstance(axis.get_major_locator(),
4236 mticker.FixedLocator):
4237 locator = mticker.FixedLocator([])
4238 axis.set_major_locator(locator)
4239 locator.locs = np.array([*locator.locs, *positions])
4240 formatter = axis.get_major_formatter()
4241 if not isinstance(axis.get_major_formatter(),
4242 mticker.FixedFormatter):
4243 formatter = mticker.FixedFormatter([])
4244 axis.set_major_formatter(formatter)
4245 formatter.seq = [*formatter.seq, *datalabels]
4247 self._request_autoscale_view()
4249 return dict(whiskers=whiskers, caps=caps, boxes=boxes,
4250 medians=medians, fliers=fliers, means=means)
4252 @staticmethod
4253 def _parse_scatter_color_args(c, edgecolors, kwargs, xsize,
4254 get_next_color_func):
4255 """
4256 Helper function to process color related arguments of `.Axes.scatter`.
4258 Argument precedence for facecolors:
4260 - c (if not None)
4261 - kwargs['facecolor']
4262 - kwargs['facecolors']
4263 - kwargs['color'] (==kwcolor)
4264 - 'b' if in classic mode else the result of ``get_next_color_func()``
4266 Argument precedence for edgecolors:
4268 - kwargs['edgecolor']
4269 - edgecolors (is an explicit kw argument in scatter())
4270 - kwargs['color'] (==kwcolor)
4271 - 'face' if not in classic mode else None
4273 Parameters
4274 ----------
4275 c : color or sequence or sequence of color or None
4276 See argument description of `.Axes.scatter`.
4277 edgecolors : color or sequence of color or {'face', 'none'} or None
4278 See argument description of `.Axes.scatter`.
4279 kwargs : dict
4280 Additional kwargs. If these keys exist, we pop and process them:
4281 'facecolors', 'facecolor', 'edgecolor', 'color'
4282 Note: The dict is modified by this function.
4283 xsize : int
4284 The size of the x and y arrays passed to `.Axes.scatter`.
4285 get_next_color_func : callable
4286 A callable that returns a color. This color is used as facecolor
4287 if no other color is provided.
4289 Note, that this is a function rather than a fixed color value to
4290 support conditional evaluation of the next color. As of the
4291 current implementation obtaining the next color from the
4292 property cycle advances the cycle. This must only happen if we
4293 actually use the color, which will only be decided within this
4294 method.
4296 Returns
4297 -------
4298 c
4299 The input *c* if it was not *None*, else a color derived from the
4300 other inputs or defaults.
4301 colors : array(N, 4) or None
4302 The facecolors as RGBA values, or *None* if a colormap is used.
4303 edgecolors
4304 The edgecolor.
4306 """
4307 facecolors = kwargs.pop('facecolors', None)
4308 facecolors = kwargs.pop('facecolor', facecolors)
4309 edgecolors = kwargs.pop('edgecolor', edgecolors)
4311 kwcolor = kwargs.pop('color', None)
4313 if kwcolor is not None and c is not None:
4314 raise ValueError("Supply a 'c' argument or a 'color'"
4315 " kwarg but not both; they differ but"
4316 " their functionalities overlap.")
4318 if kwcolor is not None:
4319 try:
4320 mcolors.to_rgba_array(kwcolor)
4321 except ValueError as err:
4322 raise ValueError(
4323 "'color' kwarg must be a color or sequence of color "
4324 "specs. For a sequence of values to be color-mapped, use "
4325 "the 'c' argument instead.") from err
4326 if edgecolors is None:
4327 edgecolors = kwcolor
4328 if facecolors is None:
4329 facecolors = kwcolor
4331 if edgecolors is None and not mpl.rcParams['_internal.classic_mode']:
4332 edgecolors = mpl.rcParams['scatter.edgecolors']
4334 c_was_none = c is None
4335 if c is None:
4336 c = (facecolors if facecolors is not None
4337 else "b" if mpl.rcParams['_internal.classic_mode']
4338 else get_next_color_func())
4339 c_is_string_or_strings = (
4340 isinstance(c, str)
4341 or (np.iterable(c) and len(c) > 0
4342 and isinstance(cbook._safe_first_finite(c), str)))
4344 def invalid_shape_exception(csize, xsize):
4345 return ValueError(
4346 f"'c' argument has {csize} elements, which is inconsistent "
4347 f"with 'x' and 'y' with size {xsize}.")
4349 c_is_mapped = False # Unless proven otherwise below.
4350 valid_shape = True # Unless proven otherwise below.
4351 if not c_was_none and kwcolor is None and not c_is_string_or_strings:
4352 try: # First, does 'c' look suitable for value-mapping?
4353 c = np.asanyarray(c, dtype=float)
4354 except ValueError:
4355 pass # Failed to convert to float array; must be color specs.
4356 else:
4357 # handle the documented special case of a 2D array with 1
4358 # row which as RGB(A) to broadcast.
4359 if c.shape == (1, 4) or c.shape == (1, 3):
4360 c_is_mapped = False
4361 if c.size != xsize:
4362 valid_shape = False
4363 # If c can be either mapped values or a RGB(A) color, prefer
4364 # the former if shapes match, the latter otherwise.
4365 elif c.size == xsize:
4366 c = c.ravel()
4367 c_is_mapped = True
4368 else: # Wrong size; it must not be intended for mapping.
4369 if c.shape in ((3,), (4,)):
4370 _log.warning(
4371 "*c* argument looks like a single numeric RGB or "
4372 "RGBA sequence, which should be avoided as value-"
4373 "mapping will have precedence in case its length "
4374 "matches with *x* & *y*. Please use the *color* "
4375 "keyword-argument or provide a 2D array "
4376 "with a single row if you intend to specify "
4377 "the same RGB or RGBA value for all points.")
4378 valid_shape = False
4379 if not c_is_mapped:
4380 try: # Is 'c' acceptable as PathCollection facecolors?
4381 colors = mcolors.to_rgba_array(c)
4382 except (TypeError, ValueError) as err:
4383 if "RGBA values should be within 0-1 range" in str(err):
4384 raise
4385 else:
4386 if not valid_shape:
4387 raise invalid_shape_exception(c.size, xsize) from err
4388 # Both the mapping *and* the RGBA conversion failed: pretty
4389 # severe failure => one may appreciate a verbose feedback.
4390 raise ValueError(
4391 f"'c' argument must be a color, a sequence of colors, "
4392 f"or a sequence of numbers, not {c}") from err
4393 else:
4394 if len(colors) not in (0, 1, xsize):
4395 # NB: remember that a single color is also acceptable.
4396 # Besides *colors* will be an empty array if c == 'none'.
4397 raise invalid_shape_exception(len(colors), xsize)
4398 else:
4399 colors = None # use cmap, norm after collection is created
4400 return c, colors, edgecolors
4402 @_preprocess_data(replace_names=["x", "y", "s", "linewidths",
4403 "edgecolors", "c", "facecolor",
4404 "facecolors", "color"],
4405 label_namer="y")
4406 @_docstring.interpd
4407 def scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None,
4408 vmin=None, vmax=None, alpha=None, linewidths=None, *,
4409 edgecolors=None, plotnonfinite=False, **kwargs):
4410 """
4411 A scatter plot of *y* vs. *x* with varying marker size and/or color.
4413 Parameters
4414 ----------
4415 x, y : float or array-like, shape (n, )
4416 The data positions.
4418 s : float or array-like, shape (n, ), optional
4419 The marker size in points**2 (typographic points are 1/72 in.).
4420 Default is ``rcParams['lines.markersize'] ** 2``.
4422 c : array-like or list of colors or color, optional
4423 The marker colors. Possible values:
4425 - A scalar or sequence of n numbers to be mapped to colors using
4426 *cmap* and *norm*.
4427 - A 2D array in which the rows are RGB or RGBA.
4428 - A sequence of colors of length n.
4429 - A single color format string.
4431 Note that *c* should not be a single numeric RGB or RGBA sequence
4432 because that is indistinguishable from an array of values to be
4433 colormapped. If you want to specify the same RGB or RGBA value for
4434 all points, use a 2D array with a single row. Otherwise, value-
4435 matching will have precedence in case of a size matching with *x*
4436 and *y*.
4438 If you wish to specify a single color for all points
4439 prefer the *color* keyword argument.
4441 Defaults to `None`. In that case the marker color is determined
4442 by the value of *color*, *facecolor* or *facecolors*. In case
4443 those are not specified or `None`, the marker color is determined
4444 by the next color of the ``Axes``' current "shape and fill" color
4445 cycle. This cycle defaults to :rc:`axes.prop_cycle`.
4447 marker : `~.markers.MarkerStyle`, default: :rc:`scatter.marker`
4448 The marker style. *marker* can be either an instance of the class
4449 or the text shorthand for a particular marker.
4450 See :mod:`matplotlib.markers` for more information about marker
4451 styles.
4453 %(cmap_doc)s
4455 This parameter is ignored if *c* is RGB(A).
4457 %(norm_doc)s
4459 This parameter is ignored if *c* is RGB(A).
4461 %(vmin_vmax_doc)s
4463 This parameter is ignored if *c* is RGB(A).
4465 alpha : float, default: None
4466 The alpha blending value, between 0 (transparent) and 1 (opaque).
4468 linewidths : float or array-like, default: :rc:`lines.linewidth`
4469 The linewidth of the marker edges. Note: The default *edgecolors*
4470 is 'face'. You may want to change this as well.
4472 edgecolors : {'face', 'none', *None*} or color or sequence of color, \
4473default: :rc:`scatter.edgecolors`
4474 The edge color of the marker. Possible values:
4476 - 'face': The edge color will always be the same as the face color.
4477 - 'none': No patch boundary will be drawn.
4478 - A color or sequence of colors.
4480 For non-filled markers, *edgecolors* is ignored. Instead, the color
4481 is determined like with 'face', i.e. from *c*, *colors*, or
4482 *facecolors*.
4484 plotnonfinite : bool, default: False
4485 Whether to plot points with nonfinite *c* (i.e. ``inf``, ``-inf``
4486 or ``nan``). If ``True`` the points are drawn with the *bad*
4487 colormap color (see `.Colormap.set_bad`).
4489 Returns
4490 -------
4491 `~matplotlib.collections.PathCollection`
4493 Other Parameters
4494 ----------------
4495 data : indexable object, optional
4496 DATA_PARAMETER_PLACEHOLDER
4497 **kwargs : `~matplotlib.collections.Collection` properties
4499 See Also
4500 --------
4501 plot : To plot scatter plots when markers are identical in size and
4502 color.
4504 Notes
4505 -----
4506 * The `.plot` function will be faster for scatterplots where markers
4507 don't vary in size or color.
4509 * Any or all of *x*, *y*, *s*, and *c* may be masked arrays, in which
4510 case all masks will be combined and only unmasked points will be
4511 plotted.
4513 * Fundamentally, scatter works with 1D arrays; *x*, *y*, *s*, and *c*
4514 may be input as N-D arrays, but within scatter they will be
4515 flattened. The exception is *c*, which will be flattened only if its
4516 size matches the size of *x* and *y*.
4518 """
4519 # Process **kwargs to handle aliases, conflicts with explicit kwargs:
4520 x, y = self._process_unit_info([("x", x), ("y", y)], kwargs)
4521 # np.ma.ravel yields an ndarray, not a masked array,
4522 # unless its argument is a masked array.
4523 x = np.ma.ravel(x)
4524 y = np.ma.ravel(y)
4525 if x.size != y.size:
4526 raise ValueError("x and y must be the same size")
4528 if s is None:
4529 s = (20 if mpl.rcParams['_internal.classic_mode'] else
4530 mpl.rcParams['lines.markersize'] ** 2.0)
4531 s = np.ma.ravel(s)
4532 if (len(s) not in (1, x.size) or
4533 (not np.issubdtype(s.dtype, np.floating) and
4534 not np.issubdtype(s.dtype, np.integer))):
4535 raise ValueError(
4536 "s must be a scalar, "
4537 "or float array-like with the same size as x and y")
4539 # get the original edgecolor the user passed before we normalize
4540 orig_edgecolor = edgecolors
4541 if edgecolors is None:
4542 orig_edgecolor = kwargs.get('edgecolor', None)
4543 c, colors, edgecolors = \
4544 self._parse_scatter_color_args(
4545 c, edgecolors, kwargs, x.size,
4546 get_next_color_func=self._get_patches_for_fill.get_next_color)
4548 if plotnonfinite and colors is None:
4549 c = np.ma.masked_invalid(c)
4550 x, y, s, edgecolors, linewidths = \
4551 cbook._combine_masks(x, y, s, edgecolors, linewidths)
4552 else:
4553 x, y, s, c, colors, edgecolors, linewidths = \
4554 cbook._combine_masks(
4555 x, y, s, c, colors, edgecolors, linewidths)
4556 # Unmask edgecolors if it was actually a single RGB or RGBA.
4557 if (x.size in (3, 4)
4558 and np.ma.is_masked(edgecolors)
4559 and not np.ma.is_masked(orig_edgecolor)):
4560 edgecolors = edgecolors.data
4562 scales = s # Renamed for readability below.
4564 # load default marker from rcParams
4565 if marker is None:
4566 marker = mpl.rcParams['scatter.marker']
4568 if isinstance(marker, mmarkers.MarkerStyle):
4569 marker_obj = marker
4570 else:
4571 marker_obj = mmarkers.MarkerStyle(marker)
4573 path = marker_obj.get_path().transformed(
4574 marker_obj.get_transform())
4575 if not marker_obj.is_filled():
4576 if orig_edgecolor is not None:
4577 _api.warn_external(
4578 f"You passed a edgecolor/edgecolors ({orig_edgecolor!r}) "
4579 f"for an unfilled marker ({marker!r}). Matplotlib is "
4580 "ignoring the edgecolor in favor of the facecolor. This "
4581 "behavior may change in the future."
4582 )
4583 # We need to handle markers that can not be filled (like
4584 # '+' and 'x') differently than markers that can be
4585 # filled, but have their fillstyle set to 'none'. This is
4586 # to get:
4587 #
4588 # - respecting the fillestyle if set
4589 # - maintaining back-compatibility for querying the facecolor of
4590 # the un-fillable markers.
4591 #
4592 # While not an ideal situation, but is better than the
4593 # alternatives.
4594 if marker_obj.get_fillstyle() == 'none':
4595 # promote the facecolor to be the edgecolor
4596 edgecolors = colors
4597 # set the facecolor to 'none' (at the last chance) because
4598 # we can not fill a path if the facecolor is non-null
4599 # (which is defendable at the renderer level).
4600 colors = 'none'
4601 else:
4602 # if we are not nulling the face color we can do this
4603 # simpler
4604 edgecolors = 'face'
4606 if linewidths is None:
4607 linewidths = mpl.rcParams['lines.linewidth']
4608 elif np.iterable(linewidths):
4609 linewidths = [
4610 lw if lw is not None else mpl.rcParams['lines.linewidth']
4611 for lw in linewidths]
4613 offsets = np.ma.column_stack([x, y])
4615 collection = mcoll.PathCollection(
4616 (path,), scales,
4617 facecolors=colors,
4618 edgecolors=edgecolors,
4619 linewidths=linewidths,
4620 offsets=offsets,
4621 offset_transform=kwargs.pop('transform', self.transData),
4622 alpha=alpha,
4623 )
4624 collection.set_transform(mtransforms.IdentityTransform())
4625 if colors is None:
4626 collection.set_array(c)
4627 collection.set_cmap(cmap)
4628 collection.set_norm(norm)
4629 collection._scale_norm(norm, vmin, vmax)
4630 else:
4631 extra_kwargs = {
4632 'cmap': cmap, 'norm': norm, 'vmin': vmin, 'vmax': vmax
4633 }
4634 extra_keys = [k for k, v in extra_kwargs.items() if v is not None]
4635 if any(extra_keys):
4636 keys_str = ", ".join(f"'{k}'" for k in extra_keys)
4637 _api.warn_external(
4638 "No data for colormapping provided via 'c'. "
4639 f"Parameters {keys_str} will be ignored")
4640 collection._internal_update(kwargs)
4642 # Classic mode only:
4643 # ensure there are margins to allow for the
4644 # finite size of the symbols. In v2.x, margins
4645 # are present by default, so we disable this
4646 # scatter-specific override.
4647 if mpl.rcParams['_internal.classic_mode']:
4648 if self._xmargin < 0.05 and x.size > 0:
4649 self.set_xmargin(0.05)
4650 if self._ymargin < 0.05 and x.size > 0:
4651 self.set_ymargin(0.05)
4653 self.add_collection(collection)
4654 self._request_autoscale_view()
4656 return collection
4658 @_preprocess_data(replace_names=["x", "y", "C"], label_namer="y")
4659 @_docstring.dedent_interpd
4660 def hexbin(self, x, y, C=None, gridsize=100, bins=None,
4661 xscale='linear', yscale='linear', extent=None,
4662 cmap=None, norm=None, vmin=None, vmax=None,
4663 alpha=None, linewidths=None, edgecolors='face',
4664 reduce_C_function=np.mean, mincnt=None, marginals=False,
4665 **kwargs):
4666 """
4667 Make a 2D hexagonal binning plot of points *x*, *y*.
4669 If *C* is *None*, the value of the hexagon is determined by the number
4670 of points in the hexagon. Otherwise, *C* specifies values at the
4671 coordinate (x[i], y[i]). For each hexagon, these values are reduced
4672 using *reduce_C_function*.
4674 Parameters
4675 ----------
4676 x, y : array-like
4677 The data positions. *x* and *y* must be of the same length.
4679 C : array-like, optional
4680 If given, these values are accumulated in the bins. Otherwise,
4681 every point has a value of 1. Must be of the same length as *x*
4682 and *y*.
4684 gridsize : int or (int, int), default: 100
4685 If a single int, the number of hexagons in the *x*-direction.
4686 The number of hexagons in the *y*-direction is chosen such that
4687 the hexagons are approximately regular.
4689 Alternatively, if a tuple (*nx*, *ny*), the number of hexagons
4690 in the *x*-direction and the *y*-direction. In the
4691 *y*-direction, counting is done along vertically aligned
4692 hexagons, not along the zig-zag chains of hexagons; see the
4693 following illustration.
4695 .. plot::
4697 import numpy
4698 import matplotlib.pyplot as plt
4700 np.random.seed(19680801)
4701 n= 300
4702 x = np.random.standard_normal(n)
4703 y = np.random.standard_normal(n)
4705 fig, ax = plt.subplots(figsize=(4, 4))
4706 h = ax.hexbin(x, y, gridsize=(5, 3))
4707 hx, hy = h.get_offsets().T
4708 ax.plot(hx[24::3], hy[24::3], 'ro-')
4709 ax.plot(hx[-3:], hy[-3:], 'ro-')
4710 ax.set_title('gridsize=(5, 3)')
4711 ax.axis('off')
4713 To get approximately regular hexagons, choose
4714 :math:`n_x = \\sqrt{3}\\,n_y`.
4716 bins : 'log' or int or sequence, default: None
4717 Discretization of the hexagon values.
4719 - If *None*, no binning is applied; the color of each hexagon
4720 directly corresponds to its count value.
4721 - If 'log', use a logarithmic scale for the colormap.
4722 Internally, :math:`log_{10}(i+1)` is used to determine the
4723 hexagon color. This is equivalent to ``norm=LogNorm()``.
4724 - If an integer, divide the counts in the specified number
4725 of bins, and color the hexagons accordingly.
4726 - If a sequence of values, the values of the lower bound of
4727 the bins to be used.
4729 xscale : {'linear', 'log'}, default: 'linear'
4730 Use a linear or log10 scale on the horizontal axis.
4732 yscale : {'linear', 'log'}, default: 'linear'
4733 Use a linear or log10 scale on the vertical axis.
4735 mincnt : int > 0, default: *None*
4736 If not *None*, only display cells with more than *mincnt*
4737 number of points in the cell.
4739 marginals : bool, default: *False*
4740 If marginals is *True*, plot the marginal density as
4741 colormapped rectangles along the bottom of the x-axis and
4742 left of the y-axis.
4744 extent : 4-tuple of float, default: *None*
4745 The limits of the bins (xmin, xmax, ymin, ymax).
4746 The default assigns the limits based on
4747 *gridsize*, *x*, *y*, *xscale* and *yscale*.
4749 If *xscale* or *yscale* is set to 'log', the limits are
4750 expected to be the exponent for a power of 10. E.g. for
4751 x-limits of 1 and 50 in 'linear' scale and y-limits
4752 of 10 and 1000 in 'log' scale, enter (1, 50, 1, 3).
4754 Returns
4755 -------
4756 `~matplotlib.collections.PolyCollection`
4757 A `.PolyCollection` defining the hexagonal bins.
4759 - `.PolyCollection.get_offsets` contains a Mx2 array containing
4760 the x, y positions of the M hexagon centers.
4761 - `.PolyCollection.get_array` contains the values of the M
4762 hexagons.
4764 If *marginals* is *True*, horizontal
4765 bar and vertical bar (both PolyCollections) will be attached
4766 to the return collection as attributes *hbar* and *vbar*.
4768 Other Parameters
4769 ----------------
4770 %(cmap_doc)s
4772 %(norm_doc)s
4774 %(vmin_vmax_doc)s
4776 alpha : float between 0 and 1, optional
4777 The alpha blending value, between 0 (transparent) and 1 (opaque).
4779 linewidths : float, default: *None*
4780 If *None*, defaults to 1.0.
4782 edgecolors : {'face', 'none', *None*} or color, default: 'face'
4783 The color of the hexagon edges. Possible values are:
4785 - 'face': Draw the edges in the same color as the fill color.
4786 - 'none': No edges are drawn. This can sometimes lead to unsightly
4787 unpainted pixels between the hexagons.
4788 - *None*: Draw outlines in the default color.
4789 - An explicit color.
4791 reduce_C_function : callable, default: `numpy.mean`
4792 The function to aggregate *C* within the bins. It is ignored if
4793 *C* is not given. This must have the signature::
4795 def reduce_C_function(C: array) -> float
4797 Commonly used functions are:
4799 - `numpy.mean`: average of the points
4800 - `numpy.sum`: integral of the point values
4801 - `numpy.amax`: value taken from the largest point
4803 data : indexable object, optional
4804 DATA_PARAMETER_PLACEHOLDER
4806 **kwargs : `~matplotlib.collections.PolyCollection` properties
4807 All other keyword arguments are passed on to `.PolyCollection`:
4809 %(PolyCollection:kwdoc)s
4811 See Also
4812 --------
4813 hist2d : 2D histogram rectangular bins
4814 """
4815 self._process_unit_info([("x", x), ("y", y)], kwargs, convert=False)
4817 x, y, C = cbook.delete_masked_points(x, y, C)
4819 # Set the size of the hexagon grid
4820 if np.iterable(gridsize):
4821 nx, ny = gridsize
4822 else:
4823 nx = gridsize
4824 ny = int(nx / math.sqrt(3))
4825 # Count the number of data in each hexagon
4826 x = np.asarray(x, float)
4827 y = np.asarray(y, float)
4829 # Will be log()'d if necessary, and then rescaled.
4830 tx = x
4831 ty = y
4833 if xscale == 'log':
4834 if np.any(x <= 0.0):
4835 raise ValueError("x contains non-positive values, so can not "
4836 "be log-scaled")
4837 tx = np.log10(tx)
4838 if yscale == 'log':
4839 if np.any(y <= 0.0):
4840 raise ValueError("y contains non-positive values, so can not "
4841 "be log-scaled")
4842 ty = np.log10(ty)
4843 if extent is not None:
4844 xmin, xmax, ymin, ymax = extent
4845 else:
4846 xmin, xmax = (tx.min(), tx.max()) if len(x) else (0, 1)
4847 ymin, ymax = (ty.min(), ty.max()) if len(y) else (0, 1)
4849 # to avoid issues with singular data, expand the min/max pairs
4850 xmin, xmax = mtransforms.nonsingular(xmin, xmax, expander=0.1)
4851 ymin, ymax = mtransforms.nonsingular(ymin, ymax, expander=0.1)
4853 nx1 = nx + 1
4854 ny1 = ny + 1
4855 nx2 = nx
4856 ny2 = ny
4857 n = nx1 * ny1 + nx2 * ny2
4859 # In the x-direction, the hexagons exactly cover the region from
4860 # xmin to xmax. Need some padding to avoid roundoff errors.
4861 padding = 1.e-9 * (xmax - xmin)
4862 xmin -= padding
4863 xmax += padding
4864 sx = (xmax - xmin) / nx
4865 sy = (ymax - ymin) / ny
4866 # Positions in hexagon index coordinates.
4867 ix = (tx - xmin) / sx
4868 iy = (ty - ymin) / sy
4869 ix1 = np.round(ix).astype(int)
4870 iy1 = np.round(iy).astype(int)
4871 ix2 = np.floor(ix).astype(int)
4872 iy2 = np.floor(iy).astype(int)
4873 # flat indices, plus one so that out-of-range points go to position 0.
4874 i1 = np.where((0 <= ix1) & (ix1 < nx1) & (0 <= iy1) & (iy1 < ny1),
4875 ix1 * ny1 + iy1 + 1, 0)
4876 i2 = np.where((0 <= ix2) & (ix2 < nx2) & (0 <= iy2) & (iy2 < ny2),
4877 ix2 * ny2 + iy2 + 1, 0)
4879 d1 = (ix - ix1) ** 2 + 3.0 * (iy - iy1) ** 2
4880 d2 = (ix - ix2 - 0.5) ** 2 + 3.0 * (iy - iy2 - 0.5) ** 2
4881 bdist = (d1 < d2)
4883 if C is None: # [1:] drops out-of-range points.
4884 counts1 = np.bincount(i1[bdist], minlength=1 + nx1 * ny1)[1:]
4885 counts2 = np.bincount(i2[~bdist], minlength=1 + nx2 * ny2)[1:]
4886 accum = np.concatenate([counts1, counts2]).astype(float)
4887 if mincnt is not None:
4888 accum[accum < mincnt] = np.nan
4889 C = np.ones(len(x))
4890 else:
4891 # store the C values in a list per hexagon index
4892 Cs_at_i1 = [[] for _ in range(1 + nx1 * ny1)]
4893 Cs_at_i2 = [[] for _ in range(1 + nx2 * ny2)]
4894 for i in range(len(x)):
4895 if bdist[i]:
4896 Cs_at_i1[i1[i]].append(C[i])
4897 else:
4898 Cs_at_i2[i2[i]].append(C[i])
4899 if mincnt is None:
4900 mincnt = 0
4901 accum = np.array(
4902 [reduce_C_function(acc) if len(acc) > mincnt else np.nan
4903 for Cs_at_i in [Cs_at_i1, Cs_at_i2]
4904 for acc in Cs_at_i[1:]], # [1:] drops out-of-range points.
4905 float)
4907 good_idxs = ~np.isnan(accum)
4909 offsets = np.zeros((n, 2), float)
4910 offsets[:nx1 * ny1, 0] = np.repeat(np.arange(nx1), ny1)
4911 offsets[:nx1 * ny1, 1] = np.tile(np.arange(ny1), nx1)
4912 offsets[nx1 * ny1:, 0] = np.repeat(np.arange(nx2) + 0.5, ny2)
4913 offsets[nx1 * ny1:, 1] = np.tile(np.arange(ny2), nx2) + 0.5
4914 offsets[:, 0] *= sx
4915 offsets[:, 1] *= sy
4916 offsets[:, 0] += xmin
4917 offsets[:, 1] += ymin
4918 # remove accumulation bins with no data
4919 offsets = offsets[good_idxs, :]
4920 accum = accum[good_idxs]
4922 polygon = [sx, sy / 3] * np.array(
4923 [[.5, -.5], [.5, .5], [0., 1.], [-.5, .5], [-.5, -.5], [0., -1.]])
4925 if linewidths is None:
4926 linewidths = [1.0]
4928 if xscale == 'log' or yscale == 'log':
4929 polygons = np.expand_dims(polygon, 0) + np.expand_dims(offsets, 1)
4930 if xscale == 'log':
4931 polygons[:, :, 0] = 10.0 ** polygons[:, :, 0]
4932 xmin = 10.0 ** xmin
4933 xmax = 10.0 ** xmax
4934 self.set_xscale(xscale)
4935 if yscale == 'log':
4936 polygons[:, :, 1] = 10.0 ** polygons[:, :, 1]
4937 ymin = 10.0 ** ymin
4938 ymax = 10.0 ** ymax
4939 self.set_yscale(yscale)
4940 collection = mcoll.PolyCollection(
4941 polygons,
4942 edgecolors=edgecolors,
4943 linewidths=linewidths,
4944 )
4945 else:
4946 collection = mcoll.PolyCollection(
4947 [polygon],
4948 edgecolors=edgecolors,
4949 linewidths=linewidths,
4950 offsets=offsets,
4951 offset_transform=mtransforms.AffineDeltaTransform(
4952 self.transData),
4953 )
4955 # Set normalizer if bins is 'log'
4956 if bins == 'log':
4957 if norm is not None:
4958 _api.warn_external("Only one of 'bins' and 'norm' arguments "
4959 f"can be supplied, ignoring bins={bins}")
4960 else:
4961 norm = mcolors.LogNorm(vmin=vmin, vmax=vmax)
4962 vmin = vmax = None
4963 bins = None
4965 # autoscale the norm with current accum values if it hasn't been set
4966 if norm is not None:
4967 if norm.vmin is None and norm.vmax is None:
4968 norm.autoscale(accum)
4970 if bins is not None:
4971 if not np.iterable(bins):
4972 minimum, maximum = min(accum), max(accum)
4973 bins -= 1 # one less edge than bins
4974 bins = minimum + (maximum - minimum) * np.arange(bins) / bins
4975 bins = np.sort(bins)
4976 accum = bins.searchsorted(accum)
4978 collection.set_array(accum)
4979 collection.set_cmap(cmap)
4980 collection.set_norm(norm)
4981 collection.set_alpha(alpha)
4982 collection._internal_update(kwargs)
4983 collection._scale_norm(norm, vmin, vmax)
4985 corners = ((xmin, ymin), (xmax, ymax))
4986 self.update_datalim(corners)
4987 self._request_autoscale_view(tight=True)
4989 # add the collection last
4990 self.add_collection(collection, autolim=False)
4991 if not marginals:
4992 return collection
4994 # Process marginals
4995 bars = []
4996 for zname, z, zmin, zmax, zscale, nbins in [
4997 ("x", x, xmin, xmax, xscale, nx),
4998 ("y", y, ymin, ymax, yscale, 2 * ny),
4999 ]:
5001 if zscale == "log":
5002 bin_edges = np.geomspace(zmin, zmax, nbins + 1)
5003 else:
5004 bin_edges = np.linspace(zmin, zmax, nbins + 1)
5006 verts = np.empty((nbins, 4, 2))
5007 verts[:, 0, 0] = verts[:, 1, 0] = bin_edges[:-1]
5008 verts[:, 2, 0] = verts[:, 3, 0] = bin_edges[1:]
5009 verts[:, 0, 1] = verts[:, 3, 1] = .00
5010 verts[:, 1, 1] = verts[:, 2, 1] = .05
5011 if zname == "y":
5012 verts = verts[:, :, ::-1] # Swap x and y.
5014 # Sort z-values into bins defined by bin_edges.
5015 bin_idxs = np.searchsorted(bin_edges, z) - 1
5016 values = np.empty(nbins)
5017 for i in range(nbins):
5018 # Get C-values for each bin, and compute bin value with
5019 # reduce_C_function.
5020 ci = C[bin_idxs == i]
5021 values[i] = reduce_C_function(ci) if len(ci) > 0 else np.nan
5023 mask = ~np.isnan(values)
5024 verts = verts[mask]
5025 values = values[mask]
5027 trans = getattr(self, f"get_{zname}axis_transform")(which="grid")
5028 bar = mcoll.PolyCollection(
5029 verts, transform=trans, edgecolors="face")
5030 bar.set_array(values)
5031 bar.set_cmap(cmap)
5032 bar.set_norm(norm)
5033 bar.set_alpha(alpha)
5034 bar._internal_update(kwargs)
5035 bars.append(self.add_collection(bar, autolim=False))
5037 collection.hbar, collection.vbar = bars
5039 def on_changed(collection):
5040 collection.hbar.set_cmap(collection.get_cmap())
5041 collection.hbar.set_cmap(collection.get_cmap())
5042 collection.vbar.set_clim(collection.get_clim())
5043 collection.vbar.set_clim(collection.get_clim())
5045 collection.callbacks.connect('changed', on_changed)
5047 return collection
5049 @_docstring.dedent_interpd
5050 def arrow(self, x, y, dx, dy, **kwargs):
5051 """
5052 Add an arrow to the Axes.
5054 This draws an arrow from ``(x, y)`` to ``(x+dx, y+dy)``.
5056 Parameters
5057 ----------
5058 %(FancyArrow)s
5060 Returns
5061 -------
5062 `.FancyArrow`
5063 The created `.FancyArrow` object.
5065 Notes
5066 -----
5067 The resulting arrow is affected by the Axes aspect ratio and limits.
5068 This may produce an arrow whose head is not square with its stem. To
5069 create an arrow whose head is square with its stem,
5070 use :meth:`annotate` for example:
5072 >>> ax.annotate("", xy=(0.5, 0.5), xytext=(0, 0),
5073 ... arrowprops=dict(arrowstyle="->"))
5075 """
5076 # Strip away units for the underlying patch since units
5077 # do not make sense to most patch-like code
5078 x = self.convert_xunits(x)
5079 y = self.convert_yunits(y)
5080 dx = self.convert_xunits(dx)
5081 dy = self.convert_yunits(dy)
5083 a = mpatches.FancyArrow(x, y, dx, dy, **kwargs)
5084 self.add_patch(a)
5085 self._request_autoscale_view()
5086 return a
5088 @_docstring.copy(mquiver.QuiverKey.__init__)
5089 def quiverkey(self, Q, X, Y, U, label, **kwargs):
5090 qk = mquiver.QuiverKey(Q, X, Y, U, label, **kwargs)
5091 self.add_artist(qk)
5092 return qk
5094 # Handle units for x and y, if they've been passed
5095 def _quiver_units(self, args, kwargs):
5096 if len(args) > 3:
5097 x, y = args[0:2]
5098 x, y = self._process_unit_info([("x", x), ("y", y)], kwargs)
5099 return (x, y) + args[2:]
5100 return args
5102 # args can by a combination if X, Y, U, V, C and all should be replaced
5103 @_preprocess_data()
5104 @_docstring.dedent_interpd
5105 def quiver(self, *args, **kwargs):
5106 """%(quiver_doc)s"""
5107 # Make sure units are handled for x and y values
5108 args = self._quiver_units(args, kwargs)
5109 q = mquiver.Quiver(self, *args, **kwargs)
5110 self.add_collection(q, autolim=True)
5111 self._request_autoscale_view()
5112 return q
5114 # args can be some combination of X, Y, U, V, C and all should be replaced
5115 @_preprocess_data()
5116 @_docstring.dedent_interpd
5117 def barbs(self, *args, **kwargs):
5118 """%(barbs_doc)s"""
5119 # Make sure units are handled for x and y values
5120 args = self._quiver_units(args, kwargs)
5121 b = mquiver.Barbs(self, *args, **kwargs)
5122 self.add_collection(b, autolim=True)
5123 self._request_autoscale_view()
5124 return b
5126 # Uses a custom implementation of data-kwarg handling in
5127 # _process_plot_var_args.
5128 def fill(self, *args, data=None, **kwargs):
5129 """
5130 Plot filled polygons.
5132 Parameters
5133 ----------
5134 *args : sequence of x, y, [color]
5135 Each polygon is defined by the lists of *x* and *y* positions of
5136 its nodes, optionally followed by a *color* specifier. See
5137 :mod:`matplotlib.colors` for supported color specifiers. The
5138 standard color cycle is used for polygons without a color
5139 specifier.
5141 You can plot multiple polygons by providing multiple *x*, *y*,
5142 *[color]* groups.
5144 For example, each of the following is legal::
5146 ax.fill(x, y) # a polygon with default color
5147 ax.fill(x, y, "b") # a blue polygon
5148 ax.fill(x, y, x2, y2) # two polygons
5149 ax.fill(x, y, "b", x2, y2, "r") # a blue and a red polygon
5151 data : indexable object, optional
5152 An object with labelled data. If given, provide the label names to
5153 plot in *x* and *y*, e.g.::
5155 ax.fill("time", "signal",
5156 data={"time": [0, 1, 2], "signal": [0, 1, 0]})
5158 Returns
5159 -------
5160 list of `~matplotlib.patches.Polygon`
5162 Other Parameters
5163 ----------------
5164 **kwargs : `~matplotlib.patches.Polygon` properties
5166 Notes
5167 -----
5168 Use :meth:`fill_between` if you would like to fill the region between
5169 two curves.
5170 """
5171 # For compatibility(!), get aliases from Line2D rather than Patch.
5172 kwargs = cbook.normalize_kwargs(kwargs, mlines.Line2D)
5173 # _get_patches_for_fill returns a generator, convert it to a list.
5174 patches = [*self._get_patches_for_fill(*args, data=data, **kwargs)]
5175 for poly in patches:
5176 self.add_patch(poly)
5177 self._request_autoscale_view()
5178 return patches
5180 def _fill_between_x_or_y(
5181 self, ind_dir, ind, dep1, dep2=0, *,
5182 where=None, interpolate=False, step=None, **kwargs):
5183 # Common implementation between fill_between (*ind_dir*="x") and
5184 # fill_betweenx (*ind_dir*="y"). *ind* is the independent variable,
5185 # *dep* the dependent variable. The docstring below is interpolated
5186 # to generate both methods' docstrings.
5187 """
5188 Fill the area between two {dir} curves.
5190 The curves are defined by the points (*{ind}*, *{dep}1*) and (*{ind}*,
5191 *{dep}2*). This creates one or multiple polygons describing the filled
5192 area.
5194 You may exclude some {dir} sections from filling using *where*.
5196 By default, the edges connect the given points directly. Use *step*
5197 if the filling should be a step function, i.e. constant in between
5198 *{ind}*.
5200 Parameters
5201 ----------
5202 {ind} : array (length N)
5203 The {ind} coordinates of the nodes defining the curves.
5205 {dep}1 : array (length N) or scalar
5206 The {dep} coordinates of the nodes defining the first curve.
5208 {dep}2 : array (length N) or scalar, default: 0
5209 The {dep} coordinates of the nodes defining the second curve.
5211 where : array of bool (length N), optional
5212 Define *where* to exclude some {dir} regions from being filled.
5213 The filled regions are defined by the coordinates ``{ind}[where]``.
5214 More precisely, fill between ``{ind}[i]`` and ``{ind}[i+1]`` if
5215 ``where[i] and where[i+1]``. Note that this definition implies
5216 that an isolated *True* value between two *False* values in *where*
5217 will not result in filling. Both sides of the *True* position
5218 remain unfilled due to the adjacent *False* values.
5220 interpolate : bool, default: False
5221 This option is only relevant if *where* is used and the two curves
5222 are crossing each other.
5224 Semantically, *where* is often used for *{dep}1* > *{dep}2* or
5225 similar. By default, the nodes of the polygon defining the filled
5226 region will only be placed at the positions in the *{ind}* array.
5227 Such a polygon cannot describe the above semantics close to the
5228 intersection. The {ind}-sections containing the intersection are
5229 simply clipped.
5231 Setting *interpolate* to *True* will calculate the actual
5232 intersection point and extend the filled region up to this point.
5234 step : {{'pre', 'post', 'mid'}}, optional
5235 Define *step* if the filling should be a step function,
5236 i.e. constant in between *{ind}*. The value determines where the
5237 step will occur:
5239 - 'pre': The y value is continued constantly to the left from
5240 every *x* position, i.e. the interval ``(x[i-1], x[i]]`` has the
5241 value ``y[i]``.
5242 - 'post': The y value is continued constantly to the right from
5243 every *x* position, i.e. the interval ``[x[i], x[i+1])`` has the
5244 value ``y[i]``.
5245 - 'mid': Steps occur half-way between the *x* positions.
5247 Returns
5248 -------
5249 `.PolyCollection`
5250 A `.PolyCollection` containing the plotted polygons.
5252 Other Parameters
5253 ----------------
5254 data : indexable object, optional
5255 DATA_PARAMETER_PLACEHOLDER
5257 **kwargs
5258 All other keyword arguments are passed on to `.PolyCollection`.
5259 They control the `.Polygon` properties:
5261 %(PolyCollection:kwdoc)s
5263 See Also
5264 --------
5265 fill_between : Fill between two sets of y-values.
5266 fill_betweenx : Fill between two sets of x-values.
5267 """
5269 dep_dir = {"x": "y", "y": "x"}[ind_dir]
5271 if not mpl.rcParams["_internal.classic_mode"]:
5272 kwargs = cbook.normalize_kwargs(kwargs, mcoll.Collection)
5273 if not any(c in kwargs for c in ("color", "facecolor")):
5274 kwargs["facecolor"] = \
5275 self._get_patches_for_fill.get_next_color()
5277 # Handle united data, such as dates
5278 ind, dep1, dep2 = map(
5279 ma.masked_invalid, self._process_unit_info(
5280 [(ind_dir, ind), (dep_dir, dep1), (dep_dir, dep2)], kwargs))
5282 for name, array in [
5283 (ind_dir, ind), (f"{dep_dir}1", dep1), (f"{dep_dir}2", dep2)]:
5284 if array.ndim > 1:
5285 raise ValueError(f"{name!r} is not 1-dimensional")
5287 if where is None:
5288 where = True
5289 else:
5290 where = np.asarray(where, dtype=bool)
5291 if where.size != ind.size:
5292 raise ValueError(f"where size ({where.size}) does not match "
5293 f"{ind_dir} size ({ind.size})")
5294 where = where & ~functools.reduce(
5295 np.logical_or, map(np.ma.getmaskarray, [ind, dep1, dep2]))
5297 ind, dep1, dep2 = np.broadcast_arrays(
5298 np.atleast_1d(ind), dep1, dep2, subok=True)
5300 polys = []
5301 for idx0, idx1 in cbook.contiguous_regions(where):
5302 indslice = ind[idx0:idx1]
5303 dep1slice = dep1[idx0:idx1]
5304 dep2slice = dep2[idx0:idx1]
5305 if step is not None:
5306 step_func = cbook.STEP_LOOKUP_MAP["steps-" + step]
5307 indslice, dep1slice, dep2slice = \
5308 step_func(indslice, dep1slice, dep2slice)
5310 if not len(indslice):
5311 continue
5313 N = len(indslice)
5314 pts = np.zeros((2 * N + 2, 2))
5316 if interpolate:
5317 def get_interp_point(idx):
5318 im1 = max(idx - 1, 0)
5319 ind_values = ind[im1:idx+1]
5320 diff_values = dep1[im1:idx+1] - dep2[im1:idx+1]
5321 dep1_values = dep1[im1:idx+1]
5323 if len(diff_values) == 2:
5324 if np.ma.is_masked(diff_values[1]):
5325 return ind[im1], dep1[im1]
5326 elif np.ma.is_masked(diff_values[0]):
5327 return ind[idx], dep1[idx]
5329 diff_order = diff_values.argsort()
5330 diff_root_ind = np.interp(
5331 0, diff_values[diff_order], ind_values[diff_order])
5332 ind_order = ind_values.argsort()
5333 diff_root_dep = np.interp(
5334 diff_root_ind,
5335 ind_values[ind_order], dep1_values[ind_order])
5336 return diff_root_ind, diff_root_dep
5338 start = get_interp_point(idx0)
5339 end = get_interp_point(idx1)
5340 else:
5341 # Handle scalar dep2 (e.g. 0): the fill should go all
5342 # the way down to 0 even if none of the dep1 sample points do.
5343 start = indslice[0], dep2slice[0]
5344 end = indslice[-1], dep2slice[-1]
5346 pts[0] = start
5347 pts[N + 1] = end
5349 pts[1:N+1, 0] = indslice
5350 pts[1:N+1, 1] = dep1slice
5351 pts[N+2:, 0] = indslice[::-1]
5352 pts[N+2:, 1] = dep2slice[::-1]
5354 if ind_dir == "y":
5355 pts = pts[:, ::-1]
5357 polys.append(pts)
5359 collection = mcoll.PolyCollection(polys, **kwargs)
5361 # now update the datalim and autoscale
5362 pts = np.row_stack([np.column_stack([ind[where], dep1[where]]),
5363 np.column_stack([ind[where], dep2[where]])])
5364 if ind_dir == "y":
5365 pts = pts[:, ::-1]
5366 self.update_datalim(pts, updatex=True, updatey=True)
5367 self.add_collection(collection, autolim=False)
5368 self._request_autoscale_view()
5369 return collection
5371 def fill_between(self, x, y1, y2=0, where=None, interpolate=False,
5372 step=None, **kwargs):
5373 return self._fill_between_x_or_y(
5374 "x", x, y1, y2,
5375 where=where, interpolate=interpolate, step=step, **kwargs)
5377 if _fill_between_x_or_y.__doc__:
5378 fill_between.__doc__ = _fill_between_x_or_y.__doc__.format(
5379 dir="horizontal", ind="x", dep="y"
5380 )
5381 fill_between = _preprocess_data(
5382 _docstring.dedent_interpd(fill_between),
5383 replace_names=["x", "y1", "y2", "where"])
5385 def fill_betweenx(self, y, x1, x2=0, where=None,
5386 step=None, interpolate=False, **kwargs):
5387 return self._fill_between_x_or_y(
5388 "y", y, x1, x2,
5389 where=where, interpolate=interpolate, step=step, **kwargs)
5391 if _fill_between_x_or_y.__doc__:
5392 fill_betweenx.__doc__ = _fill_between_x_or_y.__doc__.format(
5393 dir="vertical", ind="y", dep="x"
5394 )
5395 fill_betweenx = _preprocess_data(
5396 _docstring.dedent_interpd(fill_betweenx),
5397 replace_names=["y", "x1", "x2", "where"])
5399 #### plotting z(x, y): imshow, pcolor and relatives, contour
5401 # Once this deprecation elapses, also move vmin, vmax right after norm, to
5402 # match the signature of other methods returning ScalarMappables and keep
5403 # the documentation for *norm*, *vmax* and *vmin* together.
5404 @_api.make_keyword_only("3.5", "aspect")
5405 @_preprocess_data()
5406 @_docstring.interpd
5407 def imshow(self, X, cmap=None, norm=None, aspect=None,
5408 interpolation=None, alpha=None,
5409 vmin=None, vmax=None, origin=None, extent=None, *,
5410 interpolation_stage=None, filternorm=True, filterrad=4.0,
5411 resample=None, url=None, **kwargs):
5412 """
5413 Display data as an image, i.e., on a 2D regular raster.
5415 The input may either be actual RGB(A) data, or 2D scalar data, which
5416 will be rendered as a pseudocolor image. For displaying a grayscale
5417 image set up the colormapping using the parameters
5418 ``cmap='gray', vmin=0, vmax=255``.
5420 The number of pixels used to render an image is set by the Axes size
5421 and the *dpi* of the figure. This can lead to aliasing artifacts when
5422 the image is resampled because the displayed image size will usually
5423 not match the size of *X* (see
5424 :doc:`/gallery/images_contours_and_fields/image_antialiasing`).
5425 The resampling can be controlled via the *interpolation* parameter
5426 and/or :rc:`image.interpolation`.
5428 Parameters
5429 ----------
5430 X : array-like or PIL image
5431 The image data. Supported array shapes are:
5433 - (M, N): an image with scalar data. The values are mapped to
5434 colors using normalization and a colormap. See parameters *norm*,
5435 *cmap*, *vmin*, *vmax*.
5436 - (M, N, 3): an image with RGB values (0-1 float or 0-255 int).
5437 - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int),
5438 i.e. including transparency.
5440 The first two dimensions (M, N) define the rows and columns of
5441 the image.
5443 Out-of-range RGB(A) values are clipped.
5445 %(cmap_doc)s
5447 This parameter is ignored if *X* is RGB(A).
5449 %(norm_doc)s
5451 This parameter is ignored if *X* is RGB(A).
5453 %(vmin_vmax_doc)s
5455 This parameter is ignored if *X* is RGB(A).
5457 aspect : {'equal', 'auto'} or float, default: :rc:`image.aspect`
5458 The aspect ratio of the Axes. This parameter is particularly
5459 relevant for images since it determines whether data pixels are
5460 square.
5462 This parameter is a shortcut for explicitly calling
5463 `.Axes.set_aspect`. See there for further details.
5465 - 'equal': Ensures an aspect ratio of 1. Pixels will be square
5466 (unless pixel sizes are explicitly made non-square in data
5467 coordinates using *extent*).
5468 - 'auto': The Axes is kept fixed and the aspect is adjusted so
5469 that the data fit in the Axes. In general, this will result in
5470 non-square pixels.
5472 interpolation : str, default: :rc:`image.interpolation`
5473 The interpolation method used.
5475 Supported values are 'none', 'antialiased', 'nearest', 'bilinear',
5476 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite',
5477 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell',
5478 'sinc', 'lanczos', 'blackman'.
5480 If *interpolation* is 'none', then no interpolation is performed
5481 on the Agg, ps, pdf and svg backends. Other backends will fall back
5482 to 'nearest'. Note that most SVG renderers perform interpolation at
5483 rendering and that the default interpolation method they implement
5484 may differ.
5486 If *interpolation* is the default 'antialiased', then 'nearest'
5487 interpolation is used if the image is upsampled by more than a
5488 factor of three (i.e. the number of display pixels is at least
5489 three times the size of the data array). If the upsampling rate is
5490 smaller than 3, or the image is downsampled, then 'hanning'
5491 interpolation is used to act as an anti-aliasing filter, unless the
5492 image happens to be upsampled by exactly a factor of two or one.
5494 See
5495 :doc:`/gallery/images_contours_and_fields/interpolation_methods`
5496 for an overview of the supported interpolation methods, and
5497 :doc:`/gallery/images_contours_and_fields/image_antialiasing` for
5498 a discussion of image antialiasing.
5500 Some interpolation methods require an additional radius parameter,
5501 which can be set by *filterrad*. Additionally, the antigrain image
5502 resize filter is controlled by the parameter *filternorm*.
5504 interpolation_stage : {'data', 'rgba'}, default: 'data'
5505 If 'data', interpolation
5506 is carried out on the data provided by the user. If 'rgba', the
5507 interpolation is carried out after the colormapping has been
5508 applied (visual interpolation).
5510 alpha : float or array-like, optional
5511 The alpha blending value, between 0 (transparent) and 1 (opaque).
5512 If *alpha* is an array, the alpha blending values are applied pixel
5513 by pixel, and *alpha* must have the same shape as *X*.
5515 origin : {'upper', 'lower'}, default: :rc:`image.origin`
5516 Place the [0, 0] index of the array in the upper left or lower
5517 left corner of the Axes. The convention (the default) 'upper' is
5518 typically used for matrices and images.
5520 Note that the vertical axis points upward for 'lower'
5521 but downward for 'upper'.
5523 See the :doc:`/tutorials/intermediate/imshow_extent` tutorial for
5524 examples and a more detailed description.
5526 extent : floats (left, right, bottom, top), optional
5527 The bounding box in data coordinates that the image will fill.
5528 The image is stretched individually along x and y to fill the box.
5530 The default extent is determined by the following conditions.
5531 Pixels have unit size in data coordinates. Their centers are on
5532 integer coordinates, and their center coordinates range from 0 to
5533 columns-1 horizontally and from 0 to rows-1 vertically.
5535 Note that the direction of the vertical axis and thus the default
5536 values for top and bottom depend on *origin*:
5538 - For ``origin == 'upper'`` the default is
5539 ``(-0.5, numcols-0.5, numrows-0.5, -0.5)``.
5540 - For ``origin == 'lower'`` the default is
5541 ``(-0.5, numcols-0.5, -0.5, numrows-0.5)``.
5543 See the :doc:`/tutorials/intermediate/imshow_extent` tutorial for
5544 examples and a more detailed description.
5546 filternorm : bool, default: True
5547 A parameter for the antigrain image resize filter (see the
5548 antigrain documentation). If *filternorm* is set, the filter
5549 normalizes integer values and corrects the rounding errors. It
5550 doesn't do anything with the source floating point values, it
5551 corrects only integers according to the rule of 1.0 which means
5552 that any sum of pixel weights must be equal to 1.0. So, the
5553 filter function must produce a graph of the proper shape.
5555 filterrad : float > 0, default: 4.0
5556 The filter radius for filters that have a radius parameter, i.e.
5557 when interpolation is one of: 'sinc', 'lanczos' or 'blackman'.
5559 resample : bool, default: :rc:`image.resample`
5560 When *True*, use a full resampling method. When *False*, only
5561 resample when the output image is larger than the input image.
5563 url : str, optional
5564 Set the url of the created `.AxesImage`. See `.Artist.set_url`.
5566 Returns
5567 -------
5568 `~matplotlib.image.AxesImage`
5570 Other Parameters
5571 ----------------
5572 data : indexable object, optional
5573 DATA_PARAMETER_PLACEHOLDER
5575 **kwargs : `~matplotlib.artist.Artist` properties
5576 These parameters are passed on to the constructor of the
5577 `.AxesImage` artist.
5579 See Also
5580 --------
5581 matshow : Plot a matrix or an array as an image.
5583 Notes
5584 -----
5585 Unless *extent* is used, pixel centers will be located at integer
5586 coordinates. In other words: the origin will coincide with the center
5587 of pixel (0, 0).
5589 There are two common representations for RGB images with an alpha
5590 channel:
5592 - Straight (unassociated) alpha: R, G, and B channels represent the
5593 color of the pixel, disregarding its opacity.
5594 - Premultiplied (associated) alpha: R, G, and B channels represent
5595 the color of the pixel, adjusted for its opacity by multiplication.
5597 `~matplotlib.pyplot.imshow` expects RGB images adopting the straight
5598 (unassociated) alpha representation.
5599 """
5600 if aspect is None:
5601 aspect = mpl.rcParams['image.aspect']
5602 self.set_aspect(aspect)
5603 im = mimage.AxesImage(self, cmap=cmap, norm=norm,
5604 interpolation=interpolation, origin=origin,
5605 extent=extent, filternorm=filternorm,
5606 filterrad=filterrad, resample=resample,
5607 interpolation_stage=interpolation_stage,
5608 **kwargs)
5610 im.set_data(X)
5611 im.set_alpha(alpha)
5612 if im.get_clip_path() is None:
5613 # image does not already have clipping set, clip to axes patch
5614 im.set_clip_path(self.patch)
5615 im._scale_norm(norm, vmin, vmax)
5616 im.set_url(url)
5618 # update ax.dataLim, and, if autoscaling, set viewLim
5619 # to tightly fit the image, regardless of dataLim.
5620 im.set_extent(im.get_extent())
5622 self.add_image(im)
5623 return im
5625 def _pcolorargs(self, funcname, *args, shading='auto', **kwargs):
5626 # - create X and Y if not present;
5627 # - reshape X and Y as needed if they are 1-D;
5628 # - check for proper sizes based on `shading` kwarg;
5629 # - reset shading if shading='auto' to flat or nearest
5630 # depending on size;
5632 _valid_shading = ['gouraud', 'nearest', 'flat', 'auto']
5633 try:
5634 _api.check_in_list(_valid_shading, shading=shading)
5635 except ValueError:
5636 _api.warn_external(f"shading value '{shading}' not in list of "
5637 f"valid values {_valid_shading}. Setting "
5638 "shading='auto'.")
5639 shading = 'auto'
5641 if len(args) == 1:
5642 C = np.asanyarray(args[0])
5643 nrows, ncols = C.shape
5644 if shading in ['gouraud', 'nearest']:
5645 X, Y = np.meshgrid(np.arange(ncols), np.arange(nrows))
5646 else:
5647 X, Y = np.meshgrid(np.arange(ncols + 1), np.arange(nrows + 1))
5648 shading = 'flat'
5649 C = cbook.safe_masked_invalid(C)
5650 return X, Y, C, shading
5652 if len(args) == 3:
5653 # Check x and y for bad data...
5654 C = np.asanyarray(args[2])
5655 # unit conversion allows e.g. datetime objects as axis values
5656 X, Y = args[:2]
5657 X, Y = self._process_unit_info([("x", X), ("y", Y)], kwargs)
5658 X, Y = [cbook.safe_masked_invalid(a) for a in [X, Y]]
5660 if funcname == 'pcolormesh':
5661 if np.ma.is_masked(X) or np.ma.is_masked(Y):
5662 raise ValueError(
5663 'x and y arguments to pcolormesh cannot have '
5664 'non-finite values or be of type '
5665 'numpy.ma.core.MaskedArray with masked values')
5666 # safe_masked_invalid() returns an ndarray for dtypes other
5667 # than floating point.
5668 if isinstance(X, np.ma.core.MaskedArray):
5669 X = X.data # strip mask as downstream doesn't like it...
5670 if isinstance(Y, np.ma.core.MaskedArray):
5671 Y = Y.data
5672 nrows, ncols = C.shape
5673 else:
5674 raise TypeError(f'{funcname}() takes 1 or 3 positional arguments '
5675 f'but {len(args)} were given')
5677 Nx = X.shape[-1]
5678 Ny = Y.shape[0]
5679 if X.ndim != 2 or X.shape[0] == 1:
5680 x = X.reshape(1, Nx)
5681 X = x.repeat(Ny, axis=0)
5682 if Y.ndim != 2 or Y.shape[1] == 1:
5683 y = Y.reshape(Ny, 1)
5684 Y = y.repeat(Nx, axis=1)
5685 if X.shape != Y.shape:
5686 raise TypeError(f'Incompatible X, Y inputs to {funcname}; '
5687 f'see help({funcname})')
5689 if shading == 'auto':
5690 if ncols == Nx and nrows == Ny:
5691 shading = 'nearest'
5692 else:
5693 shading = 'flat'
5695 if shading == 'flat':
5696 if (Nx, Ny) != (ncols + 1, nrows + 1):
5697 raise TypeError('Dimensions of C %s are incompatible with'
5698 ' X (%d) and/or Y (%d); see help(%s)' % (
5699 C.shape, Nx, Ny, funcname))
5700 else: # ['nearest', 'gouraud']:
5701 if (Nx, Ny) != (ncols, nrows):
5702 raise TypeError('Dimensions of C %s are incompatible with'
5703 ' X (%d) and/or Y (%d); see help(%s)' % (
5704 C.shape, Nx, Ny, funcname))
5705 if shading == 'nearest':
5706 # grid is specified at the center, so define corners
5707 # at the midpoints between the grid centers and then use the
5708 # flat algorithm.
5709 def _interp_grid(X):
5710 # helper for below
5711 if np.shape(X)[1] > 1:
5712 dX = np.diff(X, axis=1)/2.
5713 if not (np.all(dX >= 0) or np.all(dX <= 0)):
5714 _api.warn_external(
5715 f"The input coordinates to {funcname} are "
5716 "interpreted as cell centers, but are not "
5717 "monotonically increasing or decreasing. "
5718 "This may lead to incorrectly calculated cell "
5719 "edges, in which case, please supply "
5720 f"explicit cell edges to {funcname}.")
5721 X = np.hstack((X[:, [0]] - dX[:, [0]],
5722 X[:, :-1] + dX,
5723 X[:, [-1]] + dX[:, [-1]]))
5724 else:
5725 # This is just degenerate, but we can't reliably guess
5726 # a dX if there is just one value.
5727 X = np.hstack((X, X))
5728 return X
5730 if ncols == Nx:
5731 X = _interp_grid(X)
5732 Y = _interp_grid(Y)
5733 if nrows == Ny:
5734 X = _interp_grid(X.T).T
5735 Y = _interp_grid(Y.T).T
5736 shading = 'flat'
5738 C = cbook.safe_masked_invalid(C)
5739 return X, Y, C, shading
5741 def _pcolor_grid_deprecation_helper(self):
5742 grid_active = any(axis._major_tick_kw["gridOn"]
5743 for axis in self._axis_map.values())
5744 # explicit is-True check because get_axisbelow() can also be 'line'
5745 grid_hidden_by_pcolor = self.get_axisbelow() is True
5746 if grid_active and not grid_hidden_by_pcolor:
5747 _api.warn_deprecated(
5748 "3.5", message="Auto-removal of grids by pcolor() and "
5749 "pcolormesh() is deprecated since %(since)s and will be "
5750 "removed %(removal)s; please call grid(False) first.")
5751 self.grid(False)
5753 @_preprocess_data()
5754 @_docstring.dedent_interpd
5755 def pcolor(self, *args, shading=None, alpha=None, norm=None, cmap=None,
5756 vmin=None, vmax=None, **kwargs):
5757 r"""
5758 Create a pseudocolor plot with a non-regular rectangular grid.
5760 Call signature::
5762 pcolor([X, Y,] C, **kwargs)
5764 *X* and *Y* can be used to specify the corners of the quadrilaterals.
5766 .. hint::
5768 ``pcolor()`` can be very slow for large arrays. In most
5769 cases you should use the similar but much faster
5770 `~.Axes.pcolormesh` instead. See
5771 :ref:`Differences between pcolor() and pcolormesh()
5772 <differences-pcolor-pcolormesh>` for a discussion of the
5773 differences.
5775 Parameters
5776 ----------
5777 C : 2D array-like
5778 The color-mapped values. Color-mapping is controlled by *cmap*,
5779 *norm*, *vmin*, and *vmax*.
5781 X, Y : array-like, optional
5782 The coordinates of the corners of quadrilaterals of a pcolormesh::
5784 (X[i+1, j], Y[i+1, j]) (X[i+1, j+1], Y[i+1, j+1])
5785 +-----+
5786 | |
5787 +-----+
5788 (X[i, j], Y[i, j]) (X[i, j+1], Y[i, j+1])
5790 Note that the column index corresponds to the x-coordinate, and
5791 the row index corresponds to y. For details, see the
5792 :ref:`Notes <axes-pcolormesh-grid-orientation>` section below.
5794 If ``shading='flat'`` the dimensions of *X* and *Y* should be one
5795 greater than those of *C*, and the quadrilateral is colored due
5796 to the value at ``C[i, j]``. If *X*, *Y* and *C* have equal
5797 dimensions, a warning will be raised and the last row and column
5798 of *C* will be ignored.
5800 If ``shading='nearest'``, the dimensions of *X* and *Y* should be
5801 the same as those of *C* (if not, a ValueError will be raised). The
5802 color ``C[i, j]`` will be centered on ``(X[i, j], Y[i, j])``.
5804 If *X* and/or *Y* are 1-D arrays or column vectors they will be
5805 expanded as needed into the appropriate 2D arrays, making a
5806 rectangular grid.
5808 shading : {'flat', 'nearest', 'auto'}, default: :rc:`pcolor.shading`
5809 The fill style for the quadrilateral. Possible values:
5811 - 'flat': A solid color is used for each quad. The color of the
5812 quad (i, j), (i+1, j), (i, j+1), (i+1, j+1) is given by
5813 ``C[i, j]``. The dimensions of *X* and *Y* should be
5814 one greater than those of *C*; if they are the same as *C*,
5815 then a deprecation warning is raised, and the last row
5816 and column of *C* are dropped.
5817 - 'nearest': Each grid point will have a color centered on it,
5818 extending halfway between the adjacent grid centers. The
5819 dimensions of *X* and *Y* must be the same as *C*.
5820 - 'auto': Choose 'flat' if dimensions of *X* and *Y* are one
5821 larger than *C*. Choose 'nearest' if dimensions are the same.
5823 See :doc:`/gallery/images_contours_and_fields/pcolormesh_grids`
5824 for more description.
5826 %(cmap_doc)s
5828 %(norm_doc)s
5830 %(vmin_vmax_doc)s
5832 edgecolors : {'none', None, 'face', color, color sequence}, optional
5833 The color of the edges. Defaults to 'none'. Possible values:
5835 - 'none' or '': No edge.
5836 - *None*: :rc:`patch.edgecolor` will be used. Note that currently
5837 :rc:`patch.force_edgecolor` has to be True for this to work.
5838 - 'face': Use the adjacent face color.
5839 - A color or sequence of colors will set the edge color.
5841 The singular form *edgecolor* works as an alias.
5843 alpha : float, default: None
5844 The alpha blending value of the face color, between 0 (transparent)
5845 and 1 (opaque). Note: The edgecolor is currently not affected by
5846 this.
5848 snap : bool, default: False
5849 Whether to snap the mesh to pixel boundaries.
5851 Returns
5852 -------
5853 `matplotlib.collections.Collection`
5855 Other Parameters
5856 ----------------
5857 antialiaseds : bool, default: False
5858 The default *antialiaseds* is False if the default
5859 *edgecolors*\ ="none" is used. This eliminates artificial lines
5860 at patch boundaries, and works regardless of the value of alpha.
5861 If *edgecolors* is not "none", then the default *antialiaseds*
5862 is taken from :rc:`patch.antialiased`.
5863 Stroking the edges may be preferred if *alpha* is 1, but will
5864 cause artifacts otherwise.
5866 data : indexable object, optional
5867 DATA_PARAMETER_PLACEHOLDER
5869 **kwargs
5870 Additionally, the following arguments are allowed. They are passed
5871 along to the `~matplotlib.collections.PolyCollection` constructor:
5873 %(PolyCollection:kwdoc)s
5875 See Also
5876 --------
5877 pcolormesh : for an explanation of the differences between
5878 pcolor and pcolormesh.
5879 imshow : If *X* and *Y* are each equidistant, `~.Axes.imshow` can be a
5880 faster alternative.
5882 Notes
5883 -----
5884 **Masked arrays**
5886 *X*, *Y* and *C* may be masked arrays. If either ``C[i, j]``, or one
5887 of the vertices surrounding ``C[i, j]`` (*X* or *Y* at
5888 ``[i, j], [i+1, j], [i, j+1], [i+1, j+1]``) is masked, nothing is
5889 plotted.
5891 .. _axes-pcolor-grid-orientation:
5893 **Grid orientation**
5895 The grid orientation follows the standard matrix convention: An array
5896 *C* with shape (nrows, ncolumns) is plotted with the column number as
5897 *X* and the row number as *Y*.
5898 """
5900 if shading is None:
5901 shading = mpl.rcParams['pcolor.shading']
5902 shading = shading.lower()
5903 X, Y, C, shading = self._pcolorargs('pcolor', *args, shading=shading,
5904 kwargs=kwargs)
5905 Ny, Nx = X.shape
5907 # convert to MA, if necessary.
5908 C = ma.asarray(C)
5909 X = ma.asarray(X)
5910 Y = ma.asarray(Y)
5912 mask = ma.getmaskarray(X) + ma.getmaskarray(Y)
5913 xymask = (mask[0:-1, 0:-1] + mask[1:, 1:] +
5914 mask[0:-1, 1:] + mask[1:, 0:-1])
5915 # don't plot if C or any of the surrounding vertices are masked.
5916 mask = ma.getmaskarray(C) + xymask
5918 unmask = ~mask
5919 X1 = ma.filled(X[:-1, :-1])[unmask]
5920 Y1 = ma.filled(Y[:-1, :-1])[unmask]
5921 X2 = ma.filled(X[1:, :-1])[unmask]
5922 Y2 = ma.filled(Y[1:, :-1])[unmask]
5923 X3 = ma.filled(X[1:, 1:])[unmask]
5924 Y3 = ma.filled(Y[1:, 1:])[unmask]
5925 X4 = ma.filled(X[:-1, 1:])[unmask]
5926 Y4 = ma.filled(Y[:-1, 1:])[unmask]
5927 npoly = len(X1)
5929 xy = np.stack([X1, Y1, X2, Y2, X3, Y3, X4, Y4, X1, Y1], axis=-1)
5930 verts = xy.reshape((npoly, 5, 2))
5932 C = ma.filled(C[:Ny - 1, :Nx - 1])[unmask]
5934 linewidths = (0.25,)
5935 if 'linewidth' in kwargs:
5936 kwargs['linewidths'] = kwargs.pop('linewidth')
5937 kwargs.setdefault('linewidths', linewidths)
5939 if 'edgecolor' in kwargs:
5940 kwargs['edgecolors'] = kwargs.pop('edgecolor')
5941 ec = kwargs.setdefault('edgecolors', 'none')
5943 # aa setting will default via collections to patch.antialiased
5944 # unless the boundary is not stroked, in which case the
5945 # default will be False; with unstroked boundaries, aa
5946 # makes artifacts that are often disturbing.
5947 if 'antialiased' in kwargs:
5948 kwargs['antialiaseds'] = kwargs.pop('antialiased')
5949 if 'antialiaseds' not in kwargs and cbook._str_lower_equal(ec, "none"):
5950 kwargs['antialiaseds'] = False
5952 kwargs.setdefault('snap', False)
5954 collection = mcoll.PolyCollection(
5955 verts, array=C, cmap=cmap, norm=norm, alpha=alpha, **kwargs)
5956 collection._scale_norm(norm, vmin, vmax)
5957 self._pcolor_grid_deprecation_helper()
5959 x = X.compressed()
5960 y = Y.compressed()
5962 # Transform from native to data coordinates?
5963 t = collection._transform
5964 if (not isinstance(t, mtransforms.Transform) and
5965 hasattr(t, '_as_mpl_transform')):
5966 t = t._as_mpl_transform(self.axes)
5968 if t and any(t.contains_branch_seperately(self.transData)):
5969 trans_to_data = t - self.transData
5970 pts = np.vstack([x, y]).T.astype(float)
5971 transformed_pts = trans_to_data.transform(pts)
5972 x = transformed_pts[..., 0]
5973 y = transformed_pts[..., 1]
5975 self.add_collection(collection, autolim=False)
5977 minx = np.min(x)
5978 maxx = np.max(x)
5979 miny = np.min(y)
5980 maxy = np.max(y)
5981 collection.sticky_edges.x[:] = [minx, maxx]
5982 collection.sticky_edges.y[:] = [miny, maxy]
5983 corners = (minx, miny), (maxx, maxy)
5984 self.update_datalim(corners)
5985 self._request_autoscale_view()
5986 return collection
5988 @_preprocess_data()
5989 @_docstring.dedent_interpd
5990 def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
5991 vmax=None, shading=None, antialiased=False, **kwargs):
5992 """
5993 Create a pseudocolor plot with a non-regular rectangular grid.
5995 Call signature::
5997 pcolormesh([X, Y,] C, **kwargs)
5999 *X* and *Y* can be used to specify the corners of the quadrilaterals.
6001 .. hint::
6003 `~.Axes.pcolormesh` is similar to `~.Axes.pcolor`. It is much faster
6004 and preferred in most cases. For a detailed discussion on the
6005 differences see :ref:`Differences between pcolor() and pcolormesh()
6006 <differences-pcolor-pcolormesh>`.
6008 Parameters
6009 ----------
6010 C : 2D array-like
6011 The color-mapped values. Color-mapping is controlled by *cmap*,
6012 *norm*, *vmin*, and *vmax*.
6014 X, Y : array-like, optional
6015 The coordinates of the corners of quadrilaterals of a pcolormesh::
6017 (X[i+1, j], Y[i+1, j]) (X[i+1, j+1], Y[i+1, j+1])
6018 +-----+
6019 | |
6020 +-----+
6021 (X[i, j], Y[i, j]) (X[i, j+1], Y[i, j+1])
6023 Note that the column index corresponds to the x-coordinate, and
6024 the row index corresponds to y. For details, see the
6025 :ref:`Notes <axes-pcolormesh-grid-orientation>` section below.
6027 If ``shading='flat'`` the dimensions of *X* and *Y* should be one
6028 greater than those of *C*, and the quadrilateral is colored due
6029 to the value at ``C[i, j]``. If *X*, *Y* and *C* have equal
6030 dimensions, a warning will be raised and the last row and column
6031 of *C* will be ignored.
6033 If ``shading='nearest'`` or ``'gouraud'``, the dimensions of *X*
6034 and *Y* should be the same as those of *C* (if not, a ValueError
6035 will be raised). For ``'nearest'`` the color ``C[i, j]`` is
6036 centered on ``(X[i, j], Y[i, j])``. For ``'gouraud'``, a smooth
6037 interpolation is caried out between the quadrilateral corners.
6039 If *X* and/or *Y* are 1-D arrays or column vectors they will be
6040 expanded as needed into the appropriate 2D arrays, making a
6041 rectangular grid.
6043 %(cmap_doc)s
6045 %(norm_doc)s
6047 %(vmin_vmax_doc)s
6049 edgecolors : {'none', None, 'face', color, color sequence}, optional
6050 The color of the edges. Defaults to 'none'. Possible values:
6052 - 'none' or '': No edge.
6053 - *None*: :rc:`patch.edgecolor` will be used. Note that currently
6054 :rc:`patch.force_edgecolor` has to be True for this to work.
6055 - 'face': Use the adjacent face color.
6056 - A color or sequence of colors will set the edge color.
6058 The singular form *edgecolor* works as an alias.
6060 alpha : float, default: None
6061 The alpha blending value, between 0 (transparent) and 1 (opaque).
6063 shading : {'flat', 'nearest', 'gouraud', 'auto'}, optional
6064 The fill style for the quadrilateral; defaults to
6065 'flat' or :rc:`pcolor.shading`. Possible values:
6067 - 'flat': A solid color is used for each quad. The color of the
6068 quad (i, j), (i+1, j), (i, j+1), (i+1, j+1) is given by
6069 ``C[i, j]``. The dimensions of *X* and *Y* should be
6070 one greater than those of *C*; if they are the same as *C*,
6071 then a deprecation warning is raised, and the last row
6072 and column of *C* are dropped.
6073 - 'nearest': Each grid point will have a color centered on it,
6074 extending halfway between the adjacent grid centers. The
6075 dimensions of *X* and *Y* must be the same as *C*.
6076 - 'gouraud': Each quad will be Gouraud shaded: The color of the
6077 corners (i', j') are given by ``C[i', j']``. The color values of
6078 the area in between is interpolated from the corner values.
6079 The dimensions of *X* and *Y* must be the same as *C*. When
6080 Gouraud shading is used, *edgecolors* is ignored.
6081 - 'auto': Choose 'flat' if dimensions of *X* and *Y* are one
6082 larger than *C*. Choose 'nearest' if dimensions are the same.
6084 See :doc:`/gallery/images_contours_and_fields/pcolormesh_grids`
6085 for more description.
6087 snap : bool, default: False
6088 Whether to snap the mesh to pixel boundaries.
6090 rasterized : bool, optional
6091 Rasterize the pcolormesh when drawing vector graphics. This can
6092 speed up rendering and produce smaller files for large data sets.
6093 See also :doc:`/gallery/misc/rasterization_demo`.
6095 Returns
6096 -------
6097 `matplotlib.collections.QuadMesh`
6099 Other Parameters
6100 ----------------
6101 data : indexable object, optional
6102 DATA_PARAMETER_PLACEHOLDER
6104 **kwargs
6105 Additionally, the following arguments are allowed. They are passed
6106 along to the `~matplotlib.collections.QuadMesh` constructor:
6108 %(QuadMesh:kwdoc)s
6110 See Also
6111 --------
6112 pcolor : An alternative implementation with slightly different
6113 features. For a detailed discussion on the differences see
6114 :ref:`Differences between pcolor() and pcolormesh()
6115 <differences-pcolor-pcolormesh>`.
6116 imshow : If *X* and *Y* are each equidistant, `~.Axes.imshow` can be a
6117 faster alternative.
6119 Notes
6120 -----
6121 **Masked arrays**
6123 *C* may be a masked array. If ``C[i, j]`` is masked, the corresponding
6124 quadrilateral will be transparent. Masking of *X* and *Y* is not
6125 supported. Use `~.Axes.pcolor` if you need this functionality.
6127 .. _axes-pcolormesh-grid-orientation:
6129 **Grid orientation**
6131 The grid orientation follows the standard matrix convention: An array
6132 *C* with shape (nrows, ncolumns) is plotted with the column number as
6133 *X* and the row number as *Y*.
6135 .. _differences-pcolor-pcolormesh:
6137 **Differences between pcolor() and pcolormesh()**
6139 Both methods are used to create a pseudocolor plot of a 2D array
6140 using quadrilaterals.
6142 The main difference lies in the created object and internal data
6143 handling:
6144 While `~.Axes.pcolor` returns a `.PolyCollection`, `~.Axes.pcolormesh`
6145 returns a `.QuadMesh`. The latter is more specialized for the given
6146 purpose and thus is faster. It should almost always be preferred.
6148 There is also a slight difference in the handling of masked arrays.
6149 Both `~.Axes.pcolor` and `~.Axes.pcolormesh` support masked arrays
6150 for *C*. However, only `~.Axes.pcolor` supports masked arrays for *X*
6151 and *Y*. The reason lies in the internal handling of the masked values.
6152 `~.Axes.pcolor` leaves out the respective polygons from the
6153 PolyCollection. `~.Axes.pcolormesh` sets the facecolor of the masked
6154 elements to transparent. You can see the difference when using
6155 edgecolors. While all edges are drawn irrespective of masking in a
6156 QuadMesh, the edge between two adjacent masked quadrilaterals in
6157 `~.Axes.pcolor` is not drawn as the corresponding polygons do not
6158 exist in the PolyCollection.
6160 Another difference is the support of Gouraud shading in
6161 `~.Axes.pcolormesh`, which is not available with `~.Axes.pcolor`.
6163 """
6164 if shading is None:
6165 shading = mpl.rcParams['pcolor.shading']
6166 shading = shading.lower()
6167 kwargs.setdefault('edgecolors', 'none')
6169 X, Y, C, shading = self._pcolorargs('pcolormesh', *args,
6170 shading=shading, kwargs=kwargs)
6171 coords = np.stack([X, Y], axis=-1)
6172 # convert to one dimensional array
6173 C = C.ravel()
6175 kwargs.setdefault('snap', mpl.rcParams['pcolormesh.snap'])
6177 collection = mcoll.QuadMesh(
6178 coords, antialiased=antialiased, shading=shading,
6179 array=C, cmap=cmap, norm=norm, alpha=alpha, **kwargs)
6180 collection._scale_norm(norm, vmin, vmax)
6181 self._pcolor_grid_deprecation_helper()
6183 coords = coords.reshape(-1, 2) # flatten the grid structure; keep x, y
6185 # Transform from native to data coordinates?
6186 t = collection._transform
6187 if (not isinstance(t, mtransforms.Transform) and
6188 hasattr(t, '_as_mpl_transform')):
6189 t = t._as_mpl_transform(self.axes)
6191 if t and any(t.contains_branch_seperately(self.transData)):
6192 trans_to_data = t - self.transData
6193 coords = trans_to_data.transform(coords)
6195 self.add_collection(collection, autolim=False)
6197 minx, miny = np.min(coords, axis=0)
6198 maxx, maxy = np.max(coords, axis=0)
6199 collection.sticky_edges.x[:] = [minx, maxx]
6200 collection.sticky_edges.y[:] = [miny, maxy]
6201 corners = (minx, miny), (maxx, maxy)
6202 self.update_datalim(corners)
6203 self._request_autoscale_view()
6204 return collection
6206 @_preprocess_data()
6207 @_docstring.dedent_interpd
6208 def pcolorfast(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
6209 vmax=None, **kwargs):
6210 """
6211 Create a pseudocolor plot with a non-regular rectangular grid.
6213 Call signature::
6215 ax.pcolorfast([X, Y], C, /, **kwargs)
6217 This method is similar to `~.Axes.pcolor` and `~.Axes.pcolormesh`.
6218 It's designed to provide the fastest pcolor-type plotting with the
6219 Agg backend. To achieve this, it uses different algorithms internally
6220 depending on the complexity of the input grid (regular rectangular,
6221 non-regular rectangular or arbitrary quadrilateral).
6223 .. warning::
6225 This method is experimental. Compared to `~.Axes.pcolor` or
6226 `~.Axes.pcolormesh` it has some limitations:
6228 - It supports only flat shading (no outlines)
6229 - It lacks support for log scaling of the axes.
6230 - It does not have a pyplot wrapper.
6232 Parameters
6233 ----------
6234 C : array-like
6235 The image data. Supported array shapes are:
6237 - (M, N): an image with scalar data. Color-mapping is controlled
6238 by *cmap*, *norm*, *vmin*, and *vmax*.
6239 - (M, N, 3): an image with RGB values (0-1 float or 0-255 int).
6240 - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int),
6241 i.e. including transparency.
6243 The first two dimensions (M, N) define the rows and columns of
6244 the image.
6246 This parameter can only be passed positionally.
6248 X, Y : tuple or array-like, default: ``(0, N)``, ``(0, M)``
6249 *X* and *Y* are used to specify the coordinates of the
6250 quadrilaterals. There are different ways to do this:
6252 - Use tuples ``X=(xmin, xmax)`` and ``Y=(ymin, ymax)`` to define
6253 a *uniform rectangular grid*.
6255 The tuples define the outer edges of the grid. All individual
6256 quadrilaterals will be of the same size. This is the fastest
6257 version.
6259 - Use 1D arrays *X*, *Y* to specify a *non-uniform rectangular
6260 grid*.
6262 In this case *X* and *Y* have to be monotonic 1D arrays of length
6263 *N+1* and *M+1*, specifying the x and y boundaries of the cells.
6265 The speed is intermediate. Note: The grid is checked, and if
6266 found to be uniform the fast version is used.
6268 - Use 2D arrays *X*, *Y* if you need an *arbitrary quadrilateral
6269 grid* (i.e. if the quadrilaterals are not rectangular).
6271 In this case *X* and *Y* are 2D arrays with shape (M + 1, N + 1),
6272 specifying the x and y coordinates of the corners of the colored
6273 quadrilaterals.
6275 This is the most general, but the slowest to render. It may
6276 produce faster and more compact output using ps, pdf, and
6277 svg backends, however.
6279 These arguments can only be passed positionally.
6281 %(cmap_doc)s
6283 This parameter is ignored if *C* is RGB(A).
6285 %(norm_doc)s
6287 This parameter is ignored if *C* is RGB(A).
6289 %(vmin_vmax_doc)s
6291 This parameter is ignored if *C* is RGB(A).
6293 alpha : float, default: None
6294 The alpha blending value, between 0 (transparent) and 1 (opaque).
6296 snap : bool, default: False
6297 Whether to snap the mesh to pixel boundaries.
6299 Returns
6300 -------
6301 `.AxesImage` or `.PcolorImage` or `.QuadMesh`
6302 The return type depends on the type of grid:
6304 - `.AxesImage` for a regular rectangular grid.
6305 - `.PcolorImage` for a non-regular rectangular grid.
6306 - `.QuadMesh` for a non-rectangular grid.
6308 Other Parameters
6309 ----------------
6310 data : indexable object, optional
6311 DATA_PARAMETER_PLACEHOLDER
6313 **kwargs
6314 Supported additional parameters depend on the type of grid.
6315 See return types of *image* for further description.
6316 """
6318 C = args[-1]
6319 nr, nc = np.shape(C)[:2]
6320 if len(args) == 1:
6321 style = "image"
6322 x = [0, nc]
6323 y = [0, nr]
6324 elif len(args) == 3:
6325 x, y = args[:2]
6326 x = np.asarray(x)
6327 y = np.asarray(y)
6328 if x.ndim == 1 and y.ndim == 1:
6329 if x.size == 2 and y.size == 2:
6330 style = "image"
6331 else:
6332 dx = np.diff(x)
6333 dy = np.diff(y)
6334 if (np.ptp(dx) < 0.01 * abs(dx.mean()) and
6335 np.ptp(dy) < 0.01 * abs(dy.mean())):
6336 style = "image"
6337 else:
6338 style = "pcolorimage"
6339 elif x.ndim == 2 and y.ndim == 2:
6340 style = "quadmesh"
6341 else:
6342 raise TypeError("arguments do not match valid signatures")
6343 else:
6344 raise TypeError("need 1 argument or 3 arguments")
6346 if style == "quadmesh":
6347 # data point in each cell is value at lower left corner
6348 coords = np.stack([x, y], axis=-1)
6349 if np.ndim(C) == 2:
6350 qm_kwargs = {"array": np.ma.ravel(C)}
6351 elif np.ndim(C) == 3:
6352 qm_kwargs = {"color": np.ma.reshape(C, (-1, C.shape[-1]))}
6353 else:
6354 raise ValueError("C must be 2D or 3D")
6355 collection = mcoll.QuadMesh(
6356 coords, **qm_kwargs,
6357 alpha=alpha, cmap=cmap, norm=norm,
6358 antialiased=False, edgecolors="none")
6359 self.add_collection(collection, autolim=False)
6360 xl, xr, yb, yt = x.min(), x.max(), y.min(), y.max()
6361 ret = collection
6363 else: # It's one of the two image styles.
6364 extent = xl, xr, yb, yt = x[0], x[-1], y[0], y[-1]
6365 if style == "image":
6366 im = mimage.AxesImage(
6367 self, cmap=cmap, norm=norm,
6368 data=C, alpha=alpha, extent=extent,
6369 interpolation='nearest', origin='lower',
6370 **kwargs)
6371 elif style == "pcolorimage":
6372 im = mimage.PcolorImage(
6373 self, x, y, C,
6374 cmap=cmap, norm=norm, alpha=alpha, extent=extent,
6375 **kwargs)
6376 self.add_image(im)
6377 ret = im
6379 if np.ndim(C) == 2: # C.ndim == 3 is RGB(A) so doesn't need scaling.
6380 ret._scale_norm(norm, vmin, vmax)
6382 if ret.get_clip_path() is None:
6383 # image does not already have clipping set, clip to axes patch
6384 ret.set_clip_path(self.patch)
6386 ret.sticky_edges.x[:] = [xl, xr]
6387 ret.sticky_edges.y[:] = [yb, yt]
6388 self.update_datalim(np.array([[xl, yb], [xr, yt]]))
6389 self._request_autoscale_view(tight=True)
6390 return ret
6392 @_preprocess_data()
6393 @_docstring.dedent_interpd
6394 def contour(self, *args, **kwargs):
6395 """
6396 Plot contour lines.
6398 Call signature::
6400 contour([X, Y,] Z, [levels], **kwargs)
6401 %(contour_doc)s
6402 """
6403 kwargs['filled'] = False
6404 contours = mcontour.QuadContourSet(self, *args, **kwargs)
6405 self._request_autoscale_view()
6406 return contours
6408 @_preprocess_data()
6409 @_docstring.dedent_interpd
6410 def contourf(self, *args, **kwargs):
6411 """
6412 Plot filled contours.
6414 Call signature::
6416 contourf([X, Y,] Z, [levels], **kwargs)
6417 %(contour_doc)s
6418 """
6419 kwargs['filled'] = True
6420 contours = mcontour.QuadContourSet(self, *args, **kwargs)
6421 self._request_autoscale_view()
6422 return contours
6424 def clabel(self, CS, levels=None, **kwargs):
6425 """
6426 Label a contour plot.
6428 Adds labels to line contours in given `.ContourSet`.
6430 Parameters
6431 ----------
6432 CS : `.ContourSet` instance
6433 Line contours to label.
6435 levels : array-like, optional
6436 A list of level values, that should be labeled. The list must be
6437 a subset of ``CS.levels``. If not given, all levels are labeled.
6439 **kwargs
6440 All other parameters are documented in `~.ContourLabeler.clabel`.
6441 """
6442 return CS.clabel(levels, **kwargs)
6444 #### Data analysis
6446 @_preprocess_data(replace_names=["x", 'weights'], label_namer="x")
6447 def hist(self, x, bins=None, range=None, density=False, weights=None,
6448 cumulative=False, bottom=None, histtype='bar', align='mid',
6449 orientation='vertical', rwidth=None, log=False,
6450 color=None, label=None, stacked=False, **kwargs):
6451 """
6452 Compute and plot a histogram.
6454 This method uses `numpy.histogram` to bin the data in *x* and count the
6455 number of values in each bin, then draws the distribution either as a
6456 `.BarContainer` or `.Polygon`. The *bins*, *range*, *density*, and
6457 *weights* parameters are forwarded to `numpy.histogram`.
6459 If the data has already been binned and counted, use `~.bar` or
6460 `~.stairs` to plot the distribution::
6462 counts, bins = np.histogram(x)
6463 plt.stairs(counts, bins)
6465 Alternatively, plot pre-computed bins and counts using ``hist()`` by
6466 treating each bin as a single point with a weight equal to its count::
6468 plt.hist(bins[:-1], bins, weights=counts)
6470 The data input *x* can be a singular array, a list of datasets of
6471 potentially different lengths ([*x0*, *x1*, ...]), or a 2D ndarray in
6472 which each column is a dataset. Note that the ndarray form is
6473 transposed relative to the list form. If the input is an array, then
6474 the return value is a tuple (*n*, *bins*, *patches*); if the input is a
6475 sequence of arrays, then the return value is a tuple
6476 ([*n0*, *n1*, ...], *bins*, [*patches0*, *patches1*, ...]).
6478 Masked arrays are not supported.
6480 Parameters
6481 ----------
6482 x : (n,) array or sequence of (n,) arrays
6483 Input values, this takes either a single array or a sequence of
6484 arrays which are not required to be of the same length.
6486 bins : int or sequence or str, default: :rc:`hist.bins`
6487 If *bins* is an integer, it defines the number of equal-width bins
6488 in the range.
6490 If *bins* is a sequence, it defines the bin edges, including the
6491 left edge of the first bin and the right edge of the last bin;
6492 in this case, bins may be unequally spaced. All but the last
6493 (righthand-most) bin is half-open. In other words, if *bins* is::
6495 [1, 2, 3, 4]
6497 then the first bin is ``[1, 2)`` (including 1, but excluding 2) and
6498 the second ``[2, 3)``. The last bin, however, is ``[3, 4]``, which
6499 *includes* 4.
6501 If *bins* is a string, it is one of the binning strategies
6502 supported by `numpy.histogram_bin_edges`: 'auto', 'fd', 'doane',
6503 'scott', 'stone', 'rice', 'sturges', or 'sqrt'.
6505 range : tuple or None, default: None
6506 The lower and upper range of the bins. Lower and upper outliers
6507 are ignored. If not provided, *range* is ``(x.min(), x.max())``.
6508 Range has no effect if *bins* is a sequence.
6510 If *bins* is a sequence or *range* is specified, autoscaling
6511 is based on the specified bin range instead of the
6512 range of x.
6514 density : bool, default: False
6515 If ``True``, draw and return a probability density: each bin
6516 will display the bin's raw count divided by the total number of
6517 counts *and the bin width*
6518 (``density = counts / (sum(counts) * np.diff(bins))``),
6519 so that the area under the histogram integrates to 1
6520 (``np.sum(density * np.diff(bins)) == 1``).
6522 If *stacked* is also ``True``, the sum of the histograms is
6523 normalized to 1.
6525 weights : (n,) array-like or None, default: None
6526 An array of weights, of the same shape as *x*. Each value in
6527 *x* only contributes its associated weight towards the bin count
6528 (instead of 1). If *density* is ``True``, the weights are
6529 normalized, so that the integral of the density over the range
6530 remains 1.
6532 cumulative : bool or -1, default: False
6533 If ``True``, then a histogram is computed where each bin gives the
6534 counts in that bin plus all bins for smaller values. The last bin
6535 gives the total number of datapoints.
6537 If *density* is also ``True`` then the histogram is normalized such
6538 that the last bin equals 1.
6540 If *cumulative* is a number less than 0 (e.g., -1), the direction
6541 of accumulation is reversed. In this case, if *density* is also
6542 ``True``, then the histogram is normalized such that the first bin
6543 equals 1.
6545 bottom : array-like, scalar, or None, default: None
6546 Location of the bottom of each bin, ie. bins are drawn from
6547 ``bottom`` to ``bottom + hist(x, bins)`` If a scalar, the bottom
6548 of each bin is shifted by the same amount. If an array, each bin
6549 is shifted independently and the length of bottom must match the
6550 number of bins. If None, defaults to 0.
6552 histtype : {'bar', 'barstacked', 'step', 'stepfilled'}, default: 'bar'
6553 The type of histogram to draw.
6555 - 'bar' is a traditional bar-type histogram. If multiple data
6556 are given the bars are arranged side by side.
6557 - 'barstacked' is a bar-type histogram where multiple
6558 data are stacked on top of each other.
6559 - 'step' generates a lineplot that is by default unfilled.
6560 - 'stepfilled' generates a lineplot that is by default filled.
6562 align : {'left', 'mid', 'right'}, default: 'mid'
6563 The horizontal alignment of the histogram bars.
6565 - 'left': bars are centered on the left bin edges.
6566 - 'mid': bars are centered between the bin edges.
6567 - 'right': bars are centered on the right bin edges.
6569 orientation : {'vertical', 'horizontal'}, default: 'vertical'
6570 If 'horizontal', `~.Axes.barh` will be used for bar-type histograms
6571 and the *bottom* kwarg will be the left edges.
6573 rwidth : float or None, default: None
6574 The relative width of the bars as a fraction of the bin width. If
6575 ``None``, automatically compute the width.
6577 Ignored if *histtype* is 'step' or 'stepfilled'.
6579 log : bool, default: False
6580 If ``True``, the histogram axis will be set to a log scale.
6582 color : color or array-like of colors or None, default: None
6583 Color or sequence of colors, one per dataset. Default (``None``)
6584 uses the standard line color sequence.
6586 label : str or None, default: None
6587 String, or sequence of strings to match multiple datasets. Bar
6588 charts yield multiple patches per dataset, but only the first gets
6589 the label, so that `~.Axes.legend` will work as expected.
6591 stacked : bool, default: False
6592 If ``True``, multiple data are stacked on top of each other If
6593 ``False`` multiple data are arranged side by side if histtype is
6594 'bar' or on top of each other if histtype is 'step'
6596 Returns
6597 -------
6598 n : array or list of arrays
6599 The values of the histogram bins. See *density* and *weights* for a
6600 description of the possible semantics. If input *x* is an array,
6601 then this is an array of length *nbins*. If input is a sequence of
6602 arrays ``[data1, data2, ...]``, then this is a list of arrays with
6603 the values of the histograms for each of the arrays in the same
6604 order. The dtype of the array *n* (or of its element arrays) will
6605 always be float even if no weighting or normalization is used.
6607 bins : array
6608 The edges of the bins. Length nbins + 1 (nbins left edges and right
6609 edge of last bin). Always a single array even when multiple data
6610 sets are passed in.
6612 patches : `.BarContainer` or list of a single `.Polygon` or list of \
6613such objects
6614 Container of individual artists used to create the histogram
6615 or list of such containers if there are multiple input datasets.
6617 Other Parameters
6618 ----------------
6619 data : indexable object, optional
6620 DATA_PARAMETER_PLACEHOLDER
6622 **kwargs
6623 `~matplotlib.patches.Patch` properties
6625 See Also
6626 --------
6627 hist2d : 2D histogram with rectangular bins
6628 hexbin : 2D histogram with hexagonal bins
6630 Notes
6631 -----
6632 For large numbers of bins (>1000), plotting can be significantly faster
6633 if *histtype* is set to 'step' or 'stepfilled' rather than 'bar' or
6634 'barstacked'.
6635 """
6636 # Avoid shadowing the builtin.
6637 bin_range = range
6638 from builtins import range
6640 if np.isscalar(x):
6641 x = [x]
6643 if bins is None:
6644 bins = mpl.rcParams['hist.bins']
6646 # Validate string inputs here to avoid cluttering subsequent code.
6647 _api.check_in_list(['bar', 'barstacked', 'step', 'stepfilled'],
6648 histtype=histtype)
6649 _api.check_in_list(['left', 'mid', 'right'], align=align)
6650 _api.check_in_list(['horizontal', 'vertical'], orientation=orientation)
6652 if histtype == 'barstacked' and not stacked:
6653 stacked = True
6655 # Massage 'x' for processing.
6656 x = cbook._reshape_2D(x, 'x')
6657 nx = len(x) # number of datasets
6659 # Process unit information. _process_unit_info sets the unit and
6660 # converts the first dataset; then we convert each following dataset
6661 # one at a time.
6662 if orientation == "vertical":
6663 convert_units = self.convert_xunits
6664 x = [*self._process_unit_info([("x", x[0])], kwargs),
6665 *map(convert_units, x[1:])]
6666 else: # horizontal
6667 convert_units = self.convert_yunits
6668 x = [*self._process_unit_info([("y", x[0])], kwargs),
6669 *map(convert_units, x[1:])]
6671 if bin_range is not None:
6672 bin_range = convert_units(bin_range)
6674 if not cbook.is_scalar_or_string(bins):
6675 bins = convert_units(bins)
6677 # We need to do to 'weights' what was done to 'x'
6678 if weights is not None:
6679 w = cbook._reshape_2D(weights, 'weights')
6680 else:
6681 w = [None] * nx
6683 if len(w) != nx:
6684 raise ValueError('weights should have the same shape as x')
6686 input_empty = True
6687 for xi, wi in zip(x, w):
6688 len_xi = len(xi)
6689 if wi is not None and len(wi) != len_xi:
6690 raise ValueError('weights should have the same shape as x')
6691 if len_xi:
6692 input_empty = False
6694 if color is None:
6695 color = [self._get_lines.get_next_color() for i in range(nx)]
6696 else:
6697 color = mcolors.to_rgba_array(color)
6698 if len(color) != nx:
6699 raise ValueError(f"The 'color' keyword argument must have one "
6700 f"color per dataset, but {nx} datasets and "
6701 f"{len(color)} colors were provided")
6703 hist_kwargs = dict()
6705 # if the bin_range is not given, compute without nan numpy
6706 # does not do this for us when guessing the range (but will
6707 # happily ignore nans when computing the histogram).
6708 if bin_range is None:
6709 xmin = np.inf
6710 xmax = -np.inf
6711 for xi in x:
6712 if len(xi):
6713 # python's min/max ignore nan,
6714 # np.minnan returns nan for all nan input
6715 xmin = min(xmin, np.nanmin(xi))
6716 xmax = max(xmax, np.nanmax(xi))
6717 if xmin <= xmax: # Only happens if we have seen a finite value.
6718 bin_range = (xmin, xmax)
6720 # If bins are not specified either explicitly or via range,
6721 # we need to figure out the range required for all datasets,
6722 # and supply that to np.histogram.
6723 if not input_empty and len(x) > 1:
6724 if weights is not None:
6725 _w = np.concatenate(w)
6726 else:
6727 _w = None
6728 bins = np.histogram_bin_edges(
6729 np.concatenate(x), bins, bin_range, _w)
6730 else:
6731 hist_kwargs['range'] = bin_range
6733 density = bool(density)
6734 if density and not stacked:
6735 hist_kwargs['density'] = density
6737 # List to store all the top coordinates of the histograms
6738 tops = [] # Will have shape (n_datasets, n_bins).
6739 # Loop through datasets
6740 for i in range(nx):
6741 # this will automatically overwrite bins,
6742 # so that each histogram uses the same bins
6743 m, bins = np.histogram(x[i], bins, weights=w[i], **hist_kwargs)
6744 tops.append(m)
6745 tops = np.array(tops, float) # causes problems later if it's an int
6746 bins = np.array(bins, float) # causes problems if float16
6747 if stacked:
6748 tops = tops.cumsum(axis=0)
6749 # If a stacked density plot, normalize so the area of all the
6750 # stacked histograms together is 1
6751 if density:
6752 tops = (tops / np.diff(bins)) / tops[-1].sum()
6753 if cumulative:
6754 slc = slice(None)
6755 if isinstance(cumulative, Number) and cumulative < 0:
6756 slc = slice(None, None, -1)
6757 if density:
6758 tops = (tops * np.diff(bins))[:, slc].cumsum(axis=1)[:, slc]
6759 else:
6760 tops = tops[:, slc].cumsum(axis=1)[:, slc]
6762 patches = []
6764 if histtype.startswith('bar'):
6766 totwidth = np.diff(bins)
6768 if rwidth is not None:
6769 dr = np.clip(rwidth, 0, 1)
6770 elif (len(tops) > 1 and
6771 ((not stacked) or mpl.rcParams['_internal.classic_mode'])):
6772 dr = 0.8
6773 else:
6774 dr = 1.0
6776 if histtype == 'bar' and not stacked:
6777 width = dr * totwidth / nx
6778 dw = width
6779 boffset = -0.5 * dr * totwidth * (1 - 1 / nx)
6780 elif histtype == 'barstacked' or stacked:
6781 width = dr * totwidth
6782 boffset, dw = 0.0, 0.0
6784 if align == 'mid':
6785 boffset += 0.5 * totwidth
6786 elif align == 'right':
6787 boffset += totwidth
6789 if orientation == 'horizontal':
6790 _barfunc = self.barh
6791 bottom_kwarg = 'left'
6792 else: # orientation == 'vertical'
6793 _barfunc = self.bar
6794 bottom_kwarg = 'bottom'
6796 for m, c in zip(tops, color):
6797 if bottom is None:
6798 bottom = np.zeros(len(m))
6799 if stacked:
6800 height = m - bottom
6801 else:
6802 height = m
6803 bars = _barfunc(bins[:-1]+boffset, height, width,
6804 align='center', log=log,
6805 color=c, **{bottom_kwarg: bottom})
6806 patches.append(bars)
6807 if stacked:
6808 bottom = m
6809 boffset += dw
6810 # Remove stickies from all bars but the lowest ones, as otherwise
6811 # margin expansion would be unable to cross the stickies in the
6812 # middle of the bars.
6813 for bars in patches[1:]:
6814 for patch in bars:
6815 patch.sticky_edges.x[:] = patch.sticky_edges.y[:] = []
6817 elif histtype.startswith('step'):
6818 # these define the perimeter of the polygon
6819 x = np.zeros(4 * len(bins) - 3)
6820 y = np.zeros(4 * len(bins) - 3)
6822 x[0:2*len(bins)-1:2], x[1:2*len(bins)-1:2] = bins, bins[:-1]
6823 x[2*len(bins)-1:] = x[1:2*len(bins)-1][::-1]
6825 if bottom is None:
6826 bottom = 0
6828 y[1:2*len(bins)-1:2] = y[2:2*len(bins):2] = bottom
6829 y[2*len(bins)-1:] = y[1:2*len(bins)-1][::-1]
6831 if log:
6832 if orientation == 'horizontal':
6833 self.set_xscale('log', nonpositive='clip')
6834 else: # orientation == 'vertical'
6835 self.set_yscale('log', nonpositive='clip')
6837 if align == 'left':
6838 x -= 0.5*(bins[1]-bins[0])
6839 elif align == 'right':
6840 x += 0.5*(bins[1]-bins[0])
6842 # If fill kwarg is set, it will be passed to the patch collection,
6843 # overriding this
6844 fill = (histtype == 'stepfilled')
6846 xvals, yvals = [], []
6847 for m in tops:
6848 if stacked:
6849 # top of the previous polygon becomes the bottom
6850 y[2*len(bins)-1:] = y[1:2*len(bins)-1][::-1]
6851 # set the top of this polygon
6852 y[1:2*len(bins)-1:2] = y[2:2*len(bins):2] = m + bottom
6854 # The starting point of the polygon has not yet been
6855 # updated. So far only the endpoint was adjusted. This
6856 # assignment closes the polygon. The redundant endpoint is
6857 # later discarded (for step and stepfilled).
6858 y[0] = y[-1]
6860 if orientation == 'horizontal':
6861 xvals.append(y.copy())
6862 yvals.append(x.copy())
6863 else:
6864 xvals.append(x.copy())
6865 yvals.append(y.copy())
6867 # stepfill is closed, step is not
6868 split = -1 if fill else 2 * len(bins)
6869 # add patches in reverse order so that when stacking,
6870 # items lower in the stack are plotted on top of
6871 # items higher in the stack
6872 for x, y, c in reversed(list(zip(xvals, yvals, color))):
6873 patches.append(self.fill(
6874 x[:split], y[:split],
6875 closed=True if fill else None,
6876 facecolor=c,
6877 edgecolor=None if fill else c,
6878 fill=fill if fill else None,
6879 zorder=None if fill else mlines.Line2D.zorder))
6880 for patch_list in patches:
6881 for patch in patch_list:
6882 if orientation == 'vertical':
6883 patch.sticky_edges.y.append(0)
6884 elif orientation == 'horizontal':
6885 patch.sticky_edges.x.append(0)
6887 # we return patches, so put it back in the expected order
6888 patches.reverse()
6890 # If None, make all labels None (via zip_longest below); otherwise,
6891 # cast each element to str, but keep a single str as it.
6892 labels = [] if label is None else np.atleast_1d(np.asarray(label, str))
6893 for patch, lbl in itertools.zip_longest(patches, labels):
6894 if patch:
6895 p = patch[0]
6896 p._internal_update(kwargs)
6897 if lbl is not None:
6898 p.set_label(lbl)
6899 for p in patch[1:]:
6900 p._internal_update(kwargs)
6901 p.set_label('_nolegend_')
6903 if nx == 1:
6904 return tops[0], bins, patches[0]
6905 else:
6906 patch_type = ("BarContainer" if histtype.startswith("bar")
6907 else "list[Polygon]")
6908 return tops, bins, cbook.silent_list(patch_type, patches)
6910 @_preprocess_data()
6911 def stairs(self, values, edges=None, *,
6912 orientation='vertical', baseline=0, fill=False, **kwargs):
6913 """
6914 A stepwise constant function as a line with bounding edges
6915 or a filled plot.
6917 Parameters
6918 ----------
6919 values : array-like
6920 The step heights.
6922 edges : array-like
6923 The edge positions, with ``len(edges) == len(vals) + 1``,
6924 between which the curve takes on vals values.
6926 orientation : {'vertical', 'horizontal'}, default: 'vertical'
6927 The direction of the steps. Vertical means that *values* are along
6928 the y-axis, and edges are along the x-axis.
6930 baseline : float, array-like or None, default: 0
6931 The bottom value of the bounding edges or when
6932 ``fill=True``, position of lower edge. If *fill* is
6933 True or an array is passed to *baseline*, a closed
6934 path is drawn.
6936 fill : bool, default: False
6937 Whether the area under the step curve should be filled.
6939 Returns
6940 -------
6941 StepPatch : `matplotlib.patches.StepPatch`
6943 Other Parameters
6944 ----------------
6945 data : indexable object, optional
6946 DATA_PARAMETER_PLACEHOLDER
6948 **kwargs
6949 `~matplotlib.patches.StepPatch` properties
6951 """
6953 if 'color' in kwargs:
6954 _color = kwargs.pop('color')
6955 else:
6956 _color = self._get_lines.get_next_color()
6957 if fill:
6958 kwargs.setdefault('linewidth', 0)
6959 kwargs.setdefault('facecolor', _color)
6960 else:
6961 kwargs.setdefault('edgecolor', _color)
6963 if edges is None:
6964 edges = np.arange(len(values) + 1)
6966 edges, values, baseline = self._process_unit_info(
6967 [("x", edges), ("y", values), ("y", baseline)], kwargs)
6969 patch = mpatches.StepPatch(values,
6970 edges,
6971 baseline=baseline,
6972 orientation=orientation,
6973 fill=fill,
6974 **kwargs)
6975 self.add_patch(patch)
6976 if baseline is None:
6977 baseline = 0
6978 if orientation == 'vertical':
6979 patch.sticky_edges.y.append(np.min(baseline))
6980 self.update_datalim([(edges[0], np.min(baseline))])
6981 else:
6982 patch.sticky_edges.x.append(np.min(baseline))
6983 self.update_datalim([(np.min(baseline), edges[0])])
6984 self._request_autoscale_view()
6985 return patch
6987 @_preprocess_data(replace_names=["x", "y", "weights"])
6988 @_docstring.dedent_interpd
6989 def hist2d(self, x, y, bins=10, range=None, density=False, weights=None,
6990 cmin=None, cmax=None, **kwargs):
6991 """
6992 Make a 2D histogram plot.
6994 Parameters
6995 ----------
6996 x, y : array-like, shape (n, )
6997 Input values
6999 bins : None or int or [int, int] or array-like or [array, array]
7001 The bin specification:
7003 - If int, the number of bins for the two dimensions
7004 (nx=ny=bins).
7005 - If ``[int, int]``, the number of bins in each dimension
7006 (nx, ny = bins).
7007 - If array-like, the bin edges for the two dimensions
7008 (x_edges=y_edges=bins).
7009 - If ``[array, array]``, the bin edges in each dimension
7010 (x_edges, y_edges = bins).
7012 The default value is 10.
7014 range : array-like shape(2, 2), optional
7015 The leftmost and rightmost edges of the bins along each dimension
7016 (if not specified explicitly in the bins parameters): ``[[xmin,
7017 xmax], [ymin, ymax]]``. All values outside of this range will be
7018 considered outliers and not tallied in the histogram.
7020 density : bool, default: False
7021 Normalize histogram. See the documentation for the *density*
7022 parameter of `~.Axes.hist` for more details.
7024 weights : array-like, shape (n, ), optional
7025 An array of values w_i weighing each sample (x_i, y_i).
7027 cmin, cmax : float, default: None
7028 All bins that has count less than *cmin* or more than *cmax* will
7029 not be displayed (set to NaN before passing to imshow) and these
7030 count values in the return value count histogram will also be set
7031 to nan upon return.
7033 Returns
7034 -------
7035 h : 2D array
7036 The bi-dimensional histogram of samples x and y. Values in x are
7037 histogrammed along the first dimension and values in y are
7038 histogrammed along the second dimension.
7039 xedges : 1D array
7040 The bin edges along the x axis.
7041 yedges : 1D array
7042 The bin edges along the y axis.
7043 image : `~.matplotlib.collections.QuadMesh`
7045 Other Parameters
7046 ----------------
7047 %(cmap_doc)s
7049 %(norm_doc)s
7051 %(vmin_vmax_doc)s
7053 alpha : ``0 <= scalar <= 1`` or ``None``, optional
7054 The alpha blending value.
7056 data : indexable object, optional
7057 DATA_PARAMETER_PLACEHOLDER
7059 **kwargs
7060 Additional parameters are passed along to the
7061 `~.Axes.pcolormesh` method and `~matplotlib.collections.QuadMesh`
7062 constructor.
7064 See Also
7065 --------
7066 hist : 1D histogram plotting
7067 hexbin : 2D histogram with hexagonal bins
7069 Notes
7070 -----
7071 - Currently ``hist2d`` calculates its own axis limits, and any limits
7072 previously set are ignored.
7073 - Rendering the histogram with a logarithmic color scale is
7074 accomplished by passing a `.colors.LogNorm` instance to the *norm*
7075 keyword argument. Likewise, power-law normalization (similar
7076 in effect to gamma correction) can be accomplished with
7077 `.colors.PowerNorm`.
7078 """
7080 h, xedges, yedges = np.histogram2d(x, y, bins=bins, range=range,
7081 density=density, weights=weights)
7083 if cmin is not None:
7084 h[h < cmin] = None
7085 if cmax is not None:
7086 h[h > cmax] = None
7088 pc = self.pcolormesh(xedges, yedges, h.T, **kwargs)
7089 self.set_xlim(xedges[0], xedges[-1])
7090 self.set_ylim(yedges[0], yedges[-1])
7092 return h, xedges, yedges, pc
7094 @_preprocess_data(replace_names=["x"])
7095 @_docstring.dedent_interpd
7096 def psd(self, x, NFFT=None, Fs=None, Fc=None, detrend=None,
7097 window=None, noverlap=None, pad_to=None,
7098 sides=None, scale_by_freq=None, return_line=None, **kwargs):
7099 r"""
7100 Plot the power spectral density.
7102 The power spectral density :math:`P_{xx}` by Welch's average
7103 periodogram method. The vector *x* is divided into *NFFT* length
7104 segments. Each segment is detrended by function *detrend* and
7105 windowed by function *window*. *noverlap* gives the length of
7106 the overlap between segments. The :math:`|\mathrm{fft}(i)|^2`
7107 of each segment :math:`i` are averaged to compute :math:`P_{xx}`,
7108 with a scaling to correct for power loss due to windowing.
7110 If len(*x*) < *NFFT*, it will be zero padded to *NFFT*.
7112 Parameters
7113 ----------
7114 x : 1-D array or sequence
7115 Array or sequence containing the data
7117 %(Spectral)s
7119 %(PSD)s
7121 noverlap : int, default: 0 (no overlap)
7122 The number of points of overlap between segments.
7124 Fc : int, default: 0
7125 The center frequency of *x*, which offsets the x extents of the
7126 plot to reflect the frequency range used when a signal is acquired
7127 and then filtered and downsampled to baseband.
7129 return_line : bool, default: False
7130 Whether to include the line object plotted in the returned values.
7132 Returns
7133 -------
7134 Pxx : 1-D array
7135 The values for the power spectrum :math:`P_{xx}` before scaling
7136 (real valued).
7138 freqs : 1-D array
7139 The frequencies corresponding to the elements in *Pxx*.
7141 line : `~matplotlib.lines.Line2D`
7142 The line created by this function.
7143 Only returned if *return_line* is True.
7145 Other Parameters
7146 ----------------
7147 data : indexable object, optional
7148 DATA_PARAMETER_PLACEHOLDER
7150 **kwargs
7151 Keyword arguments control the `.Line2D` properties:
7153 %(Line2D:kwdoc)s
7155 See Also
7156 --------
7157 specgram
7158 Differs in the default overlap; in not returning the mean of the
7159 segment periodograms; in returning the times of the segments; and
7160 in plotting a colormap instead of a line.
7161 magnitude_spectrum
7162 Plots the magnitude spectrum.
7163 csd
7164 Plots the spectral density between two signals.
7166 Notes
7167 -----
7168 For plotting, the power is plotted as
7169 :math:`10\log_{10}(P_{xx})` for decibels, though *Pxx* itself
7170 is returned.
7172 References
7173 ----------
7174 Bendat & Piersol -- Random Data: Analysis and Measurement Procedures,
7175 John Wiley & Sons (1986)
7176 """
7177 if Fc is None:
7178 Fc = 0
7180 pxx, freqs = mlab.psd(x=x, NFFT=NFFT, Fs=Fs, detrend=detrend,
7181 window=window, noverlap=noverlap, pad_to=pad_to,
7182 sides=sides, scale_by_freq=scale_by_freq)
7183 freqs += Fc
7185 if scale_by_freq in (None, True):
7186 psd_units = 'dB/Hz'
7187 else:
7188 psd_units = 'dB'
7190 line = self.plot(freqs, 10 * np.log10(pxx), **kwargs)
7191 self.set_xlabel('Frequency')
7192 self.set_ylabel('Power Spectral Density (%s)' % psd_units)
7193 self.grid(True)
7195 vmin, vmax = self.get_ybound()
7196 step = max(10 * int(np.log10(vmax - vmin)), 1)
7197 ticks = np.arange(math.floor(vmin), math.ceil(vmax) + 1, step)
7198 self.set_yticks(ticks)
7200 if return_line is None or not return_line:
7201 return pxx, freqs
7202 else:
7203 return pxx, freqs, line
7205 @_preprocess_data(replace_names=["x", "y"], label_namer="y")
7206 @_docstring.dedent_interpd
7207 def csd(self, x, y, NFFT=None, Fs=None, Fc=None, detrend=None,
7208 window=None, noverlap=None, pad_to=None,
7209 sides=None, scale_by_freq=None, return_line=None, **kwargs):
7210 r"""
7211 Plot the cross-spectral density.
7213 The cross spectral density :math:`P_{xy}` by Welch's average
7214 periodogram method. The vectors *x* and *y* are divided into
7215 *NFFT* length segments. Each segment is detrended by function
7216 *detrend* and windowed by function *window*. *noverlap* gives
7217 the length of the overlap between segments. The product of
7218 the direct FFTs of *x* and *y* are averaged over each segment
7219 to compute :math:`P_{xy}`, with a scaling to correct for power
7220 loss due to windowing.
7222 If len(*x*) < *NFFT* or len(*y*) < *NFFT*, they will be zero
7223 padded to *NFFT*.
7225 Parameters
7226 ----------
7227 x, y : 1-D arrays or sequences
7228 Arrays or sequences containing the data.
7230 %(Spectral)s
7232 %(PSD)s
7234 noverlap : int, default: 0 (no overlap)
7235 The number of points of overlap between segments.
7237 Fc : int, default: 0
7238 The center frequency of *x*, which offsets the x extents of the
7239 plot to reflect the frequency range used when a signal is acquired
7240 and then filtered and downsampled to baseband.
7242 return_line : bool, default: False
7243 Whether to include the line object plotted in the returned values.
7245 Returns
7246 -------
7247 Pxy : 1-D array
7248 The values for the cross spectrum :math:`P_{xy}` before scaling
7249 (complex valued).
7251 freqs : 1-D array
7252 The frequencies corresponding to the elements in *Pxy*.
7254 line : `~matplotlib.lines.Line2D`
7255 The line created by this function.
7256 Only returned if *return_line* is True.
7258 Other Parameters
7259 ----------------
7260 data : indexable object, optional
7261 DATA_PARAMETER_PLACEHOLDER
7263 **kwargs
7264 Keyword arguments control the `.Line2D` properties:
7266 %(Line2D:kwdoc)s
7268 See Also
7269 --------
7270 psd : is equivalent to setting ``y = x``.
7272 Notes
7273 -----
7274 For plotting, the power is plotted as
7275 :math:`10 \log_{10}(P_{xy})` for decibels, though :math:`P_{xy}` itself
7276 is returned.
7278 References
7279 ----------
7280 Bendat & Piersol -- Random Data: Analysis and Measurement Procedures,
7281 John Wiley & Sons (1986)
7282 """
7283 if Fc is None:
7284 Fc = 0
7286 pxy, freqs = mlab.csd(x=x, y=y, NFFT=NFFT, Fs=Fs, detrend=detrend,
7287 window=window, noverlap=noverlap, pad_to=pad_to,
7288 sides=sides, scale_by_freq=scale_by_freq)
7289 # pxy is complex
7290 freqs += Fc
7292 line = self.plot(freqs, 10 * np.log10(np.abs(pxy)), **kwargs)
7293 self.set_xlabel('Frequency')
7294 self.set_ylabel('Cross Spectrum Magnitude (dB)')
7295 self.grid(True)
7297 vmin, vmax = self.get_ybound()
7298 step = max(10 * int(np.log10(vmax - vmin)), 1)
7299 ticks = np.arange(math.floor(vmin), math.ceil(vmax) + 1, step)
7300 self.set_yticks(ticks)
7302 if return_line is None or not return_line:
7303 return pxy, freqs
7304 else:
7305 return pxy, freqs, line
7307 @_preprocess_data(replace_names=["x"])
7308 @_docstring.dedent_interpd
7309 def magnitude_spectrum(self, x, Fs=None, Fc=None, window=None,
7310 pad_to=None, sides=None, scale=None,
7311 **kwargs):
7312 """
7313 Plot the magnitude spectrum.
7315 Compute the magnitude spectrum of *x*. Data is padded to a
7316 length of *pad_to* and the windowing function *window* is applied to
7317 the signal.
7319 Parameters
7320 ----------
7321 x : 1-D array or sequence
7322 Array or sequence containing the data.
7324 %(Spectral)s
7326 %(Single_Spectrum)s
7328 scale : {'default', 'linear', 'dB'}
7329 The scaling of the values in the *spec*. 'linear' is no scaling.
7330 'dB' returns the values in dB scale, i.e., the dB amplitude
7331 (20 * log10). 'default' is 'linear'.
7333 Fc : int, default: 0
7334 The center frequency of *x*, which offsets the x extents of the
7335 plot to reflect the frequency range used when a signal is acquired
7336 and then filtered and downsampled to baseband.
7338 Returns
7339 -------
7340 spectrum : 1-D array
7341 The values for the magnitude spectrum before scaling (real valued).
7343 freqs : 1-D array
7344 The frequencies corresponding to the elements in *spectrum*.
7346 line : `~matplotlib.lines.Line2D`
7347 The line created by this function.
7349 Other Parameters
7350 ----------------
7351 data : indexable object, optional
7352 DATA_PARAMETER_PLACEHOLDER
7354 **kwargs
7355 Keyword arguments control the `.Line2D` properties:
7357 %(Line2D:kwdoc)s
7359 See Also
7360 --------
7361 psd
7362 Plots the power spectral density.
7363 angle_spectrum
7364 Plots the angles of the corresponding frequencies.
7365 phase_spectrum
7366 Plots the phase (unwrapped angle) of the corresponding frequencies.
7367 specgram
7368 Can plot the magnitude spectrum of segments within the signal in a
7369 colormap.
7370 """
7371 if Fc is None:
7372 Fc = 0
7374 spec, freqs = mlab.magnitude_spectrum(x=x, Fs=Fs, window=window,
7375 pad_to=pad_to, sides=sides)
7376 freqs += Fc
7378 yunits = _api.check_getitem(
7379 {None: 'energy', 'default': 'energy', 'linear': 'energy',
7380 'dB': 'dB'},
7381 scale=scale)
7382 if yunits == 'energy':
7383 Z = spec
7384 else: # yunits == 'dB'
7385 Z = 20. * np.log10(spec)
7387 line, = self.plot(freqs, Z, **kwargs)
7388 self.set_xlabel('Frequency')
7389 self.set_ylabel('Magnitude (%s)' % yunits)
7391 return spec, freqs, line
7393 @_preprocess_data(replace_names=["x"])
7394 @_docstring.dedent_interpd
7395 def angle_spectrum(self, x, Fs=None, Fc=None, window=None,
7396 pad_to=None, sides=None, **kwargs):
7397 """
7398 Plot the angle spectrum.
7400 Compute the angle spectrum (wrapped phase spectrum) of *x*.
7401 Data is padded to a length of *pad_to* and the windowing function
7402 *window* is applied to the signal.
7404 Parameters
7405 ----------
7406 x : 1-D array or sequence
7407 Array or sequence containing the data.
7409 %(Spectral)s
7411 %(Single_Spectrum)s
7413 Fc : int, default: 0
7414 The center frequency of *x*, which offsets the x extents of the
7415 plot to reflect the frequency range used when a signal is acquired
7416 and then filtered and downsampled to baseband.
7418 Returns
7419 -------
7420 spectrum : 1-D array
7421 The values for the angle spectrum in radians (real valued).
7423 freqs : 1-D array
7424 The frequencies corresponding to the elements in *spectrum*.
7426 line : `~matplotlib.lines.Line2D`
7427 The line created by this function.
7429 Other Parameters
7430 ----------------
7431 data : indexable object, optional
7432 DATA_PARAMETER_PLACEHOLDER
7434 **kwargs
7435 Keyword arguments control the `.Line2D` properties:
7437 %(Line2D:kwdoc)s
7439 See Also
7440 --------
7441 magnitude_spectrum
7442 Plots the magnitudes of the corresponding frequencies.
7443 phase_spectrum
7444 Plots the unwrapped version of this function.
7445 specgram
7446 Can plot the angle spectrum of segments within the signal in a
7447 colormap.
7448 """
7449 if Fc is None:
7450 Fc = 0
7452 spec, freqs = mlab.angle_spectrum(x=x, Fs=Fs, window=window,
7453 pad_to=pad_to, sides=sides)
7454 freqs += Fc
7456 lines = self.plot(freqs, spec, **kwargs)
7457 self.set_xlabel('Frequency')
7458 self.set_ylabel('Angle (radians)')
7460 return spec, freqs, lines[0]
7462 @_preprocess_data(replace_names=["x"])
7463 @_docstring.dedent_interpd
7464 def phase_spectrum(self, x, Fs=None, Fc=None, window=None,
7465 pad_to=None, sides=None, **kwargs):
7466 """
7467 Plot the phase spectrum.
7469 Compute the phase spectrum (unwrapped angle spectrum) of *x*.
7470 Data is padded to a length of *pad_to* and the windowing function
7471 *window* is applied to the signal.
7473 Parameters
7474 ----------
7475 x : 1-D array or sequence
7476 Array or sequence containing the data
7478 %(Spectral)s
7480 %(Single_Spectrum)s
7482 Fc : int, default: 0
7483 The center frequency of *x*, which offsets the x extents of the
7484 plot to reflect the frequency range used when a signal is acquired
7485 and then filtered and downsampled to baseband.
7487 Returns
7488 -------
7489 spectrum : 1-D array
7490 The values for the phase spectrum in radians (real valued).
7492 freqs : 1-D array
7493 The frequencies corresponding to the elements in *spectrum*.
7495 line : `~matplotlib.lines.Line2D`
7496 The line created by this function.
7498 Other Parameters
7499 ----------------
7500 data : indexable object, optional
7501 DATA_PARAMETER_PLACEHOLDER
7503 **kwargs
7504 Keyword arguments control the `.Line2D` properties:
7506 %(Line2D:kwdoc)s
7508 See Also
7509 --------
7510 magnitude_spectrum
7511 Plots the magnitudes of the corresponding frequencies.
7512 angle_spectrum
7513 Plots the wrapped version of this function.
7514 specgram
7515 Can plot the phase spectrum of segments within the signal in a
7516 colormap.
7517 """
7518 if Fc is None:
7519 Fc = 0
7521 spec, freqs = mlab.phase_spectrum(x=x, Fs=Fs, window=window,
7522 pad_to=pad_to, sides=sides)
7523 freqs += Fc
7525 lines = self.plot(freqs, spec, **kwargs)
7526 self.set_xlabel('Frequency')
7527 self.set_ylabel('Phase (radians)')
7529 return spec, freqs, lines[0]
7531 @_preprocess_data(replace_names=["x", "y"])
7532 @_docstring.dedent_interpd
7533 def cohere(self, x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none,
7534 window=mlab.window_hanning, noverlap=0, pad_to=None,
7535 sides='default', scale_by_freq=None, **kwargs):
7536 r"""
7537 Plot the coherence between *x* and *y*.
7539 Coherence is the normalized cross spectral density:
7541 .. math::
7543 C_{xy} = \frac{|P_{xy}|^2}{P_{xx}P_{yy}}
7545 Parameters
7546 ----------
7547 %(Spectral)s
7549 %(PSD)s
7551 noverlap : int, default: 0 (no overlap)
7552 The number of points of overlap between blocks.
7554 Fc : int, default: 0
7555 The center frequency of *x*, which offsets the x extents of the
7556 plot to reflect the frequency range used when a signal is acquired
7557 and then filtered and downsampled to baseband.
7559 Returns
7560 -------
7561 Cxy : 1-D array
7562 The coherence vector.
7564 freqs : 1-D array
7565 The frequencies for the elements in *Cxy*.
7567 Other Parameters
7568 ----------------
7569 data : indexable object, optional
7570 DATA_PARAMETER_PLACEHOLDER
7572 **kwargs
7573 Keyword arguments control the `.Line2D` properties:
7575 %(Line2D:kwdoc)s
7577 References
7578 ----------
7579 Bendat & Piersol -- Random Data: Analysis and Measurement Procedures,
7580 John Wiley & Sons (1986)
7581 """
7582 cxy, freqs = mlab.cohere(x=x, y=y, NFFT=NFFT, Fs=Fs, detrend=detrend,
7583 window=window, noverlap=noverlap,
7584 scale_by_freq=scale_by_freq, sides=sides,
7585 pad_to=pad_to)
7586 freqs += Fc
7588 self.plot(freqs, cxy, **kwargs)
7589 self.set_xlabel('Frequency')
7590 self.set_ylabel('Coherence')
7591 self.grid(True)
7593 return cxy, freqs
7595 @_preprocess_data(replace_names=["x"])
7596 @_docstring.dedent_interpd
7597 def specgram(self, x, NFFT=None, Fs=None, Fc=None, detrend=None,
7598 window=None, noverlap=None,
7599 cmap=None, xextent=None, pad_to=None, sides=None,
7600 scale_by_freq=None, mode=None, scale=None,
7601 vmin=None, vmax=None, **kwargs):
7602 """
7603 Plot a spectrogram.
7605 Compute and plot a spectrogram of data in *x*. Data are split into
7606 *NFFT* length segments and the spectrum of each section is
7607 computed. The windowing function *window* is applied to each
7608 segment, and the amount of overlap of each segment is
7609 specified with *noverlap*. The spectrogram is plotted as a colormap
7610 (using imshow).
7612 Parameters
7613 ----------
7614 x : 1-D array or sequence
7615 Array or sequence containing the data.
7617 %(Spectral)s
7619 %(PSD)s
7621 mode : {'default', 'psd', 'magnitude', 'angle', 'phase'}
7622 What sort of spectrum to use. Default is 'psd', which takes the
7623 power spectral density. 'magnitude' returns the magnitude
7624 spectrum. 'angle' returns the phase spectrum without unwrapping.
7625 'phase' returns the phase spectrum with unwrapping.
7627 noverlap : int, default: 128
7628 The number of points of overlap between blocks.
7630 scale : {'default', 'linear', 'dB'}
7631 The scaling of the values in the *spec*. 'linear' is no scaling.
7632 'dB' returns the values in dB scale. When *mode* is 'psd',
7633 this is dB power (10 * log10). Otherwise this is dB amplitude
7634 (20 * log10). 'default' is 'dB' if *mode* is 'psd' or
7635 'magnitude' and 'linear' otherwise. This must be 'linear'
7636 if *mode* is 'angle' or 'phase'.
7638 Fc : int, default: 0
7639 The center frequency of *x*, which offsets the x extents of the
7640 plot to reflect the frequency range used when a signal is acquired
7641 and then filtered and downsampled to baseband.
7643 cmap : `.Colormap`, default: :rc:`image.cmap`
7645 xextent : *None* or (xmin, xmax)
7646 The image extent along the x-axis. The default sets *xmin* to the
7647 left border of the first bin (*spectrum* column) and *xmax* to the
7648 right border of the last bin. Note that for *noverlap>0* the width
7649 of the bins is smaller than those of the segments.
7651 data : indexable object, optional
7652 DATA_PARAMETER_PLACEHOLDER
7654 **kwargs
7655 Additional keyword arguments are passed on to `~.axes.Axes.imshow`
7656 which makes the specgram image. The origin keyword argument
7657 is not supported.
7659 Returns
7660 -------
7661 spectrum : 2D array
7662 Columns are the periodograms of successive segments.
7664 freqs : 1-D array
7665 The frequencies corresponding to the rows in *spectrum*.
7667 t : 1-D array
7668 The times corresponding to midpoints of segments (i.e., the columns
7669 in *spectrum*).
7671 im : `.AxesImage`
7672 The image created by imshow containing the spectrogram.
7674 See Also
7675 --------
7676 psd
7677 Differs in the default overlap; in returning the mean of the
7678 segment periodograms; in not returning times; and in generating a
7679 line plot instead of colormap.
7680 magnitude_spectrum
7681 A single spectrum, similar to having a single segment when *mode*
7682 is 'magnitude'. Plots a line instead of a colormap.
7683 angle_spectrum
7684 A single spectrum, similar to having a single segment when *mode*
7685 is 'angle'. Plots a line instead of a colormap.
7686 phase_spectrum
7687 A single spectrum, similar to having a single segment when *mode*
7688 is 'phase'. Plots a line instead of a colormap.
7690 Notes
7691 -----
7692 The parameters *detrend* and *scale_by_freq* do only apply when *mode*
7693 is set to 'psd'.
7694 """
7695 if NFFT is None:
7696 NFFT = 256 # same default as in mlab.specgram()
7697 if Fc is None:
7698 Fc = 0 # same default as in mlab._spectral_helper()
7699 if noverlap is None:
7700 noverlap = 128 # same default as in mlab.specgram()
7701 if Fs is None:
7702 Fs = 2 # same default as in mlab._spectral_helper()
7704 if mode == 'complex':
7705 raise ValueError('Cannot plot a complex specgram')
7707 if scale is None or scale == 'default':
7708 if mode in ['angle', 'phase']:
7709 scale = 'linear'
7710 else:
7711 scale = 'dB'
7712 elif mode in ['angle', 'phase'] and scale == 'dB':
7713 raise ValueError('Cannot use dB scale with angle or phase mode')
7715 spec, freqs, t = mlab.specgram(x=x, NFFT=NFFT, Fs=Fs,
7716 detrend=detrend, window=window,
7717 noverlap=noverlap, pad_to=pad_to,
7718 sides=sides,
7719 scale_by_freq=scale_by_freq,
7720 mode=mode)
7722 if scale == 'linear':
7723 Z = spec
7724 elif scale == 'dB':
7725 if mode is None or mode == 'default' or mode == 'psd':
7726 Z = 10. * np.log10(spec)
7727 else:
7728 Z = 20. * np.log10(spec)
7729 else:
7730 raise ValueError(f'Unknown scale {scale!r}')
7732 Z = np.flipud(Z)
7734 if xextent is None:
7735 # padding is needed for first and last segment:
7736 pad_xextent = (NFFT-noverlap) / Fs / 2
7737 xextent = np.min(t) - pad_xextent, np.max(t) + pad_xextent
7738 xmin, xmax = xextent
7739 freqs += Fc
7740 extent = xmin, xmax, freqs[0], freqs[-1]
7742 if 'origin' in kwargs:
7743 raise TypeError("specgram() got an unexpected keyword argument "
7744 "'origin'")
7746 im = self.imshow(Z, cmap, extent=extent, vmin=vmin, vmax=vmax,
7747 origin='upper', **kwargs)
7748 self.axis('auto')
7750 return spec, freqs, t, im
7752 @_docstring.dedent_interpd
7753 def spy(self, Z, precision=0, marker=None, markersize=None,
7754 aspect='equal', origin="upper", **kwargs):
7755 """
7756 Plot the sparsity pattern of a 2D array.
7758 This visualizes the non-zero values of the array.
7760 Two plotting styles are available: image and marker. Both
7761 are available for full arrays, but only the marker style
7762 works for `scipy.sparse.spmatrix` instances.
7764 **Image style**
7766 If *marker* and *markersize* are *None*, `~.Axes.imshow` is used. Any
7767 extra remaining keyword arguments are passed to this method.
7769 **Marker style**
7771 If *Z* is a `scipy.sparse.spmatrix` or *marker* or *markersize* are
7772 *None*, a `.Line2D` object will be returned with the value of marker
7773 determining the marker type, and any remaining keyword arguments
7774 passed to `~.Axes.plot`.
7776 Parameters
7777 ----------
7778 Z : (M, N) array-like
7779 The array to be plotted.
7781 precision : float or 'present', default: 0
7782 If *precision* is 0, any non-zero value will be plotted. Otherwise,
7783 values of :math:`|Z| > precision` will be plotted.
7785 For `scipy.sparse.spmatrix` instances, you can also
7786 pass 'present'. In this case any value present in the array
7787 will be plotted, even if it is identically zero.
7789 aspect : {'equal', 'auto', None} or float, default: 'equal'
7790 The aspect ratio of the Axes. This parameter is particularly
7791 relevant for images since it determines whether data pixels are
7792 square.
7794 This parameter is a shortcut for explicitly calling
7795 `.Axes.set_aspect`. See there for further details.
7797 - 'equal': Ensures an aspect ratio of 1. Pixels will be square.
7798 - 'auto': The Axes is kept fixed and the aspect is adjusted so
7799 that the data fit in the Axes. In general, this will result in
7800 non-square pixels.
7801 - *None*: Use :rc:`image.aspect`.
7803 origin : {'upper', 'lower'}, default: :rc:`image.origin`
7804 Place the [0, 0] index of the array in the upper left or lower left
7805 corner of the Axes. The convention 'upper' is typically used for
7806 matrices and images.
7808 Returns
7809 -------
7810 `~matplotlib.image.AxesImage` or `.Line2D`
7811 The return type depends on the plotting style (see above).
7813 Other Parameters
7814 ----------------
7815 **kwargs
7816 The supported additional parameters depend on the plotting style.
7818 For the image style, you can pass the following additional
7819 parameters of `~.Axes.imshow`:
7821 - *cmap*
7822 - *alpha*
7823 - *url*
7824 - any `.Artist` properties (passed on to the `.AxesImage`)
7826 For the marker style, you can pass any `.Line2D` property except
7827 for *linestyle*:
7829 %(Line2D:kwdoc)s
7830 """
7831 if marker is None and markersize is None and hasattr(Z, 'tocoo'):
7832 marker = 's'
7833 _api.check_in_list(["upper", "lower"], origin=origin)
7834 if marker is None and markersize is None:
7835 Z = np.asarray(Z)
7836 mask = np.abs(Z) > precision
7838 if 'cmap' not in kwargs:
7839 kwargs['cmap'] = mcolors.ListedColormap(['w', 'k'],
7840 name='binary')
7841 if 'interpolation' in kwargs:
7842 raise TypeError(
7843 "spy() got an unexpected keyword argument 'interpolation'")
7844 if 'norm' not in kwargs:
7845 kwargs['norm'] = mcolors.NoNorm()
7846 ret = self.imshow(mask, interpolation='nearest',
7847 aspect=aspect, origin=origin,
7848 **kwargs)
7849 else:
7850 if hasattr(Z, 'tocoo'):
7851 c = Z.tocoo()
7852 if precision == 'present':
7853 y = c.row
7854 x = c.col
7855 else:
7856 nonzero = np.abs(c.data) > precision
7857 y = c.row[nonzero]
7858 x = c.col[nonzero]
7859 else:
7860 Z = np.asarray(Z)
7861 nonzero = np.abs(Z) > precision
7862 y, x = np.nonzero(nonzero)
7863 if marker is None:
7864 marker = 's'
7865 if markersize is None:
7866 markersize = 10
7867 if 'linestyle' in kwargs:
7868 raise TypeError(
7869 "spy() got an unexpected keyword argument 'linestyle'")
7870 ret = mlines.Line2D(
7871 x, y, linestyle='None', marker=marker, markersize=markersize,
7872 **kwargs)
7873 self.add_line(ret)
7874 nr, nc = Z.shape
7875 self.set_xlim(-0.5, nc - 0.5)
7876 if origin == "upper":
7877 self.set_ylim(nr - 0.5, -0.5)
7878 else:
7879 self.set_ylim(-0.5, nr - 0.5)
7880 self.set_aspect(aspect)
7881 self.title.set_y(1.05)
7882 if origin == "upper":
7883 self.xaxis.tick_top()
7884 else: # lower
7885 self.xaxis.tick_bottom()
7886 self.xaxis.set_ticks_position('both')
7887 self.xaxis.set_major_locator(
7888 mticker.MaxNLocator(nbins=9, steps=[1, 2, 5, 10], integer=True))
7889 self.yaxis.set_major_locator(
7890 mticker.MaxNLocator(nbins=9, steps=[1, 2, 5, 10], integer=True))
7891 return ret
7893 def matshow(self, Z, **kwargs):
7894 """
7895 Plot the values of a 2D matrix or array as color-coded image.
7897 The matrix will be shown the way it would be printed, with the first
7898 row at the top. Row and column numbering is zero-based.
7900 Parameters
7901 ----------
7902 Z : (M, N) array-like
7903 The matrix to be displayed.
7905 Returns
7906 -------
7907 `~matplotlib.image.AxesImage`
7909 Other Parameters
7910 ----------------
7911 **kwargs : `~matplotlib.axes.Axes.imshow` arguments
7913 See Also
7914 --------
7915 imshow : More general function to plot data on a 2D regular raster.
7917 Notes
7918 -----
7919 This is just a convenience function wrapping `.imshow` to set useful
7920 defaults for displaying a matrix. In particular:
7922 - Set ``origin='upper'``.
7923 - Set ``interpolation='nearest'``.
7924 - Set ``aspect='equal'``.
7925 - Ticks are placed to the left and above.
7926 - Ticks are formatted to show integer indices.
7928 """
7929 Z = np.asanyarray(Z)
7930 kw = {'origin': 'upper',
7931 'interpolation': 'nearest',
7932 'aspect': 'equal', # (already the imshow default)
7933 **kwargs}
7934 im = self.imshow(Z, **kw)
7935 self.title.set_y(1.05)
7936 self.xaxis.tick_top()
7937 self.xaxis.set_ticks_position('both')
7938 self.xaxis.set_major_locator(
7939 mticker.MaxNLocator(nbins=9, steps=[1, 2, 5, 10], integer=True))
7940 self.yaxis.set_major_locator(
7941 mticker.MaxNLocator(nbins=9, steps=[1, 2, 5, 10], integer=True))
7942 return im
7944 @_preprocess_data(replace_names=["dataset"])
7945 def violinplot(self, dataset, positions=None, vert=True, widths=0.5,
7946 showmeans=False, showextrema=True, showmedians=False,
7947 quantiles=None, points=100, bw_method=None):
7948 """
7949 Make a violin plot.
7951 Make a violin plot for each column of *dataset* or each vector in
7952 sequence *dataset*. Each filled area extends to represent the
7953 entire data range, with optional lines at the mean, the median,
7954 the minimum, the maximum, and user-specified quantiles.
7956 Parameters
7957 ----------
7958 dataset : Array or a sequence of vectors.
7959 The input data.
7961 positions : array-like, default: [1, 2, ..., n]
7962 The positions of the violins. The ticks and limits are
7963 automatically set to match the positions.
7965 vert : bool, default: True.
7966 If true, creates a vertical violin plot.
7967 Otherwise, creates a horizontal violin plot.
7969 widths : array-like, default: 0.5
7970 Either a scalar or a vector that sets the maximal width of
7971 each violin. The default is 0.5, which uses about half of the
7972 available horizontal space.
7974 showmeans : bool, default: False
7975 If `True`, will toggle rendering of the means.
7977 showextrema : bool, default: True
7978 If `True`, will toggle rendering of the extrema.
7980 showmedians : bool, default: False
7981 If `True`, will toggle rendering of the medians.
7983 quantiles : array-like, default: None
7984 If not None, set a list of floats in interval [0, 1] for each violin,
7985 which stands for the quantiles that will be rendered for that
7986 violin.
7988 points : int, default: 100
7989 Defines the number of points to evaluate each of the
7990 gaussian kernel density estimations at.
7992 bw_method : str, scalar or callable, optional
7993 The method used to calculate the estimator bandwidth. This can be
7994 'scott', 'silverman', a scalar constant or a callable. If a
7995 scalar, this will be used directly as `kde.factor`. If a
7996 callable, it should take a `matplotlib.mlab.GaussianKDE` instance as
7997 its only parameter and return a scalar. If None (default), 'scott'
7998 is used.
8000 data : indexable object, optional
8001 DATA_PARAMETER_PLACEHOLDER
8003 Returns
8004 -------
8005 dict
8006 A dictionary mapping each component of the violinplot to a
8007 list of the corresponding collection instances created. The
8008 dictionary has the following keys:
8010 - ``bodies``: A list of the `~.collections.PolyCollection`
8011 instances containing the filled area of each violin.
8013 - ``cmeans``: A `~.collections.LineCollection` instance that marks
8014 the mean values of each of the violin's distribution.
8016 - ``cmins``: A `~.collections.LineCollection` instance that marks
8017 the bottom of each violin's distribution.
8019 - ``cmaxes``: A `~.collections.LineCollection` instance that marks
8020 the top of each violin's distribution.
8022 - ``cbars``: A `~.collections.LineCollection` instance that marks
8023 the centers of each violin's distribution.
8025 - ``cmedians``: A `~.collections.LineCollection` instance that
8026 marks the median values of each of the violin's distribution.
8028 - ``cquantiles``: A `~.collections.LineCollection` instance created
8029 to identify the quantile values of each of the violin's
8030 distribution.
8032 """
8034 def _kde_method(X, coords):
8035 # Unpack in case of e.g. Pandas or xarray object
8036 X = cbook._unpack_to_numpy(X)
8037 # fallback gracefully if the vector contains only one value
8038 if np.all(X[0] == X):
8039 return (X[0] == coords).astype(float)
8040 kde = mlab.GaussianKDE(X, bw_method)
8041 return kde.evaluate(coords)
8043 vpstats = cbook.violin_stats(dataset, _kde_method, points=points,
8044 quantiles=quantiles)
8045 return self.violin(vpstats, positions=positions, vert=vert,
8046 widths=widths, showmeans=showmeans,
8047 showextrema=showextrema, showmedians=showmedians)
8049 def violin(self, vpstats, positions=None, vert=True, widths=0.5,
8050 showmeans=False, showextrema=True, showmedians=False):
8051 """
8052 Drawing function for violin plots.
8054 Draw a violin plot for each column of *vpstats*. Each filled area
8055 extends to represent the entire data range, with optional lines at the
8056 mean, the median, the minimum, the maximum, and the quantiles values.
8058 Parameters
8059 ----------
8060 vpstats : list of dicts
8061 A list of dictionaries containing stats for each violin plot.
8062 Required keys are:
8064 - ``coords``: A list of scalars containing the coordinates that
8065 the violin's kernel density estimate were evaluated at.
8067 - ``vals``: A list of scalars containing the values of the
8068 kernel density estimate at each of the coordinates given
8069 in *coords*.
8071 - ``mean``: The mean value for this violin's dataset.
8073 - ``median``: The median value for this violin's dataset.
8075 - ``min``: The minimum value for this violin's dataset.
8077 - ``max``: The maximum value for this violin's dataset.
8079 Optional keys are:
8081 - ``quantiles``: A list of scalars containing the quantile values
8082 for this violin's dataset.
8084 positions : array-like, default: [1, 2, ..., n]
8085 The positions of the violins. The ticks and limits are
8086 automatically set to match the positions.
8088 vert : bool, default: True.
8089 If true, plots the violins vertically.
8090 Otherwise, plots the violins horizontally.
8092 widths : array-like, default: 0.5
8093 Either a scalar or a vector that sets the maximal width of
8094 each violin. The default is 0.5, which uses about half of the
8095 available horizontal space.
8097 showmeans : bool, default: False
8098 If true, will toggle rendering of the means.
8100 showextrema : bool, default: True
8101 If true, will toggle rendering of the extrema.
8103 showmedians : bool, default: False
8104 If true, will toggle rendering of the medians.
8106 Returns
8107 -------
8108 dict
8109 A dictionary mapping each component of the violinplot to a
8110 list of the corresponding collection instances created. The
8111 dictionary has the following keys:
8113 - ``bodies``: A list of the `~.collections.PolyCollection`
8114 instances containing the filled area of each violin.
8116 - ``cmeans``: A `~.collections.LineCollection` instance that marks
8117 the mean values of each of the violin's distribution.
8119 - ``cmins``: A `~.collections.LineCollection` instance that marks
8120 the bottom of each violin's distribution.
8122 - ``cmaxes``: A `~.collections.LineCollection` instance that marks
8123 the top of each violin's distribution.
8125 - ``cbars``: A `~.collections.LineCollection` instance that marks
8126 the centers of each violin's distribution.
8128 - ``cmedians``: A `~.collections.LineCollection` instance that
8129 marks the median values of each of the violin's distribution.
8131 - ``cquantiles``: A `~.collections.LineCollection` instance created
8132 to identify the quantiles values of each of the violin's
8133 distribution.
8134 """
8136 # Statistical quantities to be plotted on the violins
8137 means = []
8138 mins = []
8139 maxes = []
8140 medians = []
8141 quantiles = []
8143 qlens = [] # Number of quantiles in each dataset.
8145 artists = {} # Collections to be returned
8147 N = len(vpstats)
8148 datashape_message = ("List of violinplot statistics and `{0}` "
8149 "values must have the same length")
8151 # Validate positions
8152 if positions is None:
8153 positions = range(1, N + 1)
8154 elif len(positions) != N:
8155 raise ValueError(datashape_message.format("positions"))
8157 # Validate widths
8158 if np.isscalar(widths):
8159 widths = [widths] * N
8160 elif len(widths) != N:
8161 raise ValueError(datashape_message.format("widths"))
8163 # Calculate ranges for statistics lines (shape (2, N)).
8164 line_ends = [[-0.25], [0.25]] * np.array(widths) + positions
8166 # Colors.
8167 if mpl.rcParams['_internal.classic_mode']:
8168 fillcolor = 'y'
8169 linecolor = 'r'
8170 else:
8171 fillcolor = linecolor = self._get_lines.get_next_color()
8173 # Check whether we are rendering vertically or horizontally
8174 if vert:
8175 fill = self.fill_betweenx
8176 perp_lines = functools.partial(self.hlines, colors=linecolor)
8177 par_lines = functools.partial(self.vlines, colors=linecolor)
8178 else:
8179 fill = self.fill_between
8180 perp_lines = functools.partial(self.vlines, colors=linecolor)
8181 par_lines = functools.partial(self.hlines, colors=linecolor)
8183 # Render violins
8184 bodies = []
8185 for stats, pos, width in zip(vpstats, positions, widths):
8186 # The 0.5 factor reflects the fact that we plot from v-p to v+p.
8187 vals = np.array(stats['vals'])
8188 vals = 0.5 * width * vals / vals.max()
8189 bodies += [fill(stats['coords'], -vals + pos, vals + pos,
8190 facecolor=fillcolor, alpha=0.3)]
8191 means.append(stats['mean'])
8192 mins.append(stats['min'])
8193 maxes.append(stats['max'])
8194 medians.append(stats['median'])
8195 q = stats.get('quantiles') # a list of floats, or None
8196 if q is None:
8197 q = []
8198 quantiles.extend(q)
8199 qlens.append(len(q))
8200 artists['bodies'] = bodies
8202 if showmeans: # Render means
8203 artists['cmeans'] = perp_lines(means, *line_ends)
8204 if showextrema: # Render extrema
8205 artists['cmaxes'] = perp_lines(maxes, *line_ends)
8206 artists['cmins'] = perp_lines(mins, *line_ends)
8207 artists['cbars'] = par_lines(positions, mins, maxes)
8208 if showmedians: # Render medians
8209 artists['cmedians'] = perp_lines(medians, *line_ends)
8210 if quantiles: # Render quantiles: each width is repeated qlen times.
8211 artists['cquantiles'] = perp_lines(
8212 quantiles, *np.repeat(line_ends, qlens, axis=1))
8214 return artists
8216 # Methods that are entirely implemented in other modules.
8218 table = mtable.table
8220 # args can by either Y or y1, y2, ... and all should be replaced
8221 stackplot = _preprocess_data()(mstack.stackplot)
8223 streamplot = _preprocess_data(
8224 replace_names=["x", "y", "u", "v", "start_points"])(mstream.streamplot)
8226 tricontour = mtri.tricontour
8227 tricontourf = mtri.tricontourf
8228 tripcolor = mtri.tripcolor
8229 triplot = mtri.triplot
8231 def _get_aspect_ratio(self):
8232 """
8233 Convenience method to calculate the aspect ratio of the axes in
8234 the display coordinate system.
8235 """
8236 figure_size = self.get_figure().get_size_inches()
8237 ll, ur = self.get_position() * figure_size
8238 width, height = ur - ll
8239 return height / (width * self.get_data_ratio())