From 37f96e1965c838e3bccaec6d4461632f9ecdc4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sat, 18 Feb 2023 16:31:40 +0100 Subject: [PATCH 1/6] ENH: add a reusable matplotlib stylesheet for yt's classic style --- MANIFEST.in | 2 ++ yt/default.mplstyle | 15 +++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 yt/default.mplstyle diff --git a/MANIFEST.in b/MANIFEST.in index 69ccaccccf5..4d9dbcb3269 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -23,6 +23,8 @@ recursive-include yt/visualization/volume_rendering/shaders *.fragmentshader *.v include yt/sample_data_registry.json include conftest.py include yt/py.typed +include yt/default.mplstyle + prune yt/frontends/_skeleton recursive-include yt/frontends/amrvac *.par exclude .codecov.yml .coveragerc .git-blame-ignore-revs .gitmodules .hgchurn .mailmap diff --git a/yt/default.mplstyle b/yt/default.mplstyle new file mode 100644 index 00000000000..b52c6a667c0 --- /dev/null +++ b/yt/default.mplstyle @@ -0,0 +1,15 @@ +# basic usage (requires matplotlib 3.7+) +# >>> import matplotlib as mpl +# >>> mpl.style.use("yt.default") + +xtick.top: True +ytick.right: True +xtick.minor.visible: True +ytick.minor.visible: True +xtick.direction: in +ytick.direction: in + +font.family: stixgeneral + +mathtext.fontset: cm +mathtext.fallback: cm From b1bc7c772aec6760ac59d523da0bbe38c41970ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sat, 18 Feb 2023 16:09:38 +0100 Subject: [PATCH 2/6] ENH: revive and update yt.funcs.matplotlib_style_context context manager --- yt/funcs.py | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/yt/funcs.py b/yt/funcs.py index 3cc9c90286c..3f48268a063 100644 --- a/yt/funcs.py +++ b/yt/funcs.py @@ -994,35 +994,22 @@ def get_brewer_cmap(cmap): return bmap.get_mpl_colormap(N=cmap[2]) -@contextlib.contextmanager -def dummy_context_manager(*args, **kwargs): - yield - - -def matplotlib_style_context(style_name=None, after_reset=False): +def matplotlib_style_context(style="yt.default", after_reset=False): """Returns a context manager for controlling matplotlib style. Arguments are passed to matplotlib.style.context() if specified. Defaults - to setting "classic" style, after resetting to the default config parameters. - - On older matplotlib versions (<=1.5.0) where matplotlib.style isn't - available, returns a dummy context manager. + to setting yt's "yt.default" style, after resetting to the default config parameters. """ - if style_name is None: - import matplotlib + # FUTURE: this function should be deprecated in favour of matplotlib.style.context + # after support for matplotlib 3.6 and older versions is dropped. + import matplotlib.style - style_name = {"mathtext.fontset": "cm"} - if Version(matplotlib.__version__) >= Version("3.3.0"): - style_name["mathtext.fallback"] = "cm" - else: - style_name["mathtext.fallback_to_cm"] = True - try: - import matplotlib.style + from yt.visualization._commons import MPL_VERSION - return matplotlib.style.context(style_name, after_reset=after_reset) - except ImportError: - pass - return dummy_context_manager() + if style == "yt.default" and MPL_VERSION < Version("3.7"): + style = importlib_resources.files("yt") / "default.mplstyle" + + return matplotlib.style.context(style, after_reset=after_reset) interactivity = False From 04896557b7fadeab74c796bdadffd2be3afcd8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sun, 19 Feb 2023 10:39:11 +0100 Subject: [PATCH 3/6] DOC: document yt.funcs.matplotlib_style_context --- doc/source/visualizing/plots.rst | 77 ++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/doc/source/visualizing/plots.rst b/doc/source/visualizing/plots.rst index 9376968890a..fe4c2e49d86 100644 --- a/doc/source/visualizing/plots.rst +++ b/doc/source/visualizing/plots.rst @@ -2419,3 +2419,80 @@ an example that includes slices and phase plots: ) mp.save_fig("multi_slice_phase") + + +Using yt's style with matplotlib +-------------------------------- + +It is possible to use yt's plot style in outside of yt itself, with the +:func:`~yt.funcs.matplotlib_style_context` context manager + +.. code-block:: python + + import matplotlib.pyplot as plt + import numpy as np + import yt + + plt.rcParams["font.size"] = 14 + + x = np.linspace(-np.pi, np.pi, 100) + y = np.sin(x) + + with yt.funcs.matplotlib_style_context(): + fig, ax = plt.subplots() + ax.plot(x, y) + ax.set( + xlabel=r"$x$", + ylabel=r"$y$", + title="A yt-styled matplotlib figure", + ) + +Note that :func:`~yt.funcs.matplotlib_style_context` doesn't control the font +size, so we adjust it manually in the preamble. + +With matplotlib 3.7 and newer, you can avoid importing yt altogether + +.. code-block:: python + + # requires matplotlib>=3.7 + import matplotlib.pyplot as plt + import numpy as np + + plt.rcParams["font.size"] = 14 + + x = np.linspace(-np.pi, np.pi, 100) + y = np.sin(x) + + with plt.style.context("yt.default"): + fig, ax = plt.subplots() + ax.plot(x, y) + ax.set( + xlabel=r"$x$", + ylabel=r"$y$", + title="A yt-styled matplotlib figure", + ) + +and you can also enable yt's style without a context manager as + +.. code-block:: python + + # requires matplotlib>=3.7 + import matplotlib.pyplot as plt + import numpy as np + + plt.style.use("yt.default") + plt.rcParams["font.size"] = 14 + + x = np.linspace(-np.pi, np.pi, 100) + y = np.sin(x) + + fig, ax = plt.subplots() + ax.plot(x, y) + ax.set( + xlabel=r"$x$", + ylabel=r"$y$", + title="A yt-styled matplotlib figure", + ) + +For more details, see `matplotlib's documentation +_` From d88d77af305ebbf6b4ae8505d25f518d66e9e017 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Wed, 22 Mar 2023 11:35:49 +0100 Subject: [PATCH 4/6] RFC: drop unnecessary fallback matplotlib parameter --- yt/default.mplstyle | 1 - 1 file changed, 1 deletion(-) diff --git a/yt/default.mplstyle b/yt/default.mplstyle index b52c6a667c0..a0793fc8e6e 100644 --- a/yt/default.mplstyle +++ b/yt/default.mplstyle @@ -12,4 +12,3 @@ ytick.direction: in font.family: stixgeneral mathtext.fontset: cm -mathtext.fallback: cm From 65d52cc46930e47ad6593108dc02b2b6d337451d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Wed, 22 Mar 2023 11:41:27 +0100 Subject: [PATCH 5/6] RFC: avoid rcParam duplication for DEFAULT_FONT_PROPERTIES --- yt/visualization/_commons.py | 19 +++++++++++++------ yt/visualization/plot_container.py | 7 ++++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/yt/visualization/_commons.py b/yt/visualization/_commons.py index 990a00e1f93..f07484cf9a9 100644 --- a/yt/visualization/_commons.py +++ b/yt/visualization/_commons.py @@ -5,12 +5,18 @@ from importlib.metadata import version from typing import TYPE_CHECKING, Optional, Type, TypeVar +import matplotlib as mpl import numpy as np from more_itertools import always_iterable from packaging.version import Version from yt.config import ytcfg +if sys.version_info >= (3, 9): + import importlib.resources as importlib_resources +else: + import importlib_resources + if sys.version_info >= (3, 10): pass else: @@ -20,15 +26,16 @@ from ._mpl_imports import FigureCanvasBase -DEFAULT_FONT_PROPERTIES = { - "family": "stixgeneral", - "size": 18, -} - MPL_VERSION = Version(version("matplotlib")) +_yt_style = mpl.rc_params_from_file( + importlib_resources.files("yt") / "default.mplstyle", use_default_template=False +) +DEFAULT_FONT_PROPERTIES = {"family": _yt_style["font.family"][0]} + if MPL_VERSION >= Version("3.4"): - DEFAULT_FONT_PROPERTIES["math_fontfamily"] = "cm" + DEFAULT_FONT_PROPERTIES["math_fontfamily"] = _yt_style["mathtext.fontset"] +del _yt_style def _get_supported_image_file_formats(): diff --git a/yt/visualization/plot_container.py b/yt/visualization/plot_container.py index 51d221eb66a..eb2b307445f 100644 --- a/yt/visualization/plot_container.py +++ b/yt/visualization/plot_container.py @@ -133,7 +133,7 @@ def __init__(self, data_source, figure_size=None, fontsize: Optional[float] = No if sys.version_info >= (3, 9): font_dict = DEFAULT_FONT_PROPERTIES | {"size": fontsize} else: - font_dict = {**DEFAULT_FONT_PROPERTIES, "size": fontsize} # type:ignore + font_dict = {**DEFAULT_FONT_PROPERTIES, "size": fontsize} self._font_properties = FontProperties(**font_dict) self._font_color = None @@ -451,10 +451,11 @@ def set_font(self, font_dict=None): self._font_color = font_dict.pop("color") # Set default values if the user does not explicitly set them. # this prevents reverting to the matplotlib defaults. + _default_size = {"size": self.__class__._default_font_size} if sys.version_info >= (3, 9): - font_dict = DEFAULT_FONT_PROPERTIES | font_dict + font_dict = DEFAULT_FONT_PROPERTIES | _default_size | font_dict else: - font_dict = {**DEFAULT_FONT_PROPERTIES, **font_dict} + font_dict = {**DEFAULT_FONT_PROPERTIES, **_default_size, **font_dict} self._font_properties = FontProperties(**font_dict) return self From 25b1d7be9bf753b4d31d53327f37bde4ae49d0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Wed, 22 Mar 2023 13:50:38 +0100 Subject: [PATCH 6/6] TST: fix an erroneous version cap in conftest.py --- conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conftest.py b/conftest.py index 7b34930e595..8e44c914efb 100644 --- a/conftest.py +++ b/conftest.py @@ -145,7 +145,7 @@ def pytest_configure(config): r"Use Palette\.ADAPTIVE instead\.:DeprecationWarning", ) - if NUMPY_VERSION < Version("1.19") and MPL_VERSION < Version("3.3"): + if NUMPY_VERSION < Version("1.19") and MPL_VERSION < Version("3.4"): # This warning is triggered from matplotlib in exactly one test at the time of writing # and exclusively on the minimal test env. Upgrading numpy or matplotlib resolves # the issue, so we can afford to ignore it.