FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Prepare to turn matplotlib.style into a plain module. by anntzer · Pull Request #30163 · matplotlib/matplotlib · GitHub

Repository navigation

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .build  (1) .py  (3) .pyi  (2) .rst  (1) All 4 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
9 changes: 9 additions & 0 deletions doc/api/next_api_changes/deprecations/30163-AL.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
``matplotlib.style.core``
~~~~~~~~~~~~~~~~~~~~~~~~~
The ``matplotlib.style.core`` module is deprecated. All APIs intended for
public use are now available in `matplotlib.style` directly (including
``USER_LIBRARY_PATHS``, which was previously not reexported).

The following APIs of ``matplotlib.style.core`` have been deprecated with no
replacement: ``BASE_LIBRARY_PATH``, ``STYLE_EXTENSION``, ``STYLE_BLACKLIST``,
``update_user_library``, ``read_style_directory``, ``update_nested_dict``.
252 changes: 250 additions & 2 deletions lib/matplotlib/style/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -1,4 +1,252 @@
from .core import available, context, library, reload_library, use
"""
Core functions and attributes for the matplotlib style library:

``use``
Select style sheet to override the current matplotlib settings.
``context``
Context manager to use a style sheet temporarily.
``available``
List available style sheets.
``library``
A dictionary of style names and matplotlib settings.
"""

__all__ = ["available", "context", "library", "reload_library", "use"]
import contextlib
import importlib.resources
import logging
import os
from pathlib import Path
import warnings

import matplotlib as mpl
from matplotlib import _api, _docstring, rc_params_from_file, rcParamsDefault

_log = logging.getLogger(__name__)

__all__ = ['use', 'context', 'available', 'library', 'reload_library']


_BASE_LIBRARY_PATH = os.path.join(mpl.get_data_path(), 'stylelib')
# Users may want multiple library paths, so store a list of paths.
USER_LIBRARY_PATHS = [os.path.join(mpl.get_configdir(), 'stylelib')]
_STYLE_EXTENSION = 'mplstyle'
# A list of rcParams that should not be applied from styles
_STYLE_BLACKLIST = {
'interactive', 'backend', 'webagg.port', 'webagg.address',
'webagg.port_retries', 'webagg.open_in_browser', 'backend_fallback',
'toolbar', 'timezone', 'figure.max_open_warning',
'figure.raise_window', 'savefig.directory', 'tk.window_focus',
'docstring.hardcopy', 'date.epoch'}


@_docstring.Substitution(
"\n".join(map("- {}".format, sorted(_STYLE_BLACKLIST, key=str.lower)))
)
def use(style):
"""
Use Matplotlib style settings from a style specification.

The style name of 'default' is reserved for reverting back to
the default style settings.

.. note::

This updates the `.rcParams` with the settings from the style.
`.rcParams` not defined in the style are kept.

Parameters
----------
style : str, dict, Path or list

A style specification. Valid options are:

str
- One of the style names in `.style.available` (a builtin style or
a style installed in the user library path).

- A dotted name of the form "package.style_name"; in that case,
"package" should be an importable Python package name, e.g. at
``/path/to/package/__init__.py``; the loaded style file is
``/path/to/package/style_name.mplstyle``. (Style files in
subpackages are likewise supported.)

- The path or URL to a style file, which gets loaded by
`.rc_params_from_file`.

dict
A mapping of key/value pairs for `matplotlib.rcParams`.

Path
The path to a style file, which gets loaded by
`.rc_params_from_file`.

list
A list of style specifiers (str, Path or dict), which are applied
from first to last in the list.

Notes
-----
The following `.rcParams` are not related to style and will be ignored if
found in a style specification:

%s
"""
if isinstance(style, (str, Path)) or hasattr(style, 'keys'):
# If name is a single str, Path or dict, make it a single element list.
styles = [style]
else:
styles = style

style_alias = {'mpl20': 'default', 'mpl15': 'classic'}

for style in styles:
if isinstance(style, str):
style = style_alias.get(style, style)
if style == "default":
# Deprecation warnings were already handled when creating
# rcParamsDefault, no need to reemit them here.
with _api.suppress_matplotlib_deprecation_warning():
# don't trigger RcParams.__getitem__('backend')
style = {k: rcParamsDefault[k] for k in rcParamsDefault
if k not in _STYLE_BLACKLIST}
elif style in library:
style = library[style]
elif "." in style:
pkg, _, name = style.rpartition(".")
try:
path = importlib.resources.files(pkg) / f"{name}.{_STYLE_EXTENSION}"
style = rc_params_from_file(path, use_default_template=False)
except (ModuleNotFoundError, OSError, TypeError) as exc:
# There is an ambiguity whether a dotted name refers to a
# package.style_name or to a dotted file path. Currently,
# we silently try the first form and then the second one;
# in the future, we may consider forcing file paths to
# either use Path objects or be prepended with "./" and use
# the slash as marker for file paths.
pass
if isinstance(style, (str, Path)):
try:
style = rc_params_from_file(style, use_default_template=False)
except OSError as err:
raise OSError(
f"{style!r} is not a valid package style, path of style "
f"file, URL of style file, or library style name (library "
f"styles are listed in `style.available`)") from err
filtered = {}
for k in style: # don't trigger RcParams.__getitem__('backend')
if k in _STYLE_BLACKLIST:
_api.warn_external(
f"Style includes a parameter, {k!r}, that is not "
f"related to style. Ignoring this parameter.")
else:
filtered[k] = style[k]
mpl.rcParams.update(filtered)


@contextlib.contextmanager
def context(style, after_reset=False):
"""
Context manager for using style settings temporarily.

Parameters
----------
style : str, dict, Path or list
A style specification. Valid options are:

str
- One of the style names in `.style.available` (a builtin style or
a style installed in the user library path).

- A dotted name of the form "package.style_name"; in that case,
"package" should be an importable Python package name, e.g. at
``/path/to/package/__init__.py``; the loaded style file is
``/path/to/package/style_name.mplstyle``. (Style files in
subpackages are likewise supported.)

- The path or URL to a style file, which gets loaded by
`.rc_params_from_file`.
dict
A mapping of key/value pairs for `matplotlib.rcParams`.

Path
The path to a style file, which gets loaded by
`.rc_params_from_file`.

list
A list of style specifiers (str, Path or dict), which are applied
from first to last in the list.

after_reset : bool
If True, apply style after resetting settings to their defaults;
otherwise, apply style on top of the current settings.
"""
with mpl.rc_context():
if after_reset:
mpl.rcdefaults()
use(style)
yield


def _update_user_library(library):
"""Update style library with user-defined rc files."""
for stylelib_path in map(os.path.expanduser, USER_LIBRARY_PATHS):
styles = _read_style_directory(stylelib_path)
_update_nested_dict(library, styles)
return library


@_api.deprecated("3.11")
def update_user_library(library):
return _update_user_library(library)


def _read_style_directory(style_dir):
"""Return dictionary of styles defined in *style_dir*."""
styles = dict()
for path in Path(style_dir).glob(f"*.{_STYLE_EXTENSION}"):
with warnings.catch_warnings(record=True) as warns:
styles[path.stem] = rc_params_from_file(path, use_default_template=False)
for w in warns:
_log.warning('In %s: %s', path, w.message)
return styles


@_api.deprecated("3.11")
def read_style_directory(style_dir):
return _read_style_directory(style_dir)


def _update_nested_dict(main_dict, new_dict):
"""
Update nested dict (only level of nesting) with new values.

Unlike `dict.update`, this assumes that the values of the parent dict are
dicts (or dict-like), so you shouldn't replace the nested dict if it
already exists. Instead you should update the sub-dict.
"""
# update named styles specified by user
for name, rc_dict in new_dict.items():
main_dict.setdefault(name, {}).update(rc_dict)
return main_dict


@_api.deprecated("3.11")
def update_nested_dict(main_dict, new_dict):
return _update_nested_dict(main_dict, new_dict)


# Load style library
# ==================
_base_library = _read_style_directory(_BASE_LIBRARY_PATH)
library = {}
available = []


def reload_library():
"""Reload the style library."""
library.clear()
library.update(_update_user_library(_base_library))
available[:] = sorted(library.keys())


reload_library()
20 changes: 20 additions & 0 deletions lib/matplotlib/style/__init__.pyi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from collections.abc import Generator
import contextlib

from matplotlib import RcParams
from matplotlib.typing import RcStyleType

USER_LIBRARY_PATHS: list[str] = ...

def use(style: RcStyleType) -> None: ...
@contextlib.contextmanager
def context(
style: RcStyleType, after_reset: bool = ...
) -> Generator[None, None, None]: ...

library: dict[str, RcParams]
available: list[str]

def reload_library() -> None: ...

__all__ = ['use', 'context', 'available', 'library', 'reload_library']
Loading

Back | FazBrowse Home | New Git URL