return r  <ins>def _calculate_quad_point_coordinates(x, y, width, height, angle=0):    """    Calculate the coordinates of rectangle when rotated by angle around x, y    """    angle = math.radians(-angle)    sin_angle = math.sin(angle)    cos_angle = math.cos(angle)    a = x + height * sin_angle    b = y + height * cos_angle    c = x + width * cos_angle + height * sin_angle    d = y - width * sin_angle + height * cos_angle    e = x + width * cos_angle    f = y - width * sin_angle    return ((x, y), (e, f), (c, d), (a, b))def _get_coordinates_of_block(x, y, width, height, angle=0):    """    Get the coordinates of rotated rectangle and rectangle that covers the    rotated rectangle.    """    vertices = _calculate_quad_point_coordinates(x, y, width,                                                 height, angle)    # Find min and max values for rectangle    # adjust so that QuadPoints is inside Rect    # PDF docs says that QuadPoints should be ignored if any point lies    # outside Rect, but for Acrobat it is enough that QuadPoints is on the    # border of Rect.    pad = 0.00001 if angle % 90 else 0    min_x = min(v[0] for v in vertices) - pad    min_y = min(v[1] for v in vertices) - pad    max_x = max(v[0] for v in vertices) + pad    max_y = max(v[1] for v in vertices) + pad    return (tuple(itertools.chain.from_iterable(vertices)),            (min_x, min_y, max_x, max_y))def _get_link_annotation(gc, x, y, width, height, angle=0):    """    Create a link annotation object for embedding URLs.    """    quadpoints, rect = _get_coordinates_of_block(x, y, width, height, angle)    link_annotation = {        'Type': Name('Annot'),        'Subtype': Name('Link'),        'Rect': rect,        'Border': [0, 0, 0],        'A': {            'S': Name('URI'),            'URI': gc.get_url(),        },    }    if angle % 90:        # Add QuadPoints        link_annotation['QuadPoints'] = quadpoints    return link_annotation</ins> def pdfRepr(obj):     """Map Python objects to PDF syntax."""


self._text2path.mathtext_parser.parse(s, 72, prop)          if gc.get_url() is not None:            link_annotation = {                'Type': Name('Annot'),                'Subtype': Name('Link'),                'Rect': (x, y, x + width, y + height),                'Border': [0, 0, 0],                'A': {                    'S': Name('URI'),                    'URI': gc.get_url(),                },            }            self.file._annotations[-1][1].append(link_annotation)            self.file._annotations[-1][1].append(_get_link_annotation(                gc, x, y, width, height, angle))          fonttype = mpl.rcParams['pdf.fonttype']


page, = dvi          if gc.get_url() is not None:            link_annotation = {                'Type': Name('Annot'),                'Subtype': Name('Link'),                'Rect': (x, y, x + page.width, y + page.height),                'Border': [0, 0, 0],                'A': {                    'S': Name('URI'),                    'URI': gc.get_url(),                },            }            self.file._annotations[-1][1].append(link_annotation)            self.file._annotations[-1][1].append(_get_link_annotation(                gc, x, y, page.width, page.height, angle))          # Gather font information and do some setup for combining         # characters into strings. The variable seq will contain a


if gc.get_url() is not None:             font.set_text(s)             width, height = font.get_width_height()            link_annotation = {                'Type': Name('Annot'),                'Subtype': Name('Link'),                'Rect': (x, y, x + width / 64, y + height / 64),                'Border': [0, 0, 0],                'A': {                    'S': Name('URI'),                    'URI': gc.get_url(),                },            }            self.file._annotations[-1][1].append(link_annotation)            self.file._annotations[-1][1].append(_get_link_annotation(                gc, x, y, width / 64, height / 64, angle))          # If fonttype is neither 3 nor 42, emit the whole string at once         # without manual kerning.


"""     Return a context manager for temporarily changing rcParams. <ins>    The :rc:`backend` will not be reset by the context manager.</ins>     Parameters     ----------     rc : dict


plt.plot(x, y)  # uses 'print.rc'      """    orig = rcParams.copy()    orig = dict(rcParams.copy())    del orig['backend']     try:         if fname:             rc_file(fname)


@martist.allow_rasterization     def draw(self, renderer):<ins>        if not self.get_visible():            return</ins>         self._unstale_viewLim()          # draw the background patch


import functools import logging import mathimport numbersfrom numbers import Real import weakref  import numpy as np


self._renderer = None         if linespacing is None:             linespacing = 1.2  # Maybe use rcParam later.        self._linespacing = linespacing        self.set_linespacing(linespacing)         self.set_rotation_mode(rotation_mode)         self.update(kwargs)


----------         spacing : float (multiple of font size)         """<ins>        _api.check_isinstance(Real, spacing=spacing)</ins>         self._linespacing = spacing         self.stale = True


The rotation angle in degrees in mathematically positive direction             (counterclockwise). 'horizontal' equals 0, 'vertical' equals 90.         """        if isinstance(s, numbers.Real):        if isinstance(s, Real):             self._rotation = float(s) % 360         elif cbook._str_equal(s, 'horizontal') or s is None:             self._rotation = 0.


Showing a cursor on multiple plots simultaneously. This example generates two subplots and on hovering the cursor over data in onesubplot, the values of that datapoint are shown in both respectively.This example generates three axes split over two different figures.  Onhovering the cursor over data in one subplot, the values of that datapoint areshown in all axes. """ import numpy as np import matplotlib.pyplot as plt from matplotlib.widgets import MultiCursor  t = np.arange(0.0, 2.0, 0.01) s1 = np.sin(2*np.pi*t)s2 = np.sin(4*np.pi*t)s2 = np.sin(3*np.pi*t)s3 = np.sin(4*np.pi*t)  fig, (ax1, ax2) = plt.subplots(2, sharex=True) ax1.plot(t, s1) ax2.plot(t, s2)fig, ax3 = plt.subplots()ax3.plot(t, s3) multi = MultiCursor(fig.canvas, (ax1, ax2), color='r', lw=1)multi = MultiCursor(None, (ax1, ax2, ax3), color='r', lw=1) plt.show()  #############################################################################diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py-- a/lib/matplotlib/widgets.py++ b/lib/matplotlib/widgets.py


Parameters     ----------    canvas : `matplotlib.backend_bases.FigureCanvasBase`        The FigureCanvas that contains all the Axes.    canvas : object        This parameter is entirely unused and only kept for back-compatibility.      axes : list of `matplotlib.axes.Axes`         The `~.axes.Axes` to attach the cursor to.


See :doc:`/gallery/widgets/multicursor`.     """     @_api.make_keyword_only("3.6", "useblit")     def __init__(self, canvas, axes, useblit=True, horizOn=False, vertOn=True,                  **lineprops):        self.canvas = canvas        # canvas is stored only to provide the deprecated .canvas attribute;        # once it goes away the unused argument won't need to be stored at all.        self._canvas = canvas         self.axes = axes         self.horizOn = horizOn         self.vertOn = vertOn         self._canvas_infos = {            ax.figure.canvas: {"cids": [], "background": None} for ax in axes}         xmin, xmax = axes[-1].get_xlim()         ymin, ymax = axes[-1].get_ylim()         xmid = 0.5 * (xmin + xmax)         ymid = 0.5 * (ymin + ymax)          self.visible = True        self.useblit = useblit and self.canvas.supports_blit        self.background = None        self.useblit = (            useblit            and all(canvas.supports_blit for canvas in self._canvas_infos))         self.needclear = False          if self.useblit:


self.connect()     canvas = _api.deprecate_privatize_attribute("3.6")    background = _api.deprecated("3.6")(lambda self: (        self._backgrounds[self.axes[0].figure.canvas] if self.axes else None))     def connect(self):         """Connect events."""        self._cidmotion = self.canvas.mpl_connect('motion_notify_event',                                                  self.onmove)        self._ciddraw = self.canvas.mpl_connect('draw_event', self.clear)        for canvas, info in self._canvas_infos.items():            info["cids"] = [                canvas.mpl_connect('motion_notify_event', self.onmove),                canvas.mpl_connect('draw_event', self.clear),            ]      def disconnect(self):         """Disconnect events."""        self.canvas.mpl_disconnect(self._cidmotion)        self.canvas.mpl_disconnect(self._ciddraw)        for canvas, info in self._canvas_infos.items():            for cid in info["cids"]:                canvas.mpl_disconnect(cid)            info["cids"].clear()      def clear(self, event):         """Clear the cursor."""         if self.ignore(event):             return         if self.useblit:            self.background = (                self.canvas.copy_from_bbox(self.canvas.figure.bbox))            for canvas, info in self._canvas_infos.items():                info["background"] = canvas.copy_from_bbox(canvas.figure.bbox)         for line in self.vlines + self.hlines:             line.set_visible(False)      def onmove(self, event):        if self.ignore(event):            return        if event.inaxes not in self.axes:            return        if not self.canvas.widgetlock.available(self):        if (self.ignore(event)                or event.inaxes not in self.axes                or not event.canvas.widgetlock.available(self)):             return         self.needclear = True         if not self.visible:


def _update(self):         if self.useblit:            if self.background is not None:                self.canvas.restore_region(self.background)            for canvas, info in self._canvas_infos.items():                if info["background"]:                    canvas.restore_region(info["background"])             if self.vertOn:                 for ax, line in zip(self.axes, self.vlines):                     ax.draw_artist(line)             if self.horizOn:                 for ax, line in zip(self.axes, self.hlines):                     ax.draw_artist(line)            self.canvas.blit()            for canvas in self._canvas_infos:                canvas.blit()         else:            self.canvas.draw_idle()            for canvas in self._canvas_infos:                canvas.draw_idle()   class _SelectorWidget(AxesWidget):


# docstring inherited         if not self.get_visible():             return        # Patch has traditionally ignored the dashoffset.        with cbook._setattr_cm(                 self, _dash_pattern=(0, self._dash_pattern[1])), \        with cbook._setattr_cm(self, _dash_pattern=(self._dash_pattern)), \              self._bind_draw_path_function(renderer) as draw_path:             path = self.get_path()             transform = self.get_transform()


# Set cached renderer to None -- it can't be pickled.         state["_cachedRenderer"] = None <ins>        # discard any changes to the dpi due to pixel ratio changes        state["_dpi"] = state.get('_original_dpi', state['_dpi'])</ins>         # add version information to the state         state['__mpl_version__'] = mpl.__version__


collection.set_cmap(cmap)             collection.set_norm(norm)             collection._scale_norm(norm, vmin, vmax)<ins>        else:            extra_kwargs = {                    'cmap': cmap, 'norm': norm, 'vmin': vmin, 'vmax': vmax                    }            extra_keys = [k for k, v in extra_kwargs.items() if v is not None]            if any(extra_keys):                keys_str = ", ".join(f"'{k}'" for k in extra_keys)                _api.warn_external(                    "No data for colormapping provided via 'c'. "                    f"Parameters {keys_str} will be ignored")</ins>         collection._internal_update(kwargs)          # Classic mode only:


self.stale = True      def get_facecolor(self):        # docstring inherited        # self._facecolors2d is not initialized until do_3d_projection        if not hasattr(self, '_facecolors2d'):            self.axes.M = self.axes.get_proj()            self.do_3d_projection()         return self._facecolors2d      def get_edgecolor(self):        # docstring inherited        # self._edgecolors2d is not initialized until do_3d_projection        if not hasattr(self, '_edgecolors2d'):            self.axes.M = self.axes.get_proj()            self.do_3d_projection()         return self._edgecolors2d


def set_3d_properties(self, zs=0, zdir='z'):         xs = self.get_xdata()         ys = self.get_ydata()<ins>        zs = cbook._to_unmasked_float_array(zs).ravel()</ins>         zs = np.broadcast_to(zs, len(xs))         self._verts3d = juggle_axes(xs, ys, zs, zdir)         self.stale = True


"""          if ax is None:            ax = getattr(mappable, "axes", self.gca())            ax = getattr(mappable, "axes", None)          if (self.get_layout_engine() is not None and                 not self.get_layout_engine().colorbar_gridspec):             use_gridspec = False         # Store the value of gca so that we can set it back later on.         if cax is None:            if ax is None:                raise ValueError(                    'Unable to determine Axes to steal space for Colorbar. '                    'Either provide the *cax* argument to use as the Axes for '                    'the Colorbar, provide the *ax* argument to steal space '                    'from it, or add *mappable* to an Axes.')             current_ax = self.gca()             userax = False             if (use_gridspec and isinstance(ax, SubplotBase)):


import matplotlib as mplfrom matplotlib.backends.backend_webagg_core import (from matplotlib.backends.backend_webagg import (     FigureManagerWebAgg, new_figure_manager_given_figure) from matplotlib.figure import Figure diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py-- a/lib/matplotlib/backends/backend_webagg_core.py++ b/lib/matplotlib/backends/backend_webagg_core.py


class FigureManagerWebAgg(backend_bases.FigureManagerBase):    _toolbar2_class = ToolbarCls = NavigationToolbar2WebAgg    # This must be None to not break ipympl    _toolbar2_class = None    ToolbarCls = NavigationToolbar2WebAgg      def __init__(self, canvas, num):         self.web_sockets = set()


The custom dictionary mapping instances or types to a legend     handler. This *handler_map* updates the default handler map     found at `matplotlib.legend.Legend.get_legend_handler_map`.<ins>draggable : bool, default: False    Whether the legend can be dragged with the mouse.</ins> """)


title_fontproperties=None,  # properties for the legend title         alignment="center",       # control the alignment within the legend box         *,        ncol=1  # synonym for ncols (backward compatibility)        ncol=1,  # synonym for ncols (backward compatibility)        draggable=False  # whether the legend can be dragged with the mouse     ):         """         Parameters


title_prop_fp.set_size(title_fontsize)          self.set_title(title, prop=title_prop_fp)         self._draggable = None        self.set_draggable(state=draggable)          # set the text color


curr_stream[1].append(                     (item.x, item.ft_object.get_glyph_name(item.glyph_idx))                 )            # append the last entry            stream.append(curr_stream)            # append the last entry if exists            if curr_stream:                stream.append(curr_stream)          self.set_color(*gc.get_rgb())


if isinstance(tight_layout, dict):                 self.get_layout_engine().set(**tight_layout)         elif constrained_layout is not None:            self.set_layout_engine(layout='constrained')             if isinstance(constrained_layout, dict):                self.set_layout_engine(layout='constrained')                 self.get_layout_engine().set(**constrained_layout)            elif constrained_layout:                self.set_layout_engine(layout='constrained')         else:             # everything is None, so use default:             self.set_layout_engine(layout=layout)


(https://stackoverflow.com/users/66549/doug) """ <ins>import itertools</ins> import numpy as np  from matplotlib import _api


labels = iter(labels)     if colors is not None:        axes.set_prop_cycle(color=colors)        colors = itertools.cycle(colors)    else:        colors = (axes._get_lines.get_next_color() for _ in y)      # Assume data passed has not been 'stacked', so stack it here.     # We'll need a float buffer for the upcoming calculations.


stack += first_line      # Color between x = 0 and the first array.    color = axes._get_lines.get_next_color()     coll = axes.fill_between(x, first_line, stack[0, :],                             facecolor=color, label=next(labels, None),                             facecolor=next(colors), label=next(labels, None),                              **kwargs)     coll.sticky_edges.y[:] = [0]     r = [coll]      # Color between array i-1 and array i     for i in range(len(y) - 1):        color = axes._get_lines.get_next_color()         r.append(axes.fill_between(x, stack[i, :], stack[i + 1, :],                                   facecolor=color, label=next(labels, None),                                   facecolor=next(colors),                                   label=next(labels, None),                                    **kwargs))     return r


# Store the value of gca so that we can set it back later on.         if cax is None:             if ax is None:                raise ValueError(                _api.warn_deprecated("3.6", message=(                     'Unable to determine Axes to steal space for Colorbar. '                    'Using gca(), but will raise in the future. '                     'Either provide the *cax* argument to use as the Axes for '                     'the Colorbar, provide the *ax* argument to steal space '                    'from it, or add *mappable* to an Axes.')                    'from it, or add *mappable* to an Axes.'))                ax = self.gca()             current_ax = self.gca()             userax = False             if (use_gridspec and isinstance(ax, SubplotBase)):


r"""     Container for colormaps that are known to Matplotlib by name. <del>    .. admonition:: Experimental       While we expect the API to be final, we formally mark it as       experimental for 3.5 because we want to keep the option to still adapt       the API for 3.6 should the need arise.</del>     The universal registry instance is `matplotlib.colormaps`. There should be     no need for users to instantiate `.ColormapRegistry` themselves.


"colormap.")         self._cmaps.pop(name, None) <ins>    def get_cmap(self, cmap):        """        Return a color map specified through *cmap*.        Parameters        ----------        cmap : str or `~matplotlib.colors.Colormap` or None            - if a `.Colormap`, return it            - if a string, look it up in ``mpl.colormaps``            - if None, return the Colormap defined in :rc:`image.cmap`        Returns        -------        Colormap        """        # get the default color map        if cmap is None:            return self[mpl.rcParams["image.cmap"]]        # if the user passed in a Colormap, simply return it        if isinstance(cmap, colors.Colormap):            return cmap        if isinstance(cmap, str):            _api.check_in_list(sorted(_colormaps), cmap=cmap)            # otherwise, it must be a string so look it up            return self[cmap]        raise TypeError(            'get_cmap expects None or an instance of a str or Colormap . ' +            f'you passed {cmap!r} of type {type(cmap)}'        )</ins>  # public access to the colormaps should be via `matplotlib.colormaps`. For now, # we still create the registry here, but that should stay an implementation


# pyplot. get_cmap = _api.deprecated(     '3.6',    name='get_cmap', pending=True, alternative="``matplotlib.colormaps[name]``"    name='get_cmap',    pending=True,    alternative=(        "``matplotlib.colormaps[name]`` " +        "or ``matplotlib.colormaps.get_cmap(obj)``"    ) )(_get_cmap)


"""     Ensure that we have a `.Colormap` object. <ins>    For internal use to preserve type stability of errors.</ins>     Parameters     ----------     cmap : None, str, Colormap


Returns     -------     Colormap<ins></ins>     """     if isinstance(cmap, colors.Colormap):         return cmap


x0 = cbook._safe_first_finite(x0)             except (TypeError, IndexError, KeyError):                 pass            except StopIteration:                # this means we found no finite element, fall back to first                # element unconditionally                x0 = cbook.safe_first_element(x0)              try:                 x = cbook._safe_first_finite(xconv)             except (TypeError, IndexError, KeyError):                 x = xconv            except StopIteration:                # this means we found no finite element, fall back to first                # element unconditionally                x = cbook.safe_first_element(xconv)              delist = False             if not np.iterable(dx):


# Get all vertices on the path         # Loop through each segment to get extrema for Bezier curve sections         vertices = []        for curve, code in p.iter_bezier():        for curve, code in p.iter_bezier(simplify=False):             # Get distance along the curve of any extrema             _, dzeros = curve.axis_aligned_extrema()             # Calculate vertices of start, end and any extrema in between


Defines the relative widths of the columns. Each column gets a             relative width of ``width_ratios[i] / sum(width_ratios)``.             If not given, all columns will have the same width.  Equivalent            to ``gridspec_kw={'width_ratios': [...]}``.            to ``gridspec_kw={'width_ratios': [...]}``. In the case of nested            layouts, this argument applies only to the outer layout.          height_ratios : array-like of length *nrows*, optional             Defines the relative heights of the rows. Each row gets a             relative height of ``height_ratios[i] / sum(height_ratios)``.             If not given, all rows will have the same height. Equivalent            to ``gridspec_kw={'height_ratios': [...]}``.            to ``gridspec_kw={'height_ratios': [...]}``. In the case of nested            layouts, this argument applies only to the outer layout.          subplot_kw : dict, optional             Dictionary with keywords passed to the `.Figure.add_subplot` call


gridspec_kw : dict, optional             Dictionary with keywords passed to the `.GridSpec` constructor used            to create the grid the subplots are placed on.            to create the grid the subplots are placed on. In the case of            nested layouts, this argument applies only to the outer layout.            For more complex layouts, users should use `.Figure.subfigures`            to create the nesting.          empty_sentinel : object, optional             Entry in the layout to mean "leave this space empty".  Defaults


# recursively add the nested mosaic                     rows, cols = nested_mosaic.shape                     nested_output = _do_layout(                        gs[j, k].subgridspec(rows, cols, **gridspec_kw),                        gs[j, k].subgridspec(rows, cols),                         nested_mosaic,                         *_identify_keys_and_nested(nested_mosaic)                     )


UTC = datetime.timezone.utc  <ins>@_api.caching_module_getattrclass __getattr__:    JULIAN_OFFSET = _api.deprecated("3.7")(property(lambda self: 1721424.5))    # Julian date at 0000-12-31    # note that the Julian day epoch is achievable w/    # np.datetime64('-4713-11-24T12:00:00'); datetime64 is proleptic    # Gregorian and BC has a one-year offset.  So    # np.datetime64('0000-12-31') - np.datetime64('-4713-11-24T12:00') =    # 1721424.5    # Ref: https://en.wikipedia.org/wiki/Julian_day</ins> def _get_tzinfo(tz=None):     """     Generate tzinfo from a string or return tzinfo. If None,


# Time-related constants. EPOCH_OFFSET = float(datetime.datetime(1970, 1, 1).toordinal()) # EPOCH_OFFSET is not used by matplotlib<del>JULIAN_OFFSET = 1721424.5  # Julian date at 0000-12-31# note that the Julian day epoch is achievable w/# np.datetime64('-4713-11-24T12:00:00'); datetime64 is proleptic# Gregorian and BC has a one-year offset.  So# np.datetime64('0000-12-31') - np.datetime64('-4713-11-24T12:00') = 1721424.5# Ref: https://en.wikipedia.org/wiki/Julian_day</del> MICROSECONDLY = SECONDLY + 1 HOURS_PER_DAY = 24. MIN_PER_HOUR = 60.


return d if iterable else d[0]  <ins>@_api.deprecated("3.7")</ins> def julian2num(j):     """     Convert a Julian date (or sequence) to a Matplotlib date (or sequence).


ep0 = np.datetime64('0000-12-31T00:00:00', 'h').astype(float) / 24.     # Julian offset defined above is relative to 0000-12-31, but we need     # relative to our current epoch:    dt = JULIAN_OFFSET - ep0 + ep    dt = __getattr__("JULIAN_OFFSET") - ep0 + ep     return np.subtract(j, dt)  # Handles both scalar & nonscalar j.  @_api.deprecated("3.7") def num2julian(n):     """     Convert a Matplotlib date (or sequence) to a Julian date (or sequence).


ep0 = np.datetime64('0000-12-31T00:00:00', 'h').astype(float) / 24.     # Julian offset defined above is relative to 0000-12-31, but we need     # relative to our current epoch:    dt = JULIAN_OFFSET - ep0 + ep    dt = __getattr__("JULIAN_OFFSET") - ep0 + ep     return np.add(n, dt)  # Handles both scalar & nonscalar j.


# pickling.         self._canvas_callbacks = cbook.CallbackRegistry(             signals=FigureCanvasBase.events)<del>        self._button_pick_id = self._canvas_callbacks._connect_picklable(            'button_press_event', self.pick)        self._scroll_pick_id = self._canvas_callbacks._connect_picklable(            'scroll_event', self.pick)</del>         connect = self._canvas_callbacks._connect_picklable         self._mouse_key_ids = [             connect('key_press_event', backend_bases._key_handler),


connect('scroll_event', backend_bases._mouse_handler),             connect('motion_notify_event', backend_bases._mouse_handler),         ]<ins>        self._button_pick_id = connect('button_press_event', self.pick)        self._scroll_pick_id = connect('scroll_event', self.pick)</ins>          if figsize is None:             figsize = mpl.rcParams['figure.figsize']


import logging import os from pathlib import Pathimport sys import warnings if sys.version_info >= (3, 10):    import importlib.resources as importlib_resourceselse:    # Even though Py3.9 has importlib.resources, it doesn't properly handle    # modules added in sys.path.    import importlib_resources import matplotlib as mplfrom matplotlib import _api, _docstring, rc_params_from_file, rcParamsDefaultfrom matplotlib import _api, _docstring, _rc_params_in_file, rcParamsDefault  _log = logging.getLogger(__name__)


"directly use the seaborn API instead.")  <del>def _remove_blacklisted_style_params(d, warn=True):    o = {}    for key in d:  # prevent triggering RcParams.__getitem__('backend')        if key in STYLE_BLACKLIST:            if warn:                _api.warn_external(                    f"Style includes a parameter, {key!r}, that is not "                    "related to style.  Ignoring this parameter.")        else:            o[key] = d[key]    return odef _apply_style(d, warn=True):    mpl.rcParams.update(_remove_blacklisted_style_params(d, warn=warn))</del> @_docstring.Substitution(     "\n".join(map("- {}".format, sorted(STYLE_BLACKLIST, key=str.lower))) )


Parameters     ----------     style : str, dict, Path or list        A style specification. Valid options are:         +------+-------------------------------------------------------------+        | str  | The name of a style or a path/URL to a style file. For a    |        |      | list of available style names, see `.style.available`.      |        +------+-------------------------------------------------------------+        | dict | Dictionary with valid key/value pairs for                   |        |      | `matplotlib.rcParams`.                                      |        +------+-------------------------------------------------------------+        | Path | A path-like object which is a path to a style file.         |        +------+-------------------------------------------------------------+        | list | A list of style specifiers (str, Path or dict) applied from |        |      | first to last in the list.                                  |        +------+-------------------------------------------------------------+        A style specification.        - If a str, this can be one of the style names in `.style.available`          (a builtin style or a style installed in the user library path).          This can also be a dotted name of the form "package.style_name"; in          that case, "package" should be an importable Python package name,          e.g. at ``/path/to/package/__init__.py``; the loaded style file is          ``/path/to/package/style_name.mplstyle``.  (Style files in          subpackages are likewise supported.)          This can also be the path or URL to a style file, which gets loaded          by `.rc_params_from_file`.        - If a dict, this is a mapping of key/value pairs for `.rcParams`.        - If a Path, this is the path to a style file, which gets loaded by          `.rc_params_from_file`.        - If a list, this is a list of style specifiers (str, Path or dict),          which get applied from first to last in the list.      Notes     -----


style_alias = {'mpl20': 'default', 'mpl15': 'classic'}     def fix_style(s):        if isinstance(s, str):            s = style_alias.get(s, s)            if s in _DEPRECATED_SEABORN_STYLES:    for style in styles:        if isinstance(style, str):            style = style_alias.get(style, style)            if style in _DEPRECATED_SEABORN_STYLES:                 _api.warn_deprecated("3.6", message=_DEPRECATED_SEABORN_MSG)                s = _DEPRECATED_SEABORN_STYLES[s]        return s    for style in map(fix_style, styles):        if not isinstance(style, (str, Path)):            _apply_style(style)        elif style == 'default':            # Deprecation warnings were already handled when creating            # rcParamsDefault, no need to reemit them here.            with _api.suppress_matplotlib_deprecation_warning():                _apply_style(rcParamsDefault, warn=False)        elif style in library:            _apply_style(library[style])        else:                style = _DEPRECATED_SEABORN_STYLES[style]            if style == "default":                # Deprecation warnings were already handled when creating                # rcParamsDefault, no need to reemit them here.                with _api.suppress_matplotlib_deprecation_warning():                    # don't trigger RcParams.__getitem__('backend')                    style = {k: rcParamsDefault[k] for k in rcParamsDefault                             if k not in STYLE_BLACKLIST}            elif style in library:                style = library[style]            elif "." in style:                pkg, _, name = style.rpartition(".")                try:                    path = (importlib_resources.files(pkg)                            / f"{name}.{STYLE_EXTENSION}")                    style = _rc_params_in_file(path)                except (ModuleNotFoundError, IOError) as exc:                    # There is an ambiguity whether a dotted name refers to a                    # package.style_name or to a dotted file path.  Currently,                    # we silently try the first form and then the second one;                    # in the future, we may consider forcing file paths to                    # either use Path objects or be prepended with "./" and use                    # the slash as marker for file paths.                    pass        if isinstance(style, (str, Path)):             try:                rc = rc_params_from_file(style, use_default_template=False)                _apply_style(rc)                style = _rc_params_in_file(style)             except IOError as err:                 raise IOError(                    "{!r} not found in the style library and input is not a "                    "valid URL or path; see `style.available` for list of "                    "available styles".format(style)) from err                    f"{style!r} is not a valid package style, path of style "                    f"file, URL of style file, or library style name (library "                    f"styles are listed in `style.available`)") from err        filtered = {}        for k in style:  # don't trigger RcParams.__getitem__('backend')            if k in STYLE_BLACKLIST:                _api.warn_external(                    f"Style includes a parameter, {k!r}, that is not "                    f"related to style.  Ignoring this parameter.")            else:                filtered[k] = style[k]        mpl.rcParams.update(filtered)   @contextlib.contextmanager


styles = dict()     for path in Path(style_dir).glob(f"*.{STYLE_EXTENSION}"):         with warnings.catch_warnings(record=True) as warns:            styles[path.stem] = rc_params_from_file(                path, use_default_template=False)            styles[path.stem] = _rc_params_in_file(path)         for w in warns:             _log.warning('In %s: %s', path, w.message)     return stylesdiff --git a/setup.py b/setup.py-- a/setup.py++ b/setup.py


os.environ.get("CIBUILDWHEEL", "0") != "1"         ) else []     ),    extras_require={        ':python_version<"3.10"': [            "importlib-resources>=3.2.0",        ],    },     use_scm_version={         "version_scheme": "release-branch-semver",         "local_scheme": "node-and-date",diff --git a/tutorials/introductory/customizing.py b/tutorials/introductory/customizing.py-- a/tutorials/introductory/customizing.py++ b/tutorials/introductory/customizing.py


There are three ways to customize Matplotlib:     1. :ref:`Setting rcParams at runtime<customizing-with-dynamic-rc-settings>`.    2. :ref:`Using style sheets<customizing-with-style-sheets>`.    3. :ref:`Changing your matplotlibrc file<customizing-with-matplotlibrc-files>`.1. :ref:`Setting rcParams at runtime<customizing-with-dynamic-rc-settings>`.2. :ref:`Using style sheets<customizing-with-style-sheets>`.3. :ref:`Changing your matplotlibrc file<customizing-with-matplotlibrc-files>`.  Setting rcParams at runtime takes precedence over style sheets, style sheets take precedence over :file:`matplotlibrc` files.


#    >>> import matplotlib.pyplot as plt #    >>> plt.style.use('./images/presentation.mplstyle') #<ins>## Distributing styles# -------------------## You can include style sheets into standard importable Python packages (which# can be e.g. distributed on PyPI).  If your package is importable as# ``import mypackage``, with a ``mypackage/__init__.py`` module, and you add# a ``mypackage/presentation.mplstyle`` style sheet, then it can be used as# ``plt.style.use("mypackage.presentation")``.  Subpackages (e.g.# ``dotted.package.name``) are also supported.#</ins> # Alternatively, you can make your style known to Matplotlib by placing # your ``<style-name>.mplstyle`` file into ``mpl_configdir/stylelib``.  You # can then load your custom style sheet with a call to


'toolbar', 'timezone', 'figure.max_open_warning',     'figure.raise_window', 'savefig.directory', 'tk.window_focus',     'docstring.hardcopy', 'date.epoch'}<ins>_DEPRECATED_SEABORN_STYLES = {    s: s.replace("seaborn", "seaborn-v0_8")    for s in [        "seaborn",        "seaborn-bright",        "seaborn-colorblind",        "seaborn-dark",        "seaborn-darkgrid",        "seaborn-dark-palette",        "seaborn-deep",        "seaborn-muted",        "seaborn-notebook",        "seaborn-paper",        "seaborn-pastel",        "seaborn-poster",        "seaborn-talk",        "seaborn-ticks",        "seaborn-white",        "seaborn-whitegrid",    ]}_DEPRECATED_SEABORN_MSG = (    "The seaborn styles shipped by Matplotlib are deprecated since %(since)s, "    "as they no longer correspond to the styles shipped by seaborn. However, "    "they will remain available as 'seaborn-v0_8-<style>'. Alternatively, "    "directly use the seaborn API instead.")</ins>   def _remove_blacklisted_style_params(d, warn=True):


def fix_style(s):         if isinstance(s, str):             s = style_alias.get(s, s)            if s in [                "seaborn",                "seaborn-bright",                "seaborn-colorblind",                "seaborn-dark",                "seaborn-darkgrid",                "seaborn-dark-palette",                "seaborn-deep",                "seaborn-muted",                "seaborn-notebook",                "seaborn-paper",                "seaborn-pastel",                "seaborn-poster",                "seaborn-talk",                "seaborn-ticks",                "seaborn-white",                "seaborn-whitegrid",            ]:                _api.warn_deprecated(                    "3.6", message="The seaborn styles shipped by Matplotlib "                    "are deprecated since %(since)s, as they no longer "                    "correspond to the styles shipped by seaborn. However, "                    "they will remain available as 'seaborn-v0_8-


return main_dict  class _StyleLibrary(dict):    def __getitem__(self, key):        if key in _DEPRECATED_SEABORN_STYLES:            _api.warn_deprecated("3.6", message=_DEPRECATED_SEABORN_MSG)            key = _DEPRECATED_SEABORN_STYLES[key]        return dict.__getitem__(self, key) # Load style library # ================== _base_library = read_style_directory(BASE_LIBRARY_PATH)library = Nonelibrary = _StyleLibrary() available = []   def reload_library():     """Reload the style library."""    global library    library = update_user_library(_base_library)    library.clear()    library.update(update_user_library(_base_library))     available[:] = sorted(library.keys())


other limits, you should set the limits explicitly after setting the         ticks.         """<ins>        if labels is None and kwargs:            raise ValueError('labels argument cannot be None when '                             'kwargs are passed')</ins>         result = self._set_tick_locations(ticks, minor=minor)         if labels is not None:             self.set_ticklabels(labels, minor=minor, **kwargs)


raise ValueError("GridSpec.subplots() only works for GridSpecs "                              "created with a parent figure")         if isinstance(sharex, bool):        if not isinstance(sharex, str):             sharex = "all" if sharex else "none"        if isinstance(sharey, bool):        if not isinstance(sharey, str):             sharey = "all" if sharey else "none"        # This check was added because it is very easy to type        # `subplots(1, 2, 1)` when `subplot(1, 2, 1)` was intended.        # In most cases, no error will ever occur, but mysterious behavior        # will result because what was intended to be the subplot index is        # instead treated as a bool for sharex.  This check should go away        # once sharex becomes kwonly.        if isinstance(sharex, Integral):            _api.warn_external(                "sharex argument to subplots() was an integer.  Did you "                "intend to use subplot() (without 's')?")        _api.check_in_list(["all", "row", "col", "none"],        _api.check_in_list(["all", "row", "col", "none", False, True],                            sharex=sharex, sharey=sharey)         if subplot_kw is None:             subplot_kw = {}


# severe failure => one may appreciate a verbose feedback.                     raise ValueError(                         f"'c' argument must be a color, a sequence of colors, "                        f"or a sequence of numbers, not {c}") from err                        f"or a sequence of numbers, not {c!r}") from err             else:                 if len(colors) not in (0, 1, xsize):                     # NB: remember that a single color is also acceptable.


"colors", "linestyles"])     @_docstring.dedent_interpd     def eventplot(self, positions, orientation='horizontal', lineoffsets=1,                  linelengths=1, linewidths=None, colors=None,                  linelengths=1, linewidths=None, colors=None, alpha=None,                   linestyles='solid', **kwargs):         """         Plot identical parallel lines at the given positions.


If *positions* is 2D, this can be a sequence with length matching             the length of *positions*. <ins>        alpha : float or array-like, default: 1            The alpha blending value(s), between 0 (transparent) and 1            (opaque).            If *positions* is 2D, this can be a sequence with length matching            the length of *positions*.</ins>         linestyles : str or tuple or list of such values, default: 'solid'             Default is 'solid'. Valid strings are ['solid', 'dashed',             'dashdot', 'dotted', '-', '--', '-.', ':']. Dash tuples


Notes         -----        For *linelengths*, *linewidths*, *colors*, and *linestyles*, if only        a single value is given, that value is applied to all lines.  If an        For *linelengths*, *linewidths*, *colors*, *alpha* and *linestyles*, if        only a single value is given, that value is applied to all lines. If an         array-like is given, it must have the same length as *positions*, and         each value will be applied to the corresponding row of the array.


linewidths = [linewidths]         if not np.iterable(colors):             colors = [colors]<ins>        if not np.iterable(alpha):            alpha = [alpha]</ins>         if hasattr(linestyles, 'lower') or not np.iterable(linestyles):             linestyles = [linestyles]


if len(linewidths) == 1:             linewidths = np.tile(linewidths, len(positions))         if len(colors) == 1:            colors = list(colors)            colors = colors * len(positions)            colors = list(colors) * len(positions)        if len(alpha) == 1:            alpha = list(alpha) * len(positions)         if len(linestyles) == 1:             linestyles = [linestyles] * len(positions)


if len(colors) != len(positions):             raise ValueError('colors and positions are unequal sized '                              'sequences')        if len(alpha) != len(positions):            raise ValueError('alpha and positions are unequal sized '                             'sequences')         if len(linestyles) != len(positions):             raise ValueError('linestyles and positions are unequal sized '                              'sequences')          colls = []        for position, lineoffset, linelength, linewidth, color, linestyle in \        for position, lineoffset, linelength, linewidth, color, alpha_, \            linestyle in \                 zip(positions, lineoffsets, linelengths, linewidths,                    colors, linestyles):                    colors, alpha, linestyles):             coll = mcoll.EventCollection(position,                                          orientation=orientation,                                          lineoffset=lineoffset,                                          linelength=linelength,                                          linewidth=linewidth,                                          color=color,                                         alpha=alpha_,                                          linestyle=linestyle)             self.add_collection(coll, autolim=False)             coll._internal_update(kwargs)diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py-- a/lib/matplotlib/pyplot.py++ b/lib/matplotlib/pyplot.py


@_copy_docstring_and_deprecators(Axes.eventplot) def eventplot(         positions, orientation='horizontal', lineoffsets=1,        linelengths=1, linewidths=None, colors=None,        linelengths=1, linewidths=None, colors=None, alpha=None,         linestyles='solid', *, data=None, **kwargs):     return gca().eventplot(         positions, orientation=orientation, lineoffsets=lineoffsets,         linelengths=linelengths, linewidths=linewidths, colors=colors,        linestyles=linestyles,        alpha=alpha, linestyles=linestyles,         **({"data": data} if data is not None else {}), **kwargs)


descent = max(d for h, d in hd_list)         height = height_descent + descent         offsets = [0. for h, d in hd_list]    elif align in ["left", "top"]:    elif align in ["left", "bottom"]:         descent = 0.         offsets = [d for h, d in hd_list]    elif align in ["right", "bottom"]:    elif align in ["right", "top"]:         descent = 0.         offsets = [height - h + d for h, d in hd_list]     elif align == "center":


if len(args) == 1:             C = np.asanyarray(args[0])            nrows, ncols = C.shape            nrows, ncols = C.shape[:2]             if shading in ['gouraud', 'nearest']:                 X, Y = np.meshgrid(np.arange(ncols), np.arange(nrows))             else:


X = X.data  # strip mask as downstream doesn't like it...                 if isinstance(Y, np.ma.core.MaskedArray):                     Y = Y.data            nrows, ncols = C.shape            nrows, ncols = C.shape[:2]         else:             raise _api.nargs_error(funcname, takes="1 or 3", given=len(args))


Parameters         ----------        C : 2D array-like            The color-mapped values.  Color-mapping is controlled by *cmap*,            *norm*, *vmin*, and *vmax*.        C : array-like            The mesh data. Supported array shapes are:            - (M, N) or M*N: a mesh with scalar data. The values are mapped to              colors using normalization and a colormap. See parameters *norm*,              *cmap*, *vmin*, *vmax*.            - (M, N, 3): an image with RGB values (0-1 float or 0-255 int).            - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int),              i.e. including transparency.            The first two dimensions (M, N) define the rows and columns of            the mesh data.          X, Y : array-like, optional             The coordinates of the corners of quadrilaterals of a pcolormesh::


X, Y, C, shading = self._pcolorargs('pcolormesh', *args,                                             shading=shading, kwargs=kwargs)         coords = np.stack([X, Y], axis=-1)        # convert to one dimensional array        C = C.ravel()        # convert to one dimensional array, except for 3D RGB(A) arrays        if C.ndim != 3:            C = C.ravel()          kwargs.setdefault('snap', mpl.rcParams['pcolormesh.snap'])


if style == "quadmesh":             # data point in each cell is value at lower left corner             coords = np.stack([x, y], axis=-1)            if np.ndim(C) == 2:                qm_kwargs = {"array": np.ma.ravel(C)}            elif np.ndim(C) == 3:                qm_kwargs = {"color": np.ma.reshape(C, (-1, C.shape[-1]))}            else:            if np.ndim(C) not in {2, 3}:                 raise ValueError("C must be 2D or 3D")             collection = mcoll.QuadMesh(                coords, **qm_kwargs,                coords, array=C,                 alpha=alpha, cmap=cmap, norm=norm,                 antialiased=False, edgecolors="none")             self.add_collection(collection, autolim=False)diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py-- a/lib/matplotlib/collections.py++ b/lib/matplotlib/collections.py


Parameters         ----------        A : (M, N) array-like or M*N array-like        A : array-like            The mesh data. Supported array shapes are:            - (M, N) or M*N: a mesh with scalar data. The values are mapped to              colors using normalization and a colormap. See parameters *norm*,              *cmap*, *vmin*, *vmax*.            - (M, N, 3): an image with RGB values (0-1 float or 0-255 int).            - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int),              i.e. including transparency.             If the values are provided as a 2D grid, the shape must match the             coordinates grid. If the values are 1D, they are reshaped to 2D.             M, N follow from the coordinates grid, where the coordinates grid


if len(shape) == 1:                 if shape[0] != (h*w):                     faulty_data = True            elif shape != (h, w):                if np.prod(shape) == (h * w):            elif shape[:2] != (h, w):                if np.prod(shape[:2]) == (h * w):                     misshapen_data = True                 else:                     faulty_data = True            elif len(shape) == 3 and shape[2] not in {3, 4}:                # 3D data must be RGB(A) (h, w, [3,4])                # the (h, w) check is taken care of above                raise ValueError(                    f"For X ({width}) and Y ({height}) with "                    f"{self._shading} shading, the expected shape of "                    f"A with RGB(A) colors is ({h}, {w}, [3 or 4]), not "                    f"{A.shape}")              if misshapen_data:                 raise ValueError(


self._get_patches_for_fill = _process_plot_var_args(self, 'fill')          self._gridOn = mpl.rcParams['axes.grid']        self._children = []        old_children, self._children = self._children, []        for chld in old_children:            chld.axes = chld.figure = None         self._mouseover_set = _OrderedSet()         self.child_axes = []         self._current_image = None  # strictly for pyplot via _sci, _gci


self._renderer = renderer         if not self.get_visible() or not self._check_xy(renderer):             return<ins>        renderer.open_group(self.__class__.__name__, gid=self.get_gid())</ins>         self.update_positions(renderer)         if self.arrow_patch is not None:             if self.arrow_patch.figure is None and self.figure is not None:


self.arrow_patch.draw(renderer)         self.patch.draw(renderer)         self.offsetbox.draw(renderer)<ins>        renderer.close_group(self.__class__.__name__)</ins>         self.stale = False


"""=================================Ways to set a color's alpha value=================================Compare setting alpha by the *alpha* keyword argument and by one of the Matplotlib colorformats. Often, the *alpha* keyword is the only tool needed to add transparency to acolor. In some cases, the *(matplotlib_color, alpha)* color format provides an easy wayto fine-tune the appearance of a Figure."""import matplotlib.pyplot as pltimport numpy as np# Fixing random state for reproducibility.np.random.seed(19680801)fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(8, 4))x_values = [n for n in range(20)]y_values = np.random.randn(20)facecolors = ['green' if y > 0 else 'red' for y in y_values]edgecolors = facecolorsax1.bar(x_values, y_values, color=facecolors, edgecolor=edgecolors, alpha=0.5)ax1.set_title("Explicit 'alpha' keyword value\nshared by all bars and edges")# Normalize y values to get distinct face alpha values.abs_y = [abs(y) for y in y_values]face_alphas = [n / max(abs_y) for n in abs_y]edge_alphas = [1 - alpha for alpha in face_alphas]colors_with_alphas = list(zip(facecolors, face_alphas))edgecolors_with_alphas = list(zip(edgecolors, edge_alphas))ax2.bar(x_values, y_values, color=colors_with_alphas,        edgecolor=edgecolors_with_alphas)ax2.set_title('Normalized alphas for\neach bar and each edge')plt.show()# %%## .. admonition:: References##    The use of the following functions, methods, classes and modules is shown#    in this example:##    - `matplotlib.axes.Axes.bar`#    - `matplotlib.pyplot.subplots`diff --git a/galleries/users_explain/colors/colors.py b/galleries/users_explain/colors/colors.py-- a/galleries/users_explain/colors/colors.py++ b/galleries/users_explain/colors/colors.py


|           to black if cycle does not |                                      | |           include color.             |                                      | +--------------------------------------+--------------------------------------+| Tuple of one of the above color      | - ``('green', 0.3)``                 || formats and an alpha float.          | - ``('#f00', 0.9)``                  |+--------------------------------------+--------------------------------------+  .. _xkcd color survey: https://xkcd.com/color/rgb/ diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py-- a/lib/matplotlib/colors.py++ b/lib/matplotlib/colors.py


*alpha* is ignored for the color value ``"none"`` (case-insensitive),     which always maps to ``(0, 0, 0, 0)``.     """<ins>    if isinstance(c, tuple) and len(c) == 2:        if alpha is None:            c, alpha = c        else:            c = c[0]    if alpha is not None and not 0 <= alpha <= 1:        raise ValueError("'alpha' must be between 0 and 1, inclusive")</ins>     orig_c = c     if c is np.ma.masked:         return (0., 0., 0., 0.)


(n, 4) array of RGBA colors,  where each channel (red, green, blue,         alpha) can assume values between 0 and 1.     """<ins>    if isinstance(c, tuple) and len(c) == 2:        if alpha is None:            c, alpha = c        else:            c = c[0]</ins>     # Special-case inputs that are already arrays, for performance.  (If the     # array has the wrong kind or shape, raise the error during one-at-a-time     # conversion.)


return np.array([to_rgba(c, a) for a in alpha], float)         else:             return np.array([to_rgba(c, alpha)], float)    except (ValueError, TypeError):    except TypeError:         pass    except ValueError as e:        if e.args == ("'alpha' must be between 0 and 1, inclusive", ):            # ValueError is from _to_rgba_no_colorcycle().            raise e     if isinstance(c, str):         raise ValueError(f"{c!r} is not a valid color value.")


"""         Process args and kwargs.         """        if isinstance(args[0], QuadContourSet):        if args and isinstance(args[0], QuadContourSet):             if self.levels is None:                 self.levels = args[0].levels             self.zmin = args[0].zmin


else:             fn = 'contour'         nargs = len(args)        if nargs <= 2:        if 0 < nargs <= 2:             z, *args = args             z = ma.asarray(z)             x, y = self._initialize_x_y(z)        elif nargs <= 4:        elif 2 < nargs <= 4:             x, y, z_orig, *args = args             x, y, z = self._check_xyz(x, y, z_orig, kwargs)         else:             raise _api.nargs_error(fn, takes="from 1 to 4", given=nargs)         z = ma.masked_invalid(z, copy=False)


if (rasterization_zorder is not None and                 artists and artists[0].zorder < rasterization_zorder):            renderer.start_rasterizing()            artists_rasterized = [a for a in artists                                  if a.zorder < rasterization_zorder]            artists = [a for a in artists                       if a.zorder >= rasterization_zorder]            split_index = np.searchsorted(                [art.zorder for art in artists],                rasterization_zorder, side='right'            )            artists_rasterized = artists[:split_index]            artists = artists[split_index:]         else:             artists_rasterized = []         # the patch draws the background rectangle -- the frame below        # will draw the edges         if self.axison and self._frameon:            self.patch.draw(renderer)            if artists_rasterized:                artists_rasterized = [self.patch] + artists_rasterized            else:                artists = [self.patch] + artists          if artists_rasterized:            for a in artists_rasterized:                a.draw(renderer)            renderer.stop_rasterizing()            _draw_rasterized(self.figure, artists_rasterized, renderer)          mimage._draw_list_compositing_images(             renderer, self, artists, self.figure.suppressComposite)


self.yaxis.set_tick_params(which="both", labelright=False)             if self.yaxis.offsetText.get_position()[0] == 1:                 self.yaxis.offsetText.set_visible(False)<ins>def _draw_rasterized(figure, artists, renderer):    """    A helper function for rasterizing the list of artists.    The bookkeeping to track if we are or are not in rasterizing mode    with the mixed-mode backends is relatively complicated and is now    handled in the matplotlib.artist.allow_rasterization decorator.    This helper defines the absolute minimum methods and attributes on a    shim class to be compatible with that decorator and then uses it to    rasterize the list of artists.    This is maybe too-clever, but allows us to re-use the same code that is    used on normal artists to participate in the "are we rasterizing"    accounting.    Please do not use this outside of the "rasterize below a given zorder"    functionality of Axes.    Parameters    ----------    figure : matplotlib.figure.Figure        The figure all of the artists belong to (not checked).  We need this        because we can at the figure level suppress composition and insert each        rasterized artist as its own image.    artists : List[matplotlib.artist.Artist]        The list of Artists to be rasterized.  These are assumed to all        be in the same Figure.    renderer : matplotlib.backendbases.RendererBase        The currently active renderer    Returns    -------    None    """    class _MinimalArtist:        def get_rasterized(self):            return True        def get_agg_filter(self):            return None        def __init__(self, figure, artists):            self.figure = figure            self.artists = artists        @martist.allow_rasterization        def draw(self, renderer):            for a in self.artists:                a.draw(renderer)    return _MinimalArtist(figure, artists).draw(renderer)</ins>


line segments). """ <ins>import itertools</ins> import math from numbers import Number import warnings


# list of unbroadcast/scaled linewidths         self._us_lw = [0]         self._linewidths = [0]<ins>        self._gapcolor = None  # Currently only used by LineCollection.</ins>         # Flags set by _set_mappable_flags: are colors from mapping an array?         self._face_is_mapped = None         self._edge_is_mapped = None


gc, paths[0], combined_transform.frozen(),                 mpath.Path(offsets), offset_trf, tuple(facecolors[0]))         else:<ins>            if self._gapcolor is not None:                # First draw paths within the gaps.                ipaths, ilinestyles = self._get_inverse_paths_linestyles()                renderer.draw_path_collection(                    gc, transform.frozen(), ipaths,                    self.get_transforms(), offsets, offset_trf,                    [mcolors.to_rgba("none")], self._gapcolor,                    self._linewidths, ilinestyles,                    self._antialiaseds, self._urls,                    "screen")</ins>             renderer.draw_path_collection(                 gc, transform.frozen(), paths,                 self.get_transforms(), offsets, offset_trf,


def _get_default_facecolor(self):         return 'none' <ins>    def set_alpha(self, alpha):        # docstring inherited        super().set_alpha(alpha)        if self._gapcolor is not None:            self.set_gapcolor(self._original_gapcolor)</ins>     def set_color(self, c):         """         Set the edgecolor(s) of the LineCollection.


get_colors = get_color  # for compatibility with old versions     def set_gapcolor(self, gapcolor):        """        Set a color to fill the gaps in the dashed line style.        .. note::            Striped lines are created by drawing two interleaved dashed lines.            There can be overlaps between those two, which may result in            artifacts when using transparency.            This functionality is experimental and may change.        Parameters        ----------        gapcolor : color or list of colors or None            The color with which to fill the gaps. If None, the gaps are            unfilled.        """        self._original_gapcolor = gapcolor        self._set_gapcolor(gapcolor)    def _set_gapcolor(self, gapcolor):        if gapcolor is not None:            gapcolor = mcolors.to_rgba_array(gapcolor, self._alpha)        self._gapcolor = gapcolor        self.stale = True    def get_gapcolor(self):        return self._gapcolor    def _get_inverse_paths_linestyles(self):        """        Returns the path and pattern for the gaps in the non-solid lines.        This path and pattern is the inverse of the path and pattern used to        construct the non-solid lines. For solid lines, we set the inverse path        to nans to prevent drawing an inverse line.        """        path_patterns = [            (mpath.Path(np.full((1, 2), np.nan)), ls)            if ls == (0, None) else            (path, mlines._get_inverse_dash_pattern(*ls))            for (path, ls) in            zip(self._paths, itertools.cycle(self._linestyles))]        return zip(*path_patterns)  class EventCollection(LineCollection):     """diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py-- a/lib/matplotlib/lines.py++ b/lib/matplotlib/lines.py


return offset, dashes  <ins>def _get_inverse_dash_pattern(offset, dashes):    """Return the inverse of the given dash pattern, for filling the gaps."""    # Define the inverse pattern by moving the last gap to the start of the    # sequence.    gaps = dashes[-1:] + dashes[:-1]    # Set the offset so that this new first segment is skipped    # (see backend_bases.GraphicsContextBase.set_dashes for offset definition).    offset_gaps = offset + dashes[-1]    return offset_gaps, gaps</ins> def _scale_dashes(offset, dashes, lw):     if not mpl.rcParams['lines.scale_dashes']:         return offset, dashes


lc_rgba = mcolors.to_rgba(self._gapcolor, self._alpha)                     gc.set_foreground(lc_rgba, isRGBA=True)                     # Define the inverse pattern by moving the last gap to the                    # start of the sequence.                    dashes = self._dash_pattern[1]                    gaps = dashes[-1:] + dashes[:-1]                    # Set the offset so that this new first segment is skipped                    # (see backend_bases.GraphicsContextBase.set_dashes for                    # offset definition).                    offset_gaps = self._dash_pattern[0] + dashes[-1]                    offset_gaps, gaps = _get_inverse_dash_pattern(                        *self._dash_pattern)                      gc.set_dashes(offset_gaps, gaps)                     renderer.draw_path(gc, tpath, affine.frozen())


return lev[i0:i1]     def _process_contour_level_args(self, args):    def _process_contour_level_args(self, args, z_dtype):         """         Determine the contour levels and store in self.levels.         """         if self.levels is None:            if len(args) == 0:                levels_arg = 7  # Default, hard-wired.            else:            if args:                 levels_arg = args[0]            elif np.issubdtype(z_dtype, bool):                if self.filled:                    levels_arg = [0, .5, 1]                else:                    levels_arg = [.5]            else:                levels_arg = 7  # Default, hard-wired.         else:             levels_arg = self.levels         if isinstance(levels_arg, Integral):


fn = 'contour'         nargs = len(args)         if nargs <= 2:            z = ma.asarray(args[0], dtype=np.float64)            z, *args = args            z = ma.asarray(z)             x, y = self._initialize_x_y(z)            args = args[1:]         elif nargs <= 4:            x, y, z = self._check_xyz(args[:3], kwargs)            args = args[3:]            x, y, z_orig, *args = args            x, y, z = self._check_xyz(x, y, z_orig, kwargs)         else:             raise _api.nargs_error(fn, takes="from 1 to 4", given=nargs)         z = ma.masked_invalid(z, copy=False)


z = ma.masked_where(z <= 0, z)             _api.warn_external('Log scale: values of z <= 0 have been masked')             self.zmin = float(z.min())        self._process_contour_level_args(args)        self._process_contour_level_args(args, z.dtype)         return (x, y, z)     def _check_xyz(self, args, kwargs):    def _check_xyz(self, x, y, z, kwargs):         """         Check that the shapes of the input arrays match; if x and y are 1D,         convert them to 2D using meshgrid.         """        x, y = args[:2]         x, y = self.axes._process_unit_info([("x", x), ("y", y)], kwargs)          x = np.asarray(x, dtype=np.float64)         y = np.asarray(y, dtype=np.float64)        z = ma.asarray(args[2], dtype=np.float64)        z = ma.asarray(z)          if z.ndim != 2:             raise TypeError(f"Input z must be 2D, not {z.ndim}D")diff --git a/lib/matplotlib/tri/_tricontour.py b/lib/matplotlib/tri/_tricontour.py-- a/lib/matplotlib/tri/_tricontour.py++ b/lib/matplotlib/tri/_tricontour.py


def _contour_args(self, args, kwargs):         tri, args, kwargs = Triangulation.get_from_args_and_kwargs(*args,                                                                    **kwargs)        z = np.ma.asarray(args[0])        z, *args = args        z = np.ma.asarray(z)         if z.shape != tri.x.shape:             raise ValueError('z array must have same length as triangulation x'                              ' and y arrays')


if self.logscale and self.zmin <= 0:             func = 'contourf' if self.filled else 'contour'             raise ValueError(f'Cannot {func} log of negative values.')        self._process_contour_level_args(args[1:])        self._process_contour_level_args(args, z.dtype)         return (tri, z)


self.levels = self._autolev(levels_arg)         else:             self.levels = np.asarray(levels_arg, np.float64)        if not self.filled:            inside = (self.levels > self.zmin) & (self.levels < self.zmax)            levels_in = self.levels[inside]            if len(levels_in) == 0:                self.levels = [self.zmin]                _api.warn_external(                    "No contour levels were found within the data range.")         if self.filled and len(self.levels) < 2:             raise ValueError("Filled contours require at least 2 levels.")         if len(self.levels) > 1 and np.min(np.diff(self.levels)) <= 0.0:             raise ValueError("Contour levels must be increasing")


"""         if tight is None:             tight = mpl.rcParams['figure.autolayout']        _tight = 'tight' if bool(tight) else 'none'         _tight_parameters = tight if isinstance(tight, dict) else {}        if bool(tight):            self.set_layout_engine(TightLayoutEngine(**_tight_parameters))        self.set_layout_engine(_tight, **_tight_parameters)         self.stale = True      def get_constrained_layout(self):


"""         if constrained is None:             constrained = mpl.rcParams['figure.constrained_layout.use']        _constrained = bool(constrained)        _constrained = 'constrained' if bool(constrained) else 'none'         _parameters = constrained if isinstance(constrained, dict) else {}        if _constrained:            self.set_layout_engine(ConstrainedLayoutEngine(**_parameters))        self.set_layout_engine(_constrained, **_parameters)         self.stale = True      @_api.deprecated(


if not xa.dtype.isnative:             xa = xa.byteswap().newbyteorder()  # Native byteorder is faster.         if xa.dtype.kind == "f":            with np.errstate(invalid="ignore"):                xa *= self.N                # Negative values are out of range, but astype(int) would                # truncate them towards zero.                xa[xa < 0] = -1                # xa == 1 (== N after multiplication) is not out of range.                xa[xa == self.N] = self.N - 1                # Avoid converting large positive values to negative integers.                np.clip(xa, -1, self.N, out=xa)                xa = xa.astype(int)            xa *= self.N            # Negative values are out of range, but astype(int) would            # truncate them towards zero.            xa[xa < 0] = -1            # xa == 1 (== N after multiplication) is not out of range.            xa[xa == self.N] = self.N - 1            # Avoid converting large positive values to negative integers.            np.clip(xa, -1, self.N, out=xa)        with np.errstate(invalid="ignore"):            # We need this cast for unsigned ints as well as floats            xa = xa.astype(int)         # Set the over-range indices before the under-range;         # otherwise the under-range values get converted to over-range.         xa[xa > self.N - 1] = self._i_over


"""     origBbox = fig.bbox     origBboxInches = fig.bbox_inches<del>    orig_layout = fig.get_layout_engine()    fig.set_layout_engine(None)</del>     _boxout = fig.transFigure._boxout      old_aspect = []


fig.bbox = origBbox         fig.bbox_inches = origBboxInches<del>        fig.set_layout_engine(orig_layout)</del>         fig.transFigure._boxout = _boxout         fig.transFigure.invalidate()         fig.patch.set_bounds(0, 0, 1, 1)


loc : str             The position of the cell with respect to *ax*. This must be one of             the `~.Table.codes`.        bbox : `.Bbox` or None        bbox : `.Bbox` or [xmin, ymin, width, height], optional             A bounding box to draw the table into. If this is not *None*, this             overrides *loc*.


if self._bbox is not None:             # Position according to bbox            rl, rb, rw, rh = self._bbox            if isinstance(self._bbox, Bbox):                rl, rb, rw, rh = self._bbox.bounds            else:                rl, rb, rw, rh = self._bbox             self.scale(rw / w, rh / h)             ox = rl - l             oy = rb - b


The position of the cell with respect to *ax*. This must be one of         the `~.Table.codes`.     bbox : `.Bbox`, optional    bbox : `.Bbox` or [xmin, ymin, width, height], optional         A bounding box to draw the table into. If this is not *None*, this         overrides *loc*.


def autoscale(self, A):         """Set *vmin*, *vmax* to min, max of *A*."""        self.vmin = self.vmax = None        self.autoscale_None(A)        with self.callbacks.blocked():            # Pause callbacks while we are updating so we only get            # a single update signal at the end            self.vmin = self.vmax = None            self.autoscale_None(A)        self._changed()      def autoscale_None(self, A):         """If vmin or vmax are not set, use the min/max of *A* to set them."""


"""         return not self.active <ins>    def _changed_canvas(self):        """        Someone has switched the canvas on us!        This happens if `savefig` needs to save to a format the previous        backend did not support (e.g. saving a figure using an Agg based        backend saved to a vector format).        Returns        -------        bool           True if the canvas has been changed.        """        return self.canvas is not self.ax.figure.canvas</ins>  class AxesWidget(Widget):     """


def _clear(self, event):         """Internal event handler to clear the buttons."""        if self.ignore(event):        if self.ignore(event) or self._changed_canvas():             return         self._background = self.canvas.copy_from_bbox(self.ax.bbox)         self.ax.draw_artist(self._checks)


def _clear(self, event):         """Internal event handler to clear the buttons."""        if self.ignore(event):        if self.ignore(event) or self._changed_canvas():             return         self._background = self.canvas.copy_from_bbox(self.ax.bbox)         self.ax.draw_artist(self._buttons)


def clear(self, event):         """Internal event handler to clear the cursor."""        if self.ignore(event):        if self.ignore(event) or self._changed_canvas():             return         if self.useblit:             self.background = self.canvas.copy_from_bbox(self.ax.bbox)


return         if self.useblit:             for canvas, info in self._canvas_infos.items():<ins>                # someone has switched the canvas on us!  This happens if                # `savefig` needs to save to a format the previous backend did                # not support (e.g. saving a figure using an Agg based backend                # saved to a vector format).                if canvas is not canvas.figure.canvas:                    continue</ins>                 info["background"] = canvas.copy_from_bbox(canvas.figure.bbox)      def onmove(self, event):


elif mode == 'psd':         result = np.conj(result) * result     elif mode == 'magnitude':        result = np.abs(result) / np.abs(window).sum()        result = np.abs(result) / window.sum()     elif mode == 'angle' or mode == 'phase':         # we unwrap the phase later to handle the onesided vs. twosided case         result = np.angle(result)     elif mode == 'complex':        result /= np.abs(window).sum()        result /= window.sum()      if mode == 'psd':


result /= Fs             # Scale the spectrum by the norm of the window to compensate for             # windowing loss; see Bendat & Piersol Sec 11.5.2.            result /= (np.abs(window)**2).sum()            result /= (window**2).sum()         else:             # In this case, preserve power in the segment, not amplitude            result /= np.abs(window).sum()**2            result /= window.sum()**2      t = np.arange(NFFT/2, len(x) - NFFT/2 + 1, NFFT - noverlap)/Fs


dimensions as the current child.         """         if hasattr(self, "_child"):  # Absent during init.<ins>            self.invalidate()</ins>             new_dims = (child.input_dims, child.output_dims)             old_dims = (self._child.input_dims, self._child.output_dims)             if new_dims != old_dims:


The DPI (or resolution) for the file.  This controls the size             in pixels of the resulting movie file.         """<ins>        # Check that path is valid        Path(outfile).parent.resolve(strict=True)</ins>         self.outfile = outfile         self.fig = fig         if dpi is None:


deleted by `finish`; if not *None*, no temporary files are             deleted.         """<ins>        # Check that path is valid        Path(outfile).parent.resolve(strict=True)</ins>         self.fig = fig         self.outfile = outfile         if dpi is None:


self.fname_format_str = '%s%%07d.%s'      def __del__(self):        if self._tmpdir:        if hasattr(self, '_tmpdir') and self._tmpdir:             self._tmpdir.cleanup()      @property


import itertools import logging<ins>import numbers</ins> import time  import numpy as np


if not self.isaxes and loc in [0, 'best']:                 loc = 'upper right' <ins>        type_err_message = ("loc must be string, coordinate tuple, or"                            f" an integer 0-10, not {loc!r}")</ins>         # handle outside legends:         self._outside_loc = None         if isinstance(loc, str):


loc = locs[0] + ' ' + locs[1]             # check that loc is in acceptable strings             loc = _api.check_getitem(self.codes, loc=loc)<ins>        elif np.iterable(loc):            # coerce iterable into tuple            loc = tuple(loc)            # validate the tuple represents Real coordinates            if len(loc) != 2 or not all(isinstance(e, numbers.Real) for e in loc):                raise ValueError(type_err_message)        elif isinstance(loc, int):            # validate the integer represents a string numeric value            if loc < 0 or loc > 10:                raise ValueError(type_err_message)        else:            # all other cases are invalid values of loc            raise ValueError(type_err_message)</ins>          if self.isaxes and self._outside_loc:             raise ValueError(


)         self.label_position = 'bottom'         if mpl.rcParams['xtick.labelcolor'] == 'inherit':            tick_color = mpl.rcParams['xtick.color']        else:            tick_color = mpl.rcParams['xtick.labelcolor']         self.offsetText.set(             x=1, y=0,             verticalalignment='top', horizontalalignment='right',             transform=mtransforms.blended_transform_factory(                 self.axes.transAxes, mtransforms.IdentityTransform()),             fontsize=mpl.rcParams['xtick.labelsize'],            color=mpl.rcParams['xtick.color'],            color=tick_color         )         self.offset_text_position = 'bottom'


mtransforms.IdentityTransform(), self.axes.transAxes),         )         self.label_position = 'left'<ins>        if mpl.rcParams['ytick.labelcolor'] == 'inherit':            tick_color = mpl.rcParams['ytick.color']        else:            tick_color = mpl.rcParams['ytick.labelcolor']</ins>         # x in axes coords, y in display coords(!).         self.offsetText.set(             x=0, y=0.5,


transform=mtransforms.blended_transform_factory(                 self.axes.transAxes, mtransforms.IdentityTransform()),             fontsize=mpl.rcParams['ytick.labelsize'],            color=mpl.rcParams['ytick.color'],            color=tick_color         )         self.offset_text_position = 'left'


if not ref_artist.pickable():             ref_artist.set_picker(True)         self.got_artist = False<del>        self.canvas = self.ref_artist.figure.canvas</del>         self._use_blit = use_blit and self.canvas.supports_blit         self.cids = [             self.canvas.callbacks._connect_picklable(


'button_release_event', self.on_release),         ] <ins>    # A property, not an attribute, to maintain picklability.    canvas = property(lambda self: self.ref_artist.figure.canvas)</ins>     def on_motion(self, evt):         if self._check_still_parented() and self.got_artist:             dx = evt.x - self.mouse_x


def __init__(self, init=()):         self._mapping = {weakref.ref(x): [weakref.ref(x)] for x in init} <ins>    def __getstate__(self):        return {            **vars(self),            # Convert weak refs to strong ones.            "_mapping": {k(): [v() for v in vs] for k, vs in self._mapping.items()},        }    def __setstate__(self, state):        vars(self).update(state)        # Convert strong refs to weak ones.        self._mapping = {weakref.ref(k): [*map(weakref.ref, vs)]                         for k, vs in self._mapping.items()}</ins>     def __contains__(self, item):         return weakref.ref(item) in self._mapping


else:             raise _api.nargs_error(fn, takes="from 1 to 4", given=nargs)         z = ma.masked_invalid(z, copy=False)        self.zmax = float(z.max())        self.zmin = float(z.min())        self.zmax = z.max().astype(float)        self.zmin = z.min().astype(float)         if self.logscale and self.zmin <= 0:             z = ma.masked_where(z <= 0, z)             _api.warn_external('Log scale: values of z <= 0 have been masked')            self.zmin = float(z.min())            self.zmin = z.min().astype(float)         self._process_contour_level_args(args, z.dtype)         return (x, y, z)


valmin, valmax, valfmt, dragging, valstep)          # Set a value to allow _value_in_bounds() to work.        self.val = [valmin, valmax]        self.val = (valmin, valmax)         if valinit is None:             # Place at the 25th and 75th percentiles             extent = valmax - valmin


"""         val = np.sort(val)         _api.check_shape((2,), val=val)        vmin, vmax = val        vmin = self._min_in_bounds(vmin)        vmax = self._max_in_bounds(vmax)        # Reset value to allow _value_in_bounds() to work.        self.val = (self.valmin, self.valmax)        vmin, vmax = self._value_in_bounds(val)         self._update_selection_poly(vmin, vmax)         if self.orientation == "vertical":             self._handles[0].set_ydata([vmin])


of a rotated text when necessary.         """         thisx, thisy = 0.0, 0.0        lines = self.get_text().split("\n")  # Ensures lines is not empty.        lines = self._get_wrapped_text().split("\n")  # Ensures lines is not empty.          ws = []         hs = []


def set_props(self, **props):         """        Set the properties of the selector artist. See the `props` argument        in the selector docstring to know which properties are supported.        Set the properties of the selector artist.        See the *props* argument in the selector docstring to know which properties are        supported.         """         artist = self._selection_artist         props = cbook.normalize_kwargs(props, artist)         artist.set(**props)         if self.useblit:             self.update()        self._props.update(props)      def set_handle_props(self, **handle_props):         """


# but we maintain it until it is removed         self._pressv = None <del>        self._props = props</del>         self.onmove_callback = onmove_callback         self.minspan = minspan


# Reset canvas so that `new_axes` connects events.         self.canvas = None        self.new_axes(ax)        self.new_axes(ax, _props=props)          # Setup handles         self._handle_props = {


# prev attribute is deprecated but we still need to maintain it         self._prev = (0, 0)     def new_axes(self, ax):    def new_axes(self, ax, *, _props=None):         """Set SpanSelector to operate on a new Axes."""         self.ax = ax         if self.canvas is not ax.figure.canvas:


else:             trans = ax.get_yaxis_transform()             w, h = 1, 0        rect_artist = Rectangle((0, 0), w, h,                                transform=trans,                                visible=False,                                **self._props)        rect_artist = Rectangle((0, 0), w, h, transform=trans, visible=False)        if _props is not None:            rect_artist.update(_props)        elif self._selection_artist is not None:            rect_artist.update_from(self._selection_artist)          self.ax.add_patch(rect_artist)         self._selection_artist = rect_artist


if props is None:             props = dict(facecolor='red', edgecolor='black',                          alpha=0.2, fill=True)        self._props = {**props, 'animated': self.useblit}        self._visible = self._props.pop('visible', self._visible)        to_draw = self._init_shape(**self._props)        props = {**props, 'animated': self.useblit}        self._visible = props.pop('visible', self._visible)        to_draw = self._init_shape(**props)         self.ax.add_patch(to_draw)          self._selection_artist = to_draw


if self._interactive:             self._handle_props = {                'markeredgecolor': (self._props or {}).get(                    'edgecolor', 'black'),                'markeredgecolor': (props or {}).get('edgecolor', 'black'),                 **cbook.normalize_kwargs(handle_props, Line2D)}              self._corner_order = ['SW', 'SE', 'NE', 'NW']


if props is None:             props = dict(color='k', linestyle='-', linewidth=2, alpha=0.5)        self._props = {**props, 'animated': self.useblit}        self._selection_artist = line = Line2D([], [], **self._props)        props = {**props, 'animated': self.useblit}        self._selection_artist = line = Line2D([], [], **props)         self.ax.add_line(line)          if handle_props is None:             handle_props = dict(markeredgecolor='k',                                markerfacecolor=self._props.get('color', 'k'))                                markerfacecolor=props.get('color', 'k'))         self._handle_props = handle_props         self._polygon_handles = ToolHandles(self.ax, [], [],                                             useblit=self.useblit,


# Get decades between major ticks.         stride = (max(math.ceil(numdec / (numticks - 1)), 1)                   if mpl.rcParams['_internal.classic_mode'] else                  (numdec + 1) // numticks + 1)                  numdec // numticks + 1)          # if we have decided that the stride is as big or bigger than         # the range, clip the stride back to the available range - 1


def __str__(self):         try:            size = self.get_size()            return f"{type(self).__name__}(size={size!r})"            shape = self.get_shape()            return f"{type(self).__name__}(shape={shape!r})"         except RuntimeError:             return type(self).__name__


def get_size(self):         """Return the size of the image as tuple (numrows, numcols)."""        return self.get_shape()[:2]    def get_shape(self):        """        Return the shape of the image as tuple (numrows, numcols, channels).        """         if self._A is None:             raise RuntimeError('You must first set the image array')         return self._A.shape[:2]        return self._A.shape      def set_alpha(self, alpha):         """


"""         return self.renderer.buffer_rgba()     def print_raw(self, filename_or_obj):    def print_raw(self, filename_or_obj, *, metadata=None):        if metadata is not None:            raise ValueError("metadata not supported for raw/rgba")         FigureCanvasAgg.draw(self)         renderer = self.get_renderer()         with cbook.open_file_cm(filename_or_obj, "wb") as fh:


# print_figure(), and the latter ensures that `self.figure.dpi` already     # matches the dpi kwarg (if any).     def print_jpg(self, filename_or_obj, *, pil_kwargs=None):    def print_jpg(self, filename_or_obj, *, metadata=None, pil_kwargs=None):         # savefig() has already applied savefig.facecolor; we now set it to         # white to make imsave() blend semi-transparent figures against an         # assumed white background.         with mpl.rc_context({"savefig.facecolor": "white"}):            self._print_pil(filename_or_obj, "jpeg", pil_kwargs)            self._print_pil(filename_or_obj, "jpeg", pil_kwargs, metadata)      print_jpeg = print_jpg     def print_tif(self, filename_or_obj, *, pil_kwargs=None):        self._print_pil(filename_or_obj, "tiff", pil_kwargs)    def print_tif(self, filename_or_obj, *, metadata=None, pil_kwargs=None):        self._print_pil(filename_or_obj, "tiff", pil_kwargs, metadata)      print_tiff = print_tif     def print_webp(self, filename_or_obj, *, pil_kwargs=None):        self._print_pil(filename_or_obj, "webp", pil_kwargs)    def print_webp(self, filename_or_obj, *, metadata=None, pil_kwargs=None):        self._print_pil(filename_or_obj, "webp", pil_kwargs, metadata)      print_jpg.__doc__, print_tif.__doc__, print_webp.__doc__ = map(         """diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py-- a/lib/matplotlib/figure.py++ b/lib/matplotlib/figure.py


`~.FigureCanvasSVG.print_svg`.             - 'eps' and 'ps' with PS backend: Only 'Creator' is supported.             Not supported for 'pgf', 'raw', and 'rgba' as those formats do not support            embedding metadata.            Does not currently support 'jpg', 'tiff', or 'webp', but may include            embedding EXIF metadata in the future.         bbox_inches : str or `.Bbox`, default: :rc:`savefig.bbox`             Bounding box in inches: only the given portion of the figure is             saved.  If 'tight', try to figure out the tight bbox of the figure.diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py-- a/lib/matplotlib/image.py++ b/lib/matplotlib/image.py


Metadata in the image file.  The supported keys depend on the output         format, see the documentation of the respective backends for more         information.<ins>        Currently only supported for "png", "pdf", "ps", "eps", and "svg".</ins>     pil_kwargs : dict, optional         Keyword arguments passed to `PIL.Image.Image.save`.  If the 'pnginfo'         key is present, it completely overrides *metadata*, including the


for k, v in metadata.items():                     if v is not None:                         pnginfo.add_text(k, v)<ins>        elif metadata is not None:            raise ValueError(f"metadata not supported for format {format!r}")</ins>         if format in ["jpg", "jpeg"]:             format = "jpeg"  # Pillow doesn't recognize "jpg".             facecolor = mpl.rcParams["savefig.facecolor"]


self._axobservers.process("_axes_change_event", self)         self.stale = True         self._localaxes.remove(ax)<ins>        self.canvas.release_mouse(ax)</ins>          # Break link between any shared axes         for name in ax._axis_names:


ref_artist.set_picker(True)         self.got_artist = False         self._use_blit = use_blit and self.canvas.supports_blit        self.cids = [            self.canvas.callbacks._connect_picklable(                'pick_event', self.on_pick),            self.canvas.callbacks._connect_picklable(                'button_release_event', self.on_release),        callbacks = ref_artist.figure._canvas_callbacks        self._disconnectors = [            functools.partial(                callbacks.disconnect, callbacks._connect_picklable(name, func))            for name, func in [                ("pick_event", self.on_pick),                ("button_release_event", self.on_release),                ("motion_notify_event", self.on_motion),            ]         ]      # A property, not an attribute, to maintain picklability.     canvas = property(lambda self: self.ref_artist.figure.canvas)     cids = property(lambda self: [        disconnect.args[0] for disconnect in self._disconnectors[:2]])     def on_motion(self, evt):         if self._check_still_parented() and self.got_artist:             dx = evt.x - self.mouse_x


self.ref_artist.draw(                     self.ref_artist.figure._get_renderer())                 self.canvas.blit()            self._c1 = self.canvas.callbacks._connect_picklable(                "motion_notify_event", self.on_motion)             self.save_offset()      def on_release(self, event):         if self._check_still_parented() and self.got_artist:             self.finalize_offset()             self.got_artist = False            self.canvas.mpl_disconnect(self._c1)             if self._use_blit:                 self.ref_artist.set_animated(False)


def disconnect(self):         """Disconnect the callbacks."""        for cid in self.cids:            self.canvas.mpl_disconnect(cid)        try:            c1 = self._c1        except AttributeError:            pass        else:            self.canvas.mpl_disconnect(c1)        for disconnector in self._disconnectors:            disconnector()      def save_offset(self):         pass


"that was already in the registry.")          self._cmaps[name] = cmap.copy()        # Someone may set the extremes of a builtin colormap and want to register it        # with a different name for future lookups. The object would still have the        # builtin name, so we should update it to the registered name        if self._cmaps[name].name != name:            self._cmaps[name].name = name      def unregister(self, name):         """diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py-- a/lib/matplotlib/colors.py++ b/lib/matplotlib/colors.py


return cmapobject      def __eq__(self, other):        if (not isinstance(other, Colormap) or self.name != other.name or        if (not isinstance(other, Colormap) or                 self.colorbar_extend != other.colorbar_extend):             return False         # To compare lookup tables the Colormaps have to be initialized


if mappable is None:             mappable = cm.ScalarMappable(norm=norm, cmap=cmap) <del>        # Ensure the given mappable's norm has appropriate vmin and vmax        # set even if mappable.draw has not yet been called.        if mappable.get_array() is not None:            mappable.autoscale_None()</del>         self.mappable = mappable         cmap = mappable.cmap         norm = mappable.norm


b = np.hstack((b, b[-1] + 1))          # transform from 0-1 to vmin-vmax:        if self.mappable.get_array() is not None:            self.mappable.autoscale_None()         if not self.norm.scaled():            # If we still aren't scaled after autoscaling, use 0, 1 as default             self.norm.vmin = 0             self.norm.vmax = 1         self.norm.vmin, self.norm.vmax = mtransforms.nonsingular(


locator_list = []     sentinel = object()     for ax in fig.axes:        locator_list.append(ax.get_axes_locator())        locator = ax.get_axes_locator()        if locator is not None:            ax.apply_aspect(locator(ax, None))        locator_list.append(locator)         current_pos = ax.get_position(original=False).frozen()         ax.set_axes_locator(lambda a, r, _pos=current_pos: _pos)         # override the method that enforces the aspect ratio on the Axes


x0 = cbook._safe_first_finite(x0)             except (TypeError, IndexError, KeyError):                 pass            except StopIteration:                # this means we found no finite element, fall back to first                # element unconditionally                x0 = cbook.safe_first_element(x0)              try:                 x = cbook._safe_first_finite(xconv)             except (TypeError, IndexError, KeyError):                 x = xconv            except StopIteration:                # this means we found no finite element, fall back to first                # element unconditionally                x = cbook.safe_first_element(xconv)              delist = False             if not np.iterable(dx):diff --git a/lib/matplotlib/cbook.py b/lib/matplotlib/cbook.py-- a/lib/matplotlib/cbook.py++ b/lib/matplotlib/cbook.py


def _safe_first_finite(obj, *, skip_nonfinite=True):     """    Return the first non-None (and optionally finite) element in *obj*.    Return the first finite element in *obj* if one is available and skip_nonfinite is    True. Otherwise return the first element.      This is a method for internal use.     This is a type-independent way of obtaining the first non-None element,    supporting both index access and the iterator protocol.    The first non-None element will be obtained when skip_none is True.    This is a type-independent way of obtaining the first finite element, supporting    both index access and the iterator protocol.     """     def safe_isfinite(val):         if val is None:


raise RuntimeError("matplotlib does not "                            "support generators as input")     else:        return next(val for val in obj if safe_isfinite(val))        return next((val for val in obj if safe_isfinite(val)), safe_first_element(obj))   def sanitize_sequence(data):


"""         Save information required to reproduce the current view.         Called before a view is changed, such as during a pan or zoom        initiated by the user. You may return any information you deem        necessary to describe the view.        This method is called before a view is changed, such as during a pan or zoom        initiated by the user.  It returns an opaque object that describes the current        view, in a format compatible with :meth:`_set_view`.         .. note::            Intended to be overridden by new projection types, but if not, the            default implementation saves the view limits. You *must* implement            :meth:`_set_view` if you implement this method.        The default implementation saves the view limits and autoscaling state.        Subclasses may override this as needed, as long as :meth:`_set_view` is also        adjusted accordingly.         """        xmin, xmax = self.get_xlim()        ymin, ymax = self.get_ylim()        return xmin, xmax, ymin, ymax        return {            "xlim": self.get_xlim(), "autoscalex_on": self.get_autoscalex_on(),            "ylim": self.get_ylim(), "autoscaley_on": self.get_autoscaley_on(),        }      def _set_view(self, view):         """         Apply a previously saved view.         Called when restoring a view, such as with the navigation buttons.        This method is called when restoring a view (with the return value of        :meth:`_get_view` as argument), such as with the navigation buttons.         .. note::            Intended to be overridden by new projection types, but if not, the            default implementation restores the view limits. You *must*            implement :meth:`_get_view` if you implement this method.        Subclasses that override :meth:`_get_view` also need to override this method        accordingly.         """        xmin, xmax, ymin, ymax = view        self.set_xlim((xmin, xmax))        self.set_ylim((ymin, ymax))        self.set(**view)      def _prepare_view_from_bbox(self, bbox, direction='in',                                 mode=None, twinx=False, twiny=False):diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py-- a/lib/mpl_toolkits/mplot3d/axes3d.py++ b/lib/mpl_toolkits/mplot3d/axes3d.py


def _get_view(self):         # docstring inherited        return (self.get_xlim(), self.get_ylim(), self.get_zlim(),                self.elev, self.azim, self.roll)        return {            "xlim": self.get_xlim(), "autoscalex_on": self.get_autoscalex_on(),            "ylim": self.get_ylim(), "autoscaley_on": self.get_autoscaley_on(),            "zlim": self.get_zlim(), "autoscalez_on": self.get_autoscalez_on(),        }, (self.elev, self.azim, self.roll)      def _set_view(self, view):         # docstring inherited        xlim, ylim, zlim, elev, azim, roll = view        self.set(xlim=xlim, ylim=ylim, zlim=zlim)        props, (elev, azim, roll) = view        self.set(**props)         self.elev = elev         self.azim = azim         self.roll = roll


if not hasattr(self, '_facecolors2d'):             self.axes.M = self.axes.get_proj()             self.do_3d_projection()        return self._facecolors2d        return np.asarray(self._facecolors2d)      def get_edgecolor(self):         # docstring inherited


if not hasattr(self, '_edgecolors2d'):             self.axes.M = self.axes.get_proj()             self.do_3d_projection()        return self._edgecolors2d        return np.asarray(self._edgecolors2d)   def poly_collection_2d_to_3d(col, zs=0, zdir='z'):


and previous_engine is not None:                 _api.warn_external('The figure layout has changed to tight')         finally:            self.set_layout_engine(None)            self.set_layout_engine('none')   def figaspect(arg):


Grab the image information from the figure and save as a movie frame.          All keyword arguments in *savefig_kwargs* are passed on to the        `~.Figure.savefig` call that saves the figure.        `~.Figure.savefig` call that saves the figure.  However, several        keyword arguments that are supported by `~.Figure.savefig` may not be        passed as they are controlled by the MovieWriter:        - *dpi*, *bbox_inches*:  These may not be passed because each frame of the           animation much be exactly the same size in pixels.        - *format*: This is controlled by the MovieWriter.         """      @abc.abstractmethod