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