Skip to content

Commit

Permalink
Workaround for matplotlib rc_context issue (#2925)
Browse files Browse the repository at this point in the history
* Workaround for matplotlib rc_context issue

Fixes #2914

* Add some additional comments about this workaround
  • Loading branch information
mwaskom authored Jul 31, 2022
1 parent f581300 commit 6460a21
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 7 deletions.
2 changes: 2 additions & 0 deletions doc/whatsnew/v0.12.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ Other updates

- |Fix| Subplot titles will no longer be reset when calling :meth:`FacetGrid.map` or :meth:`FacetGrid.map_dataframe` (:pr:`2705`).

- |Fix| Added a workaround for a matplotlib issue that caused figure-level functions to freeze when `plt.show` was called (:pr:`2925`).

- |Fix| Improved robustness to numerical errors in :func:`kdeplot` (:pr:`2862`).

- |Defaults| The `patch.facecolor` rc param is no longer set by :func:`set_palette` (or :func:`set_theme`). This should have no general effect, because the matplotlib default is now `"C0"` (:pr:`2906`).
Expand Down
10 changes: 5 additions & 5 deletions seaborn/axisgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

from ._oldcore import VectorPlotter, variable_type, categorical_order
from . import utils
from .utils import _check_argument, adjust_legend_subtitles, _draw_figure
from .utils import (
adjust_legend_subtitles, _check_argument, _draw_figure, _disable_autolayout
)
from .palettes import color_palette, blend_palette
from ._docstrings import (
DocstringComponents,
Expand Down Expand Up @@ -389,8 +391,7 @@ def __init__(

# --- Initialize the subplot grid

# Disable autolayout so legend_out works properly
with mpl.rc_context({"figure.autolayout": False}):
with _disable_autolayout():
fig = plt.figure(figsize=figsize)

if col_wrap is None:
Expand Down Expand Up @@ -1215,8 +1216,7 @@ def __init__(
# Create the figure and the array of subplots
figsize = len(x_vars) * height * aspect, len(y_vars) * height

# Disable autolayout so legend_out works
with mpl.rc_context({"figure.autolayout": False}):
with _disable_autolayout():
fig = plt.figure(figsize=figsize)

axes = fig.subplots(len(y_vars), len(x_vars),
Expand Down
29 changes: 27 additions & 2 deletions seaborn/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import inspect
import warnings
import colorsys
from contextlib import contextmanager
from urllib.request import urlopen, urlretrieve

import numpy as np
Expand Down Expand Up @@ -782,7 +783,7 @@ def _assign_default_kwargs(kws, call_func, source_func):
# This exists so that axes-level functions and figure-level functions can
# both call a Plotter method while having the default kwargs be defined in
# the signature of the axes-level function.
# An alternative would be to have a decorator on the method that sets its
# An alternative would be to have a decorator on the method that sets its
# defaults based on those defined in the axes-level function.
# Then the figure-level function would not need to worry about defaults.
# I am not sure which is better.
Expand All @@ -797,7 +798,12 @@ def _assign_default_kwargs(kws, call_func, source_func):


def adjust_legend_subtitles(legend):
"""Make invisible-handle "subtitles" entries look more like titles."""
"""
Make invisible-handle "subtitles" entries look more like titles.
Note: This function is not part of the public API and may be changed or removed.
"""
# Legend title not in rcParams until 3.0
font_size = plt.rcParams.get("legend.title_fontsize", None)
hpackers = legend.findobj(mpl.offsetbox.VPacker)[0].get_children()
Expand Down Expand Up @@ -834,3 +840,22 @@ def _deprecate_ci(errorbar, ci):
warnings.warn(msg, FutureWarning, stacklevel=3)

return errorbar


@contextmanager
def _disable_autolayout():
"""Context manager for preventing rc-controlled auto-layout behavior."""
# This is a workaround for an issue in matplotlib, for details see
# https://github.com/mwaskom/seaborn/issues/2914
# The only affect of this rcParam is to set the default value for
# layout= in plt.figure, so we could just do that instead.
# But then we would need to own the complexity of the transition
# from tight_layout=True -> layout="tight". This seems easier,
# but can be removed when (if) that is simpler on the matplotlib side,
# or if the layout algorithms are improved to handle figure legends.
orig_val = mpl.rcParams["figure.autolayout"]
try:
mpl.rcParams["figure.autolayout"] = False
yield
finally:
mpl.rcParams["figure.autolayout"] = orig_val

0 comments on commit 6460a21

Please sign in to comment.