Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

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)


Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

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"


Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

# 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:


Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

"""      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']


Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

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)


Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

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")


Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

"-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


Question: Postscript backend gives wrong page sizes Bug summary When creating a Figure of exactly A4 size, the PS backend chooses "letter" as document type, leading to additional borders of the output in x direction and undesired cropping in y direction. Code for reproduction Actual outcome When not specifying the papertype explicitly, the PS backend chooses "letter" format as can be seen from the resulting postscript output. It should, instead, choose A4 format. When specifying the papertype explicitly, the output looks fine. Expected outcome The PS backend should choose A4 format if the Figure is exactly this size. Anyway, nothing should ever be cropped off the Figure. If the Figure does not fit one papertype, the next larger one should be chosen. I also do not understand why the output of the PS backend is restricted to a handfull of explicit paper sizes in the first place. Postscript does well support arbitrary page sizes. Can someone explain why matplotlib chose to only support the given sizes? This is not transparent to the user, who expects to get output of exactly the size of his/her desired Figure object. Matplotlib version Operating system: Ubuntu 19.04 Matplotlib version: 3.1.1 Matplotlib backend: PS Python version: 3.7.4 Jupyter version: 1.0.0 Other libraries: Matplotlib was installed via conda.

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


Question: Typo in Poly3DCollection constructor There is a typo in that causes a exception whenever the function is called with . should be

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.")


Question: ValueError: fill value must be in categories In the preprocesscolors function, there is the code to replace na's with background color as the comment said, using , however, if the original colors do not contain the 'white' category, this line would raise the Pandas ValueError:fill value must be in categories in .

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):


Question: ValueError: fill value must be in categories In the preprocesscolors function, there is the code to replace na's with background color as the comment said, using , however, if the original colors do not contain the 'white' category, this line would raise the Pandas ValueError:fill value must be in categories in .

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,


Question: ValueError: fill value must be in categories In the preprocesscolors function, there is the code to replace na's with background color as the comment said, using , however, if the original colors do not contain the 'white' category, this line would raise the Pandas ValueError:fill value must be in categories in .

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 = []


Question: ValueError: fill value must be in categories In the preprocesscolors function, there is the code to replace na's with background color as the comment said, using , however, if the original colors do not contain the 'white' category, this line would raise the Pandas ValueError:fill value must be in categories in .

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):


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

# 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)


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

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


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

"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`.")


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

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


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

"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(


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

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


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

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


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

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}


Question: lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! lmplot(sharey=False) not working The following code behaves as if . (edit: actually, it does not behave the same, but it is still not rescaling the plots individually the way it should) If you do this, it suddenly works: Versions of seaborn and matplotlib: ! Allow xlim as parameter for lmplot Seaborn versions: latest dev version and 0.11.1 doesn't seem to accept the parameter, although FacetGrid does. Use case: when , the regression lines are extrapolated until they touch the current xlims. If one afterwards want to extend these xlims, the regression lines are floating again. A workaround is either to call FacetGrid and regplot separately, or to set very wide xmargins via the rcParams. Example code.

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


Question: histplot stat=count does not count all data points import as plt import seaborn as sns import numpy as np (style="whitegrid") dataa = [1, 2, 3] datab = [2.4, 2.5, 2.6] sns.histplot((dataa), color="red", binwidth=0.01, stat="count") sns.histplot((datab), color="blue", binwidth=0.01, stat="count") This produces The data point 2.6 is omitted in the output produced by histplot. The problem also exists, if the first sns.histplot command is removed. Interestingly, it has been pointed out to me that the following command works: but as I said, the single command also does not work.

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


Question: histplot stat=count does not count all data points import as plt import seaborn as sns import numpy as np (style="whitegrid") dataa = [1, 2, 3] datab = [2.4, 2.5, 2.6] sns.histplot((dataa), color="red", binwidth=0.01, stat="count") sns.histplot((datab), color="blue", binwidth=0.01, stat="count") This produces The data point 2.6 is omitted in the output produced by histplot. The problem also exists, if the first sns.histplot command is removed. Interestingly, it has been pointed out to me that the following command works: but as I said, the single command also does not work.

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


Question: histplot stat=count does not count all data points import as plt import seaborn as sns import numpy as np (style="whitegrid") dataa = [1, 2, 3] datab = [2.4, 2.5, 2.6] sns.histplot((dataa), color="red", binwidth=0.01, stat="count") sns.histplot((datab), color="blue", binwidth=0.01, stat="count") This produces The data point 2.6 is omitted in the output produced by histplot. The problem also exists, if the first sns.histplot command is removed. Interestingly, it has been pointed out to me that the following command works: but as I said, the single command also does not work.

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):


Question: relplot does not handle numpy-types for dimensional variables Test case: ! Note how it handles fine\, but does not create two columns (or error/warn in any useful way). handles this better: ! and solve the problem of initializing a from vector data differently. ~I do not remember if this ever worked in and is a regression (quite possibly not) and, if not, whether that was a failure of implementation or the result of a decision to punt on a particularly tricky issue. If the latter, it should at least give feedback about why it is not working.~ It looks like this never worked. the internal name used for here, , shows up in the y label, which I'm also not sure that we want. Note that there is no y axis label for the , although the internal name for the column variable is used because titles include that in their title template.

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


Question: relplot does not handle numpy-types for dimensional variables Test case: ! Note how it handles fine\, but does not create two columns (or error/warn in any useful way). handles this better: ! and solve the problem of initializing a from vector data differently. ~I do not remember if this ever worked in and is a regression (quite possibly not) and, if not, whether that was a failure of implementation or the result of a decision to punt on a particularly tricky issue. If the latter, it should at least give feedback about why it is not working.~ It looks like this never worked. the internal name used for here, , shows up in the y label, which I'm also not sure that we want. Note that there is no y axis label for the , although the internal name for the column variable is used because titles include that in their title template.

# 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()


Question: relplot does not handle numpy-types for dimensional variables Test case: ! Note how it handles fine\, but does not create two columns (or error/warn in any useful way). handles this better: ! and solve the problem of initializing a from vector data differently. ~I do not remember if this ever worked in and is a regression (quite possibly not) and, if not, whether that was a failure of implementation or the result of a decision to punt on a particularly tricky issue. If the latter, it should at least give feedback about why it is not working.~ It looks like this never worked. the internal name used for here, , shows up in the y label, which I'm also not sure that we want. Note that there is no y axis label for the , although the internal name for the column variable is used because titles include that in their title template.

# 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:


Question: PairGrid errors with assigned in In seaborn version 0.9.0 I was able to use the following Code to plot scatterplots across a PairGrid with categorical hue. The reason I am not using the "hue" keyword in creating the PairGrid is, that I want one regression line (with regplot) and not one regression per hue-category. However, since I updated to searbon 0.11.1 the following Error message occurs: My further observations are: the error does not occur when using the "hue" keyword when creating PairGrid the error does not occur for numerical values for hue changing the dtype to "categorical" does not help Edit: I tried all versions between 0.9.0 and the current release (0.11.1) and the error only occurs in the current release. If I use 0.11.0, the plot seems to work.

# 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:


Question: xestimator bars now inherit scatterkws alpha x_estimator error bars were previously always opaque, but now inherit alpha parameter from scatterplot settings (if present), since the error bars replace the scatterplot.

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)


Question: Regression: and raise when using a custom estimator This may be related to . According to (and ) documentation, the can be any callable that maps vector to scalar. However, the following example raises with on my Windows and Mac machines (and doesn't raise with ): <details<summaryException</summary</detailsIt does work, however, when changing the function to use the builtin func: The same error is raised when changing the example code to use , or when using a different numpy aggregator within the custom function.

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:


Question: Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x labels. Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x labels.

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 = (


Question: Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x labels. Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x 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


Question: Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x labels. Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x labels.

"""     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,     ):


Question: Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x labels. Visibility of internal axis labels is wrong with wrapped pair plot ! The top two subplots should have distinct x labels.

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


Question: Rename layout(algo=) to layout(engine=) Matplotlib has settled on this term with the new method in 3.6 so might as well be consistent with them. The new API also ha some implications for how the parameter should be documented / typed.

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


Question: Rename layout(algo=) to layout(engine=) Matplotlib has settled on this term with the new method in 3.6 so might as well be consistent with them. The new API also ha some implications for how the parameter should be documented / typed.

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


Question: Rename layout(algo=) to layout(engine=) Matplotlib has settled on this term with the new method in 3.6 so might as well be consistent with them. The new API also ha some implications for how the parameter should be documented / typed.

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


Question: Rename layout(algo=) to layout(engine=) Matplotlib has settled on this term with the new method in 3.6 so might as well be consistent with them. The new API also ha some implications for how the parameter should be documented / typed.

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


Question: Rename layout(algo=) to layout(engine=) Matplotlib has settled on this term with the new method in 3.6 so might as well be consistent with them. The new API also ha some implications for how the parameter should be documented / typed.

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)


Question: PolyFit is not robust to missing data <details<summaryTraceback</summary</details

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


Question: Nominal scale should be drawn the same way as categorical scales Three distinctive things happen on the categorical axis in seaborn's categorical plots: scale is drawn to +/- 0.5 from the first and last tick, rather than using the normal margin logic grid is not shown, even when it otherwise would be with the active style on the y axis, the axis is inverted It probably makes sense to have scales (including inferred ones) do this too. Some comments on implementation: is actually trickier than you'd think; I may have posted an issue over in matplotlib about this at one point, or just discussed on their gitter. I believe the suggested approach is to add an invisible artist with sticky edges and set the margin to 0. Feels like a hack! I might have looked into setting the sticky edges on the spine artist at one point? straightforward to do in . Always a good idea? How do we defer to the theme if the user wants to force a grid? Should the grid be something that is set in the scale object itself straightforward to implement but I am not exactly sure where would be best.

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


Question: Nominal scale should be drawn the same way as categorical scales Three distinctive things happen on the categorical axis in seaborn's categorical plots: scale is drawn to +/- 0.5 from the first and last tick, rather than using the normal margin logic grid is not shown, even when it otherwise would be with the active style on the y axis, the axis is inverted It probably makes sense to have scales (including inferred ones) do this too. Some comments on implementation: is actually trickier than you'd think; I may have posted an issue over in matplotlib about this at one point, or just discussed on their gitter. I believe the suggested approach is to add an invisible artist with sticky edges and set the margin to 0. Feels like a hack! I might have looked into setting the sticky edges on the spine artist at one point? straightforward to do in . Always a good idea? How do we defer to the theme if the user wants to force a grid? Should the grid be something that is set in the scale object itself straightforward to implement but I am not exactly sure where would be best.

# 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]


Question: Nominal scale should be drawn the same way as categorical scales Three distinctive things happen on the categorical axis in seaborn's categorical plots: scale is drawn to +/- 0.5 from the first and last tick, rather than using the normal margin logic grid is not shown, even when it otherwise would be with the active style on the y axis, the axis is inverted It probably makes sense to have scales (including inferred ones) do this too. Some comments on implementation: is actually trickier than you'd think; I may have posted an issue over in matplotlib about this at one point, or just discussed on their gitter. I believe the suggested approach is to add an invisible artist with sticky edges and set the margin to 0. Feels like a hack! I might have looked into setting the sticky edges on the spine artist at one point? straightforward to do in . Always a good idea? How do we defer to the theme if the user wants to force a grid? Should the grid be something that is set in the scale object itself straightforward to implement but I am not exactly sure where would be best.

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:


Question: Nominal scale should be drawn the same way as categorical scales Three distinctive things happen on the categorical axis in seaborn's categorical plots: scale is drawn to +/- 0.5 from the first and last tick, rather than using the normal margin logic grid is not shown, even when it otherwise would be with the active style on the y axis, the axis is inverted It probably makes sense to have scales (including inferred ones) do this too. Some comments on implementation: is actually trickier than you'd think; I may have posted an issue over in matplotlib about this at one point, or just discussed on their gitter. I believe the suggested approach is to add an invisible artist with sticky edges and set the margin to 0. Feels like a hack! I might have looked into setting the sticky edges on the spine artist at one point? straightforward to do in . Always a good idea? How do we defer to the theme if the user wants to force a grid? Should the grid be something that is set in the scale object itself straightforward to implement but I am not exactly sure where would be best.

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)


Question: Wrong legend values of large ranges As of 0.12.1, legends describing large numbers that were created using with an offset are formatted without their multiplicative offset value. An example: The code creates the following plot: ! which is wrong because is in the order of 1E6. The issue also reproduces if you create the mentioned plot using . I believe the issue stems from not using the offset value of the used to generate the tick labels: Examining the code of suggests the issue also depends on the following rcParam settings: However, I did not test it. The offset value can be safely retrieved from all formatters and based on that it can be used to create the legend title and/or labels.

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


Question: Wrong legend values of large ranges As of 0.12.1, legends describing large numbers that were created using with an offset are formatted without their multiplicative offset value. An example: The code creates the following plot: ! which is wrong because is in the order of 1E6. The issue also reproduces if you create the mentioned plot using . I believe the issue stems from not using the offset value of the used to generate the tick labels: Examining the code of suggests the issue also depends on the following rcParam settings: However, I did not test it. The offset value can be safely retrieved from all formatters and based on that it can be used to create the legend title and/or labels.

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


Question: Objects interface raises if faceting on partially-crossed row and column In the objects interface, one can facet two variables using rows and columns. When the faceted categories are not fully crossed, it raises: <details<summaryThe trace</summary</detailsI expect a behavior that is similar to , where the facets that contain no data are empty: !

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"]


Question: Objects interface raises if faceting on partially-crossed row and column In the objects interface, one can facet two variables using rows and columns. When the faceted categories are not fully crossed, it raises: <details<summaryThe trace</summary</detailsI expect a behavior that is similar to , where the facets that contain no data are empty: !

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)


Question: Objects interface raises if faceting on partially-crossed row and column In the objects interface, one can facet two variables using rows and columns. When the faceted categories are not fully crossed, it raises: <details<summaryThe trace</summary</detailsI expect a behavior that is similar to , where the facets that contain no data are empty: !

# 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


Question: Objects interface raises if faceting on partially-crossed row and column In the objects interface, one can facet two variables using rows and columns. When the faceted categories are not fully crossed, it raises: <details<summaryThe trace</summary</detailsI expect a behavior that is similar to , where the facets that contain no data are empty: !

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)


Question: Figure title being removed by seaborn objects API when plotting on subfigures I recently came across an odd behaviour with the seaborn objects API when using subfigures. Here is a minimal example : which results in the title missing from the image : ! Commenting the results in the title reappearing. I have done a bit of digging and found that changing line 186 from the file from to seems to solve the issue. Is there a specific reason to why it fetches the parent figure currently, since Subfigure is supposed to be a drop-in replacement for Figure ? I also expect this will not have the intended behaviour if we deal with subfigures of subfigures.

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


Question: Figure title being removed by seaborn objects API when plotting on subfigures I recently came across an odd behaviour with the seaborn objects API when using subfigures. Here is a minimal example : which results in the title missing from the image : ! Commenting the results in the title reappearing. I have done a bit of digging and found that changing line 186 from the file from to seems to solve the issue. Is there a specific reason to why it fetches the parent figure currently, since Subfigure is supposed to be a drop-in replacement for Figure ? I also expect this will not have the intended behaviour if we deal with subfigures of subfigures.

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")


Question: Width computation after histogram slightly wrong with log scale Note the slight overlap here: ! It becomes nearly imperceptible with more bins: ! This is not about ; has it too: !

) -> 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)         )


Question: Width computation after histogram slightly wrong with log scale Note the slight overlap here: ! It becomes nearly imperceptible with more bins: ! This is not about ; has it too: !

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


Question: Width computation after histogram slightly wrong with log scale Note the slight overlap here: ! It becomes nearly imperceptible with more bins: ! This is not about ; has it too: !

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)


Question: has different behaviour than without specifying the argument Hi, I'm noticing a strange behaviour when passing to a heatmap and I believe it's due to these lines: Specifically, if I use I get something like this: ! but when I use , and are lost: ! I'm happy to send a PR if this issue isn't addressed anywhere. Ștefan

# 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)


Question: pd.NA reverses axis ordering When plotting with , axis ordering get reversed into descending. does not produce this issue NAs should be excluded without reversing axis order !

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


Question: pd.NA reverses axis ordering When plotting with , axis ordering get reversed into descending. does not produce this issue NAs should be excluded without reversing axis order !

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


Question: pd.NA reverses axis ordering When plotting with , axis ordering get reversed into descending. does not produce this issue NAs should be excluded without reversing axis order !

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


Question: pd.NA reverses axis ordering When plotting with , axis ordering get reversed into descending. does not produce this issue NAs should be excluded without reversing axis order !

# 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))


Question: pd.NA reverses axis ordering When plotting with , axis ordering get reversed into descending. does not produce this issue NAs should be excluded without reversing axis order !

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


Question: pd.NA reverses axis ordering When plotting with , axis ordering get reversed into descending. does not produce this issue NAs should be excluded without reversing axis order !

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


Question: pairplot raises KeyError with MultiIndex DataFrame When trying to pairplot a MultiIndex DataFrame, raises a : MRE: Output: A workaround is to "flatten" the columns:

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)


Question: Raise error when blueprint name contains a dot This is required since every dot is now significant since blueprints can be nested. An error was already for endpoint names in 1.0, but should have been for this as well.

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


Question: Raise error when blueprint name contains a dot This is required since every dot is now significant since blueprints can be nested. An error was already for endpoint names in 1.0, but should have been for this as well.

"""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:


Question: handle Decimal in json encoder The removal () decreased the flask encoding capabilities as the built-in doesn't cover cases like types. The solution seems to be: overwrite the flask app encoder with from , but this incorporates a problem for users that relies on both and as doesn't handle , while flask encoder does. The solution I found is to build a custom encoder that tests if the value is and gives it to , otherwise, handles it with the default flask app encoder. My suggestion is to incorporate a simple test in the flask encoder to add coverage, that would remove any residual dependency on . The str(decimal) was taken from: The custom encoder: The expected behavior is to work with both and as it used to work on Flask version 1.1.2 Environment: Python version: 3.8.10 Flask version: 2.0.1 and 1.1.2 Simplejson(Optional) version: 3.17.2

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


Question: handle Decimal in json encoder The removal () decreased the flask encoding capabilities as the built-in doesn't cover cases like types. The solution seems to be: overwrite the flask app encoder with from , but this incorporates a problem for users that relies on both and as doesn't handle , while flask encoder does. The solution I found is to build a custom encoder that tests if the value is and gives it to , otherwise, handles it with the default flask app encoder. My suggestion is to incorporate a simple test in the flask encoder to add coverage, that would remove any residual dependency on . The str(decimal) was taken from: The custom encoder: The expected behavior is to work with both and as it used to work on Flask version 1.1.2 Environment: Python version: 3.8.10 Flask version: 2.0.1 and 1.1.2 Simplejson(Optional) version: 3.17.2

"""         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)


Question: handle Decimal in json encoder The removal () decreased the flask encoding capabilities as the built-in doesn't cover cases like types. The solution seems to be: overwrite the flask app encoder with from , but this incorporates a problem for users that relies on both and as doesn't handle , while flask encoder does. The solution I found is to build a custom encoder that tests if the value is and gives it to , otherwise, handles it with the default flask app encoder. My suggestion is to incorporate a simple test in the flask encoder to add coverage, that would remove any residual dependency on . The str(decimal) was taken from: The custom encoder: The expected behavior is to work with both and as it used to work on Flask version 1.1.2 Environment: Python version: 3.8.10 Flask version: 2.0.1 and 1.1.2 Simplejson(Optional) version: 3.17.2

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.


Question: handle Decimal in json encoder The removal () decreased the flask encoding capabilities as the built-in doesn't cover cases like types. The solution seems to be: overwrite the flask app encoder with from , but this incorporates a problem for users that relies on both and as doesn't handle , while flask encoder does. The solution I found is to build a custom encoder that tests if the value is and gives it to , otherwise, handles it with the default flask app encoder. My suggestion is to incorporate a simple test in the flask encoder to add coverage, that would remove any residual dependency on . The str(decimal) was taken from: The custom encoder: The expected behavior is to work with both and as it used to work on Flask version 1.1.2 Environment: Python version: 3.8.10 Flask version: 2.0.1 and 1.1.2 Simplejson(Optional) version: 3.17.2

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`.


Question: Exceptions are sometimes replaced with "TypeError: exceptions must derive from BaseException" I expected something about a RuntimeError. here worked for me Environment: Python version: 3.9.5 Flask version: 2.0.1

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"


Question: Exceptions are sometimes replaced with "TypeError: exceptions must derive from BaseException" I expected something about a RuntimeError. here worked for me Environment: Python version: 3.9.5 Flask version: 2.0.1

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):


Question: rejects When trying the development server, I find that works fine, but fails with: Isn't this somewhat counterintuitive? In ,  function insists the certificate file should have been specified, and it feels too restrictive. But I'm not familiar with Click to contribute a pretty PR... Environment: Python version: 3.9.10 Flask version: 2.0.3

@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",


Question: Move to the app object Add a method to the app object. Similar to functions like , should look for a and call its method. This will allow applications to override the redirect behavior.

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


Question: Move to the app object Add a method to the app object. Similar to functions like , should look for a and call its method. This will allow applications to override the redirect behavior.

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


Question: Move to the app object Add a method to the app object. Similar to functions like , should look for a and call its method. This will allow applications to override the redirect behavior.

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


Question: Move to the app object Add a method to the app object. Similar to functions like , should look for a and call its method. This will allow applications to override the redirect behavior.

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


Question: Move to the app object Add a method to the app object. Similar to functions like , should look for a and call its method. This will allow applications to override the redirect behavior.

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


Question: Move to the app object Add a method to the app object. Similar to functions like , should look for a and call its method. This will allow applications to override the redirect behavior.

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


Question: Move to the app object Add a method to the app object. Similar to functions like , should look for a and call its method. This will allow applications to override the redirect behavior.

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


Question: Nested blueprints are not respected when mounted on subdomains Hello, and thanks for all your work Nested blueprints work perfectly fine when using . However, when mounting the parent blueprint using a subdomain, the child routes are not accessible. The index route works as expected: So does the parent route in the subdomain: But the child responds with a 404: If we change the for when registering the blueprint however everything works as expected: This was surprising to me as I expected the same nesting to apply regardless of whether the parent is mounted using a subdomain or a URL prefix. Am I missing something? Environment: Python version: 3.10 Flask version: 2.2.2

: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


Question: Nested blueprints are not respected when mounted on subdomains Hello, and thanks for all your work Nested blueprints work perfectly fine when using . However, when mounting the parent blueprint using a subdomain, the child routes are not accessible. The index route works as expected: So does the parent route in the subdomain: But the child responds with a 404: If we change the for when registering the blueprint however everything works as expected: This was surprising to me as I expected the same nesting to apply regardless of whether the parent is mounted using a subdomain or a URL prefix. Am I missing something? Environment: Python version: 3.10 Flask version: 2.2.2

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


Question: Add a file mode parameter to flask.Config.fromfile() Python 3.11 introduced native TOML support with the package. This could work nicely with the method as an easy way to load TOML config files: However, takes an object readable in binary mode, while opens a file in text mode, resulting in this error: We can get around this with a more verbose expression, like loading from a file opened with the built-in function and passing the to : But adding a file mode parameter to would enable the use of a simpler expression. E.g.:

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


Question: Add a file mode parameter to flask.Config.fromfile() Python 3.11 introduced native TOML support with the package. This could work nicely with the method as an easy way to load TOML config files: However, takes an object readable in binary mode, while opens a file in text mode, resulting in this error: We can get around this with a more verbose expression, like loading from a file opened with the built-in function and passing the to : But adding a file mode parameter to would enable the use of a simpler expression. E.g.:

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.


Question: Add a file mode parameter to flask.Config.fromfile() Python 3.11 introduced native TOML support with the package. This could work nicely with the method as an easy way to load TOML config files: However, takes an object readable in binary mode, while opens a file in text mode, resulting in this error: We can get around this with a more verbose expression, like loading from a file opened with the built-in function and passing the to : But adding a file mode parameter to would enable the use of a simpler expression. E.g.:

: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):


Question: Require a non-empty name for Blueprints Things do not work correctly if a Blueprint is given an empty name (e.g. ). It would be helpful if a was raised when trying to do that.

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.")


Question: Flask routes to return domain/sub-domains information Currently when checking flask routes it provides all routes but it is no way to see which routes are assigned to which subdomain. Default server name: SERVERNAME: '' Domains (sub-domains): Adding blueprints: app.registerblueprint(adminblueprint,urlprefix='',subdomain='admin') app.registerblueprint(testsubdomainblueprint,urlprefix='',subdomain='test') Feature request It will be good to see something like below (that will make more clear which route for which subdomain, because now need to go and check configuration). If it is not possible to fix routes, can you add or tell which method(s) should be used to get below information from flask?

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


Question: Flask routes to return domain/sub-domains information Currently when checking flask routes it provides all routes but it is no way to see which routes are assigned to which subdomain. Default server name: SERVERNAME: '' Domains (sub-domains): Adding blueprints: app.registerblueprint(adminblueprint,urlprefix='',subdomain='admin') app.registerblueprint(testsubdomainblueprint,urlprefix='',subdomain='test') Feature request It will be good to see something like below (that will make more clear which route for which subdomain, because now need to go and check configuration). If it is not possible to fix routes, can you add or tell which method(s) should be used to get below information from flask?

@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(


Question: is ALWAYS sending content length Hi, It seems like that always adds 'content-length' header to the request. I think that the right behavior is not to add this header automatically in GET requests or add the possibility to not send it. For example returns 503 for every get request that contains 'content-length' header. Thanks, Oren

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."""


Question: Transport adapters don't work as advertised Having: We cannot currently reliably do:: We should, this is documented: Instead, because of the following might or might not work as expected: This is because there is already a default adapter for in the form of . Depending on the (seemingly random) order of keys in the dictionary, for some combinations of keys it will work, for others it won't. There are a couple. As usual, a compromise between backwards compatibility, clarity and performance. Change so that it sorts the keys every time it fetches an adapter. The advantage is that is still a vanilla dictionary, if you consider it a public API. Something like Django's which would sort the keys on insertion. The advantage is that is still a mapping and now is faster. The disadvantage is the maintenance cost of a custom data structure. Also, mild backwards incompatibility if someone somewhere used the fact that is exactly of the type (unlikely, isn't it?). Having and as the public API for adapters, we might just as well implement the sorting while mounting and just maintain as a list of tuples. The advantage is that it's the fastest solution with no additional maintenance burden. The disadvantage is backwards incompatibility. This is another design issue. It appears that sorting first from the longest key to shortest, and then alphabetically (for keys of the same length), is the way. What should we do about it? By the way, this test adapter in the example above .

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


Question: Transport adapters don't work as advertised Having: We cannot currently reliably do:: We should, this is documented: Instead, because of the following might or might not work as expected: This is because there is already a default adapter for in the form of . Depending on the (seemingly random) order of keys in the dictionary, for some combinations of keys it will work, for others it won't. There are a couple. As usual, a compromise between backwards compatibility, clarity and performance. Change so that it sorts the keys every time it fetches an adapter. The advantage is that is still a vanilla dictionary, if you consider it a public API. Something like Django's which would sort the keys on insertion. The advantage is that is still a mapping and now is faster. The disadvantage is the maintenance cost of a custom data structure. Also, mild backwards incompatibility if someone somewhere used the fact that is exactly of the type (unlikely, isn't it?). Having and as the public API for adapters, we might just as well implement the sorting while mounting and just maintain as a list of tuples. The advantage is that it's the fastest solution with no additional maintenance burden. The disadvantage is backwards incompatibility. This is another design issue. It appears that sorting first from the longest key to shortest, and then alphabetically (for keys of the same length), is the way. What should we do about it? By the way, this test adapter in the example above .

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