``*args, **kw`` are any parameters that should be passed to `setup`.         """        if mpl.rcParams['savefig.bbox'] == 'tight':            _log.info("Disabling savefig.bbox = 'tight', as it may cause "                      "frame size to vary, which is inappropriate for "                      "animation.")         # This particular sequence is what contextlib.contextmanager wants         self.setup(fig, outfile, dpi, *args, **kwargs)        try:            yield self        finally:            self.finish()        with mpl.rc_context({'savefig.bbox': None}):            try:                yield self            finally:                self.finish()   class MovieWriter(AbstractMovieWriter):


def grab_frame(self, **savefig_kwargs):         # docstring inherited<ins>        _validate_grabframe_kwargs(savefig_kwargs)</ins>         _log.debug('MovieWriter.grab_frame: Grabbing frame.')         # Readjust the figure size in case it has been changed by the user.         # All frames must have the same size to save the movie correctly.


def grab_frame(self, **savefig_kwargs):         # docstring inherited         # Creates a filename for saving using basename and counter.<ins>        _validate_grabframe_kwargs(savefig_kwargs)</ins>         path = Path(self._base_temp_name() % self._frame_counter)         self._temp_paths.append(path)  # Record the filename for later use.         self._frame_counter += 1  # Ensures each created name is unique.


self._frames = []      def grab_frame(self, **savefig_kwargs):<ins>        _validate_grabframe_kwargs(savefig_kwargs)</ins>         buf = BytesIO()         self.fig.savefig(             buf, **{**savefig_kwargs, "format": "rgba", "dpi": self.dpi})


self._clear_temp = False      def grab_frame(self, **savefig_kwargs):<ins>        _validate_grabframe_kwargs(savefig_kwargs)</ins>         if self.embed_frames:             # Just stop processing if we hit the limit             if self._hit_limit:


# TODO: Right now, after closing the figure, saving a movie won't work         # since GUI widgets are gone. Either need to remove extra code to         # allow for this non-existent use case or find a way to make it work.<del>        if mpl.rcParams['savefig.bbox'] == 'tight':            _log.info("Disabling savefig.bbox = 'tight', as it may cause "                      "frame size to vary, which is inappropriate for "                      "animation.")</del>          facecolor = savefig_kwargs.get('facecolor',                                        mpl.rcParams['savefig.facecolor'])


# canvas._is_saving = True makes the draw_event animation-starting         # callback a no-op; canvas.manager = None prevents resizing the GUI         # widget (both are likewise done in savefig()).        with mpl.rc_context({'savefig.bbox': None}), \             writer.saving(self._fig, filename, dpi), \             cbook._setattr_cm(self._fig.canvas,                               _is_saving=True, manager=None):        with writer.saving(self._fig, filename, dpi), \             cbook._setattr_cm(self._fig.canvas, _is_saving=True, manager=None):             for anim in all_anim:                 anim._init_draw()  # Clear the initial frame             frame_number = 0


a.set_animated(self._blit)      save_count = _api.deprecate_privatize_attribute("3.7")<ins>def _validate_grabframe_kwargs(savefig_kwargs):    if mpl.rcParams['savefig.bbox'] == 'tight':        raise ValueError(            f"{mpl.rcParams['savefig.bbox']=} must not be 'tight' as it "            "may cause frame size to vary, which is inappropriate for animation."        )    for k in ('dpi', 'bbox_inches', 'format'):        if k in savefig_kwargs:            raise TypeError(                f"grab_frame got an unexpected keyword argument {k!r}"            )</ins>


s = _escape_and_apply_props(s, prop)          _writeln(self.fh, r"\begin{pgfscope}")<ins>        self._print_pgf_clip(gc)</ins>          alpha = gc.get_alpha()         if alpha != 1.0:


""" <ins>    @_api.delete_parameter("3.8", "numdecs")</ins>     def __init__(self, base=10.0, subs=(1.0,), numdecs=4, numticks=None):         """Place ticks on the locations : subs[j] * base**i."""         if numticks is None:


numticks = 'auto'         self._base = float(base)         self._set_subs(subs)        self.numdecs = numdecs        self._numdecs = numdecs         self.numticks = numticks     @_api.delete_parameter("3.8", "numdecs")     def set_params(self, base=None, subs=None, numdecs=None, numticks=None):         """Set parameters within this locator."""         if base is not None:


if subs is not None:             self._set_subs(subs)         if numdecs is not None:            self.numdecs = numdecs            self._numdecs = numdecs         if numticks is not None:             self.numticks = numticks     numdecs = _api.deprecate_privatize_attribute(        "3.8", addendum="This attribute has no effect.")     def _set_subs(self, subs):         """         Set the minor ticks for the log scaling every ``base**i*subs[j]``.


height : float or array-like             The height(s) of the bars.             Note that if *bottom* has units (e.g. datetime), *height* should be in            units that are a difference from the value of *bottom* (e.g. timedelta).         width : float or array-like, default: 0.8             The width(s) of the bars.             Note that if *x* has units (e.g. datetime), then *width* should be in            units that are a difference (e.g. timedelta) around the *x* values.         bottom : float or array-like, default: 0             The y coordinate(s) of the bottom side(s) of the bars.             Note that if *bottom* has units, then the y-axis will get a Locator and            Formatter appropriate for the units (e.g. dates, or categorical).         align : {'center', 'edge'}, default: 'center'             Alignment of the bars to the *x* coordinates:


x = 0          if orientation == 'vertical':            # It is possible for y (bottom) to contain unit information.            # However, it is also possible for y=0 for the default and height            # to contain unit information.  This will prioritize the units of y.             self._process_unit_info(                [("x", x), ("y", height)], kwargs, convert=False)                [("x", x), ("y", y), ("y", height)], kwargs, convert=False)             if log:                 self.set_yscale('log', nonpositive='clip')         else:  # horizontal            # It is possible for x (left) to contain unit information.            # However, it is also possible for x=0 for the default and width            # to contain unit information.  This will prioritize the units of x.             self._process_unit_info(                [("x", width), ("y", y)], kwargs, convert=False)                [("x", x), ("x", width), ("y", y)], kwargs, convert=False)             if log:                 self.set_xscale('log', nonpositive='clip')


width : float or array-like             The width(s) of the bars.             Note that if *left* has units (e.g. datetime), *width* should be in            units that are a difference from the value of *left* (e.g. timedelta).         height : float or array-like, default: 0.8             The heights of the bars.             Note that if *y* has units (e.g. datetime), then *height* should be in            units that are a difference (e.g. timedelta) around the *y* values.         left : float or array-like, default: 0             The x coordinates of the left side(s) of the bars.             Note that if *left* has units, then the x-axis will get a Locator and            Formatter appropriate for the units (e.g. dates, or categorical).         align : {'center', 'edge'}, default: 'center'             Alignment of the base to the *y* coordinates*:


np.column_stack([ind[where], dep2[where]])])         if ind_dir == "y":             pts = pts[:, ::-1]        self.update_datalim(pts, updatex=True, updatey=True)        up_x = up_y = True        if "transform" in kwargs:            up_x, up_y = kwargs["transform"].contains_branch_seperately(self.transData)        self.update_datalim(pts, updatex=up_x, updatey=up_y)         self.add_collection(collection, autolim=False)         self._request_autoscale_view()         return collection


Tick label font size in points or as a string (e.g., 'large').         labelcolor : color             Tick label color.        labelfontfamily : str            Tick label font.         colors : color             Tick color and label color.         zorder : floatdiff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py-- a/lib/matplotlib/axis.py++ b/lib/matplotlib/axis.py


pad=None,         labelsize=None,         labelcolor=None,<ins>        labelfontfamily=None,</ins>         zorder=None,         gridOn=None,  # defaults to axes.grid depending on axes.grid.which         tick1On=True,


self.label1 = mtext.Text(             np.nan, np.nan,             fontsize=labelsize, color=labelcolor, visible=label1On,            rotation=self._labelrotation[1])            fontfamily=labelfontfamily, rotation=self._labelrotation[1])         self.label2 = mtext.Text(             np.nan, np.nan,             fontsize=labelsize, color=labelcolor, visible=label2On,            rotation=self._labelrotation[1])            fontfamily=labelfontfamily, rotation=self._labelrotation[1])          self._apply_tickdir(tickdir)


self.label2.set(rotation=self._labelrotation[1])          label_kw = {k[5:]: v for k, v in kwargs.items()                    if k in ['labelsize', 'labelcolor']}                    if k in ['labelsize', 'labelcolor', 'labelfontfamily']}         self.label1.set(**label_kw)         self.label2.set(**label_kw)


# The following lists may be moved to a more accessible location.         allowed_keys = [             'size', 'width', 'color', 'tickdir', 'pad',            'labelsize', 'labelcolor', 'zorder', 'gridOn',            'labelsize', 'labelcolor', 'labelfontfamily', 'zorder', 'gridOn',             'tick1On', 'tick2On', 'label1On', 'label2On',             'length', 'direction', 'left', 'bottom', 'right', 'top',             'labelleft', 'labelbottom', 'labelright', 'labeltop',


else:         raise ImportError(             "Failed to import any of the following Qt binding modules: {}"            .format(", ".join(_ETS.values())))            .format(", ".join([QT_API for _, QT_API in _candidates]))        ) else:  # We should not get there.     raise AssertionError(f"Unexpected QT_API: {QT_API}") _version_info = tuple(QtCore.QLibraryInfo.version().segments())


"""===================================Ellipse with orientation arrow demo===================================This demo shows how to draw an ellipse withan orientation arrow (clockwise or counterclockwise).Compare this to the :doc:`Ellipse collection example</gallery/shapes_and_collections/ellipse_collection>`."""import matplotlib.pyplot as pltfrom matplotlib.markers import MarkerStylefrom matplotlib.patches import Ellipsefrom matplotlib.transforms import Affine2D# Create a figure and axisfig, ax = plt.subplots(subplot_kw={"aspect": "equal"})ellipse = Ellipse(    xy=(2, 4),    width=30,    height=20,    angle=35,    facecolor="none",    edgecolor="b")ax.add_patch(ellipse)# Plot an arrow marker at the end point of minor axisvertices = ellipse.get_co_vertices()t = Affine2D().rotate_deg(ellipse.angle)ax.plot(    vertices[0][0],    vertices[0][1],    color="b",    marker=MarkerStyle(">", "full", t),    markersize=10)# Note: To reverse the orientation arrow, switch the marker type from > to <.plt.show()# %%## .. admonition:: References##    The use of the following functions, methods, classes and modules is shown#    in this example:##    - `matplotlib.patches`#    - `matplotlib.patches.Ellipse`diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py-- a/lib/matplotlib/patches.py++ b/lib/matplotlib/patches.py


return self.get_patch_transform().transform(             [(-1, -1), (1, -1), (1, 1), (-1, 1)]) <ins>    def _calculate_length_between_points(self, x0, y0, x1, y1):        return np.sqrt((x1 - x0)**2 + (y1 - y0)**2)    def get_vertices(self):        """        Return the vertices coordinates of the ellipse.        The definition can be found `here <https://en.wikipedia.org/wiki/Ellipse>`_        .. versionadded:: 3.8        """        if self.width < self.height:            ret = self.get_patch_transform().transform([(0, 1), (0, -1)])        else:            ret = self.get_patch_transform().transform([(1, 0), (-1, 0)])        return [tuple(x) for x in ret]    def get_co_vertices(self):        """        Return the co-vertices coordinates of the ellipse.        The definition can be found `here <https://en.wikipedia.org/wiki/Ellipse>`_        .. versionadded:: 3.8        """        if self.width < self.height:            ret = self.get_patch_transform().transform([(1, 0), (-1, 0)])        else:            ret = self.get_patch_transform().transform([(0, 1), (0, -1)])        return [tuple(x) for x in ret]</ins>  class Annulus(Patch):     """


# find the appropriate papertype         width, height = self.figure.get_size_inches()         if papertype == 'auto':            papertype = _get_papertype(                *orientation.swap_if_landscape((width, height)))        paper_width, paper_height = orientation.swap_if_landscape(            papersize[papertype])            _api.warn_deprecated("3.8", name="papertype='auto'",                                 addendum="Pass an explicit paper type, or omit the "                                 "*papertype* argument entirely.")            papertype = _get_papertype(*orientation.swap_if_landscape((width, height)))         if mpl.rcParams['ps.usedistiller']:            # distillers improperly clip eps files if pagesize is too small            if width > paper_width or height > paper_height:                papertype = _get_papertype(                    *orientation.swap_if_landscape((width, height)))                paper_width, paper_height = orientation.swap_if_landscape(                    papersize[papertype])        if is_eps:            paper_width, paper_height = width, height        else:            paper_width, paper_height = orientation.swap_if_landscape(                papersize[papertype])            if mpl.rcParams['ps.usedistiller']:                # distillers improperly clip eps files if pagesize is too small                if width > paper_width or height > paper_height:                    papertype = _get_papertype(                        *orientation.swap_if_landscape((width, height)))                    paper_width, paper_height = orientation.swap_if_landscape(                        papersize[papertype])          # center the figure on the paper         xo = 72 * 0.5 * (paper_width - width)


self.figure.get_size_inches())             else:                 if papertype == 'auto':                    _api.warn_deprecated("3.8", name="papertype='auto'",                                         addendum="Pass an explicit paper type, or "                                         "omit the *papertype* argument entirely.")                     papertype = _get_papertype(width, height)                 paper_width, paper_height = papersize[papertype] diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py-- a/lib/matplotlib/rcsetup.py++ b/lib/matplotlib/rcsetup.py


return ValidateInStrings('ps.usedistiller', ['ghostscript', 'xpdf'])(s)  <ins>def _validate_papersize(s):    # Re-inline this validator when the 'auto' deprecation expires.    s = ValidateInStrings("ps.papersize",                          ["auto", "letter", "legal", "ledger",                           *[f"{ab}{i}" for ab in "ab" for i in range(11)]],                          ignorecase=True)(s)    if s == "auto":        _api.warn_deprecated("3.8", name="ps.papersize='auto'",                             addendum="Pass an explicit paper type, or omit the "                             "*ps.papersize* rcParam entirely.")    return s</ins> # A validator dedicated to the named line styles, based on the items in # ls_mapper, and a list of possible strings read from Line2D.set_linestyle _validate_named_linestyle = ValidateInStrings(


"tk.window_focus": validate_bool,  # Maintain shell focus for TkAgg      # Set the papersize/type    "ps.papersize":       _ignorecase(["auto", "letter", "legal", "ledger",                                      *[f"{ab}{i}"                                        for ab in "ab" for i in range(11)]]),    "ps.papersize":       _validate_papersize,     "ps.useafm":          validate_bool,     # use ghostscript or xpdf to distill ps output     "ps.usedistiller":    validate_ps_distiller,


size matches the size of *x* and *y*.          """<ins>        # add edgecolors and linewidths to kwargs so they        # can be processed by normailze_kwargs        if edgecolors is not None:            kwargs.update({'edgecolors': edgecolors})        if linewidths is not None:            kwargs.update({'linewidths': linewidths})        kwargs = cbook.normalize_kwargs(kwargs, mcoll.Collection)        # re direct linewidth and edgecolor so it can be        # further processed by the rest of the function        linewidths = kwargs.pop('linewidth', None)        edgecolors = kwargs.pop('edgecolor', None)</ins>         # Process **kwargs to handle aliases, conflicts with explicit kwargs:         x, y = self._process_unit_info([("x", x), ("y", y)], kwargs)         # np.ma.ravel yields an ndarray, not a masked array,


# This puts the rectangle into figure-relative coordinates.         inset_locator = _TransformedBoundsLocator(bounds, transform)         bounds = inset_locator(self, None).bounds        projection_class, pkw = self.figure._process_projection_requirements(                bounds, **kwargs)        projection_class, pkw = self.figure._process_projection_requirements(**kwargs)         inset_ax = projection_class(self.figure, bounds, zorder=zorder, **pkw)          # this locator lets the axes move if in data coordinates.diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py-- a/lib/matplotlib/figure.py++ b/lib/matplotlib/figure.py


args = (kwargs.pop('rect'), )          if isinstance(args[0], Axes):            a = args[0]            a, *extra_args = args             key = a._projection_init             if a.get_figure() is not self:                 raise ValueError(                     "The Axes must have been created in the present figure")         else:            rect = args[0]            rect, *extra_args = args             if not np.isfinite(rect).all():                raise ValueError('all entries in rect must be finite '                                 f'not {rect}')            projection_class, pkw = self._process_projection_requirements(                *args, **kwargs)                raise ValueError(f'all entries in rect must be finite not {rect}')            projection_class, pkw = self._process_projection_requirements(**kwargs)              # create the new axes using the axes class given             a = projection_class(self, rect, **pkw)             key = (projection_class, pkw)        if extra_args:            _api.warn_deprecated(                "3.8",                name="Passing more than one positional argument to Figure.add_axes",                addendum="Any additional positional arguments are currently ignored.")         return self._add_axes_internal(a, key)      @_docstring.dedent_interpd


if (len(args) == 1 and isinstance(args[0], Integral)                     and 100 <= args[0] <= 999):                 args = tuple(map(int, str(args[0])))            projection_class, pkw = self._process_projection_requirements(                *args, **kwargs)            projection_class, pkw = self._process_projection_requirements(**kwargs)             ax = projection_class(self, *args, **pkw)             key = (projection_class, pkw)         return self._add_axes_internal(ax, key)


return im         return None     def _process_projection_requirements(            self, *args, axes_class=None, polar=False, projection=None,            **kwargs):    def _process_projection_requirements(self, *, axes_class=None, polar=False,                                         projection=None, **kwargs):         """         Handle the args/kwargs to add_axes/add_subplot/gca, returning:: diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py-- a/lib/matplotlib/pyplot.py++ b/lib/matplotlib/pyplot.py


if (ax.get_subplotspec() == key             and (kwargs == {}                  or (ax._projection_init                     == fig._process_projection_requirements(*args, **kwargs)))):                     == fig._process_projection_requirements(**kwargs)))):             break     else:         # we have exhausted the known Axes and none match, make a new one!


wspace, hspace : float, default: None             The amount of width/height reserved for space between subfigures,             expressed as a fraction of the average subfigure width/height.            If not given, the values will be inferred from a figure or            rcParams when necessary.            If not given, the values will be inferred from rcParams if using            constrained layout (see `~.ConstrainedLayoutEngine`), or zero if            not using a layout engine.          width_ratios : array-like of length *ncols*, optional             Defines the relative widths of the columns. Each column gets a


gs = GridSpec(nrows=nrows, ncols=ncols, figure=self,                       wspace=wspace, hspace=hspace,                       width_ratios=width_ratios,                      height_ratios=height_ratios)                      height_ratios=height_ratios,                      left=0, right=1, bottom=0, top=1)          sfarr = np.empty((nrows, ncols), dtype=object)         for i in range(ncols):             for j in range(nrows):                 sfarr[j, i] = self.add_subfigure(gs[j, i], **kwargs)         if self.get_layout_engine() is None and (wspace is not None or                                                 hspace is not None):            # Gridspec wspace and hspace is ignored on subfigure instantiation,            # and no space is left.  So need to account for it here if required.            bottoms, tops, lefts, rights = gs.get_grid_positions(self)            for sfrow, bottom, top in zip(sfarr, bottoms, tops):                for sf, left, right in zip(sfrow, lefts, rights):                    bbox = Bbox.from_extents(left, bottom, right, top)                    sf._redo_transform_rel_fig(bbox=bbox)         if squeeze:             # Discarding unneeded dimensions that equal 1.  If we only have one             # subfigure, just return it instead of a 1-element array.


self.axes.callbacks.process(f"{name}lim_changed", self.axes)             # Call all of the other axes that are shared with this one             for other in self._get_shared_axes():                if other is not self.axes:                    other._axis_map[name]._set_lim(                        v0, v1, emit=False, auto=auto)                    if other.figure != self.figure:                        other.figure.canvas.draw_idle()                if other is self.axes:                    continue                other._axis_map[name]._set_lim(v0, v1, emit=False, auto=auto)                if emit:                    other.callbacks.process(f"{name}lim_changed", other)                if other.figure != self.figure:                    other.figure.canvas.draw_idle()          self.stale = True         return v0, v1


from numbers import Number import functools<ins>from types import MethodType</ins>  import numpy as np


from matplotlib.gridspec import SubplotSpec  from .axes_divider import Size, SubplotDivider, Dividerfrom .mpl_axes import Axesfrom .mpl_axes import Axes, SimpleAxisArtist   def _tick_only(ax, bottom_on, left_on):     bottom_off = not bottom_on     left_off = not left_on    ax.axis["bottom"].toggle(ticklabels=bottom_off, label=bottom_off)    ax.axis["left"].toggle(ticklabels=left_off, label=left_off)    if isinstance(ax.axis, MethodType):        bottom = SimpleAxisArtist(ax.xaxis, 1, ax.spines["bottom"])        left = SimpleAxisArtist(ax.yaxis, 1, ax.spines["left"])    else:        bottom = ax.axis["bottom"]        left = ax.axis["left"]    bottom.toggle(ticklabels=bottom_off, label=bottom_off)    left.toggle(ticklabels=left_off, label=left_off)   class CbarAxesBase:


'leftparen'                : 40,     'rightparen'               : 41,     'bigoplus'                 : 10753,<del>    'leftangle'                : 10216,    'rightangle'               : 10217,</del>     'leftbrace'                : 124,     'rightbrace'               : 125,     'jmath'                    : 567,


'guilsinglleft'            : 8249,     'plus'                     : 43,     'thorn'                    : 254,    'dagger'                   : 8224    'dagger'                   : 8224,    'increment'                : 8710,    'smallin'                  : 8714,    'notsmallowns'             : 8716,    'smallowns'                : 8717,    'QED'                      : 8718,    'rightangle'               : 8735,    'smallintclockwise'        : 8753,    'smallvarointclockwise'    : 8754,    'smallointctrcclockwise'   : 8755,    'ratio'                    : 8758,    'minuscolon'               : 8761,    'dotsminusdots'            : 8762,    'sinewave'                 : 8767,    'simneqq'                  : 8774,    'nlesssim'                 : 8820,    'ngtrsim'                  : 8821,    'nlessgtr'                 : 8824,    'ngtrless'                 : 8825,    'cupleftarrow'             : 8844,    'oequal'                   : 8860,    'rightassert'              : 8870,    'rightModels'              : 8875,    'hermitmatrix'             : 8889,    'barvee'                   : 8893,    'measuredrightangle'       : 8894,    'varlrtriangle'            : 8895,    'equalparallel'            : 8917,    'npreccurlyeq'             : 8928,    'nsucccurlyeq'             : 8929,    'nsqsubseteq'              : 8930,    'nsqsupseteq'              : 8931,    'sqsubsetneq'              : 8932,    'sqsupsetneq'              : 8933,    'disin'                    : 8946,    'varisins'                 : 8947,    'isins'                    : 8948,    'isindot'                  : 8949,    'varisinobar'              : 8950,    'isinobar'                 : 8951,    'isinvb'                   : 8952,    'isinE'                    : 8953,    'nisd'                     : 8954,    'varnis'                   : 8955,    'nis'                      : 8956,    'varniobar'                : 8957,    'niobar'                   : 8958,    'bagmember'                : 8959,    'triangle'                 : 9651 }  # Each element is a 4-tuple of the form:


_legend_kw_doc_base) _docstring.interpd.update(_legend_kw_doc=_legend_kw_both_st) <ins>_legend_kw_set_loc_st = (    _loc_doc_base.format(parent='axes/figure',                         default=":rc:`legend.loc` for Axes, 'upper right' for Figure",                         best=_loc_doc_best, outside=_outside_doc))_docstring.interpd.update(_legend_kw_set_loc_doc=_legend_kw_set_loc_st)</ins>  class Legend(Artist):     """


)         self.parent = parent <del>        loc0 = loc        self._loc_used_default = loc is None        if loc is None:            loc = mpl.rcParams["legend.loc"]            if not self.isaxes and loc in [0, 'best']:                loc = 'upper right'        type_err_message = ("loc must be string, coordinate tuple, or"                            f" an integer 0-10, not {loc!r}")        # handle outside legends:        self._outside_loc = None        if isinstance(loc, str):            if loc.split()[0] == 'outside':                # strip outside:                loc = loc.split('outside ')[1]                # strip "center" at the beginning                self._outside_loc = loc.replace('center ', '')                # strip first                self._outside_loc = self._outside_loc.split()[0]                locs = loc.split()                if len(locs) > 1 and locs[0] in ('right', 'left'):                    # locs doesn't accept "left upper", etc, so swap                    if locs[0] != 'center':                        locs = locs[::-1]                    loc = locs[0] + ' ' + locs[1]            # check that loc is in acceptable strings            loc = _api.check_getitem(self.codes, loc=loc)        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)        if self.isaxes and self._outside_loc:            raise ValueError(                f"'outside' option for loc='{loc0}' keyword argument only "                "works for figure legends")        if not self.isaxes and loc == 0:            raise ValueError(                "Automatic legend placement (loc='best') not implemented for "                "figure legend")</del>         self._mode = mode         self.set_bbox_to_anchor(bbox_to_anchor, bbox_transform)


# init with null renderer         self._init_legend_box(handles, labels, markerfirst)         tmp = self._loc_used_default        self._set_loc(loc)        self._loc_used_default = tmp  # ignore changes done by _set_loc        # Set legend location        self.set_loc(loc)          # figure out title font properties:         if title_fontsize is not None and title_fontproperties is not None:


a.set_transform(self.get_transform()) <ins>    @_docstring.dedent_interpd    def set_loc(self, loc=None):        """        Set the location of the legend.        .. versionadded:: 3.8        Parameters        ----------        %(_legend_kw_set_loc_doc)s        """        loc0 = loc        self._loc_used_default = loc is None        if loc is None:            loc = mpl.rcParams["legend.loc"]            if not self.isaxes and loc in [0, 'best']:                loc = 'upper right'        type_err_message = ("loc must be string, coordinate tuple, or"                            f" an integer 0-10, not {loc!r}")        # handle outside legends:        self._outside_loc = None        if isinstance(loc, str):            if loc.split()[0] == 'outside':                # strip outside:                loc = loc.split('outside ')[1]                # strip "center" at the beginning                self._outside_loc = loc.replace('center ', '')                # strip first                self._outside_loc = self._outside_loc.split()[0]                locs = loc.split()                if len(locs) > 1 and locs[0] in ('right', 'left'):                    # locs doesn't accept "left upper", etc, so swap                    if locs[0] != 'center':                        locs = locs[::-1]                    loc = locs[0] + ' ' + locs[1]            # check that loc is in acceptable strings            loc = _api.check_getitem(self.codes, loc=loc)        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)        if self.isaxes and self._outside_loc:            raise ValueError(                f"'outside' option for loc='{loc0}' keyword argument only "                "works for figure legends")        if not self.isaxes and loc == 0:            raise ValueError(                "Automatic legend placement (loc='best') not implemented for "                "figure legend")        tmp = self._loc_used_default        self._set_loc(loc)        self._loc_used_default = tmp  # ignore changes done by _set_loc</ins>     def _set_loc(self, loc):         # find_offset function will be provided to _legend_box and         # _legend_box will draw itself at the location of the return


if len(text.vertices) == 0:             return         xmin, ymin = text.vertices.min(axis=0)        xmax, ymax = text.vertices.max(axis=0)        width = xmax - xmin        height = ymax - ymin        max_dim = max(width, height)        self._transform = Affine2D() \            .translate(-xmin + 0.5 * -width, -ymin + 0.5 * -height) \            .scale(1.0 / max_dim)        bbox = text.get_extents()        max_dim = max(bbox.width, bbox.height)        self._transform = (            Affine2D()            .translate(-bbox.xmin + 0.5 * -bbox.width, -bbox.ymin + 0.5 * -bbox.height)            .scale(1.0 / max_dim))         self._path = text         self._snap = False


if mincnt is None:                 mincnt = 0             accum = np.array(                [reduce_C_function(acc) if len(acc) > mincnt else np.nan                [reduce_C_function(acc) if len(acc) >= mincnt else np.nan                  for Cs_at_i in [Cs_at_i1, Cs_at_i2]                  for acc in Cs_at_i[1:]],  # [1:] drops out-of-range points.                 float)


background_gradient[:, :, :3] = [1, 1, 0]     background_gradient[:, :, 3] = [[0.1, 0.3], [0.3, 0.5]]  # alpha channel     ax.imshow(background_gradient, interpolation="bicubic", zorder=0.1,              extent=(0, 1, 0, 1), transform=ax.transAxes, aspect="auto")              extent=(0, 1, 0, 1), transform=ax.transAxes)      plt.show() diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py-- a/lib/matplotlib/axes/_axes.py++ b/lib/matplotlib/axes/_axes.py


The input may either be actual RGB(A) data, or 2D scalar data, which         will be rendered as a pseudocolor image. For displaying a grayscale        image set up the colormapping using the parameters        image, set up the colormapping using the parameters         ``cmap='gray', vmin=0, vmax=255``.          The number of pixels used to render an image is set by the Axes size        and the *dpi* of the figure. This can lead to aliasing artifacts when        the image is resampled because the displayed image size will usually        and the figure *dpi*. This can lead to aliasing artifacts when        the image is resampled, because the displayed image size will usually         not match the size of *X* (see         :doc:`/gallery/images_contours_and_fields/image_antialiasing`).         The resampling can be controlled via the *interpolation* parameter


This parameter is ignored if *X* is RGB(A). <del>        aspect : {'equal', 'auto'} or float, default: :rc:`image.aspect`</del><ins>        aspect : {'equal', 'auto'} or float or None, default: None</ins>             The aspect ratio of the Axes.  This parameter is particularly             relevant for images since it determines whether data pixels are             square.


that the data fit in the Axes. In general, this will result in               non-square pixels. <ins>            Normally, None (the default) means to use :rc:`image.aspect`.  However, if            the image uses a transform that does not contain the axes data transform,            then None means to not modify the axes aspect at all (in that case, directly            call `.Axes.set_aspect` if desired).</ins>         interpolation : str, default: :rc:`image.interpolation`             The interpolation method used.


`~matplotlib.pyplot.imshow` expects RGB images adopting the straight         (unassociated) alpha representation.         """<del>        if aspect is None:            aspect = mpl.rcParams['image.aspect']        self.set_aspect(aspect)</del>         im = mimage.AxesImage(self, cmap=cmap, norm=norm,                               interpolation=interpolation, origin=origin,                               extent=extent, filternorm=filternorm,


interpolation_stage=interpolation_stage,                               **kwargs) <ins>        if aspect is None and not (                im.is_transform_set()                and not im.get_transform().contains_branch(self.transData)):            aspect = mpl.rcParams['image.aspect']        if aspect is not None:            self.set_aspect(aspect)</ins>         im.set_data(X)         im.set_alpha(alpha)         if im.get_clip_path() is None:


# data limits should not be adjusted.             datalim = []         line = mlines._AxLine(xy1, xy2, slope, **kwargs)        line = mlines.AxLine(xy1, xy2, slope, **kwargs)         # Like add_line, but correctly handling data limits.         self._set_artist_props(line)         if line.get_clip_path() is None:diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py-- a/lib/matplotlib/lines.py++ b/lib/matplotlib/lines.py


return self._linestyle in ('--', '-.', ':')  class _AxLine(Line2D):class AxLine(Line2D):     """     A helper class that implements `~.Axes.axline`, by recomputing the artist     transform at draw time.     """      def __init__(self, xy1, xy2, slope, **kwargs):        """        Parameters        ----------        xy1 : (float, float)            The first set of (x, y) coordinates for the line to pass through.        xy2 : (float, float) or None            The second set of (x, y) coordinates for the line to pass through.            Either *xy2* or *slope* has to be given.        slope : float or None            The slope of the line. Either *xy2* or *slope* has to be given.        """         super().__init__([0, 1], [0, 1], **kwargs)          if (xy2 is None and slope is None or


self._transformed_path = None  # Force regen.         super().draw(renderer) <ins>    def get_xy1(self):        """        Return the *xy1* value of the line.        """        return self._xy1    def get_xy2(self):        """        Return the *xy2* value of the line.        """        return self._xy2    def get_slope(self):        """        Return the *slope* value of the line.        """        return self._slope    def set_xy1(self, x, y):        """        Set the *xy1* value of the line.        Parameters        ----------        x, y : float            Points for the line to pass through.        """        self._xy1 = x, y    def set_xy2(self, x, y):        """        Set the *xy2* value of the line.        Parameters        ----------        x, y : float            Points for the line to pass through.        """        if self._slope is None:            self._xy2 = x, y        else:            raise ValueError("Cannot set an 'xy2' value while 'slope' is set;"                             " they differ but their functionalities overlap")    def set_slope(self, slope):        """        Set the *slope* value of the line.        Parameters        ----------        slope : float            The slope of the line.        """        if self._xy2 is None:            self._slope = slope        else:            raise ValueError("Cannot set a 'slope' value while 'xy2' is set;"                             " they differ but their functionalities overlap")</ins>  class VertexSelector:     """


# docstring inherited         if renderer is None:             renderer = self.figure._get_renderer()        self.update_positions(renderer)         return Bbox.union([child.get_window_extent(renderer)                            for child in self.get_children()])      def get_tightbbox(self, renderer=None):         # docstring inherited        if renderer is None:            renderer = self.figure._get_renderer()        self.update_positions(renderer)         return Bbox.union([child.get_tightbbox(renderer)                            for child in self.get_children()])


self.yaxis.tick_left()         ax2.xaxis.set_visible(False)         ax2.patch.set_visible(False)<ins>        ax2.xaxis.units = self.xaxis.units</ins>         return ax2      def twiny(self):


self.xaxis.tick_bottom()         ax2.yaxis.set_visible(False)         ax2.patch.set_visible(False)<ins>        ax2.yaxis.units = self.yaxis.units</ins>         return ax2      def get_shared_x_axes(self):


else:                 X, Y = np.meshgrid(np.arange(ncols + 1), np.arange(nrows + 1))                 shading = 'flat'            C = cbook.safe_masked_invalid(C)            C = cbook.safe_masked_invalid(C, copy=True)             return X, Y, C, shading          if len(args) == 3:


Y = _interp_grid(Y.T).T                 shading = 'flat'         C = cbook.safe_masked_invalid(C)        C = cbook.safe_masked_invalid(C, copy=True)         return X, Y, C, shading      @_preprocess_data()


# unit conversion allows e.g. datetime objects as axis values             X, Y = args[:2]             X, Y = self._process_unit_info([("x", X), ("y", Y)], kwargs)            X, Y = [cbook.safe_masked_invalid(a) for a in [X, Y]]            X, Y = [cbook.safe_masked_invalid(a, copy=True) for a in [X, Y]]              if funcname == 'pcolormesh':                 if np.ma.is_masked(X) or np.ma.is_masked(Y):


*[np.ravel(np.ma.filled(t, np.nan)) for t in [xs, ys, zs]])         s = np.ma.ravel(s)  # This doesn't have to match x, y in size.         xs, ys, zs, s, c = cbook.delete_masked_points(xs, ys, zs, s, c)        xs, ys, zs, s, c, color = cbook.delete_masked_points(            xs, ys, zs, s, c, kwargs.get('color', None)            )        if kwargs.get('color', None):            kwargs['color'] = color          # For xs and ys, 2D scatter() will do the copying.         if np.may_share_memory(zs_orig, zs):  # Avoid unnecessary copies.


hatches=(None,), alpha=None, origin=None, extent=None,                  cmap=None, colors=None, norm=None, vmin=None, vmax=None,                  extend='neither', antialiased=None, nchunk=0, locator=None,                 transform=None, negative_linestyles=None,                 transform=None, negative_linestyles=None, clip_path=None,                  **kwargs):         """         Draw contour lines or filled regions, depending on


super().__init__(             antialiaseds=antialiased,             alpha=alpha,<ins>            clip_path=clip_path,</ins>             transform=transform,         )         self.axes = ax


The default is taken from :rc:`contour.algorithm`. <ins>clip_path : `~matplotlib.patches.Patch` or `.Path` or `.TransformedPath`    Set the clip path.  See `~matplotlib.artist.Artist.set_clip_path`.    .. versionadded:: 3.8</ins> data : indexable object, optional     DATA_PARAMETER_PLACEHOLDER


minor : bool, default: False             If ``False``, set the major ticks; if ``True``, the minor ticks.         **kwargs            `.Text` properties for the labels. These take effect only if you            pass *labels*. In other cases, please use `~.Axes.tick_params`.            `.Text` properties for the labels. Using these is only allowed if            you pass *labels*. In other cases, please use `~.Axes.tick_params`.          Notes         -----


ticks.         """         if labels is None and kwargs:            raise ValueError('labels argument cannot be None when '                             'kwargs are passed')            first_key = next(iter(kwargs))            raise ValueError(                f"Incorrect use of keyword argument {first_key!r}. Keyword arguments "                "other than 'minor' modify the text labels and can only be used if "                "'labels' are passed as well.")         result = self._set_tick_locations(ticks, minor=minor)         if labels is not None:             self.set_ticklabels(labels, minor=minor, **kwargs)


raise RuntimeError("No draw method should be called")      def __call__(self, ax, renderer):<ins>        if renderer is None:            renderer = ax.figure._get_renderer()</ins>         self.axes = ax         bbox = self.get_window_extent(renderer)         px, py = self.get_offset(bbox.width, bbox.height, 0, 0, renderer)


# note that here we do not permanently set the figures engine to         # tight_layout but rather just perform the layout in place and remove         # any previous engines.        engine = TightLayoutEngine(pad=pad, h_pad=h_pad, w_pad=w_pad,                                   rect=rect)        engine = TightLayoutEngine(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)         try:             previous_engine = self.get_layout_engine()             self.set_layout_engine(engine)             engine.execute(self)            if not isinstance(previous_engine, TightLayoutEngine) \                    and previous_engine is not None:            if previous_engine is not None and not isinstance(                previous_engine, (TightLayoutEngine, PlaceHolderLayoutEngine)            ):                 _api.warn_external('The figure layout has changed to tight')         finally:             self.set_layout_engine('none')


# path always starts with a MOVETO, and we consider there's an implicit         # MOVETO (closing the last path) at the end.         movetos = (codes == Path.MOVETO).nonzero()[0]        start = movetos[movetos < idx][-1]        start = movetos[movetos <= idx][-1]         try:             stop = movetos[movetos > idx][0]         except IndexError:


from contextlib import ExitStack import functools import inspect<del>import itertools</del> import logging from numbers import Real from operator import attrgetter


self.command = command         self.set_prop_cycle(None)     def __getstate__(self):        # note: it is not possible to pickle a generator (and thus a cycler).        return {'command': self.command}    def __setstate__(self, state):        self.__dict__ = state.copy()        self.set_prop_cycle(None)     def set_prop_cycle(self, cycler):         if cycler is None:             cycler = mpl.rcParams['axes.prop_cycle']        self.prop_cycler = itertools.cycle(cycler)        self._idx = 0        self._cycler_items = [*cycler]         self._prop_keys = cycler.keys  # This should make a copy      def __call__(self, axes, *args, data=None, **kwargs):


"""Return the next color in the cycle."""         if 'color' not in self._prop_keys:             return 'k'        return next(self.prop_cycler)['color']        c = self._cycler_items[self._idx]['color']        self._idx = (self._idx + 1) % len(self._cycler_items)        return c      def _getdefaults(self, ignore, kw):         """


if any(kw.get(k, None) is None for k in prop_keys):             # Need to copy this dictionary or else the next time around             # in the cycle, the dictionary could be missing entries.            default_dict = next(self.prop_cycler).copy()            default_dict = self._cycler_items[self._idx].copy()            self._idx = (self._idx + 1) % len(self._cycler_items)             for p in ignore:                 default_dict.pop(p, None)         else:diff --git a/lib/matplotlib/sankey.py b/lib/matplotlib/sankey.py-- a/lib/matplotlib/sankey.py++ b/lib/matplotlib/sankey.py


fc = kwargs.pop('fc', kwargs.pop('facecolor', None))             lw = kwargs.pop('lw', kwargs.pop('linewidth', None))         if fc is None:            fc = next(self.ax._get_patches_for_fill.prop_cycler)['color']            fc = self.ax._get_patches_for_fill.get_next_color()         patch = PathPatch(Path(vertices, codes), fc=fc, lw=lw, **kwargs)         self.ax.add_patch(patch)


return self._paths      def set_paths(self, paths):        raise NotImplementedError        self._paths = paths        self.stale = True      def get_transforms(self):         return self._transforms


self.set_sizes(sizes)         self.stale = True <del>    def set_paths(self, paths):        self._paths = paths        self.stale = True</del>     def get_paths(self):         return self._paths


return linewidths, dashes     def get_antialiased(self):        """        Get the antialiasing state for rendering.        Returns        -------        array of bools        """        return self._antialiaseds     def set_antialiased(self, aa):         """         Set the antialiasing state for rendering.diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py-- a/lib/matplotlib/contour.py++ b/lib/matplotlib/contour.py


alpha = property(lambda self: self.get_alpha())     linestyles = property(lambda self: self._orig_linestyles) <ins>    @_api.deprecated("3.8", alternative="set_antialiased or get_antialiased",                     addendum="Note that get_antialiased returns an array.")    @property    def antialiased(self):        return all(self.get_antialiased())    @antialiased.setter    def antialiased(self, aa):        self.set_antialiased(aa)</ins>     @_api.deprecated("3.8")     @property     def collections(self):


The screen units to use (pixels or points) for the offset input.         """         self._artist = artist        self._ref_coord = ref_coord        x, y = ref_coord  # Make copy when ref_coord is an array (and check the shape).        self._ref_coord = x, y         self.set_unit(unit)      def set_unit(self, unit):


"""Return the unit for input to the transform used by ``__call__``."""         return self._unit <del>    def _get_scale(self, renderer):        unit = self.get_unit()        if unit == "pixels":            return 1.        else:            return renderer.points_to_pixels(1.)</del>     def __call__(self, renderer):         """         Return the offset transform.


x, y = self._artist.transform(self._ref_coord)         else:             _api.check_isinstance((Artist, BboxBase, Transform), artist=self._artist)        sc = self._get_scale(renderer)        tr = Affine2D().scale(sc).translate(x, y)        return tr        scale = 1 if self._unit == "pixels" else renderer.points_to_pixels(1)        return Affine2D().scale(scale).translate(x, y)   class _AnnotationBase:


xycoords='data',                  annotation_clip=None):         self.xy = xy        x, y = xy  # Make copy when xy is an array (and check the shape).        self.xy = x, y         self.xycoords = xycoords         self.set_annotation_clip(annotation_clip)


import matplotlib as mpl from matplotlib import (     _api, backend_tools as tools, cbook, colors, _docstring, text,    _tight_bbox, transforms, widgets, get_backend, is_interactive, rcParams)    _tight_bbox, transforms, widgets, is_interactive, rcParams) from matplotlib._pylab_helpers import Gcf from matplotlib.backend_managers import ToolManager from matplotlib.cbook import _setattr_cm


# thus warrants a warning.             return         raise NonGuiException(            f"Matplotlib is currently using {get_backend()}, which is a "            f"non-GUI backend, so cannot show the figure.")            f"{type(self.canvas).__name__} is non-interactive, and thus cannot be "            f"shown")      def destroy(self):         passdiff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py-- a/lib/matplotlib/pyplot.py++ b/lib/matplotlib/pyplot.py


# Need to keep a global reference to the backend for compatibility reasons.     # See https://github.com/matplotlib/matplotlib/issues/6092     matplotlib.backends.backend = newbackend  # type: ignore[attr-defined]     if not cbook._str_equal(old_backend, newbackend):        if get_fignums():            _api.warn_deprecated("3.8", message=(                "Auto-close()ing of figures upon backend switching is deprecated since "                "%(since)s and will be removed %(removal)s.  To suppress this warning, "                "explicitly call plt.close('all') first."))         close("all")     # make sure the repl display hook is installed in case we become    # interactive    # Make sure the repl display hook is installed in case we become interactive.     install_repl_displayhook()


if papertype is None:             papertype = mpl.rcParams['ps.papersize']         papertype = papertype.lower()        _api.check_in_list(['auto', *papersize], papertype=papertype)        _api.check_in_list(['figure', 'auto', *papersize], papertype=papertype)          orientation = _api.check_getitem(             _Orientation, orientation=orientation.lower())


width, height = self.figure.get_size_inches()         if papertype == 'auto':             _api.warn_deprecated("3.8", name="papertype='auto'",                                 addendum="Pass an explicit paper type, or omit the "                                 "*papertype* argument entirely.")                                 addendum="Pass an explicit paper type, 'figure', or "                                 "omit the *papertype* argument entirely.")             papertype = _get_papertype(*orientation.swap_if_landscape((width, height)))         if is_eps:        if is_eps or papertype == 'figure':             paper_width, paper_height = width, height         else:             paper_width, paper_height = orientation.swap_if_landscape(                 papersize[papertype])             if mpl.rcParams['ps.usedistiller']:                # distillers improperly clip eps files if pagesize is too small                if width > paper_width or height > paper_height:                    papertype = _get_papertype(                        *orientation.swap_if_landscape((width, height)))                    paper_width, paper_height = orientation.swap_if_landscape(                        papersize[papertype])         # center the figure on the paper         xo = 72 * 0.5 * (paper_width - width)         yo = 72 * 0.5 * (paper_height - height)


if is_eps:                 print("%!PS-Adobe-3.0 EPSF-3.0", file=fh)             else:                print(f"%!PS-Adobe-3.0\n"                      f"%%DocumentPaperSizes: {papertype}\n"                      f"%%Pages: 1\n",                      end="", file=fh)                print("%!PS-Adobe-3.0", file=fh)                if papertype != 'figure':                    print(f"%%DocumentPaperSizes: {papertype}", file=fh)                print("%%Pages: 1", file=fh)             print(f"%%LanguageLevel: 3\n"                   f"{dsc_comments}\n"                   f"%%Orientation: {orientation.name}\n"


# set the paper size to the figure size if is_eps. The             # resulting ps file has the given size with correct bounding             # box so that there is no need to call 'pstoeps'            if is_eps:            if is_eps or papertype == 'figure':                 paper_width, paper_height = orientation.swap_if_landscape(                     self.figure.get_size_inches())             else:


"""      if eps:        paper_option = "-dEPSCrop"        paper_option = ["-dEPSCrop"]    elif ptype == "figure":        # The bbox will have its lower-left corner at (0, 0), so upper-right        # corner corresponds with paper size.        paper_option = [f"-dDEVICEWIDTHPOINTS={bbox[2]}",                        f"-dDEVICEHEIGHTPOINTS={bbox[3]}"]     else:        paper_option = "-sPAPERSIZE=%s" % ptype        paper_option = [f"-sPAPERSIZE={ptype}"]      psfile = tmpfile + '.ps'     dpi = mpl.rcParams['ps.distiller.res']


cbook._check_and_log_subprocess(         [mpl._get_executable_info("gs").executable,          "-dBATCH", "-dNOPAUSE", "-r%d" % dpi, "-sDEVICE=ps2write",         paper_option, "-sOutputFile=%s" % psfile, tmpfile],         *paper_option, f"-sOutputFile={psfile}", tmpfile],         _log)      os.remove(tmpfile)


mpl._get_executable_info("gs")  # Effectively checks for ps2pdf.     mpl._get_executable_info("pdftops") <ins>    if eps:        paper_option = ["-dEPSCrop"]    elif ptype == "figure":        # The bbox will have its lower-left corner at (0, 0), so upper-right        # corner corresponds with paper size.        paper_option = [f"-dDEVICEWIDTHPOINTS#{bbox[2]}",                        f"-dDEVICEHEIGHTPOINTS#{bbox[3]}"]    else:        paper_option = [f"-sPAPERSIZE#{ptype}"]</ins>     with TemporaryDirectory() as tmpdir:         tmppdf = pathlib.Path(tmpdir, "tmp.pdf")         tmpps = pathlib.Path(tmpdir, "tmp.ps")


"-sAutoRotatePages#None",              "-sGrayImageFilter#FlateEncode",              "-sColorImageFilter#FlateEncode",             "-dEPSCrop" if eps else "-sPAPERSIZE#%s" % ptype,             *paper_option,              tmpfile, tmppdf], _log)         cbook._check_and_log_subprocess(             ["pdftops", "-paper", "match", "-level3", tmppdf, tmpps], _log)diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py-- a/lib/matplotlib/rcsetup.py++ b/lib/matplotlib/rcsetup.py


def _validate_papersize(s):     # Re-inline this validator when the 'auto' deprecation expires.     s = ValidateInStrings("ps.papersize",                          ["auto", "letter", "legal", "ledger",                          ["figure", "auto", "letter", "legal", "ledger",                            *[f"{ab}{i}" for ab in "ab" for i in range(11)]],                           ignorecase=True)(s)     if s == "auto":         _api.warn_deprecated("3.8", name="ps.papersize='auto'",                             addendum="Pass an explicit paper type, or omit the "                             "*ps.papersize* rcParam entirely.")                             addendum="Pass an explicit paper type, figure, or omit "                             "the *ps.papersize* rcParam entirely.")     return s


kwargs['edgecolors'] = _shade_colors(                     edgecolors, normals, lightsource                 )            if facecolors is None and edgecolors in None:            if facecolors is None and edgecolors is None:                 raise ValueError(                     "You must provide facecolors, edgecolors, or both for "                     "shade to work.")


def _convert_colors(colors):     """Convert either a list of colors or nested lists of colors to RGB."""    to_rgb = mpl.colors.colorConverter.to_rgb    if isinstance(colors, pd.DataFrame):        # Convert dataframe        return pd.DataFrame({col: colors[col].map(to_rgb)                            for col in colors})    elif isinstance(colors, pd.Series):        return colors.map(to_rgb)    else:        try:            to_rgb(colors[0])            # If this works, there is only one level of colors            return list(map(to_rgb, colors))        except ValueError:            # If we get here, we have nested lists            return [list(map(to_rgb, l)) for l in colors]    to_rgb = mpl.colors.to_rgb    try:        to_rgb(colors[0])        # If this works, there is only one level of colors        return list(map(to_rgb, colors))    except ValueError:        # If we get here, we have nested lists        return [list(map(to_rgb, l)) for l in colors]   def _matrix_mask(data, mask):


return mask  class _HeatMapper(object):class _HeatMapper:     """Draw a heatmap plot of a matrix with nice labels and colormaps."""      def __init__(self, data, vmin, vmax, cmap, center, robust, annot, fmt,


elif yticklabels is False:             yticklabels = [] <del>        # Get the positions and used label for the ticks        nx, ny = data.T.shape</del>         if not len(xticklabels):             self.xticks = []             self.xticklabels = []


else:                     colors = colors.reindex(data.columns)                 # Replace na's with background color                # Replace na's with white color                 # TODO We should set these to transparent instead                colors = colors.fillna('white')                colors = colors.astype(object).fillna('white')                  # Extract color values and labels from frame/series                 if isinstance(colors, pd.DataFrame):


# Draw the regression line and confidence interval         line, = ax.plot(grid, yhat, **kws)        line.sticky_edges.x[:] = edges  # Prevent mpl from adding margin        if not self.truncate:            line.sticky_edges.x[:] = edges  # Prevent mpl from adding margin         if err_bands is not None:             ax.fill_between(grid, *err_bands, facecolor=fill_color, alpha=.15)


data=None,     hue=None, col=None, row=None,  # TODO move before data once * is enforced     palette=None, col_wrap=None, height=5, aspect=1, markers="o",    sharex=True, sharey=True, hue_order=None, col_order=None, row_order=None,    legend=True, legend_out=True, x_estimator=None, x_bins=None,    sharex=None, sharey=None, hue_order=None, col_order=None, row_order=None,    legend=True, legend_out=None, x_estimator=None, x_bins=None,     x_ci="ci", scatter=True, fit_reg=True, ci=95, n_boot=1000,     units=None, seed=None, order=1, logistic=False, lowess=False,     robust=False, logx=False, x_partial=None, y_partial=None,     truncate=True, x_jitter=None, y_jitter=None, scatter_kws=None,    line_kws=None, size=None    line_kws=None, facet_kws=None, size=None, ):      # Handle deprecations


"please update your code.")         warnings.warn(msg, UserWarning) <ins>    if facet_kws is None:        facet_kws = {}    def facet_kw_deprecation(key, val):        msg = (            f"{key} is deprecated from the `lmplot` function signature. "            "Please update your code to pass it using `facet_kws`."        )        if val is not None:            warnings.warn(msg, UserWarning)            facet_kws[key] = val    facet_kw_deprecation("sharex", sharex)    facet_kw_deprecation("sharey", sharey)    facet_kw_deprecation("legend_out", legend_out)</ins>     if data is None:         raise TypeError("Missing required keyword argument `data`.")


palette=palette,         row_order=row_order, col_order=col_order, hue_order=hue_order,         height=height, aspect=aspect, col_wrap=col_wrap,        sharex=sharex, sharey=sharey, legend_out=legend_out        **facet_kws,     )      # Add the markers here as FacetGrid has figured out how many levels of the


"for each level of the hue variable"))     facets.hue_kws = {"marker": markers}     # Hack to set the x limits properly, which needs to happen here    # because the extent of the regression estimate is determined    # by the limits of the plot    if sharex:        for ax in facets.axes.flat:            ax.scatter(data[x], np.ones(len(data)) * data[y].mean()).remove()    def update_datalim(data, x, y, ax, **kws):        xys = data[[x, y]].to_numpy().astype(float)        ax.update_datalim(xys, updatey=False)        ax.autoscale_view(scaley=False)    facets.map_dataframe(update_datalim, x=x, y=y)      # Draw the regression plot on each facet     regplot_kws = dict(


scatter_kws=scatter_kws, line_kws=line_kws,     )     facets.map_dataframe(regplot, x=x, y=y, **regplot_kws)<del>    # TODO this will need to change when we relax string requirement</del>     facets.set_axis_labels(x, y)      # Add a legend


Markers for the scatterplot. If a list, each marker in the list will be         used for each level of the ``hue`` variable.     {share_xy}<ins>        .. deprecated:: 0.12.0            Pass using the `facet_kws` dictionary.</ins>     {{hue,col,row}}_order : lists, optional         Order for the levels of the faceting variables. By default, this will         be the order that the levels appear in ``data`` or, if the variables


legend : bool, optional         If ``True`` and there is a ``hue`` variable, add a legend.     {legend_out}<ins>        .. deprecated:: 0.12.0            Pass using the `facet_kws` dictionary.</ins>     {x_estimator}     {x_bins}     {x_ci}


{truncate}     {xy_jitter}     {scatter_line_kws}<ins>    facet_kws : dict        Dictionary of keyword arguments for :class:`FacetGrid`.</ins>      See Also     --------


elif binwidth is not None:             step = binwidth             bin_edges = np.arange(start, stop + step, step)            # Handle roundoff error (maybe there is a less clumsy way?)            if bin_edges.max() < stop or len(bin_edges) < 2:                bin_edges = np.append(bin_edges, bin_edges.max() + step)         else:             bin_edges = np.histogram_bin_edges(                 x, bins, binrange, weights,diff --git a/seaborn/axisgrid.py b/seaborn/axisgrid.py-- a/seaborn/axisgrid.py++ b/seaborn/axisgrid.py


markers = [markers] * n_markers             if len(markers) != n_markers:                 raise ValueError("markers must be a singleton or a list of "                                  "markers for each level of the hue variable")                                 "markers for each level of the hue variable")             grid.hue_kws = {"marker": markers}         elif kind == "scatter":             if isinstance(markers, str):diff --git a/seaborn/regression.py b/seaborn/regression.py-- a/seaborn/regression.py++ b/seaborn/regression.py


markers = [markers] * n_markers     if len(markers) != n_markers:         raise ValueError("markers must be a singleton or a list of markers "                          "for each level of the hue variable")                         "for each level of the hue variable")     facets.hue_kws = {"marker": markers}      def update_datalim(data, x, y, ax, **kws):


grid_data = p.plot_data.rename(columns=p.variables)     grid_data = grid_data.loc[:, ~grid_data.columns.duplicated()]     col_name = p.variables.get("col", None)    row_name = p.variables.get("row", None)    col_name = p.variables.get("col")    row_name = p.variables.get("row")      if facet_kws is None:         facet_kws = {}diff --git a/seaborn/relational.py b/seaborn/relational.py-- a/seaborn/relational.py++ b/seaborn/relational.py


# Pass the row/col variables to FacetGrid with their original     # names so that the axes titles render correctly    grid_kws = {v: p.variables.get(v, None) for v in grid_semantics}    for var in ["row", "col"]:        # Handle faceting variables that lack name information        if var in p.variables and p.variables[var] is None:            p.variables[var] = f"_{var}_"    grid_kws = {v: p.variables.get(v) for v in grid_semantics}      # Rename the columns of the plot_data structure appropriately     new_cols = plot_variables.copy()


# Draw the plot     g.map_dataframe(func, **plot_kws)     # Label the axes    g.set_axis_labels(        variables.get("x", None), variables.get("y", None)    )    # Label the axes, using the original variables    g.set(xlabel=variables.get("x"), ylabel=variables.get("y"))      # Show the legend     if legend:


# Use a value that's in the original data vector             value = self.lookup_table[key]         except KeyError:<ins>            if self.norm is None:                # Currently we only get here in scatterplot with hue_order,                # because scatterplot does not consider hue a grouping variable                # So unused hue levels are in the data, but not the lookup table                return (0, 0, 0, 0)</ins>             # Use the colormap to interpolate between existing datapoints             # (e.g. in the context of making a continuous legend)             try:


else:             # TODO abstraction             ci_kws = {"color": kws["color"]}<ins>            if "alpha" in kws:                ci_kws["alpha"] = kws["alpha"]</ins>             ci_kws["linewidth"] = mpl.rcParams["lines.linewidth"] * 1.75             kws.setdefault("s", 50)


def __call__(self, data, var):         """Aggregate over `var` column of `data` with estimate and error interval."""         vals = data[var]        estimate = vals.agg(self.estimator)        if callable(self.estimator):            # You would think we could pass to vals.agg, and yet:            # https://github.com/mwaskom/seaborn/issues/2943            estimate = self.estimator(vals)        else:            estimate = vals.agg(self.estimator)          # Options that produce no error bars         if self.error_method is None:


visible_side = {"x": "bottom", "y": "left"}.get(axis)                 show_axis_label = (                     sub[visible_side]                    or axis in p._pair_spec and bool(p._pair_spec.get("wrap"))                     or not p._pair_spec.get("cross", True)                    or (                        axis in p._pair_spec.get("structure", {})                        and bool(p._pair_spec.get("wrap"))                    )                 )                 axis_obj.get_label().set_visible(show_axis_label)                 show_tick_labels = (


# behavior, so we will raise rather than hack together a workaround.             if axis is not None and Version(mpl.__version__) < Version("3.4.0"):                 from seaborn._core.scales import Nominal                paired_axis = axis in p._pair_spec                paired_axis = axis in p._pair_spec.get("structure", {})                 cat_scale = isinstance(scale, Nominal)                 ok_dim = {"x": "col", "y": "row"}[axis]                 shared_axes = share_state not in [False, "none", ok_dim]diff --git a/seaborn/_core/subplots.py b/seaborn/_core/subplots.py-- a/seaborn/_core/subplots.py++ b/seaborn/_core/subplots.py


"""     def __init__(        # TODO defined TypedDict types for these specs         self,        subplot_spec: dict,        subplot_spec: dict,  # TODO define as TypedDict         facet_spec: FacetSpec,         pair_spec: PairSpec,     ):


if key not in self.subplot_spec:                 if axis in pair_spec.get("structure", {}):                     # Paired axes are shared along one dimension by default                    if self.wrap in [None, 1] and pair_spec.get("cross", True):                    if self.wrap is None and pair_spec.get("cross", True):                         val = axis_to_dim[axis]                     else:                         val = False


mpl.cm.register_cmap(name, cmap)  def set_layout_engine(fig, algo):def set_layout_engine(fig, engine):     """Handle changes to auto layout engine interface in 3.6"""     if hasattr(fig, "set_layout_engine"):        fig.set_layout_engine(algo)        fig.set_layout_engine(engine)     else:        if algo == "tight":        if engine == "tight":             fig.set_tight_layout(True)        elif algo == "constrained":        elif engine == "constrained":             fig.set_constrained_layout(True)  diff --git a/seaborn/_core/plot.py b/seaborn/_core/plot.py-- a/seaborn/_core/plot.py++ b/seaborn/_core/plot.py


self,         *,         size: tuple[float, float] | Default = default,        algo: str | None | Default = default,        engine: str | None | Default = default,     ) -> Plot:         """         Control the figure size and layout.


size : (width, height)             Size of the resulting figure, in inches. Size is inclusive of legend when             using pyplot, but not otherwise.        algo : {{"tight", "constrained", None}}            Name of algorithm for automatically adjusting the layout to remove overlap.        engine : {{"tight", "constrained", None}}            Name of method for automatically adjusting the layout to remove overlap.             The default depends on whether :meth:`Plot.on` is used.          Examples


if size is not default:             new._figure_spec["figsize"] = size        if algo is not default:            new._layout_spec["algo"] = algo        if engine is not default:            new._layout_spec["engine"] = engine          return new


hi = cast(float, hi) + 0.5                     ax.set(**{f"{axis}lim": (lo, hi)})         algo_default = None if p._target is not None else "tight"        layout_algo = p._layout_spec.get("algo", algo_default)        set_layout_engine(self._figure, layout_algo)        engine_default = None if p._target is not None else "tight"        layout_engine = p._layout_spec.get("engine", engine_default)        set_layout_engine(self._figure, layout_engine)


def __call__(self, data, groupby, orient, scales):         return groupby.apply(data, self._fit_predict)        return (            groupby            .apply(data.dropna(subset=["x", "y"]), self._fit_predict)        )   @dataclass


from seaborn._stats.base import Stat from seaborn._core.data import PlotData from seaborn._core.moves import Movefrom seaborn._core.scales import Scalefrom seaborn._core.scales import Scale, Nominal from seaborn._core.subplots import Subplots from seaborn._core.groupby import GroupBy from seaborn._core.properties import PROPERTIES, Property


# This only affects us when sharing *paired* axes. This is a novel/niche             # behavior, so we will raise rather than hack together a workaround.             if axis is not None and Version(mpl.__version__) < Version("3.4.0"):<del>                from seaborn._core.scales import Nominal</del>                 paired_axis = axis in p._pair_spec.get("structure", {})                 cat_scale = isinstance(scale, Nominal)                 ok_dim = {"x": "col", "y": "row"}[axis]


ax = sub["ax"]             for axis in "xy":                 axis_key = sub[axis]<ins>                axis_obj = getattr(ax, f"{axis}axis")</ins>                  # Axis limits                 if axis_key in p._limits:


hi = cast(float, hi) + 0.5                     ax.set(**{f"{axis}lim": (lo, hi)}) <ins>                # Nominal scale special-casing                if isinstance(self._scales.get(axis_key), Nominal):                    axis_obj.grid(False, which="both")                    if axis_key not in p._limits:                        nticks = len(axis_obj.get_major_ticks())                        lo, hi = -.5, nticks - .5                        if axis == "y":                            lo, hi = hi, lo                        set_lim = getattr(ax, f"set_{axis}lim")                        set_lim(lo, hi, auto=None)</ins>         engine_default = None if p._target is not None else "tight"         layout_engine = p._layout_spec.get("engine", engine_default)         set_layout_engine(self._figure, layout_engine)


axis.set_view_interval(vmin, vmax)             locs = axis.major.locator()             locs = locs[(vmin <= locs) & (locs <= vmax)]            # Avoid having an offset / scientific notation in a legend            # as we don't represent that anywhere so it ends up incorrect.            # This could become an option (e.g. Continuous.label(offset=True))            # in which case we would need to figure out how to show it.            if hasattr(axis.major.formatter, "set_useOffset"):                axis.major.formatter.set_useOffset(False)            if hasattr(axis.major.formatter, "set_scientific"):                axis.major.formatter.set_scientific(False)             labels = axis.major.formatter.format_ticks(locs)             new._legend = list(locs), list(labels) diff --git a/seaborn/utils.py b/seaborn/utils.py-- a/seaborn/utils.py++ b/seaborn/utils.py


formatter = mpl.ticker.LogFormatter()     else:         formatter = mpl.ticker.ScalarFormatter()<ins>        # Avoid having an offset/scientific notation which we don't currently        # have any way of representing in the legend        formatter.set_useOffset(False)        formatter.set_scientific(False)</ins>     formatter.axis = dummy_axis()      # TODO: The following two lines should be replaced


self, grouping_vars: list[str], df: DataFrame, subplots: list[dict[str, Any]],     ) -> Callable[[], Generator]: <del>        allow_empty = False  # TODO will need to recreate previous categorical plots</del>         grouping_keys = []         grouping_vars = [             v for v in grouping_vars if v in df and v not in ["col", "row"]


subplot_keys[dim] = view[dim]                  if not grouping_vars or not any(grouping_keys):                    yield subplot_keys, axes_df.copy(), view["ax"]                    if not axes_df.empty:                        yield subplot_keys, axes_df.copy(), view["ax"]                     continue                  grouped_df = axes_df.groupby(grouping_vars, sort=False, as_index=False)


# case this option could be removed                         df_subset = axes_df.loc[[]]                     if df_subset.empty and not allow_empty:                    if df_subset.empty:                         continue                      sub_vars = dict(zip(grouping_vars, key))diff --git a/seaborn/_core/scales.py b/seaborn/_core/scales.py-- a/seaborn/_core/scales.py++ b/seaborn/_core/scales.py


new = new.label()          # TODO flexibility over format() which isn't great for numbers / dates        stringify = np.vectorize(format)        stringify = np.vectorize(format, otypes=["object"])          units_seed = categorical_order(data, new.order)


if hasattr(fig, "set_layout_engine"):         fig.set_layout_engine(engine)     else:        # _version_predates(mpl, 3.6)         if engine == "tight":             fig.set_tight_layout(True)         elif engine == "constrained":             fig.set_constrained_layout(True)        elif engine == "none":            fig.set_tight_layout(False)            fig.set_constrained_layout(False)   def share_axis(ax0, ax1, which):diff --git a/seaborn/_core/plot.py b/seaborn/_core/plot.py-- a/seaborn/_core/plot.py++ b/seaborn/_core/plot.py


if axis_key in self._scales:  # TODO when would it not be?                     self._scales[axis_key]._finalize(p, axis_obj)         engine_default = None if p._target is not None else "tight"        layout_engine = p._layout_spec.get("engine", engine_default)        set_layout_engine(self._figure, layout_engine)        if (engine := p._layout_spec.get("engine", default)) is not default:            # None is a valid arg for Figure.set_layout_engine, hence `default`            set_layout_engine(self._figure, engine)        elif p._target is None:            # Don't modify the layout engine if the user supplied their own            # matplotlib figure and didn't specify an engine through Plot            # TODO switch default to "constrained"?            set_layout_engine(self._figure, "tight")


) -> DataFrame:         # TODO do we still have numbers in the variable name at this point?         coord_cols = [c for c in df if re.match(r"^[xy]\D*$", str(c))]        drop_cols = [*coord_cols, "width"] if "width" in df else coord_cols         out_df = (             df            .drop(drop_cols, axis=1)            .drop(coord_cols, axis=1)             .reindex(df.columns, axis=1)  # So unscaled columns retain their place             .copy(deep=False)         )


inverted = transform(values)                 out_df.loc[values.index, str(var)] = inverted                 if var == orient and "width" in view_df:                    width = view_df["width"]                    out_df.loc[values.index, "width"] = (                        transform(values + width / 2) - transform(values - width / 2)                    )         return out_df      def _generate_pairings(diff --git a/seaborn/_marks/bar.py b/seaborn/_marks/bar.py-- a/seaborn/_marks/bar.py++ b/seaborn/_marks/bar.py


def _make_patches(self, data, scales, orient):         transform = scales[orient]._matplotlib_scale.get_transform()        forward = transform.transform        reverse = transform.inverted().transform        other = {"x": "y", "y": "x"}[orient]        pos = reverse(forward(data[orient]) - data["width"] / 2)        width = reverse(forward(data[orient]) + data["width"] / 2) - pos        val = (data[other] - data["baseline"]).to_numpy()        base = data["baseline"].to_numpy()         kws = self._resolve_properties(data, scales)         if orient == "x":            kws["x"] = (data["x"] - data["width"] / 2).to_numpy()            kws["y"] = data["baseline"].to_numpy()            kws["w"] = data["width"].to_numpy()            kws["h"] = (data["y"] - data["baseline"]).to_numpy()            kws.update(x=pos, y=base, w=width, h=val)         else:            kws["x"] = data["baseline"].to_numpy()            kws["y"] = (data["y"] - data["width"] / 2).to_numpy()            kws["w"] = (data["x"] - data["baseline"]).to_numpy()            kws["h"] = data["width"].to_numpy()            kws.update(x=base, y=pos, w=val, h=width)          kws.pop("width", None)         kws.pop("baseline", None)


# setting vmin/vmax in addition to norm is deprecated         # so avoid setting if norm is set        if "norm" not in kws:        if kws.get("norm") is None:             kws.setdefault("vmin", self.vmin)             kws.setdefault("vmax", self.vmax)


spec_error = PlotSpecError._during("Scaling operation", var)                         raise spec_error from err             # Now the transformed data series are complete, set update the layer data            # Now the transformed data series are complete, update the layer data             for layer, new_series in zip(layers, transformed_data):                 layer_df = layer["data"].frame                 if var in layer_df:                    layer_df[var] = new_series                    layer_df[var] = pd.to_numeric(new_series)      def _plot_layer(self, p: Plot, layer: Layer) -> None: diff --git a/seaborn/_core/rules.py b/seaborn/_core/rules.py-- a/seaborn/_core/rules.py++ b/seaborn/_core/rules.py


if pd.isna(vector).all():         return VarType("numeric") <ins>    # Now drop nulls to simplify further type inference    vector = vector.dropna()</ins>     # Special-case binary/boolean data, allow caller to determine     # This triggers a numpy warning when vector has strings/objects     # https://github.com/numpy/numpy/issues/6784


boolean_dtypes = ["bool"]             boolean_vector = vector.dtype in boolean_dtypes         else:            boolean_vector = bool(np.isin(vector.dropna(), [0, 1]).all())            boolean_vector = bool(np.isin(vector, [0, 1]).all())         if boolean_vector:             return VarType(boolean_type) diff --git a/seaborn/_oldcore.py b/seaborn/_oldcore.py-- a/seaborn/_oldcore.py++ b/seaborn/_oldcore.py


# it is similar to GH2419, but more complicated because                             # supporting `order` in categorical plots is tricky                             orig = orig[orig.isin(self.var_levels[var])]                    comp = pd.to_numeric(converter.convert_units(orig))                    comp = pd.to_numeric(converter.convert_units(orig)).astype(float)                     if converter.get_scale() == "log":                         comp = np.log10(comp)                     parts.append(pd.Series(comp, orig.index, name=orig.name))


if pd.isna(vector).all():         return VariableType("numeric") <ins>    # At this point, drop nans to simplify further type inference    vector = vector.dropna()</ins>     # Special-case binary/boolean data, allow caller to determine     # This triggers a numpy warning when vector has strings/objects     # https://github.com/numpy/numpy/issues/6784


warnings.simplefilter(             action='ignore', category=(FutureWarning, DeprecationWarning)         )        if np.isin(vector.dropna(), [0, 1]).all():        if np.isin(vector, [0, 1]).all():             return VariableType(boolean_type)      # Defer to positive pandas tests


for ax in diag_axes[1:]:                     share_axis(diag_axes[0], ax, "y")             self.diag_vars = np.array(diag_vars, np.object_)            self.diag_axes = np.array(diag_axes, np.object_)            self.diag_vars = diag_vars            self.diag_axes = diag_axes          if "hue" not in signature(func).parameters:             return self._map_diag_iter_hue(func, **kwargs)


template_folder=template_folder,             root_path=root_path,         )<ins>        if "." in name:            raise ValueError("'name' may not contain a dot '.' character.")</ins>         self.name = name         self.url_prefix = url_prefix         self.subdomain = subdomain


"""Like :meth:`Flask.add_url_rule` but for a blueprint.  The endpoint for         the :func:`url_for` function is prefixed with the name of the blueprint.         """        if endpoint:            assert "." not in endpoint, "Blueprint endpoints should not contain dots"        if view_func and hasattr(view_func, "__name__"):            assert (                "." not in view_func.__name__            ), "Blueprint view function name should not contain dots"        if endpoint and "." in endpoint:            raise ValueError("'endpoint' may not contain a dot '.' character.")        if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__:            raise ValueError("'view_func' name may not contain a dot '.' character.")         self.record(lambda s: s.add_url_rule(rule, endpoint, view_func, **options))      def app_template_filter(self, name: t.Optional[str] = None) -> t.Callable:


<ins>import decimal</ins> import io import json as _json import typing as t


"""         if isinstance(o, date):             return http_date(o)        if isinstance(o, uuid.UUID):        if isinstance(o, (decimal.Decimal, uuid.UUID)):             return str(o)         if dataclasses and dataclasses.is_dataclass(o):             return dataclasses.asdict(o)


or defaults.     :param kwargs: Extra arguments passed to :func:`json.dumps`. <ins>    .. versionchanged:: 2.0.2        :class:`decimal.Decimal` is supported by converting to a string.</ins>     .. versionchanged:: 2.0         ``encoding`` is deprecated and will be removed in Flask 2.1.


debug mode or if :data:`JSONIFY_PRETTYPRINT_REGULAR` is ``True``,     the output will be formatted to be easier to read. <ins>    .. versionchanged:: 2.0.2        :class:`decimal.Decimal` is supported by converting to a string.</ins>     .. versionchanged:: 0.11         Added support for serializing top-level arrays. This introduces         a security risk in ancient browsers. See :ref:`security-json`.


self.loader = loader         self._app = None         self._lock = Lock()        self._bg_loading_exc_info = None        self._bg_loading_exc = None          if use_eager_loading is None:             use_eager_loading = os.environ.get("WERKZEUG_RUN_MAIN") != "true"


with self._lock:                 try:                     self._load_unlocked()                except Exception:                    self._bg_loading_exc_info = sys.exc_info()                except Exception as e:                    self._bg_loading_exc = e          t = Thread(target=_load_app, args=())         t.start()      def _flush_bg_loading_exception(self):         __traceback_hide__ = True  # noqa: F841        exc_info = self._bg_loading_exc_info        if exc_info is not None:            self._bg_loading_exc_info = None            raise exc_info        exc = self._bg_loading_exc        if exc is not None:            self._bg_loading_exc = None            raise exc      def _load_unlocked(self):         __traceback_hide__ = True  # noqa: F841         self._app = rv = self.loader()        self._bg_loading_exc_info = None        self._bg_loading_exc = None         return rv      def __call__(self, environ, start_response):


@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.") @click.option("--port", "-p", default=5000, help="The port to bind to.") @click.option(    "--cert", type=CertParamType(), help="Specify a certificate file to use HTTPS."    "--cert",    type=CertParamType(),    help="Specify a certificate file to use HTTPS.",    is_eager=True, ) @click.option(     "--key",


from markupsafe import escape from markupsafe import Markup from werkzeug.exceptions import abort as abort<del>from werkzeug.utils import redirect as redirect</del>  from . import json as json from .app import Flask as Flask


from .helpers import get_flashed_messages as get_flashed_messages from .helpers import get_template_attribute as get_template_attribute from .helpers import make_response as make_responsefrom .helpers import redirect as redirect from .helpers import send_file as send_file from .helpers import send_from_directory as send_from_directory from .helpers import stream_with_context as stream_with_contextdiff --git a/src/flask/app.py b/src/flask/app.py-- a/src/flask/app.py++ b/src/flask/app.py


from werkzeug.routing import RequestRedirect from werkzeug.routing import RoutingException from werkzeug.routing import Rule<ins>from werkzeug.utils import redirect as _wz_redirect</ins> from werkzeug.wrappers import Response as BaseResponse  from . import cli


return asgiref_async_to_sync(func)     def redirect(self, location: str, code: int = 302) -> BaseResponse:        """Create a redirect response object.        :param location: the url of the redirect        :param code: http return code        .. versionadded:: 2.2        """        return _wz_redirect(location, code=code, Response=self.response_class)     def make_response(self, rv: ResponseReturnValue) -> Response:         """Convert the return value from a view function to an instance of         :attr:`response_class`.diff --git a/src/flask/helpers.py b/src/flask/helpers.py-- a/src/flask/helpers.py++ b/src/flask/helpers.py


import werkzeug.utils from werkzeug.routing import BuildError from werkzeug.urls import url_quote<ins>from werkzeug.utils import redirect as _wz_redirect</ins>  from .globals import _app_ctx_stack from .globals import _request_ctx_stack


from .signals import message_flashed  if t.TYPE_CHECKING:  # pragma: no cover<ins>    from werkzeug.wrappers import Response as BaseResponse</ins>     from .wrappers import Response


return rv  <ins>def redirect(    location: str, code: int = 302, Response: t.Optional[t.Type["BaseResponse"]] = None) -> "BaseResponse":    """Create a redirect response object.    If :data:`~flask.current_app` is available, it will use    :meth:`~flask.app.Flask.redirect`, otherwise it will use    :func:`werkzeug.utils.redirect`.    :param location: The URL to redirect to.    :param code: The status code for the redirect.    :param Response: The response class to use. Not used when        ``current_app`` is active, which uses ``app.response_class``.    .. versionadded:: 2.2    """    if current_app:        return current_app.redirect(location, code=code)    return _wz_redirect(location, code=code, Response=Response)</ins> def get_template_attribute(template_name: str, attribute: str) -> t.Any:     """Loads a macro (or variable) a template exports.  This can be used to     invoke a macro from within Python code.  If you for example have a


:param options: Keyword arguments forwarded from             :meth:`~Flask.register_blueprint`. <ins>        .. versionchanged:: 2.3            Nested blueprints now correctly apply subdomains.</ins>         .. versionchanged:: 2.0.1             Nested blueprints are registered with their dotted name.             This allows different blueprints with the same name to be


for blueprint, bp_options in self._blueprints:             bp_options = bp_options.copy()             bp_url_prefix = bp_options.get("url_prefix")<ins>            bp_subdomain = bp_options.get("subdomain")            if bp_subdomain is None:                bp_subdomain = blueprint.subdomain            if state.subdomain is not None and bp_subdomain is not None:                bp_options["subdomain"] = bp_subdomain + "." + state.subdomain            elif bp_subdomain is not None:                bp_options["subdomain"] = bp_subdomain            elif state.subdomain is not None:                bp_options["subdomain"] = state.subdomain</ins>              if bp_url_prefix is None:                 bp_url_prefix = blueprint.url_prefix


filename: str,         load: t.Callable[[t.IO[t.Any]], t.Mapping],         silent: bool = False,<ins>        text: bool = True,</ins>     ) -> bool:         """Update the values in the config from a file that is loaded         using the ``load`` parameter. The loaded data is passed to the


import json             app.config.from_file("config.json", load=json.load)             import toml            app.config.from_file("config.toml", load=toml.load)            import tomllib            app.config.from_file("config.toml", load=tomllib.load, text=False)          :param filename: The path to the data file. This can be an             absolute path or relative to the config root path.


:type load: ``Callable[[Reader], Mapping]`` where ``Reader``             implements a ``read`` method.         :param silent: Ignore the file if it doesn't exist.        :param text: Open the file in text or binary mode.         :return: ``True`` if the file was loaded successfully.         .. versionchanged:: 2.3            The ``text`` parameter was added.         .. versionadded:: 2.0         """         filename = os.path.join(self.root_path, filename)          try:            with open(filename) as f:            with open(filename, "r" if text else "rb") as f:                 obj = load(f)         except OSError as e:             if silent and e.errno in (errno.ENOENT, errno.EISDIR):


root_path=root_path,         ) <ins>        if not name:            raise ValueError("'name' may not be empty.")</ins>         if "." in name:             raise ValueError("'name' may not contain a dot '.' character.")


import traceback import typing as t from functools import update_wrapperfrom operator import attrgetterfrom operator import itemgetter  import click from click.core import ParameterSource


@click.option(     "--sort",     "-s",    type=click.Choice(("endpoint", "methods", "rule", "match")),    type=click.Choice(("endpoint", "methods", "domain", "rule", "match")),     default="endpoint",     help=(        'Method to sort routes by. "match" is the order that Flask will match '        "routes when dispatching a request."        "Method to sort routes by. 'match' is the order that Flask will match routes"        " when dispatching a request."     ), ) @click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") @with_appcontext def routes_command(sort: str, all_methods: bool) -> None:     """Show all registered routes with endpoints and methods."""     rules = list(current_app.url_map.iter_rules())     if not rules:         click.echo("No routes were registered.")         return     ignored_methods = set(() if all_methods else ("HEAD", "OPTIONS"))    ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"}    host_matching = current_app.url_map.host_matching    has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules)    rows = []     if sort in ("endpoint", "rule"):        rules = sorted(rules, key=attrgetter(sort))    elif sort == "methods":        rules = sorted(rules, key=lambda rule: sorted(rule.methods))  # type: ignore    for rule in rules:        row = [            rule.endpoint,            ", ".join(sorted((rule.methods or set()) - ignored_methods)),        ]     rule_methods = [        ", ".join(sorted(rule.methods - ignored_methods))  # type: ignore        for rule in rules    ]        if has_domain:            row.append((rule.host if host_matching else rule.subdomain) or "")     headers = ("Endpoint", "Methods", "Rule")    widths = (        max(len(rule.endpoint) for rule in rules),        max(len(methods) for methods in rule_methods),        max(len(rule.rule) for rule in rules),    )    widths = [max(len(h), w) for h, w in zip(headers, widths)]    row = "{{0:<{0}}}  {{1:<{1}}}  {{2:<{2}}}".format(*widths)        row.append(rule.rule)        rows.append(row)    headers = ["Endpoint", "Methods"]    sorts = ["endpoint", "methods"]    if has_domain:        headers.append("Host" if host_matching else "Subdomain")        sorts.append("domain")    headers.append("Rule")    sorts.append("rule")    try:        rows.sort(key=itemgetter(sorts.index(sort)))    except ValueError:        pass     click.echo(row.format(*headers).strip())    click.echo(row.format(*("-" * width for width in widths)))    rows.insert(0, headers)    widths = [max(len(row[i]) for row in rows) for i in range(len(headers))]    rows.insert(1, ["-" * w for w in widths])    template = "  ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths))     for rule, methods in zip(rules, rule_methods):        click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip())    for row in rows:        click.echo(template.format(*row))   cli = FlaskGroup(


self.body = body      def prepare_content_length(self, body):        self.headers['Content-Length'] = '0'         if hasattr(body, 'seek') and hasattr(body, 'tell'):             body.seek(0, 2)             self.headers['Content-Length'] = str(body.tell())             body.seek(0, 0)         elif body is not None:             self.headers['Content-Length'] = str(len(body))        elif self.method not in ('GET', 'HEAD'):            self.headers['Content-Length'] = '0'      def prepare_auth(self, auth):         """Prepares the given HTTP auth data."""


import os from datetime import datetime from .compat import cookielibfrom .compat import cookielib, OrderedDict, urljoin, urlparse from .cookies import cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar from .models import Request, PreparedRequest from .hooks import default_hooks, dispatch_hook from .utils import from_key_val_list, default_headers from .exceptions import TooManyRedirects, InvalidSchema from .compat import urlparse, urljoin from .adapters import HTTPAdapter  from .utils import requote_uri, get_environ_proxies, get_netrc_auth


self.cookies = cookiejar_from_dict({})          # Default connection adapters.        self.adapters = {}        self.mount('http://', HTTPAdapter())        self.adapters = OrderedDict()         self.mount('https://', HTTPAdapter())        self.mount('http://', HTTPAdapter())      def __enter__(self):         return self


v.close()      def mount(self, prefix, adapter):        """Registers a connection adapter to a prefix."""        """Registers a connection adapter to a prefix.        Adapters are sorted in descending order by key length."""         self.adapters[prefix] = adapter        keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]        for key in keys_to_move:            self.adapters[key] = self.adapters.pop(key)      def __getstate__(self):         return dict((attr, getattr(self, attr, None)) for attr in self.__attrs__)


"""  import os<ins>import collections</ins> from itertools import islice