diff --git a/lib/python3.12/site-packages/matplotlib/__init__.py b/lib/python3.12/site-packages/matplotlib/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f964e0b34dea11f572136a3bb6e3d9968ebe754
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/__init__.py
@@ -0,0 +1,1576 @@
+"""
+An object-oriented plotting library.
+
+A procedural interface is provided by the companion pyplot module,
+which may be imported directly, e.g.::
+
+ import matplotlib.pyplot as plt
+
+or using ipython::
+
+ ipython
+
+at your terminal, followed by::
+
+ In [1]: %matplotlib
+ In [2]: import matplotlib.pyplot as plt
+
+at the ipython shell prompt.
+
+For the most part, direct use of the explicit object-oriented library is
+encouraged when programming; the implicit pyplot interface is primarily for
+working interactively. The exceptions to this suggestion are the pyplot
+functions `.pyplot.figure`, `.pyplot.subplot`, `.pyplot.subplots`, and
+`.pyplot.savefig`, which can greatly simplify scripting. See
+:ref:`api_interfaces` for an explanation of the tradeoffs between the implicit
+and explicit interfaces.
+
+Modules include:
+
+:mod:`matplotlib.axes`
+ The `~.axes.Axes` class. Most pyplot functions are wrappers for
+ `~.axes.Axes` methods. The axes module is the highest level of OO
+ access to the library.
+
+:mod:`matplotlib.figure`
+ The `.Figure` class.
+
+:mod:`matplotlib.artist`
+ The `.Artist` base class for all classes that draw things.
+
+:mod:`matplotlib.lines`
+ The `.Line2D` class for drawing lines and markers.
+
+:mod:`matplotlib.patches`
+ Classes for drawing polygons.
+
+:mod:`matplotlib.text`
+ The `.Text` and `.Annotation` classes.
+
+:mod:`matplotlib.image`
+ The `.AxesImage` and `.FigureImage` classes.
+
+:mod:`matplotlib.collections`
+ Classes for efficient drawing of groups of lines or polygons.
+
+:mod:`matplotlib.colors`
+ Color specifications and making colormaps.
+
+:mod:`matplotlib.cm`
+ Colormaps, and the `.ScalarMappable` mixin class for providing color
+ mapping functionality to other classes.
+
+:mod:`matplotlib.ticker`
+ Calculation of tick mark locations and formatting of tick labels.
+
+:mod:`matplotlib.backends`
+ A subpackage with modules for various GUI libraries and output formats.
+
+The base matplotlib namespace includes:
+
+`~matplotlib.rcParams`
+ Default configuration settings; their defaults may be overridden using
+ a :file:`matplotlibrc` file.
+
+`~matplotlib.use`
+ Setting the Matplotlib backend. This should be called before any
+ figure is created, because it is not possible to switch between
+ different GUI backends after that.
+
+The following environment variables can be used to customize the behavior:
+
+:envvar:`MPLBACKEND`
+ This optional variable can be set to choose the Matplotlib backend. See
+ :ref:`what-is-a-backend`.
+
+:envvar:`MPLCONFIGDIR`
+ This is the directory used to store user customizations to
+ Matplotlib, as well as some caches to improve performance. If
+ :envvar:`MPLCONFIGDIR` is not defined, :file:`{HOME}/.config/matplotlib`
+ and :file:`{HOME}/.cache/matplotlib` are used on Linux, and
+ :file:`{HOME}/.matplotlib` on other platforms, if they are
+ writable. Otherwise, the Python standard library's `tempfile.gettempdir`
+ is used to find a base directory in which the :file:`matplotlib`
+ subdirectory is created.
+
+Matplotlib was initially written by John D. Hunter (1968-2012) and is now
+developed and maintained by a host of others.
+
+Occasionally the internal documentation (python docstrings) will refer
+to MATLABĀ®, a registered trademark of The MathWorks, Inc.
+
+"""
+
+__all__ = [
+ "__bibtex__",
+ "__version__",
+ "__version_info__",
+ "set_loglevel",
+ "ExecutableNotFoundError",
+ "get_configdir",
+ "get_cachedir",
+ "get_data_path",
+ "matplotlib_fname",
+ "MatplotlibDeprecationWarning",
+ "RcParams",
+ "rc_params",
+ "rc_params_from_file",
+ "rcParamsDefault",
+ "rcParams",
+ "rcParamsOrig",
+ "defaultParams",
+ "rc",
+ "rcdefaults",
+ "rc_file_defaults",
+ "rc_file",
+ "rc_context",
+ "use",
+ "get_backend",
+ "interactive",
+ "is_interactive",
+ "colormaps",
+ "multivar_colormaps",
+ "bivar_colormaps",
+ "color_sequences",
+]
+
+
+import atexit
+from collections import namedtuple
+from collections.abc import MutableMapping
+import contextlib
+import functools
+import importlib
+import inspect
+from inspect import Parameter
+import locale
+import logging
+import os
+from pathlib import Path
+import pprint
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+
+from packaging.version import parse as parse_version
+
+# cbook must import matplotlib only within function
+# definitions, so it is safe to import from it here.
+from . import _api, _version, cbook, _docstring, rcsetup
+from matplotlib._api import MatplotlibDeprecationWarning
+from matplotlib.rcsetup import cycler # noqa: F401
+
+
+_log = logging.getLogger(__name__)
+
+__bibtex__ = r"""@Article{Hunter:2007,
+ Author = {Hunter, J. D.},
+ Title = {Matplotlib: A 2D graphics environment},
+ Journal = {Computing in Science \& Engineering},
+ Volume = {9},
+ Number = {3},
+ Pages = {90--95},
+ abstract = {Matplotlib is a 2D graphics package used for Python
+ for application development, interactive scripting, and
+ publication-quality image generation across user
+ interfaces and operating systems.},
+ publisher = {IEEE COMPUTER SOC},
+ year = 2007
+}"""
+
+# modelled after sys.version_info
+_VersionInfo = namedtuple('_VersionInfo',
+ 'major, minor, micro, releaselevel, serial')
+
+
+def _parse_to_version_info(version_str):
+ """
+ Parse a version string to a namedtuple analogous to sys.version_info.
+
+ See:
+ https://packaging.pypa.io/en/latest/version.html#packaging.version.parse
+ https://docs.python.org/3/library/sys.html#sys.version_info
+ """
+ v = parse_version(version_str)
+ if v.pre is None and v.post is None and v.dev is None:
+ return _VersionInfo(v.major, v.minor, v.micro, 'final', 0)
+ elif v.dev is not None:
+ return _VersionInfo(v.major, v.minor, v.micro, 'alpha', v.dev)
+ elif v.pre is not None:
+ releaselevel = {
+ 'a': 'alpha',
+ 'b': 'beta',
+ 'rc': 'candidate'}.get(v.pre[0], 'alpha')
+ return _VersionInfo(v.major, v.minor, v.micro, releaselevel, v.pre[1])
+ else:
+ # fallback for v.post: guess-next-dev scheme from setuptools_scm
+ return _VersionInfo(v.major, v.minor, v.micro + 1, 'alpha', v.post)
+
+
+def _get_version():
+ """Return the version string used for __version__."""
+ # Only shell out to a git subprocess if really needed, i.e. when we are in
+ # a matplotlib git repo but not in a shallow clone, such as those used by
+ # CI, as the latter would trigger a warning from setuptools_scm.
+ root = Path(__file__).resolve().parents[2]
+ if ((root / ".matplotlib-repo").exists()
+ and (root / ".git").exists()
+ and not (root / ".git/shallow").exists()):
+ try:
+ import setuptools_scm
+ except ImportError:
+ pass
+ else:
+ return setuptools_scm.get_version(
+ root=root,
+ dist_name="matplotlib",
+ version_scheme="release-branch-semver",
+ local_scheme="node-and-date",
+ fallback_version=_version.version,
+ )
+ # Get the version from the _version.py file if not in repo or setuptools_scm is
+ # unavailable.
+ return _version.version
+
+
+@_api.caching_module_getattr
+class __getattr__:
+ __version__ = property(lambda self: _get_version())
+ __version_info__ = property(
+ lambda self: _parse_to_version_info(self.__version__))
+
+
+def _check_versions():
+
+ # Quickfix to ensure Microsoft Visual C++ redistributable
+ # DLLs are loaded before importing kiwisolver
+ from . import ft2font # noqa: F401
+
+ for modname, minver in [
+ ("cycler", "0.10"),
+ ("dateutil", "2.7"),
+ ("kiwisolver", "1.3.1"),
+ ("numpy", "1.23"),
+ ("pyparsing", "2.3.1"),
+ ]:
+ module = importlib.import_module(modname)
+ if parse_version(module.__version__) < parse_version(minver):
+ raise ImportError(f"Matplotlib requires {modname}>={minver}; "
+ f"you have {module.__version__}")
+
+
+_check_versions()
+
+
+# The decorator ensures this always returns the same handler (and it is only
+# attached once).
+@functools.cache
+def _ensure_handler():
+ """
+ The first time this function is called, attach a `StreamHandler` using the
+ same format as `logging.basicConfig` to the Matplotlib root logger.
+
+ Return this handler every time this function is called.
+ """
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
+ _log.addHandler(handler)
+ return handler
+
+
+def set_loglevel(level):
+ """
+ Configure Matplotlib's logging levels.
+
+ Matplotlib uses the standard library `logging` framework under the root
+ logger 'matplotlib'. This is a helper function to:
+
+ - set Matplotlib's root logger level
+ - set the root logger handler's level, creating the handler
+ if it does not exist yet
+
+ Typically, one should call ``set_loglevel("info")`` or
+ ``set_loglevel("debug")`` to get additional debugging information.
+
+ Users or applications that are installing their own logging handlers
+ may want to directly manipulate ``logging.getLogger('matplotlib')`` rather
+ than use this function.
+
+ Parameters
+ ----------
+ level : {"notset", "debug", "info", "warning", "error", "critical"}
+ The log level of the handler.
+
+ Notes
+ -----
+ The first time this function is called, an additional handler is attached
+ to Matplotlib's root handler; this handler is reused every time and this
+ function simply manipulates the logger and handler's level.
+
+ """
+ _log.setLevel(level.upper())
+ _ensure_handler().setLevel(level.upper())
+
+
+def _logged_cached(fmt, func=None):
+ """
+ Decorator that logs a function's return value, and memoizes that value.
+
+ After ::
+
+ @_logged_cached(fmt)
+ def func(): ...
+
+ the first call to *func* will log its return value at the DEBUG level using
+ %-format string *fmt*, and memoize it; later calls to *func* will directly
+ return that value.
+ """
+ if func is None: # Return the actual decorator.
+ return functools.partial(_logged_cached, fmt)
+
+ called = False
+ ret = None
+
+ @functools.wraps(func)
+ def wrapper(**kwargs):
+ nonlocal called, ret
+ if not called:
+ ret = func(**kwargs)
+ called = True
+ _log.debug(fmt, ret)
+ return ret
+
+ return wrapper
+
+
+_ExecInfo = namedtuple("_ExecInfo", "executable raw_version version")
+
+
+class ExecutableNotFoundError(FileNotFoundError):
+ """
+ Error raised when an executable that Matplotlib optionally
+ depends on can't be found.
+ """
+ pass
+
+
+@functools.cache
+def _get_executable_info(name):
+ """
+ Get the version of some executable that Matplotlib optionally depends on.
+
+ .. warning::
+ The list of executables that this function supports is set according to
+ Matplotlib's internal needs, and may change without notice.
+
+ Parameters
+ ----------
+ name : str
+ The executable to query. The following values are currently supported:
+ "dvipng", "gs", "inkscape", "magick", "pdftocairo", "pdftops". This
+ list is subject to change without notice.
+
+ Returns
+ -------
+ tuple
+ A namedtuple with fields ``executable`` (`str`) and ``version``
+ (`packaging.Version`, or ``None`` if the version cannot be determined).
+
+ Raises
+ ------
+ ExecutableNotFoundError
+ If the executable is not found or older than the oldest version
+ supported by Matplotlib. For debugging purposes, it is also
+ possible to "hide" an executable from Matplotlib by adding it to the
+ :envvar:`_MPLHIDEEXECUTABLES` environment variable (a comma-separated
+ list), which must be set prior to any calls to this function.
+ ValueError
+ If the executable is not one that we know how to query.
+ """
+
+ def impl(args, regex, min_ver=None, ignore_exit_code=False):
+ # Execute the subprocess specified by args; capture stdout and stderr.
+ # Search for a regex match in the output; if the match succeeds, the
+ # first group of the match is the version.
+ # Return an _ExecInfo if the executable exists, and has a version of
+ # at least min_ver (if set); else, raise ExecutableNotFoundError.
+ try:
+ output = subprocess.check_output(
+ args, stderr=subprocess.STDOUT,
+ text=True, errors="replace")
+ except subprocess.CalledProcessError as _cpe:
+ if ignore_exit_code:
+ output = _cpe.output
+ else:
+ raise ExecutableNotFoundError(str(_cpe)) from _cpe
+ except OSError as _ose:
+ raise ExecutableNotFoundError(str(_ose)) from _ose
+ match = re.search(regex, output)
+ if match:
+ raw_version = match.group(1)
+ version = parse_version(raw_version)
+ if min_ver is not None and version < parse_version(min_ver):
+ raise ExecutableNotFoundError(
+ f"You have {args[0]} version {version} but the minimum "
+ f"version supported by Matplotlib is {min_ver}")
+ return _ExecInfo(args[0], raw_version, version)
+ else:
+ raise ExecutableNotFoundError(
+ f"Failed to determine the version of {args[0]} from "
+ f"{' '.join(args)}, which output {output}")
+
+ if name in os.environ.get("_MPLHIDEEXECUTABLES", "").split(","):
+ raise ExecutableNotFoundError(f"{name} was hidden")
+
+ if name == "dvipng":
+ return impl(["dvipng", "-version"], "(?m)^dvipng(?: .*)? (.+)", "1.6")
+ elif name == "gs":
+ execs = (["gswin32c", "gswin64c", "mgs", "gs"] # "mgs" for miktex.
+ if sys.platform == "win32" else
+ ["gs"])
+ for e in execs:
+ try:
+ return impl([e, "--version"], "(.*)", "9")
+ except ExecutableNotFoundError:
+ pass
+ message = "Failed to find a Ghostscript installation"
+ raise ExecutableNotFoundError(message)
+ elif name == "inkscape":
+ try:
+ # Try headless option first (needed for Inkscape version < 1.0):
+ return impl(["inkscape", "--without-gui", "-V"],
+ "Inkscape ([^ ]*)")
+ except ExecutableNotFoundError:
+ pass # Suppress exception chaining.
+ # If --without-gui is not accepted, we may be using Inkscape >= 1.0 so
+ # try without it:
+ return impl(["inkscape", "-V"], "Inkscape ([^ ]*)")
+ elif name == "magick":
+ if sys.platform == "win32":
+ # Check the registry to avoid confusing ImageMagick's convert with
+ # Windows's builtin convert.exe.
+ import winreg
+ binpath = ""
+ for flag in [0, winreg.KEY_WOW64_32KEY, winreg.KEY_WOW64_64KEY]:
+ try:
+ with winreg.OpenKeyEx(
+ winreg.HKEY_LOCAL_MACHINE,
+ r"Software\Imagemagick\Current",
+ 0, winreg.KEY_QUERY_VALUE | flag) as hkey:
+ binpath = winreg.QueryValueEx(hkey, "BinPath")[0]
+ except OSError:
+ pass
+ path = None
+ if binpath:
+ for name in ["convert.exe", "magick.exe"]:
+ candidate = Path(binpath, name)
+ if candidate.exists():
+ path = str(candidate)
+ break
+ if path is None:
+ raise ExecutableNotFoundError(
+ "Failed to find an ImageMagick installation")
+ else:
+ path = "convert"
+ info = impl([path, "--version"], r"^Version: ImageMagick (\S*)")
+ if info.raw_version == "7.0.10-34":
+ # https://github.com/ImageMagick/ImageMagick/issues/2720
+ raise ExecutableNotFoundError(
+ f"You have ImageMagick {info.version}, which is unsupported")
+ return info
+ elif name == "pdftocairo":
+ return impl(["pdftocairo", "-v"], "pdftocairo version (.*)")
+ elif name == "pdftops":
+ info = impl(["pdftops", "-v"], "^pdftops version (.*)",
+ ignore_exit_code=True)
+ if info and not (
+ 3 <= info.version.major or
+ # poppler version numbers.
+ parse_version("0.9") <= info.version < parse_version("1.0")):
+ raise ExecutableNotFoundError(
+ f"You have pdftops version {info.version} but the minimum "
+ f"version supported by Matplotlib is 3.0")
+ return info
+ else:
+ raise ValueError(f"Unknown executable: {name!r}")
+
+
+def _get_xdg_config_dir():
+ """
+ Return the XDG configuration directory, according to the XDG base
+ directory spec:
+
+ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ """
+ return os.environ.get('XDG_CONFIG_HOME') or str(Path.home() / ".config")
+
+
+def _get_xdg_cache_dir():
+ """
+ Return the XDG cache directory, according to the XDG base directory spec:
+
+ https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ """
+ return os.environ.get('XDG_CACHE_HOME') or str(Path.home() / ".cache")
+
+
+def _get_config_or_cache_dir(xdg_base_getter):
+ configdir = os.environ.get('MPLCONFIGDIR')
+ if configdir:
+ configdir = Path(configdir)
+ elif sys.platform.startswith(('linux', 'freebsd')):
+ # Only call _xdg_base_getter here so that MPLCONFIGDIR is tried first,
+ # as _xdg_base_getter can throw.
+ configdir = Path(xdg_base_getter(), "matplotlib")
+ else:
+ configdir = Path.home() / ".matplotlib"
+ # Resolve the path to handle potential issues with inaccessible symlinks.
+ configdir = configdir.resolve()
+ try:
+ configdir.mkdir(parents=True, exist_ok=True)
+ except OSError as exc:
+ _log.warning("mkdir -p failed for path %s: %s", configdir, exc)
+ else:
+ if os.access(str(configdir), os.W_OK) and configdir.is_dir():
+ return str(configdir)
+ _log.warning("%s is not a writable directory", configdir)
+ # If the config or cache directory cannot be created or is not a writable
+ # directory, create a temporary one.
+ try:
+ tmpdir = tempfile.mkdtemp(prefix="matplotlib-")
+ except OSError as exc:
+ raise OSError(
+ f"Matplotlib requires access to a writable cache directory, but there "
+ f"was an issue with the default path ({configdir}), and a temporary "
+ f"directory could not be created; set the MPLCONFIGDIR environment "
+ f"variable to a writable directory") from exc
+ os.environ["MPLCONFIGDIR"] = tmpdir
+ atexit.register(shutil.rmtree, tmpdir)
+ _log.warning(
+ "Matplotlib created a temporary cache directory at %s because there was "
+ "an issue with the default path (%s); it is highly recommended to set the "
+ "MPLCONFIGDIR environment variable to a writable directory, in particular to "
+ "speed up the import of Matplotlib and to better support multiprocessing.",
+ tmpdir, configdir)
+ return tmpdir
+
+
+@_logged_cached('CONFIGDIR=%s')
+def get_configdir():
+ """
+ Return the string path of the configuration directory.
+
+ The directory is chosen as follows:
+
+ 1. If the MPLCONFIGDIR environment variable is supplied, choose that.
+ 2. On Linux, follow the XDG specification and look first in
+ ``$XDG_CONFIG_HOME``, if defined, or ``$HOME/.config``. On other
+ platforms, choose ``$HOME/.matplotlib``.
+ 3. If the chosen directory exists and is writable, use that as the
+ configuration directory.
+ 4. Else, create a temporary directory, and use it as the configuration
+ directory.
+ """
+ return _get_config_or_cache_dir(_get_xdg_config_dir)
+
+
+@_logged_cached('CACHEDIR=%s')
+def get_cachedir():
+ """
+ Return the string path of the cache directory.
+
+ The procedure used to find the directory is the same as for
+ `get_configdir`, except using ``$XDG_CACHE_HOME``/``$HOME/.cache`` instead.
+ """
+ return _get_config_or_cache_dir(_get_xdg_cache_dir)
+
+
+@_logged_cached('matplotlib data path: %s')
+def get_data_path():
+ """Return the path to Matplotlib data."""
+ return str(Path(__file__).with_name("mpl-data"))
+
+
+def matplotlib_fname():
+ """
+ Get the location of the config file.
+
+ The file location is determined in the following order
+
+ - ``$PWD/matplotlibrc``
+ - ``$MATPLOTLIBRC`` if it is not a directory
+ - ``$MATPLOTLIBRC/matplotlibrc``
+ - ``$MPLCONFIGDIR/matplotlibrc``
+ - On Linux,
+ - ``$XDG_CONFIG_HOME/matplotlib/matplotlibrc`` (if ``$XDG_CONFIG_HOME``
+ is defined)
+ - or ``$HOME/.config/matplotlib/matplotlibrc`` (if ``$XDG_CONFIG_HOME``
+ is not defined)
+ - On other platforms,
+ - ``$HOME/.matplotlib/matplotlibrc`` if ``$HOME`` is defined
+ - Lastly, it looks in ``$MATPLOTLIBDATA/matplotlibrc``, which should always
+ exist.
+ """
+
+ def gen_candidates():
+ # rely on down-stream code to make absolute. This protects us
+ # from having to directly get the current working directory
+ # which can fail if the user has ended up with a cwd that is
+ # non-existent.
+ yield 'matplotlibrc'
+ try:
+ matplotlibrc = os.environ['MATPLOTLIBRC']
+ except KeyError:
+ pass
+ else:
+ yield matplotlibrc
+ yield os.path.join(matplotlibrc, 'matplotlibrc')
+ yield os.path.join(get_configdir(), 'matplotlibrc')
+ yield os.path.join(get_data_path(), 'matplotlibrc')
+
+ for fname in gen_candidates():
+ if os.path.exists(fname) and not os.path.isdir(fname):
+ return fname
+
+ raise RuntimeError("Could not find matplotlibrc file; your Matplotlib "
+ "install is broken")
+
+
+# rcParams deprecated and automatically mapped to another key.
+# Values are tuples of (version, new_name, f_old2new, f_new2old).
+_deprecated_map = {}
+# rcParams deprecated; some can manually be mapped to another key.
+# Values are tuples of (version, new_name_or_None).
+_deprecated_ignore_map = {}
+# rcParams deprecated; can use None to suppress warnings; remain actually
+# listed in the rcParams.
+# Values are tuples of (version,)
+_deprecated_remain_as_none = {}
+
+
+@_docstring.Substitution(
+ "\n".join(map("- {}".format, sorted(rcsetup._validators, key=str.lower)))
+)
+class RcParams(MutableMapping, dict):
+ """
+ A dict-like key-value store for config parameters, including validation.
+
+ Validating functions are defined and associated with rc parameters in
+ :mod:`matplotlib.rcsetup`.
+
+ The list of rcParams is:
+
+ %s
+
+ See Also
+ --------
+ :ref:`customizing-with-matplotlibrc-files`
+ """
+
+ validate = rcsetup._validators
+
+ # validate values on the way in
+ def __init__(self, *args, **kwargs):
+ self.update(*args, **kwargs)
+
+ def _set(self, key, val):
+ """
+ Directly write data bypassing deprecation and validation logic.
+
+ Notes
+ -----
+ As end user or downstream library you almost always should use
+ ``rcParams[key] = val`` and not ``_set()``.
+
+ There are only very few special cases that need direct data access.
+ These cases previously used ``dict.__setitem__(rcParams, key, val)``,
+ which is now deprecated and replaced by ``rcParams._set(key, val)``.
+
+ Even though private, we guarantee API stability for ``rcParams._set``,
+ i.e. it is subject to Matplotlib's API and deprecation policy.
+
+ :meta public:
+ """
+ dict.__setitem__(self, key, val)
+
+ def _get(self, key):
+ """
+ Directly read data bypassing deprecation, backend and validation
+ logic.
+
+ Notes
+ -----
+ As end user or downstream library you almost always should use
+ ``val = rcParams[key]`` and not ``_get()``.
+
+ There are only very few special cases that need direct data access.
+ These cases previously used ``dict.__getitem__(rcParams, key, val)``,
+ which is now deprecated and replaced by ``rcParams._get(key)``.
+
+ Even though private, we guarantee API stability for ``rcParams._get``,
+ i.e. it is subject to Matplotlib's API and deprecation policy.
+
+ :meta public:
+ """
+ return dict.__getitem__(self, key)
+
+ def _update_raw(self, other_params):
+ """
+ Directly update the data from *other_params*, bypassing deprecation,
+ backend and validation logic on both sides.
+
+ This ``rcParams._update_raw(params)`` replaces the previous pattern
+ ``dict.update(rcParams, params)``.
+
+ Parameters
+ ----------
+ other_params : dict or `.RcParams`
+ The input mapping from which to update.
+ """
+ if isinstance(other_params, RcParams):
+ other_params = dict.items(other_params)
+ dict.update(self, other_params)
+
+ def _ensure_has_backend(self):
+ """
+ Ensure that a "backend" entry exists.
+
+ Normally, the default matplotlibrc file contains *no* entry for "backend" (the
+ corresponding line starts with ##, not #; we fill in _auto_backend_sentinel
+ in that case. However, packagers can set a different default backend
+ (resulting in a normal `#backend: foo` line) in which case we should *not*
+ fill in _auto_backend_sentinel.
+ """
+ dict.setdefault(self, "backend", rcsetup._auto_backend_sentinel)
+
+ def __setitem__(self, key, val):
+ try:
+ if key in _deprecated_map:
+ version, alt_key, alt_val, inverse_alt = _deprecated_map[key]
+ _api.warn_deprecated(
+ version, name=key, obj_type="rcparam", alternative=alt_key)
+ key = alt_key
+ val = alt_val(val)
+ elif key in _deprecated_remain_as_none and val is not None:
+ version, = _deprecated_remain_as_none[key]
+ _api.warn_deprecated(version, name=key, obj_type="rcparam")
+ elif key in _deprecated_ignore_map:
+ version, alt_key = _deprecated_ignore_map[key]
+ _api.warn_deprecated(
+ version, name=key, obj_type="rcparam", alternative=alt_key)
+ return
+ elif key == 'backend':
+ if val is rcsetup._auto_backend_sentinel:
+ if 'backend' in self:
+ return
+ try:
+ cval = self.validate[key](val)
+ except ValueError as ve:
+ raise ValueError(f"Key {key}: {ve}") from None
+ self._set(key, cval)
+ except KeyError as err:
+ raise KeyError(
+ f"{key} is not a valid rc parameter (see rcParams.keys() for "
+ f"a list of valid parameters)") from err
+
+ def __getitem__(self, key):
+ if key in _deprecated_map:
+ version, alt_key, alt_val, inverse_alt = _deprecated_map[key]
+ _api.warn_deprecated(
+ version, name=key, obj_type="rcparam", alternative=alt_key)
+ return inverse_alt(self._get(alt_key))
+
+ elif key in _deprecated_ignore_map:
+ version, alt_key = _deprecated_ignore_map[key]
+ _api.warn_deprecated(
+ version, name=key, obj_type="rcparam", alternative=alt_key)
+ return self._get(alt_key) if alt_key else None
+
+ # In theory, this should only ever be used after the global rcParams
+ # has been set up, but better be safe e.g. in presence of breakpoints.
+ elif key == "backend" and self is globals().get("rcParams"):
+ val = self._get(key)
+ if val is rcsetup._auto_backend_sentinel:
+ from matplotlib import pyplot as plt
+ plt.switch_backend(rcsetup._auto_backend_sentinel)
+
+ return self._get(key)
+
+ def _get_backend_or_none(self):
+ """Get the requested backend, if any, without triggering resolution."""
+ backend = self._get("backend")
+ return None if backend is rcsetup._auto_backend_sentinel else backend
+
+ def __repr__(self):
+ class_name = self.__class__.__name__
+ indent = len(class_name) + 1
+ with _api.suppress_matplotlib_deprecation_warning():
+ repr_split = pprint.pformat(dict(self), indent=1,
+ width=80 - indent).split('\n')
+ repr_indented = ('\n' + ' ' * indent).join(repr_split)
+ return f'{class_name}({repr_indented})'
+
+ def __str__(self):
+ return '\n'.join(map('{0[0]}: {0[1]}'.format, sorted(self.items())))
+
+ def __iter__(self):
+ """Yield sorted list of keys."""
+ with _api.suppress_matplotlib_deprecation_warning():
+ yield from sorted(dict.__iter__(self))
+
+ def __len__(self):
+ return dict.__len__(self)
+
+ def find_all(self, pattern):
+ """
+ Return the subset of this RcParams dictionary whose keys match,
+ using :func:`re.search`, the given ``pattern``.
+
+ .. note::
+
+ Changes to the returned dictionary are *not* propagated to
+ the parent RcParams dictionary.
+
+ """
+ pattern_re = re.compile(pattern)
+ return RcParams((key, value)
+ for key, value in self.items()
+ if pattern_re.search(key))
+
+ def copy(self):
+ """Copy this RcParams instance."""
+ rccopy = RcParams()
+ for k in self: # Skip deprecations and revalidation.
+ rccopy._set(k, self._get(k))
+ return rccopy
+
+
+def rc_params(fail_on_error=False):
+ """Construct a `RcParams` instance from the default Matplotlib rc file."""
+ return rc_params_from_file(matplotlib_fname(), fail_on_error)
+
+
+@functools.cache
+def _get_ssl_context():
+ try:
+ import certifi
+ except ImportError:
+ _log.debug("Could not import certifi.")
+ return None
+ import ssl
+ return ssl.create_default_context(cafile=certifi.where())
+
+
+@contextlib.contextmanager
+def _open_file_or_url(fname):
+ if (isinstance(fname, str)
+ and fname.startswith(('http://', 'https://', 'ftp://', 'file:'))):
+ import urllib.request
+ ssl_ctx = _get_ssl_context()
+ if ssl_ctx is None:
+ _log.debug(
+ "Could not get certifi ssl context, https may not work."
+ )
+ with urllib.request.urlopen(fname, context=ssl_ctx) as f:
+ yield (line.decode('utf-8') for line in f)
+ else:
+ fname = os.path.expanduser(fname)
+ with open(fname, encoding='utf-8') as f:
+ yield f
+
+
+def _rc_params_in_file(fname, transform=lambda x: x, fail_on_error=False):
+ """
+ Construct a `RcParams` instance from file *fname*.
+
+ Unlike `rc_params_from_file`, the configuration class only contains the
+ parameters specified in the file (i.e. default values are not filled in).
+
+ Parameters
+ ----------
+ fname : path-like
+ The loaded file.
+ transform : callable, default: the identity function
+ A function called on each individual line of the file to transform it,
+ before further parsing.
+ fail_on_error : bool, default: False
+ Whether invalid entries should result in an exception or a warning.
+ """
+ import matplotlib as mpl
+ rc_temp = {}
+ with _open_file_or_url(fname) as fd:
+ try:
+ for line_no, line in enumerate(fd, 1):
+ line = transform(line)
+ strippedline = cbook._strip_comment(line)
+ if not strippedline:
+ continue
+ tup = strippedline.split(':', 1)
+ if len(tup) != 2:
+ _log.warning('Missing colon in file %r, line %d (%r)',
+ fname, line_no, line.rstrip('\n'))
+ continue
+ key, val = tup
+ key = key.strip()
+ val = val.strip()
+ if val.startswith('"') and val.endswith('"'):
+ val = val[1:-1] # strip double quotes
+ if key in rc_temp:
+ _log.warning('Duplicate key in file %r, line %d (%r)',
+ fname, line_no, line.rstrip('\n'))
+ rc_temp[key] = (val, line, line_no)
+ except UnicodeDecodeError:
+ _log.warning('Cannot decode configuration file %r as utf-8.',
+ fname)
+ raise
+
+ config = RcParams()
+
+ for key, (val, line, line_no) in rc_temp.items():
+ if key in rcsetup._validators:
+ if fail_on_error:
+ config[key] = val # try to convert to proper type or raise
+ else:
+ try:
+ config[key] = val # try to convert to proper type or skip
+ except Exception as msg:
+ _log.warning('Bad value in file %r, line %d (%r): %s',
+ fname, line_no, line.rstrip('\n'), msg)
+ elif key in _deprecated_ignore_map:
+ version, alt_key = _deprecated_ignore_map[key]
+ _api.warn_deprecated(
+ version, name=key, alternative=alt_key, obj_type='rcparam',
+ addendum="Please update your matplotlibrc.")
+ else:
+ # __version__ must be looked up as an attribute to trigger the
+ # module-level __getattr__.
+ version = ('main' if '.post' in mpl.__version__
+ else f'v{mpl.__version__}')
+ _log.warning("""
+Bad key %(key)s in file %(fname)s, line %(line_no)s (%(line)r)
+You probably need to get an updated matplotlibrc file from
+https://github.com/matplotlib/matplotlib/blob/%(version)s/lib/matplotlib/mpl-data/matplotlibrc
+or from the matplotlib source distribution""",
+ dict(key=key, fname=fname, line_no=line_no,
+ line=line.rstrip('\n'), version=version))
+ return config
+
+
+def rc_params_from_file(fname, fail_on_error=False, use_default_template=True):
+ """
+ Construct a `RcParams` from file *fname*.
+
+ Parameters
+ ----------
+ fname : str or path-like
+ A file with Matplotlib rc settings.
+ fail_on_error : bool
+ If True, raise an error when the parser fails to convert a parameter.
+ use_default_template : bool
+ If True, initialize with default parameters before updating with those
+ in the given file. If False, the configuration class only contains the
+ parameters specified in the file. (Useful for updating dicts.)
+ """
+ config_from_file = _rc_params_in_file(fname, fail_on_error=fail_on_error)
+
+ if not use_default_template:
+ return config_from_file
+
+ with _api.suppress_matplotlib_deprecation_warning():
+ config = RcParams({**rcParamsDefault, **config_from_file})
+
+ if "".join(config['text.latex.preamble']):
+ _log.info("""
+*****************************************************************
+You have the following UNSUPPORTED LaTeX preamble customizations:
+%s
+Please do not ask for support with these customizations active.
+*****************************************************************
+""", '\n'.join(config['text.latex.preamble']))
+ _log.debug('loaded rc file %s', fname)
+
+ return config
+
+
+rcParamsDefault = _rc_params_in_file(
+ cbook._get_data_path("matplotlibrc"),
+ # Strip leading comment.
+ transform=lambda line: line[1:] if line.startswith("#") else line,
+ fail_on_error=True)
+rcParamsDefault._update_raw(rcsetup._hardcoded_defaults)
+rcParamsDefault._ensure_has_backend()
+
+rcParams = RcParams() # The global instance.
+rcParams._update_raw(rcParamsDefault)
+rcParams._update_raw(_rc_params_in_file(matplotlib_fname()))
+rcParamsOrig = rcParams.copy()
+with _api.suppress_matplotlib_deprecation_warning():
+ # This also checks that all rcParams are indeed listed in the template.
+ # Assigning to rcsetup.defaultParams is left only for backcompat.
+ defaultParams = rcsetup.defaultParams = {
+ # We want to resolve deprecated rcParams, but not backend...
+ key: [(rcsetup._auto_backend_sentinel if key == "backend" else
+ rcParamsDefault[key]),
+ validator]
+ for key, validator in rcsetup._validators.items()}
+if rcParams['axes.formatter.use_locale']:
+ locale.setlocale(locale.LC_ALL, '')
+
+
+def rc(group, **kwargs):
+ """
+ Set the current `.rcParams`. *group* is the grouping for the rc, e.g.,
+ for ``lines.linewidth`` the group is ``lines``, for
+ ``axes.facecolor``, the group is ``axes``, and so on. Group may
+ also be a list or tuple of group names, e.g., (*xtick*, *ytick*).
+ *kwargs* is a dictionary attribute name/value pairs, e.g.,::
+
+ rc('lines', linewidth=2, color='r')
+
+ sets the current `.rcParams` and is equivalent to::
+
+ rcParams['lines.linewidth'] = 2
+ rcParams['lines.color'] = 'r'
+
+ The following aliases are available to save typing for interactive users:
+
+ ===== =================
+ Alias Property
+ ===== =================
+ 'lw' 'linewidth'
+ 'ls' 'linestyle'
+ 'c' 'color'
+ 'fc' 'facecolor'
+ 'ec' 'edgecolor'
+ 'mew' 'markeredgewidth'
+ 'aa' 'antialiased'
+ ===== =================
+
+ Thus you could abbreviate the above call as::
+
+ rc('lines', lw=2, c='r')
+
+ Note you can use python's kwargs dictionary facility to store
+ dictionaries of default parameters. e.g., you can customize the
+ font rc as follows::
+
+ font = {'family' : 'monospace',
+ 'weight' : 'bold',
+ 'size' : 'larger'}
+ rc('font', **font) # pass in the font dict as kwargs
+
+ This enables you to easily switch between several configurations. Use
+ ``matplotlib.style.use('default')`` or :func:`~matplotlib.rcdefaults` to
+ restore the default `.rcParams` after changes.
+
+ Notes
+ -----
+ Similar functionality is available by using the normal dict interface, i.e.
+ ``rcParams.update({"lines.linewidth": 2, ...})`` (but ``rcParams.update``
+ does not support abbreviations or grouping).
+ """
+
+ aliases = {
+ 'lw': 'linewidth',
+ 'ls': 'linestyle',
+ 'c': 'color',
+ 'fc': 'facecolor',
+ 'ec': 'edgecolor',
+ 'mew': 'markeredgewidth',
+ 'aa': 'antialiased',
+ }
+
+ if isinstance(group, str):
+ group = (group,)
+ for g in group:
+ for k, v in kwargs.items():
+ name = aliases.get(k) or k
+ key = f'{g}.{name}'
+ try:
+ rcParams[key] = v
+ except KeyError as err:
+ raise KeyError(('Unrecognized key "%s" for group "%s" and '
+ 'name "%s"') % (key, g, name)) from err
+
+
+def rcdefaults():
+ """
+ Restore the `.rcParams` from Matplotlib's internal default style.
+
+ Style-blacklisted `.rcParams` (defined in
+ ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated.
+
+ See Also
+ --------
+ matplotlib.rc_file_defaults
+ Restore the `.rcParams` from the rc file originally loaded by
+ Matplotlib.
+ matplotlib.style.use
+ Use a specific style file. Call ``style.use('default')`` to restore
+ the default style.
+ """
+ # Deprecation warnings were already handled when creating rcParamsDefault,
+ # no need to reemit them here.
+ with _api.suppress_matplotlib_deprecation_warning():
+ from .style.core import STYLE_BLACKLIST
+ rcParams.clear()
+ rcParams.update({k: v for k, v in rcParamsDefault.items()
+ if k not in STYLE_BLACKLIST})
+
+
+def rc_file_defaults():
+ """
+ Restore the `.rcParams` from the original rc file loaded by Matplotlib.
+
+ Style-blacklisted `.rcParams` (defined in
+ ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated.
+ """
+ # Deprecation warnings were already handled when creating rcParamsOrig, no
+ # need to reemit them here.
+ with _api.suppress_matplotlib_deprecation_warning():
+ from .style.core import STYLE_BLACKLIST
+ rcParams.update({k: rcParamsOrig[k] for k in rcParamsOrig
+ if k not in STYLE_BLACKLIST})
+
+
+def rc_file(fname, *, use_default_template=True):
+ """
+ Update `.rcParams` from file.
+
+ Style-blacklisted `.rcParams` (defined in
+ ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated.
+
+ Parameters
+ ----------
+ fname : str or path-like
+ A file with Matplotlib rc settings.
+
+ use_default_template : bool
+ If True, initialize with default parameters before updating with those
+ in the given file. If False, the current configuration persists
+ and only the parameters specified in the file are updated.
+ """
+ # Deprecation warnings were already handled in rc_params_from_file, no need
+ # to reemit them here.
+ with _api.suppress_matplotlib_deprecation_warning():
+ from .style.core import STYLE_BLACKLIST
+ rc_from_file = rc_params_from_file(
+ fname, use_default_template=use_default_template)
+ rcParams.update({k: rc_from_file[k] for k in rc_from_file
+ if k not in STYLE_BLACKLIST})
+
+
+@contextlib.contextmanager
+def rc_context(rc=None, fname=None):
+ """
+ Return a context manager for temporarily changing rcParams.
+
+ The :rc:`backend` will not be reset by the context manager.
+
+ rcParams changed both through the context manager invocation and
+ in the body of the context will be reset on context exit.
+
+ Parameters
+ ----------
+ rc : dict
+ The rcParams to temporarily set.
+ fname : str or path-like
+ A file with Matplotlib rc settings. If both *fname* and *rc* are given,
+ settings from *rc* take precedence.
+
+ See Also
+ --------
+ :ref:`customizing-with-matplotlibrc-files`
+
+ Examples
+ --------
+ Passing explicit values via a dict::
+
+ with mpl.rc_context({'interactive': False}):
+ fig, ax = plt.subplots()
+ ax.plot(range(3), range(3))
+ fig.savefig('example.png')
+ plt.close(fig)
+
+ Loading settings from a file::
+
+ with mpl.rc_context(fname='print.rc'):
+ plt.plot(x, y) # uses 'print.rc'
+
+ Setting in the context body::
+
+ with mpl.rc_context():
+ # will be reset
+ mpl.rcParams['lines.linewidth'] = 5
+ plt.plot(x, y)
+
+ """
+ orig = dict(rcParams.copy())
+ del orig['backend']
+ try:
+ if fname:
+ rc_file(fname)
+ if rc:
+ rcParams.update(rc)
+ yield
+ finally:
+ rcParams._update_raw(orig) # Revert to the original rcs.
+
+
+def use(backend, *, force=True):
+ """
+ Select the backend used for rendering and GUI integration.
+
+ If pyplot is already imported, `~matplotlib.pyplot.switch_backend` is used
+ and if the new backend is different than the current backend, all Figures
+ will be closed.
+
+ Parameters
+ ----------
+ backend : str
+ The backend to switch to. This can either be one of the standard
+ backend names, which are case-insensitive:
+
+ - interactive backends:
+ GTK3Agg, GTK3Cairo, GTK4Agg, GTK4Cairo, MacOSX, nbAgg, notebook, QtAgg,
+ QtCairo, TkAgg, TkCairo, WebAgg, WX, WXAgg, WXCairo, Qt5Agg, Qt5Cairo
+
+ - non-interactive backends:
+ agg, cairo, pdf, pgf, ps, svg, template
+
+ or a string of the form: ``module://my.module.name``.
+
+ notebook is a synonym for nbAgg.
+
+ Switching to an interactive backend is not possible if an unrelated
+ event loop has already been started (e.g., switching to GTK3Agg if a
+ TkAgg window has already been opened). Switching to a non-interactive
+ backend is always possible.
+
+ force : bool, default: True
+ If True (the default), raise an `ImportError` if the backend cannot be
+ set up (either because it fails to import, or because an incompatible
+ GUI interactive framework is already running); if False, silently
+ ignore the failure.
+
+ See Also
+ --------
+ :ref:`backends`
+ matplotlib.get_backend
+ matplotlib.pyplot.switch_backend
+
+ """
+ name = rcsetup.validate_backend(backend)
+ # don't (prematurely) resolve the "auto" backend setting
+ if rcParams._get_backend_or_none() == name:
+ # Nothing to do if the requested backend is already set
+ pass
+ else:
+ # if pyplot is not already imported, do not import it. Doing
+ # so may trigger a `plt.switch_backend` to the _default_ backend
+ # before we get a chance to change to the one the user just requested
+ plt = sys.modules.get('matplotlib.pyplot')
+ # if pyplot is imported, then try to change backends
+ if plt is not None:
+ try:
+ # we need this import check here to re-raise if the
+ # user does not have the libraries to support their
+ # chosen backend installed.
+ plt.switch_backend(name)
+ except ImportError:
+ if force:
+ raise
+ # if we have not imported pyplot, then we can set the rcParam
+ # value which will be respected when the user finally imports
+ # pyplot
+ else:
+ rcParams['backend'] = backend
+ # if the user has asked for a given backend, do not helpfully
+ # fallback
+ rcParams['backend_fallback'] = False
+
+
+if os.environ.get('MPLBACKEND'):
+ rcParams['backend'] = os.environ.get('MPLBACKEND')
+
+
+def get_backend(*, auto_select=True):
+ """
+ Return the name of the current backend.
+
+ Parameters
+ ----------
+ auto_select : bool, default: True
+ Whether to trigger backend resolution if no backend has been
+ selected so far. If True, this ensures that a valid backend
+ is returned. If False, this returns None if no backend has been
+ selected so far.
+
+ .. versionadded:: 3.10
+
+ .. admonition:: Provisional
+
+ The *auto_select* flag is provisional. It may be changed or removed
+ without prior warning.
+
+ See Also
+ --------
+ matplotlib.use
+ """
+ if auto_select:
+ return rcParams['backend']
+ else:
+ backend = rcParams._get('backend')
+ if backend is rcsetup._auto_backend_sentinel:
+ return None
+ else:
+ return backend
+
+
+def interactive(b):
+ """
+ Set whether to redraw after every plotting command (e.g. `.pyplot.xlabel`).
+ """
+ rcParams['interactive'] = b
+
+
+def is_interactive():
+ """
+ Return whether to redraw after every plotting command.
+
+ .. note::
+
+ This function is only intended for use in backends. End users should
+ use `.pyplot.isinteractive` instead.
+ """
+ return rcParams['interactive']
+
+
+def _val_or_rc(val, rc_name):
+ """
+ If *val* is None, return ``mpl.rcParams[rc_name]``, otherwise return val.
+ """
+ return val if val is not None else rcParams[rc_name]
+
+
+def _init_tests():
+ # The version of FreeType to install locally for running the tests. This must match
+ # the value in `meson.build`.
+ LOCAL_FREETYPE_VERSION = '2.6.1'
+
+ from matplotlib import ft2font
+ if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or
+ ft2font.__freetype_build_type__ != 'local'):
+ _log.warning(
+ "Matplotlib is not built with the correct FreeType version to run tests. "
+ "Rebuild without setting system-freetype=true in Meson setup options. "
+ "Expect many image comparison failures below. "
+ "Expected freetype version %s. "
+ "Found freetype version %s. "
+ "Freetype build type is %slocal.",
+ LOCAL_FREETYPE_VERSION,
+ ft2font.__freetype_version__,
+ "" if ft2font.__freetype_build_type__ == 'local' else "not ")
+
+
+def _replacer(data, value):
+ """
+ Either returns ``data[value]`` or passes ``data`` back, converts either to
+ a sequence.
+ """
+ try:
+ # if key isn't a string don't bother
+ if isinstance(value, str):
+ # try to use __getitem__
+ value = data[value]
+ except Exception:
+ # key does not exist, silently fall back to key
+ pass
+ return cbook.sanitize_sequence(value)
+
+
+def _label_from_arg(y, default_name):
+ try:
+ return y.name
+ except AttributeError:
+ if isinstance(default_name, str):
+ return default_name
+ return None
+
+
+def _add_data_doc(docstring, replace_names):
+ """
+ Add documentation for a *data* field to the given docstring.
+
+ Parameters
+ ----------
+ docstring : str
+ The input docstring.
+ replace_names : list of str or None
+ The list of parameter names which arguments should be replaced by
+ ``data[name]`` (if ``data[name]`` does not throw an exception). If
+ None, replacement is attempted for all arguments.
+
+ Returns
+ -------
+ str
+ The augmented docstring.
+ """
+ if (docstring is None
+ or replace_names is not None and len(replace_names) == 0):
+ return docstring
+ docstring = inspect.cleandoc(docstring)
+
+ data_doc = ("""\
+ If given, all parameters also accept a string ``s``, which is
+ interpreted as ``data[s]`` if ``s`` is a key in ``data``."""
+ if replace_names is None else f"""\
+ If given, the following parameters also accept a string ``s``, which is
+ interpreted as ``data[s]`` if ``s`` is a key in ``data``:
+
+ {', '.join(map('*{}*'.format, replace_names))}""")
+ # using string replacement instead of formatting has the advantages
+ # 1) simpler indent handling
+ # 2) prevent problems with formatting characters '{', '%' in the docstring
+ if _log.level <= logging.DEBUG:
+ # test_data_parameter_replacement() tests against these log messages
+ # make sure to keep message and test in sync
+ if "data : indexable object, optional" not in docstring:
+ _log.debug("data parameter docstring error: no data parameter")
+ if 'DATA_PARAMETER_PLACEHOLDER' not in docstring:
+ _log.debug("data parameter docstring error: missing placeholder")
+ return docstring.replace(' DATA_PARAMETER_PLACEHOLDER', data_doc)
+
+
+def _preprocess_data(func=None, *, replace_names=None, label_namer=None):
+ """
+ A decorator to add a 'data' kwarg to a function.
+
+ When applied::
+
+ @_preprocess_data()
+ def func(ax, *args, **kwargs): ...
+
+ the signature is modified to ``decorated(ax, *args, data=None, **kwargs)``
+ with the following behavior:
+
+ - if called with ``data=None``, forward the other arguments to ``func``;
+ - otherwise, *data* must be a mapping; for any argument passed in as a
+ string ``name``, replace the argument by ``data[name]`` (if this does not
+ throw an exception), then forward the arguments to ``func``.
+
+ In either case, any argument that is a `MappingView` is also converted to a
+ list.
+
+ Parameters
+ ----------
+ replace_names : list of str or None, default: None
+ The list of parameter names for which lookup into *data* should be
+ attempted. If None, replacement is attempted for all arguments.
+ label_namer : str, default: None
+ If set e.g. to "namer" (which must be a kwarg in the function's
+ signature -- not as ``**kwargs``), if the *namer* argument passed in is
+ a (string) key of *data* and no *label* kwarg is passed, then use the
+ (string) value of the *namer* as *label*. ::
+
+ @_preprocess_data(label_namer="foo")
+ def func(foo, label=None): ...
+
+ func("key", data={"key": value})
+ # is equivalent to
+ func.__wrapped__(value, label="key")
+ """
+
+ if func is None: # Return the actual decorator.
+ return functools.partial(
+ _preprocess_data,
+ replace_names=replace_names, label_namer=label_namer)
+
+ sig = inspect.signature(func)
+ varargs_name = None
+ varkwargs_name = None
+ arg_names = []
+ params = list(sig.parameters.values())
+ for p in params:
+ if p.kind is Parameter.VAR_POSITIONAL:
+ varargs_name = p.name
+ elif p.kind is Parameter.VAR_KEYWORD:
+ varkwargs_name = p.name
+ else:
+ arg_names.append(p.name)
+ data_param = Parameter("data", Parameter.KEYWORD_ONLY, default=None)
+ if varkwargs_name:
+ params.insert(-1, data_param)
+ else:
+ params.append(data_param)
+ new_sig = sig.replace(parameters=params)
+ arg_names = arg_names[1:] # remove the first "ax" / self arg
+
+ assert {*arg_names}.issuperset(replace_names or []) or varkwargs_name, (
+ "Matplotlib internal error: invalid replace_names "
+ f"({replace_names!r}) for {func.__name__!r}")
+ assert label_namer is None or label_namer in arg_names, (
+ "Matplotlib internal error: invalid label_namer "
+ f"({label_namer!r}) for {func.__name__!r}")
+
+ @functools.wraps(func)
+ def inner(ax, *args, data=None, **kwargs):
+ if data is None:
+ return func(
+ ax,
+ *map(cbook.sanitize_sequence, args),
+ **{k: cbook.sanitize_sequence(v) for k, v in kwargs.items()})
+
+ bound = new_sig.bind(ax, *args, **kwargs)
+ auto_label = (bound.arguments.get(label_namer)
+ or bound.kwargs.get(label_namer))
+
+ for k, v in bound.arguments.items():
+ if k == varkwargs_name:
+ for k1, v1 in v.items():
+ if replace_names is None or k1 in replace_names:
+ v[k1] = _replacer(data, v1)
+ elif k == varargs_name:
+ if replace_names is None:
+ bound.arguments[k] = tuple(_replacer(data, v1) for v1 in v)
+ else:
+ if replace_names is None or k in replace_names:
+ bound.arguments[k] = _replacer(data, v)
+
+ new_args = bound.args
+ new_kwargs = bound.kwargs
+
+ args_and_kwargs = {**bound.arguments, **bound.kwargs}
+ if label_namer and "label" not in args_and_kwargs:
+ new_kwargs["label"] = _label_from_arg(
+ args_and_kwargs.get(label_namer), auto_label)
+
+ return func(*new_args, **new_kwargs)
+
+ inner.__doc__ = _add_data_doc(inner.__doc__, replace_names)
+ inner.__signature__ = new_sig
+ return inner
+
+
+_log.debug('interactive is %s', is_interactive())
+_log.debug('platform is %s', sys.platform)
+
+
+@_api.deprecated("3.10", alternative="matplotlib.cbook.sanitize_sequence")
+def sanitize_sequence(data):
+ return cbook.sanitize_sequence(data)
+
+
+@_api.deprecated("3.10", alternative="matplotlib.rcsetup.validate_backend")
+def validate_backend(s):
+ return rcsetup.validate_backend(s)
+
+
+# workaround: we must defer colormaps import to after loading rcParams, because
+# colormap creation depends on rcParams
+from matplotlib.cm import _colormaps as colormaps # noqa: E402
+from matplotlib.cm import _multivar_colormaps as multivar_colormaps # noqa: E402
+from matplotlib.cm import _bivar_colormaps as bivar_colormaps # noqa: E402
+from matplotlib.colors import _color_sequences as color_sequences # noqa: E402
diff --git a/lib/python3.12/site-packages/matplotlib/__init__.pyi b/lib/python3.12/site-packages/matplotlib/__init__.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..88058ffd7def28740b4942d3851a5f43e49b086a
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/__init__.pyi
@@ -0,0 +1,124 @@
+__all__ = [
+ "__bibtex__",
+ "__version__",
+ "__version_info__",
+ "set_loglevel",
+ "ExecutableNotFoundError",
+ "get_configdir",
+ "get_cachedir",
+ "get_data_path",
+ "matplotlib_fname",
+ "MatplotlibDeprecationWarning",
+ "RcParams",
+ "rc_params",
+ "rc_params_from_file",
+ "rcParamsDefault",
+ "rcParams",
+ "rcParamsOrig",
+ "defaultParams",
+ "rc",
+ "rcdefaults",
+ "rc_file_defaults",
+ "rc_file",
+ "rc_context",
+ "use",
+ "get_backend",
+ "interactive",
+ "is_interactive",
+ "colormaps",
+ "color_sequences",
+]
+
+import os
+from pathlib import Path
+
+from collections.abc import Callable, Generator
+import contextlib
+from packaging.version import Version
+
+from matplotlib._api import MatplotlibDeprecationWarning
+from typing import Any, Literal, NamedTuple, overload
+
+class _VersionInfo(NamedTuple):
+ major: int
+ minor: int
+ micro: int
+ releaselevel: str
+ serial: int
+
+__bibtex__: str
+__version__: str
+__version_info__: _VersionInfo
+
+def set_loglevel(level: str) -> None: ...
+
+class _ExecInfo(NamedTuple):
+ executable: str
+ raw_version: str
+ version: Version
+
+class ExecutableNotFoundError(FileNotFoundError): ...
+
+def _get_executable_info(name: str) -> _ExecInfo: ...
+def get_configdir() -> str: ...
+def get_cachedir() -> str: ...
+def get_data_path() -> str: ...
+def matplotlib_fname() -> str: ...
+
+class RcParams(dict[str, Any]):
+ validate: dict[str, Callable]
+ def __init__(self, *args, **kwargs) -> None: ...
+ def _set(self, key: str, val: Any) -> None: ...
+ def _get(self, key: str) -> Any: ...
+
+ def _update_raw(self, other_params: dict | RcParams) -> None: ...
+
+ def _ensure_has_backend(self) -> None: ...
+ def __setitem__(self, key: str, val: Any) -> None: ...
+ def __getitem__(self, key: str) -> Any: ...
+ def __iter__(self) -> Generator[str, None, None]: ...
+ def __len__(self) -> int: ...
+ def find_all(self, pattern: str) -> RcParams: ...
+ def copy(self) -> RcParams: ...
+
+def rc_params(fail_on_error: bool = ...) -> RcParams: ...
+def rc_params_from_file(
+ fname: str | Path | os.PathLike,
+ fail_on_error: bool = ...,
+ use_default_template: bool = ...,
+) -> RcParams: ...
+
+rcParamsDefault: RcParams
+rcParams: RcParams
+rcParamsOrig: RcParams
+defaultParams: dict[str, Any]
+
+def rc(group: str, **kwargs) -> None: ...
+def rcdefaults() -> None: ...
+def rc_file_defaults() -> None: ...
+def rc_file(
+ fname: str | Path | os.PathLike, *, use_default_template: bool = ...
+) -> None: ...
+@contextlib.contextmanager
+def rc_context(
+ rc: dict[str, Any] | None = ..., fname: str | Path | os.PathLike | None = ...
+) -> Generator[None, None, None]: ...
+def use(backend: str, *, force: bool = ...) -> None: ...
+@overload
+def get_backend(*, auto_select: Literal[True] = True) -> str: ...
+@overload
+def get_backend(*, auto_select: Literal[False]) -> str | None: ...
+def interactive(b: bool) -> None: ...
+def is_interactive() -> bool: ...
+
+def _preprocess_data(
+ func: Callable | None = ...,
+ *,
+ replace_names: list[str] | None = ...,
+ label_namer: str | None = ...
+) -> Callable: ...
+
+from matplotlib.cm import _colormaps as colormaps # noqa: E402
+from matplotlib.cm import _multivar_colormaps as multivar_colormaps # noqa: E402
+from matplotlib.cm import _bivar_colormaps as bivar_colormaps # noqa: E402
+from matplotlib.colors import _color_sequences as color_sequences # noqa: E402
diff --git a/lib/python3.12/site-packages/matplotlib/_blocking_input.py b/lib/python3.12/site-packages/matplotlib/_blocking_input.py
new file mode 100644
index 0000000000000000000000000000000000000000..45f0775714431e73c283fede1f0cf12d7eaabb8d
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_blocking_input.py
@@ -0,0 +1,30 @@
+def blocking_input_loop(figure, event_names, timeout, handler):
+ """
+ Run *figure*'s event loop while listening to interactive events.
+
+ The events listed in *event_names* are passed to *handler*.
+
+ This function is used to implement `.Figure.waitforbuttonpress`,
+ `.Figure.ginput`, and `.Axes.clabel`.
+
+ Parameters
+ ----------
+ figure : `~matplotlib.figure.Figure`
+ event_names : list of str
+ The names of the events passed to *handler*.
+ timeout : float
+ If positive, the event loop is stopped after *timeout* seconds.
+ handler : Callable[[Event], Any]
+ Function called for each event; it can force an early exit of the event
+ loop by calling ``canvas.stop_event_loop()``.
+ """
+ if figure.canvas.manager:
+ figure.show() # Ensure that the figure is shown if we are managing it.
+ # Connect the events to the on_event function call.
+ cids = [figure.canvas.mpl_connect(name, handler) for name in event_names]
+ try:
+ figure.canvas.start_event_loop(timeout) # Start event loop.
+ finally: # Run even on exception like ctrl-c.
+ # Disconnect the callbacks.
+ for cid in cids:
+ figure.canvas.mpl_disconnect(cid)
diff --git a/lib/python3.12/site-packages/matplotlib/_c_internal_utils.pyi b/lib/python3.12/site-packages/matplotlib/_c_internal_utils.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..ccc172cde27a35ad930cc618b86fdf5c8d44728e
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_c_internal_utils.pyi
@@ -0,0 +1,8 @@
+def display_is_valid() -> bool: ...
+def xdisplay_is_valid() -> bool: ...
+
+def Win32_GetForegroundWindow() -> int | None: ...
+def Win32_SetForegroundWindow(hwnd: int) -> None: ...
+def Win32_SetProcessDpiAwareness_max() -> None: ...
+def Win32_SetCurrentProcessExplicitAppUserModelID(appid: str) -> None: ...
+def Win32_GetCurrentProcessExplicitAppUserModelID() -> str | None: ...
diff --git a/lib/python3.12/site-packages/matplotlib/_cm.py b/lib/python3.12/site-packages/matplotlib/_cm.py
new file mode 100644
index 0000000000000000000000000000000000000000..b942d1697934789f26c522b3e7592671540919a6
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_cm.py
@@ -0,0 +1,1460 @@
+"""
+Nothing here but dictionaries for generating LinearSegmentedColormaps,
+and a dictionary of these dictionaries.
+
+Documentation for each is in pyplot.colormaps(). Please update this
+with the purpose and type of your colormap if you add data for one here.
+"""
+
+from functools import partial
+
+import numpy as np
+
+_binary_data = {
+ 'red': ((0., 1., 1.), (1., 0., 0.)),
+ 'green': ((0., 1., 1.), (1., 0., 0.)),
+ 'blue': ((0., 1., 1.), (1., 0., 0.))
+ }
+
+_autumn_data = {'red': ((0., 1.0, 1.0), (1.0, 1.0, 1.0)),
+ 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)),
+ 'blue': ((0., 0., 0.), (1.0, 0., 0.))}
+
+_bone_data = {'red': ((0., 0., 0.),
+ (0.746032, 0.652778, 0.652778),
+ (1.0, 1.0, 1.0)),
+ 'green': ((0., 0., 0.),
+ (0.365079, 0.319444, 0.319444),
+ (0.746032, 0.777778, 0.777778),
+ (1.0, 1.0, 1.0)),
+ 'blue': ((0., 0., 0.),
+ (0.365079, 0.444444, 0.444444),
+ (1.0, 1.0, 1.0))}
+
+_cool_data = {'red': ((0., 0., 0.), (1.0, 1.0, 1.0)),
+ 'green': ((0., 1., 1.), (1.0, 0., 0.)),
+ 'blue': ((0., 1., 1.), (1.0, 1., 1.))}
+
+_copper_data = {'red': ((0., 0., 0.),
+ (0.809524, 1.000000, 1.000000),
+ (1.0, 1.0, 1.0)),
+ 'green': ((0., 0., 0.),
+ (1.0, 0.7812, 0.7812)),
+ 'blue': ((0., 0., 0.),
+ (1.0, 0.4975, 0.4975))}
+
+def _flag_red(x): return 0.75 * np.sin((x * 31.5 + 0.25) * np.pi) + 0.5
+def _flag_green(x): return np.sin(x * 31.5 * np.pi)
+def _flag_blue(x): return 0.75 * np.sin((x * 31.5 - 0.25) * np.pi) + 0.5
+_flag_data = {'red': _flag_red, 'green': _flag_green, 'blue': _flag_blue}
+
+def _prism_red(x): return 0.75 * np.sin((x * 20.9 + 0.25) * np.pi) + 0.67
+def _prism_green(x): return 0.75 * np.sin((x * 20.9 - 0.25) * np.pi) + 0.33
+def _prism_blue(x): return -1.1 * np.sin((x * 20.9) * np.pi)
+_prism_data = {'red': _prism_red, 'green': _prism_green, 'blue': _prism_blue}
+
+def _ch_helper(gamma, s, r, h, p0, p1, x):
+ """Helper function for generating picklable cubehelix colormaps."""
+ # Apply gamma factor to emphasise low or high intensity values
+ xg = x ** gamma
+ # Calculate amplitude and angle of deviation from the black to white
+ # diagonal in the plane of constant perceived intensity.
+ a = h * xg * (1 - xg) / 2
+ phi = 2 * np.pi * (s / 3 + r * x)
+ return xg + a * (p0 * np.cos(phi) + p1 * np.sin(phi))
+
+def cubehelix(gamma=1.0, s=0.5, r=-1.5, h=1.0):
+ """
+ Return custom data dictionary of (r, g, b) conversion functions, which can
+ be used with `.ColormapRegistry.register`, for the cubehelix color scheme.
+
+ Unlike most other color schemes cubehelix was designed by D.A. Green to
+ be monotonically increasing in terms of perceived brightness.
+ Also, when printed on a black and white postscript printer, the scheme
+ results in a greyscale with monotonically increasing brightness.
+ This color scheme is named cubehelix because the (r, g, b) values produced
+ can be visualised as a squashed helix around the diagonal in the
+ (r, g, b) color cube.
+
+ For a unit color cube (i.e. 3D coordinates for (r, g, b) each in the
+ range 0 to 1) the color scheme starts at (r, g, b) = (0, 0, 0), i.e. black,
+ and finishes at (r, g, b) = (1, 1, 1), i.e. white. For some fraction *x*,
+ between 0 and 1, the color is the corresponding grey value at that
+ fraction along the black to white diagonal (x, x, x) plus a color
+ element. This color element is calculated in a plane of constant
+ perceived intensity and controlled by the following parameters.
+
+ Parameters
+ ----------
+ gamma : float, default: 1
+ Gamma factor emphasizing either low intensity values (gamma < 1), or
+ high intensity values (gamma > 1).
+ s : float, default: 0.5 (purple)
+ The starting color.
+ r : float, default: -1.5
+ The number of r, g, b rotations in color that are made from the start
+ to the end of the color scheme. The default of -1.5 corresponds to ->
+ B -> G -> R -> B.
+ h : float, default: 1
+ The hue, i.e. how saturated the colors are. If this parameter is zero
+ then the color scheme is purely a greyscale.
+ """
+ return {'red': partial(_ch_helper, gamma, s, r, h, -0.14861, 1.78277),
+ 'green': partial(_ch_helper, gamma, s, r, h, -0.29227, -0.90649),
+ 'blue': partial(_ch_helper, gamma, s, r, h, 1.97294, 0.0)}
+
+_cubehelix_data = cubehelix()
+
+_bwr_data = ((0.0, 0.0, 1.0), (1.0, 1.0, 1.0), (1.0, 0.0, 0.0))
+_brg_data = ((0.0, 0.0, 1.0), (1.0, 0.0, 0.0), (0.0, 1.0, 0.0))
+
+# Gnuplot palette functions
+def _g0(x): return 0
+def _g1(x): return 0.5
+def _g2(x): return 1
+def _g3(x): return x
+def _g4(x): return x ** 2
+def _g5(x): return x ** 3
+def _g6(x): return x ** 4
+def _g7(x): return np.sqrt(x)
+def _g8(x): return np.sqrt(np.sqrt(x))
+def _g9(x): return np.sin(x * np.pi / 2)
+def _g10(x): return np.cos(x * np.pi / 2)
+def _g11(x): return np.abs(x - 0.5)
+def _g12(x): return (2 * x - 1) ** 2
+def _g13(x): return np.sin(x * np.pi)
+def _g14(x): return np.abs(np.cos(x * np.pi))
+def _g15(x): return np.sin(x * 2 * np.pi)
+def _g16(x): return np.cos(x * 2 * np.pi)
+def _g17(x): return np.abs(np.sin(x * 2 * np.pi))
+def _g18(x): return np.abs(np.cos(x * 2 * np.pi))
+def _g19(x): return np.abs(np.sin(x * 4 * np.pi))
+def _g20(x): return np.abs(np.cos(x * 4 * np.pi))
+def _g21(x): return 3 * x
+def _g22(x): return 3 * x - 1
+def _g23(x): return 3 * x - 2
+def _g24(x): return np.abs(3 * x - 1)
+def _g25(x): return np.abs(3 * x - 2)
+def _g26(x): return (3 * x - 1) / 2
+def _g27(x): return (3 * x - 2) / 2
+def _g28(x): return np.abs((3 * x - 1) / 2)
+def _g29(x): return np.abs((3 * x - 2) / 2)
+def _g30(x): return x / 0.32 - 0.78125
+def _g31(x): return 2 * x - 0.84
+def _g32(x):
+ ret = np.zeros(len(x))
+ m = (x < 0.25)
+ ret[m] = 4 * x[m]
+ m = (x >= 0.25) & (x < 0.92)
+ ret[m] = -2 * x[m] + 1.84
+ m = (x >= 0.92)
+ ret[m] = x[m] / 0.08 - 11.5
+ return ret
+def _g33(x): return np.abs(2 * x - 0.5)
+def _g34(x): return 2 * x
+def _g35(x): return 2 * x - 0.5
+def _g36(x): return 2 * x - 1
+
+gfunc = {i: globals()[f"_g{i}"] for i in range(37)}
+
+_gnuplot_data = {
+ 'red': gfunc[7],
+ 'green': gfunc[5],
+ 'blue': gfunc[15],
+}
+
+_gnuplot2_data = {
+ 'red': gfunc[30],
+ 'green': gfunc[31],
+ 'blue': gfunc[32],
+}
+
+_ocean_data = {
+ 'red': gfunc[23],
+ 'green': gfunc[28],
+ 'blue': gfunc[3],
+}
+
+_afmhot_data = {
+ 'red': gfunc[34],
+ 'green': gfunc[35],
+ 'blue': gfunc[36],
+}
+
+_rainbow_data = {
+ 'red': gfunc[33],
+ 'green': gfunc[13],
+ 'blue': gfunc[10],
+}
+
+_seismic_data = (
+ (0.0, 0.0, 0.3), (0.0, 0.0, 1.0),
+ (1.0, 1.0, 1.0), (1.0, 0.0, 0.0),
+ (0.5, 0.0, 0.0))
+
+_terrain_data = (
+ (0.00, (0.2, 0.2, 0.6)),
+ (0.15, (0.0, 0.6, 1.0)),
+ (0.25, (0.0, 0.8, 0.4)),
+ (0.50, (1.0, 1.0, 0.6)),
+ (0.75, (0.5, 0.36, 0.33)),
+ (1.00, (1.0, 1.0, 1.0)))
+
+_gray_data = {'red': ((0., 0, 0), (1., 1, 1)),
+ 'green': ((0., 0, 0), (1., 1, 1)),
+ 'blue': ((0., 0, 0), (1., 1, 1))}
+
+_hot_data = {'red': ((0., 0.0416, 0.0416),
+ (0.365079, 1.000000, 1.000000),
+ (1.0, 1.0, 1.0)),
+ 'green': ((0., 0., 0.),
+ (0.365079, 0.000000, 0.000000),
+ (0.746032, 1.000000, 1.000000),
+ (1.0, 1.0, 1.0)),
+ 'blue': ((0., 0., 0.),
+ (0.746032, 0.000000, 0.000000),
+ (1.0, 1.0, 1.0))}
+
+_hsv_data = {'red': ((0., 1., 1.),
+ (0.158730, 1.000000, 1.000000),
+ (0.174603, 0.968750, 0.968750),
+ (0.333333, 0.031250, 0.031250),
+ (0.349206, 0.000000, 0.000000),
+ (0.666667, 0.000000, 0.000000),
+ (0.682540, 0.031250, 0.031250),
+ (0.841270, 0.968750, 0.968750),
+ (0.857143, 1.000000, 1.000000),
+ (1.0, 1.0, 1.0)),
+ 'green': ((0., 0., 0.),
+ (0.158730, 0.937500, 0.937500),
+ (0.174603, 1.000000, 1.000000),
+ (0.507937, 1.000000, 1.000000),
+ (0.666667, 0.062500, 0.062500),
+ (0.682540, 0.000000, 0.000000),
+ (1.0, 0., 0.)),
+ 'blue': ((0., 0., 0.),
+ (0.333333, 0.000000, 0.000000),
+ (0.349206, 0.062500, 0.062500),
+ (0.507937, 1.000000, 1.000000),
+ (0.841270, 1.000000, 1.000000),
+ (0.857143, 0.937500, 0.937500),
+ (1.0, 0.09375, 0.09375))}
+
+_jet_data = {'red': ((0.00, 0, 0),
+ (0.35, 0, 0),
+ (0.66, 1, 1),
+ (0.89, 1, 1),
+ (1.00, 0.5, 0.5)),
+ 'green': ((0.000, 0, 0),
+ (0.125, 0, 0),
+ (0.375, 1, 1),
+ (0.640, 1, 1),
+ (0.910, 0, 0),
+ (1.000, 0, 0)),
+ 'blue': ((0.00, 0.5, 0.5),
+ (0.11, 1, 1),
+ (0.34, 1, 1),
+ (0.65, 0, 0),
+ (1.00, 0, 0))}
+
+_pink_data = {'red': ((0., 0.1178, 0.1178), (0.015873, 0.195857, 0.195857),
+ (0.031746, 0.250661, 0.250661),
+ (0.047619, 0.295468, 0.295468),
+ (0.063492, 0.334324, 0.334324),
+ (0.079365, 0.369112, 0.369112),
+ (0.095238, 0.400892, 0.400892),
+ (0.111111, 0.430331, 0.430331),
+ (0.126984, 0.457882, 0.457882),
+ (0.142857, 0.483867, 0.483867),
+ (0.158730, 0.508525, 0.508525),
+ (0.174603, 0.532042, 0.532042),
+ (0.190476, 0.554563, 0.554563),
+ (0.206349, 0.576204, 0.576204),
+ (0.222222, 0.597061, 0.597061),
+ (0.238095, 0.617213, 0.617213),
+ (0.253968, 0.636729, 0.636729),
+ (0.269841, 0.655663, 0.655663),
+ (0.285714, 0.674066, 0.674066),
+ (0.301587, 0.691980, 0.691980),
+ (0.317460, 0.709441, 0.709441),
+ (0.333333, 0.726483, 0.726483),
+ (0.349206, 0.743134, 0.743134),
+ (0.365079, 0.759421, 0.759421),
+ (0.380952, 0.766356, 0.766356),
+ (0.396825, 0.773229, 0.773229),
+ (0.412698, 0.780042, 0.780042),
+ (0.428571, 0.786796, 0.786796),
+ (0.444444, 0.793492, 0.793492),
+ (0.460317, 0.800132, 0.800132),
+ (0.476190, 0.806718, 0.806718),
+ (0.492063, 0.813250, 0.813250),
+ (0.507937, 0.819730, 0.819730),
+ (0.523810, 0.826160, 0.826160),
+ (0.539683, 0.832539, 0.832539),
+ (0.555556, 0.838870, 0.838870),
+ (0.571429, 0.845154, 0.845154),
+ (0.587302, 0.851392, 0.851392),
+ (0.603175, 0.857584, 0.857584),
+ (0.619048, 0.863731, 0.863731),
+ (0.634921, 0.869835, 0.869835),
+ (0.650794, 0.875897, 0.875897),
+ (0.666667, 0.881917, 0.881917),
+ (0.682540, 0.887896, 0.887896),
+ (0.698413, 0.893835, 0.893835),
+ (0.714286, 0.899735, 0.899735),
+ (0.730159, 0.905597, 0.905597),
+ (0.746032, 0.911421, 0.911421),
+ (0.761905, 0.917208, 0.917208),
+ (0.777778, 0.922958, 0.922958),
+ (0.793651, 0.928673, 0.928673),
+ (0.809524, 0.934353, 0.934353),
+ (0.825397, 0.939999, 0.939999),
+ (0.841270, 0.945611, 0.945611),
+ (0.857143, 0.951190, 0.951190),
+ (0.873016, 0.956736, 0.956736),
+ (0.888889, 0.962250, 0.962250),
+ (0.904762, 0.967733, 0.967733),
+ (0.920635, 0.973185, 0.973185),
+ (0.936508, 0.978607, 0.978607),
+ (0.952381, 0.983999, 0.983999),
+ (0.968254, 0.989361, 0.989361),
+ (0.984127, 0.994695, 0.994695), (1.0, 1.0, 1.0)),
+ 'green': ((0., 0., 0.), (0.015873, 0.102869, 0.102869),
+ (0.031746, 0.145479, 0.145479),
+ (0.047619, 0.178174, 0.178174),
+ (0.063492, 0.205738, 0.205738),
+ (0.079365, 0.230022, 0.230022),
+ (0.095238, 0.251976, 0.251976),
+ (0.111111, 0.272166, 0.272166),
+ (0.126984, 0.290957, 0.290957),
+ (0.142857, 0.308607, 0.308607),
+ (0.158730, 0.325300, 0.325300),
+ (0.174603, 0.341178, 0.341178),
+ (0.190476, 0.356348, 0.356348),
+ (0.206349, 0.370899, 0.370899),
+ (0.222222, 0.384900, 0.384900),
+ (0.238095, 0.398410, 0.398410),
+ (0.253968, 0.411476, 0.411476),
+ (0.269841, 0.424139, 0.424139),
+ (0.285714, 0.436436, 0.436436),
+ (0.301587, 0.448395, 0.448395),
+ (0.317460, 0.460044, 0.460044),
+ (0.333333, 0.471405, 0.471405),
+ (0.349206, 0.482498, 0.482498),
+ (0.365079, 0.493342, 0.493342),
+ (0.380952, 0.517549, 0.517549),
+ (0.396825, 0.540674, 0.540674),
+ (0.412698, 0.562849, 0.562849),
+ (0.428571, 0.584183, 0.584183),
+ (0.444444, 0.604765, 0.604765),
+ (0.460317, 0.624669, 0.624669),
+ (0.476190, 0.643958, 0.643958),
+ (0.492063, 0.662687, 0.662687),
+ (0.507937, 0.680900, 0.680900),
+ (0.523810, 0.698638, 0.698638),
+ (0.539683, 0.715937, 0.715937),
+ (0.555556, 0.732828, 0.732828),
+ (0.571429, 0.749338, 0.749338),
+ (0.587302, 0.765493, 0.765493),
+ (0.603175, 0.781313, 0.781313),
+ (0.619048, 0.796819, 0.796819),
+ (0.634921, 0.812029, 0.812029),
+ (0.650794, 0.826960, 0.826960),
+ (0.666667, 0.841625, 0.841625),
+ (0.682540, 0.856040, 0.856040),
+ (0.698413, 0.870216, 0.870216),
+ (0.714286, 0.884164, 0.884164),
+ (0.730159, 0.897896, 0.897896),
+ (0.746032, 0.911421, 0.911421),
+ (0.761905, 0.917208, 0.917208),
+ (0.777778, 0.922958, 0.922958),
+ (0.793651, 0.928673, 0.928673),
+ (0.809524, 0.934353, 0.934353),
+ (0.825397, 0.939999, 0.939999),
+ (0.841270, 0.945611, 0.945611),
+ (0.857143, 0.951190, 0.951190),
+ (0.873016, 0.956736, 0.956736),
+ (0.888889, 0.962250, 0.962250),
+ (0.904762, 0.967733, 0.967733),
+ (0.920635, 0.973185, 0.973185),
+ (0.936508, 0.978607, 0.978607),
+ (0.952381, 0.983999, 0.983999),
+ (0.968254, 0.989361, 0.989361),
+ (0.984127, 0.994695, 0.994695), (1.0, 1.0, 1.0)),
+ 'blue': ((0., 0., 0.), (0.015873, 0.102869, 0.102869),
+ (0.031746, 0.145479, 0.145479),
+ (0.047619, 0.178174, 0.178174),
+ (0.063492, 0.205738, 0.205738),
+ (0.079365, 0.230022, 0.230022),
+ (0.095238, 0.251976, 0.251976),
+ (0.111111, 0.272166, 0.272166),
+ (0.126984, 0.290957, 0.290957),
+ (0.142857, 0.308607, 0.308607),
+ (0.158730, 0.325300, 0.325300),
+ (0.174603, 0.341178, 0.341178),
+ (0.190476, 0.356348, 0.356348),
+ (0.206349, 0.370899, 0.370899),
+ (0.222222, 0.384900, 0.384900),
+ (0.238095, 0.398410, 0.398410),
+ (0.253968, 0.411476, 0.411476),
+ (0.269841, 0.424139, 0.424139),
+ (0.285714, 0.436436, 0.436436),
+ (0.301587, 0.448395, 0.448395),
+ (0.317460, 0.460044, 0.460044),
+ (0.333333, 0.471405, 0.471405),
+ (0.349206, 0.482498, 0.482498),
+ (0.365079, 0.493342, 0.493342),
+ (0.380952, 0.503953, 0.503953),
+ (0.396825, 0.514344, 0.514344),
+ (0.412698, 0.524531, 0.524531),
+ (0.428571, 0.534522, 0.534522),
+ (0.444444, 0.544331, 0.544331),
+ (0.460317, 0.553966, 0.553966),
+ (0.476190, 0.563436, 0.563436),
+ (0.492063, 0.572750, 0.572750),
+ (0.507937, 0.581914, 0.581914),
+ (0.523810, 0.590937, 0.590937),
+ (0.539683, 0.599824, 0.599824),
+ (0.555556, 0.608581, 0.608581),
+ (0.571429, 0.617213, 0.617213),
+ (0.587302, 0.625727, 0.625727),
+ (0.603175, 0.634126, 0.634126),
+ (0.619048, 0.642416, 0.642416),
+ (0.634921, 0.650600, 0.650600),
+ (0.650794, 0.658682, 0.658682),
+ (0.666667, 0.666667, 0.666667),
+ (0.682540, 0.674556, 0.674556),
+ (0.698413, 0.682355, 0.682355),
+ (0.714286, 0.690066, 0.690066),
+ (0.730159, 0.697691, 0.697691),
+ (0.746032, 0.705234, 0.705234),
+ (0.761905, 0.727166, 0.727166),
+ (0.777778, 0.748455, 0.748455),
+ (0.793651, 0.769156, 0.769156),
+ (0.809524, 0.789314, 0.789314),
+ (0.825397, 0.808969, 0.808969),
+ (0.841270, 0.828159, 0.828159),
+ (0.857143, 0.846913, 0.846913),
+ (0.873016, 0.865261, 0.865261),
+ (0.888889, 0.883229, 0.883229),
+ (0.904762, 0.900837, 0.900837),
+ (0.920635, 0.918109, 0.918109),
+ (0.936508, 0.935061, 0.935061),
+ (0.952381, 0.951711, 0.951711),
+ (0.968254, 0.968075, 0.968075),
+ (0.984127, 0.984167, 0.984167), (1.0, 1.0, 1.0))}
+
+_spring_data = {'red': ((0., 1., 1.), (1.0, 1.0, 1.0)),
+ 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)),
+ 'blue': ((0., 1., 1.), (1.0, 0.0, 0.0))}
+
+
+_summer_data = {'red': ((0., 0., 0.), (1.0, 1.0, 1.0)),
+ 'green': ((0., 0.5, 0.5), (1.0, 1.0, 1.0)),
+ 'blue': ((0., 0.4, 0.4), (1.0, 0.4, 0.4))}
+
+
+_winter_data = {'red': ((0., 0., 0.), (1.0, 0.0, 0.0)),
+ 'green': ((0., 0., 0.), (1.0, 1.0, 1.0)),
+ 'blue': ((0., 1., 1.), (1.0, 0.5, 0.5))}
+
+_nipy_spectral_data = {
+ 'red': [
+ (0.0, 0.0, 0.0), (0.05, 0.4667, 0.4667),
+ (0.10, 0.5333, 0.5333), (0.15, 0.0, 0.0),
+ (0.20, 0.0, 0.0), (0.25, 0.0, 0.0),
+ (0.30, 0.0, 0.0), (0.35, 0.0, 0.0),
+ (0.40, 0.0, 0.0), (0.45, 0.0, 0.0),
+ (0.50, 0.0, 0.0), (0.55, 0.0, 0.0),
+ (0.60, 0.0, 0.0), (0.65, 0.7333, 0.7333),
+ (0.70, 0.9333, 0.9333), (0.75, 1.0, 1.0),
+ (0.80, 1.0, 1.0), (0.85, 1.0, 1.0),
+ (0.90, 0.8667, 0.8667), (0.95, 0.80, 0.80),
+ (1.0, 0.80, 0.80),
+ ],
+ 'green': [
+ (0.0, 0.0, 0.0), (0.05, 0.0, 0.0),
+ (0.10, 0.0, 0.0), (0.15, 0.0, 0.0),
+ (0.20, 0.0, 0.0), (0.25, 0.4667, 0.4667),
+ (0.30, 0.6000, 0.6000), (0.35, 0.6667, 0.6667),
+ (0.40, 0.6667, 0.6667), (0.45, 0.6000, 0.6000),
+ (0.50, 0.7333, 0.7333), (0.55, 0.8667, 0.8667),
+ (0.60, 1.0, 1.0), (0.65, 1.0, 1.0),
+ (0.70, 0.9333, 0.9333), (0.75, 0.8000, 0.8000),
+ (0.80, 0.6000, 0.6000), (0.85, 0.0, 0.0),
+ (0.90, 0.0, 0.0), (0.95, 0.0, 0.0),
+ (1.0, 0.80, 0.80),
+ ],
+ 'blue': [
+ (0.0, 0.0, 0.0), (0.05, 0.5333, 0.5333),
+ (0.10, 0.6000, 0.6000), (0.15, 0.6667, 0.6667),
+ (0.20, 0.8667, 0.8667), (0.25, 0.8667, 0.8667),
+ (0.30, 0.8667, 0.8667), (0.35, 0.6667, 0.6667),
+ (0.40, 0.5333, 0.5333), (0.45, 0.0, 0.0),
+ (0.5, 0.0, 0.0), (0.55, 0.0, 0.0),
+ (0.60, 0.0, 0.0), (0.65, 0.0, 0.0),
+ (0.70, 0.0, 0.0), (0.75, 0.0, 0.0),
+ (0.80, 0.0, 0.0), (0.85, 0.0, 0.0),
+ (0.90, 0.0, 0.0), (0.95, 0.0, 0.0),
+ (1.0, 0.80, 0.80),
+ ],
+}
+
+
+# 34 colormaps based on color specifications and designs
+# developed by Cynthia Brewer (https://colorbrewer2.org/).
+# The ColorBrewer palettes have been included under the terms
+# of an Apache-stype license (for details, see the file
+# LICENSE_COLORBREWER in the license directory of the matplotlib
+# source distribution).
+
+# RGB values taken from Brewer's Excel sheet, divided by 255
+
+_Blues_data = (
+ (0.96862745098039216, 0.98431372549019602, 1.0 ),
+ (0.87058823529411766, 0.92156862745098034, 0.96862745098039216),
+ (0.77647058823529413, 0.85882352941176465, 0.93725490196078431),
+ (0.61960784313725492, 0.792156862745098 , 0.88235294117647056),
+ (0.41960784313725491, 0.68235294117647061, 0.83921568627450982),
+ (0.25882352941176473, 0.5725490196078431 , 0.77647058823529413),
+ (0.12941176470588237, 0.44313725490196076, 0.70980392156862748),
+ (0.03137254901960784, 0.31764705882352939, 0.61176470588235299),
+ (0.03137254901960784, 0.18823529411764706, 0.41960784313725491)
+ )
+
+_BrBG_data = (
+ (0.32941176470588235, 0.18823529411764706, 0.0196078431372549 ),
+ (0.5490196078431373 , 0.31764705882352939, 0.0392156862745098 ),
+ (0.74901960784313726, 0.50588235294117645, 0.17647058823529413),
+ (0.87450980392156863, 0.76078431372549016, 0.49019607843137253),
+ (0.96470588235294119, 0.90980392156862744, 0.76470588235294112),
+ (0.96078431372549022, 0.96078431372549022, 0.96078431372549022),
+ (0.7803921568627451 , 0.91764705882352937, 0.89803921568627454),
+ (0.50196078431372548, 0.80392156862745101, 0.75686274509803919),
+ (0.20784313725490197, 0.59215686274509804, 0.5607843137254902 ),
+ (0.00392156862745098, 0.4 , 0.36862745098039218),
+ (0.0 , 0.23529411764705882, 0.18823529411764706)
+ )
+
+_BuGn_data = (
+ (0.96862745098039216, 0.9882352941176471 , 0.99215686274509807),
+ (0.89803921568627454, 0.96078431372549022, 0.97647058823529409),
+ (0.8 , 0.92549019607843142, 0.90196078431372551),
+ (0.6 , 0.84705882352941175, 0.78823529411764703),
+ (0.4 , 0.76078431372549016, 0.64313725490196083),
+ (0.25490196078431371, 0.68235294117647061, 0.46274509803921571),
+ (0.13725490196078433, 0.54509803921568623, 0.27058823529411763),
+ (0.0 , 0.42745098039215684, 0.17254901960784313),
+ (0.0 , 0.26666666666666666, 0.10588235294117647)
+ )
+
+_BuPu_data = (
+ (0.96862745098039216, 0.9882352941176471 , 0.99215686274509807),
+ (0.8784313725490196 , 0.92549019607843142, 0.95686274509803926),
+ (0.74901960784313726, 0.82745098039215681, 0.90196078431372551),
+ (0.61960784313725492, 0.73725490196078436, 0.85490196078431369),
+ (0.5490196078431373 , 0.58823529411764708, 0.77647058823529413),
+ (0.5490196078431373 , 0.41960784313725491, 0.69411764705882351),
+ (0.53333333333333333, 0.25490196078431371, 0.61568627450980395),
+ (0.50588235294117645, 0.05882352941176471, 0.48627450980392156),
+ (0.30196078431372547, 0.0 , 0.29411764705882354)
+ )
+
+_GnBu_data = (
+ (0.96862745098039216, 0.9882352941176471 , 0.94117647058823528),
+ (0.8784313725490196 , 0.95294117647058818, 0.85882352941176465),
+ (0.8 , 0.92156862745098034, 0.77254901960784317),
+ (0.6588235294117647 , 0.8666666666666667 , 0.70980392156862748),
+ (0.4823529411764706 , 0.8 , 0.7686274509803922 ),
+ (0.30588235294117649, 0.70196078431372544, 0.82745098039215681),
+ (0.16862745098039217, 0.5490196078431373 , 0.74509803921568629),
+ (0.03137254901960784, 0.40784313725490196, 0.67450980392156867),
+ (0.03137254901960784, 0.25098039215686274, 0.50588235294117645)
+ )
+
+_Greens_data = (
+ (0.96862745098039216, 0.9882352941176471 , 0.96078431372549022),
+ (0.89803921568627454, 0.96078431372549022, 0.8784313725490196 ),
+ (0.7803921568627451 , 0.9137254901960784 , 0.75294117647058822),
+ (0.63137254901960782, 0.85098039215686272, 0.60784313725490191),
+ (0.45490196078431372, 0.7686274509803922 , 0.46274509803921571),
+ (0.25490196078431371, 0.6705882352941176 , 0.36470588235294116),
+ (0.13725490196078433, 0.54509803921568623, 0.27058823529411763),
+ (0.0 , 0.42745098039215684, 0.17254901960784313),
+ (0.0 , 0.26666666666666666, 0.10588235294117647)
+ )
+
+_Greys_data = (
+ (1.0 , 1.0 , 1.0 ),
+ (0.94117647058823528, 0.94117647058823528, 0.94117647058823528),
+ (0.85098039215686272, 0.85098039215686272, 0.85098039215686272),
+ (0.74117647058823533, 0.74117647058823533, 0.74117647058823533),
+ (0.58823529411764708, 0.58823529411764708, 0.58823529411764708),
+ (0.45098039215686275, 0.45098039215686275, 0.45098039215686275),
+ (0.32156862745098042, 0.32156862745098042, 0.32156862745098042),
+ (0.14509803921568629, 0.14509803921568629, 0.14509803921568629),
+ (0.0 , 0.0 , 0.0 )
+ )
+
+_Oranges_data = (
+ (1.0 , 0.96078431372549022, 0.92156862745098034),
+ (0.99607843137254903, 0.90196078431372551, 0.80784313725490198),
+ (0.99215686274509807, 0.81568627450980391, 0.63529411764705879),
+ (0.99215686274509807, 0.68235294117647061, 0.41960784313725491),
+ (0.99215686274509807, 0.55294117647058827, 0.23529411764705882),
+ (0.94509803921568625, 0.41176470588235292, 0.07450980392156863),
+ (0.85098039215686272, 0.28235294117647058, 0.00392156862745098),
+ (0.65098039215686276, 0.21176470588235294, 0.01176470588235294),
+ (0.49803921568627452, 0.15294117647058825, 0.01568627450980392)
+ )
+
+_OrRd_data = (
+ (1.0 , 0.96862745098039216, 0.92549019607843142),
+ (0.99607843137254903, 0.90980392156862744, 0.78431372549019607),
+ (0.99215686274509807, 0.83137254901960789, 0.61960784313725492),
+ (0.99215686274509807, 0.73333333333333328, 0.51764705882352946),
+ (0.9882352941176471 , 0.55294117647058827, 0.34901960784313724),
+ (0.93725490196078431, 0.396078431372549 , 0.28235294117647058),
+ (0.84313725490196079, 0.18823529411764706, 0.12156862745098039),
+ (0.70196078431372544, 0.0 , 0.0 ),
+ (0.49803921568627452, 0.0 , 0.0 )
+ )
+
+_PiYG_data = (
+ (0.55686274509803924, 0.00392156862745098, 0.32156862745098042),
+ (0.77254901960784317, 0.10588235294117647, 0.49019607843137253),
+ (0.87058823529411766, 0.46666666666666667, 0.68235294117647061),
+ (0.94509803921568625, 0.71372549019607845, 0.85490196078431369),
+ (0.99215686274509807, 0.8784313725490196 , 0.93725490196078431),
+ (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
+ (0.90196078431372551, 0.96078431372549022, 0.81568627450980391),
+ (0.72156862745098038, 0.88235294117647056, 0.52549019607843139),
+ (0.49803921568627452, 0.73725490196078436, 0.25490196078431371),
+ (0.30196078431372547, 0.5725490196078431 , 0.12941176470588237),
+ (0.15294117647058825, 0.39215686274509803, 0.09803921568627451)
+ )
+
+_PRGn_data = (
+ (0.25098039215686274, 0.0 , 0.29411764705882354),
+ (0.46274509803921571, 0.16470588235294117, 0.51372549019607838),
+ (0.6 , 0.4392156862745098 , 0.6705882352941176 ),
+ (0.76078431372549016, 0.6470588235294118 , 0.81176470588235294),
+ (0.90588235294117647, 0.83137254901960789, 0.90980392156862744),
+ (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
+ (0.85098039215686272, 0.94117647058823528, 0.82745098039215681),
+ (0.65098039215686276, 0.85882352941176465, 0.62745098039215685),
+ (0.35294117647058826, 0.68235294117647061, 0.38039215686274508),
+ (0.10588235294117647, 0.47058823529411764, 0.21568627450980393),
+ (0.0 , 0.26666666666666666, 0.10588235294117647)
+ )
+
+_PuBu_data = (
+ (1.0 , 0.96862745098039216, 0.98431372549019602),
+ (0.92549019607843142, 0.90588235294117647, 0.94901960784313721),
+ (0.81568627450980391, 0.81960784313725488, 0.90196078431372551),
+ (0.65098039215686276, 0.74117647058823533, 0.85882352941176465),
+ (0.45490196078431372, 0.66274509803921566, 0.81176470588235294),
+ (0.21176470588235294, 0.56470588235294117, 0.75294117647058822),
+ (0.0196078431372549 , 0.4392156862745098 , 0.69019607843137254),
+ (0.01568627450980392, 0.35294117647058826, 0.55294117647058827),
+ (0.00784313725490196, 0.2196078431372549 , 0.34509803921568627)
+ )
+
+_PuBuGn_data = (
+ (1.0 , 0.96862745098039216, 0.98431372549019602),
+ (0.92549019607843142, 0.88627450980392153, 0.94117647058823528),
+ (0.81568627450980391, 0.81960784313725488, 0.90196078431372551),
+ (0.65098039215686276, 0.74117647058823533, 0.85882352941176465),
+ (0.40392156862745099, 0.66274509803921566, 0.81176470588235294),
+ (0.21176470588235294, 0.56470588235294117, 0.75294117647058822),
+ (0.00784313725490196, 0.50588235294117645, 0.54117647058823526),
+ (0.00392156862745098, 0.42352941176470588, 0.34901960784313724),
+ (0.00392156862745098, 0.27450980392156865, 0.21176470588235294)
+ )
+
+_PuOr_data = (
+ (0.49803921568627452, 0.23137254901960785, 0.03137254901960784),
+ (0.70196078431372544, 0.34509803921568627, 0.02352941176470588),
+ (0.8784313725490196 , 0.50980392156862742, 0.07843137254901961),
+ (0.99215686274509807, 0.72156862745098038, 0.38823529411764707),
+ (0.99607843137254903, 0.8784313725490196 , 0.71372549019607845),
+ (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
+ (0.84705882352941175, 0.85490196078431369, 0.92156862745098034),
+ (0.69803921568627447, 0.6705882352941176 , 0.82352941176470584),
+ (0.50196078431372548, 0.45098039215686275, 0.67450980392156867),
+ (0.32941176470588235, 0.15294117647058825, 0.53333333333333333),
+ (0.17647058823529413, 0.0 , 0.29411764705882354)
+ )
+
+_PuRd_data = (
+ (0.96862745098039216, 0.95686274509803926, 0.97647058823529409),
+ (0.90588235294117647, 0.88235294117647056, 0.93725490196078431),
+ (0.83137254901960789, 0.72549019607843135, 0.85490196078431369),
+ (0.78823529411764703, 0.58039215686274515, 0.7803921568627451 ),
+ (0.87450980392156863, 0.396078431372549 , 0.69019607843137254),
+ (0.90588235294117647, 0.16078431372549021, 0.54117647058823526),
+ (0.80784313725490198, 0.07058823529411765, 0.33725490196078434),
+ (0.59607843137254901, 0.0 , 0.2627450980392157 ),
+ (0.40392156862745099, 0.0 , 0.12156862745098039)
+ )
+
+_Purples_data = (
+ (0.9882352941176471 , 0.98431372549019602, 0.99215686274509807),
+ (0.93725490196078431, 0.92941176470588238, 0.96078431372549022),
+ (0.85490196078431369, 0.85490196078431369, 0.92156862745098034),
+ (0.73725490196078436, 0.74117647058823533, 0.86274509803921573),
+ (0.61960784313725492, 0.60392156862745094, 0.78431372549019607),
+ (0.50196078431372548, 0.49019607843137253, 0.72941176470588232),
+ (0.41568627450980394, 0.31764705882352939, 0.63921568627450975),
+ (0.32941176470588235, 0.15294117647058825, 0.5607843137254902 ),
+ (0.24705882352941178, 0.0 , 0.49019607843137253)
+ )
+
+_RdBu_data = (
+ (0.40392156862745099, 0.0 , 0.12156862745098039),
+ (0.69803921568627447, 0.09411764705882353, 0.16862745098039217),
+ (0.83921568627450982, 0.37647058823529411, 0.30196078431372547),
+ (0.95686274509803926, 0.6470588235294118 , 0.50980392156862742),
+ (0.99215686274509807, 0.85882352941176465, 0.7803921568627451 ),
+ (0.96862745098039216, 0.96862745098039216, 0.96862745098039216),
+ (0.81960784313725488, 0.89803921568627454, 0.94117647058823528),
+ (0.5725490196078431 , 0.77254901960784317, 0.87058823529411766),
+ (0.2627450980392157 , 0.57647058823529407, 0.76470588235294112),
+ (0.12941176470588237, 0.4 , 0.67450980392156867),
+ (0.0196078431372549 , 0.18823529411764706, 0.38039215686274508)
+ )
+
+_RdGy_data = (
+ (0.40392156862745099, 0.0 , 0.12156862745098039),
+ (0.69803921568627447, 0.09411764705882353, 0.16862745098039217),
+ (0.83921568627450982, 0.37647058823529411, 0.30196078431372547),
+ (0.95686274509803926, 0.6470588235294118 , 0.50980392156862742),
+ (0.99215686274509807, 0.85882352941176465, 0.7803921568627451 ),
+ (1.0 , 1.0 , 1.0 ),
+ (0.8784313725490196 , 0.8784313725490196 , 0.8784313725490196 ),
+ (0.72941176470588232, 0.72941176470588232, 0.72941176470588232),
+ (0.52941176470588236, 0.52941176470588236, 0.52941176470588236),
+ (0.30196078431372547, 0.30196078431372547, 0.30196078431372547),
+ (0.10196078431372549, 0.10196078431372549, 0.10196078431372549)
+ )
+
+_RdPu_data = (
+ (1.0 , 0.96862745098039216, 0.95294117647058818),
+ (0.99215686274509807, 0.8784313725490196 , 0.86666666666666667),
+ (0.9882352941176471 , 0.77254901960784317, 0.75294117647058822),
+ (0.98039215686274506, 0.62352941176470589, 0.70980392156862748),
+ (0.96862745098039216, 0.40784313725490196, 0.63137254901960782),
+ (0.86666666666666667, 0.20392156862745098, 0.59215686274509804),
+ (0.68235294117647061, 0.00392156862745098, 0.49411764705882355),
+ (0.47843137254901963, 0.00392156862745098, 0.46666666666666667),
+ (0.28627450980392155, 0.0 , 0.41568627450980394)
+ )
+
+_RdYlBu_data = (
+ (0.6470588235294118 , 0.0 , 0.14901960784313725),
+ (0.84313725490196079, 0.18823529411764706 , 0.15294117647058825),
+ (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ),
+ (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508),
+ (0.99607843137254903, 0.8784313725490196 , 0.56470588235294117),
+ (1.0 , 1.0 , 0.74901960784313726),
+ (0.8784313725490196 , 0.95294117647058818 , 0.97254901960784312),
+ (0.6705882352941176 , 0.85098039215686272 , 0.9137254901960784 ),
+ (0.45490196078431372, 0.67843137254901964 , 0.81960784313725488),
+ (0.27058823529411763, 0.45882352941176469 , 0.70588235294117652),
+ (0.19215686274509805, 0.21176470588235294 , 0.58431372549019611)
+ )
+
+_RdYlGn_data = (
+ (0.6470588235294118 , 0.0 , 0.14901960784313725),
+ (0.84313725490196079, 0.18823529411764706 , 0.15294117647058825),
+ (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ),
+ (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508),
+ (0.99607843137254903, 0.8784313725490196 , 0.54509803921568623),
+ (1.0 , 1.0 , 0.74901960784313726),
+ (0.85098039215686272, 0.93725490196078431 , 0.54509803921568623),
+ (0.65098039215686276, 0.85098039215686272 , 0.41568627450980394),
+ (0.4 , 0.74117647058823533 , 0.38823529411764707),
+ (0.10196078431372549, 0.59607843137254901 , 0.31372549019607843),
+ (0.0 , 0.40784313725490196 , 0.21568627450980393)
+ )
+
+_Reds_data = (
+ (1.0 , 0.96078431372549022 , 0.94117647058823528),
+ (0.99607843137254903, 0.8784313725490196 , 0.82352941176470584),
+ (0.9882352941176471 , 0.73333333333333328 , 0.63137254901960782),
+ (0.9882352941176471 , 0.5725490196078431 , 0.44705882352941179),
+ (0.98431372549019602, 0.41568627450980394 , 0.29019607843137257),
+ (0.93725490196078431, 0.23137254901960785 , 0.17254901960784313),
+ (0.79607843137254897, 0.094117647058823528, 0.11372549019607843),
+ (0.6470588235294118 , 0.058823529411764705, 0.08235294117647058),
+ (0.40392156862745099, 0.0 , 0.05098039215686274)
+ )
+
+_Spectral_data = (
+ (0.61960784313725492, 0.003921568627450980, 0.25882352941176473),
+ (0.83529411764705885, 0.24313725490196078 , 0.30980392156862746),
+ (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ),
+ (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508),
+ (0.99607843137254903, 0.8784313725490196 , 0.54509803921568623),
+ (1.0 , 1.0 , 0.74901960784313726),
+ (0.90196078431372551, 0.96078431372549022 , 0.59607843137254901),
+ (0.6705882352941176 , 0.8666666666666667 , 0.64313725490196083),
+ (0.4 , 0.76078431372549016 , 0.6470588235294118 ),
+ (0.19607843137254902, 0.53333333333333333 , 0.74117647058823533),
+ (0.36862745098039218, 0.30980392156862746 , 0.63529411764705879)
+ )
+
+_YlGn_data = (
+ (1.0 , 1.0 , 0.89803921568627454),
+ (0.96862745098039216, 0.9882352941176471 , 0.72549019607843135),
+ (0.85098039215686272, 0.94117647058823528 , 0.63921568627450975),
+ (0.67843137254901964, 0.8666666666666667 , 0.55686274509803924),
+ (0.47058823529411764, 0.77647058823529413 , 0.47450980392156861),
+ (0.25490196078431371, 0.6705882352941176 , 0.36470588235294116),
+ (0.13725490196078433, 0.51764705882352946 , 0.2627450980392157 ),
+ (0.0 , 0.40784313725490196 , 0.21568627450980393),
+ (0.0 , 0.27058823529411763 , 0.16078431372549021)
+ )
+
+_YlGnBu_data = (
+ (1.0 , 1.0 , 0.85098039215686272),
+ (0.92941176470588238, 0.97254901960784312 , 0.69411764705882351),
+ (0.7803921568627451 , 0.9137254901960784 , 0.70588235294117652),
+ (0.49803921568627452, 0.80392156862745101 , 0.73333333333333328),
+ (0.25490196078431371, 0.71372549019607845 , 0.7686274509803922 ),
+ (0.11372549019607843, 0.56862745098039214 , 0.75294117647058822),
+ (0.13333333333333333, 0.36862745098039218 , 0.6588235294117647 ),
+ (0.14509803921568629, 0.20392156862745098 , 0.58039215686274515),
+ (0.03137254901960784, 0.11372549019607843 , 0.34509803921568627)
+ )
+
+_YlOrBr_data = (
+ (1.0 , 1.0 , 0.89803921568627454),
+ (1.0 , 0.96862745098039216 , 0.73725490196078436),
+ (0.99607843137254903, 0.8901960784313725 , 0.56862745098039214),
+ (0.99607843137254903, 0.7686274509803922 , 0.30980392156862746),
+ (0.99607843137254903, 0.6 , 0.16078431372549021),
+ (0.92549019607843142, 0.4392156862745098 , 0.07843137254901961),
+ (0.8 , 0.29803921568627451 , 0.00784313725490196),
+ (0.6 , 0.20392156862745098 , 0.01568627450980392),
+ (0.4 , 0.14509803921568629 , 0.02352941176470588)
+ )
+
+_YlOrRd_data = (
+ (1.0 , 1.0 , 0.8 ),
+ (1.0 , 0.92941176470588238 , 0.62745098039215685),
+ (0.99607843137254903, 0.85098039215686272 , 0.46274509803921571),
+ (0.99607843137254903, 0.69803921568627447 , 0.29803921568627451),
+ (0.99215686274509807, 0.55294117647058827 , 0.23529411764705882),
+ (0.9882352941176471 , 0.30588235294117649 , 0.16470588235294117),
+ (0.8901960784313725 , 0.10196078431372549 , 0.10980392156862745),
+ (0.74117647058823533, 0.0 , 0.14901960784313725),
+ (0.50196078431372548, 0.0 , 0.14901960784313725)
+ )
+
+
+# ColorBrewer's qualitative maps, implemented using ListedColormap
+# for use with mpl.colors.NoNorm
+
+_Accent_data = (
+ (0.49803921568627452, 0.78823529411764703, 0.49803921568627452),
+ (0.74509803921568629, 0.68235294117647061, 0.83137254901960789),
+ (0.99215686274509807, 0.75294117647058822, 0.52549019607843139),
+ (1.0, 1.0, 0.6 ),
+ (0.2196078431372549, 0.42352941176470588, 0.69019607843137254),
+ (0.94117647058823528, 0.00784313725490196, 0.49803921568627452),
+ (0.74901960784313726, 0.35686274509803922, 0.09019607843137254),
+ (0.4, 0.4, 0.4 ),
+ )
+
+_Dark2_data = (
+ (0.10588235294117647, 0.61960784313725492, 0.46666666666666667),
+ (0.85098039215686272, 0.37254901960784315, 0.00784313725490196),
+ (0.45882352941176469, 0.4392156862745098, 0.70196078431372544),
+ (0.90588235294117647, 0.16078431372549021, 0.54117647058823526),
+ (0.4, 0.65098039215686276, 0.11764705882352941),
+ (0.90196078431372551, 0.6705882352941176, 0.00784313725490196),
+ (0.65098039215686276, 0.46274509803921571, 0.11372549019607843),
+ (0.4, 0.4, 0.4 ),
+ )
+
+_Paired_data = (
+ (0.65098039215686276, 0.80784313725490198, 0.8901960784313725 ),
+ (0.12156862745098039, 0.47058823529411764, 0.70588235294117652),
+ (0.69803921568627447, 0.87450980392156863, 0.54117647058823526),
+ (0.2, 0.62745098039215685, 0.17254901960784313),
+ (0.98431372549019602, 0.60392156862745094, 0.6 ),
+ (0.8901960784313725, 0.10196078431372549, 0.10980392156862745),
+ (0.99215686274509807, 0.74901960784313726, 0.43529411764705883),
+ (1.0, 0.49803921568627452, 0.0 ),
+ (0.792156862745098, 0.69803921568627447, 0.83921568627450982),
+ (0.41568627450980394, 0.23921568627450981, 0.60392156862745094),
+ (1.0, 1.0, 0.6 ),
+ (0.69411764705882351, 0.34901960784313724, 0.15686274509803921),
+ )
+
+_Pastel1_data = (
+ (0.98431372549019602, 0.70588235294117652, 0.68235294117647061),
+ (0.70196078431372544, 0.80392156862745101, 0.8901960784313725 ),
+ (0.8, 0.92156862745098034, 0.77254901960784317),
+ (0.87058823529411766, 0.79607843137254897, 0.89411764705882357),
+ (0.99607843137254903, 0.85098039215686272, 0.65098039215686276),
+ (1.0, 1.0, 0.8 ),
+ (0.89803921568627454, 0.84705882352941175, 0.74117647058823533),
+ (0.99215686274509807, 0.85490196078431369, 0.92549019607843142),
+ (0.94901960784313721, 0.94901960784313721, 0.94901960784313721),
+ )
+
+_Pastel2_data = (
+ (0.70196078431372544, 0.88627450980392153, 0.80392156862745101),
+ (0.99215686274509807, 0.80392156862745101, 0.67450980392156867),
+ (0.79607843137254897, 0.83529411764705885, 0.90980392156862744),
+ (0.95686274509803926, 0.792156862745098, 0.89411764705882357),
+ (0.90196078431372551, 0.96078431372549022, 0.78823529411764703),
+ (1.0, 0.94901960784313721, 0.68235294117647061),
+ (0.94509803921568625, 0.88627450980392153, 0.8 ),
+ (0.8, 0.8, 0.8 ),
+ )
+
+_Set1_data = (
+ (0.89411764705882357, 0.10196078431372549, 0.10980392156862745),
+ (0.21568627450980393, 0.49411764705882355, 0.72156862745098038),
+ (0.30196078431372547, 0.68627450980392157, 0.29019607843137257),
+ (0.59607843137254901, 0.30588235294117649, 0.63921568627450975),
+ (1.0, 0.49803921568627452, 0.0 ),
+ (1.0, 1.0, 0.2 ),
+ (0.65098039215686276, 0.33725490196078434, 0.15686274509803921),
+ (0.96862745098039216, 0.50588235294117645, 0.74901960784313726),
+ (0.6, 0.6, 0.6),
+ )
+
+_Set2_data = (
+ (0.4, 0.76078431372549016, 0.6470588235294118 ),
+ (0.9882352941176471, 0.55294117647058827, 0.3843137254901961 ),
+ (0.55294117647058827, 0.62745098039215685, 0.79607843137254897),
+ (0.90588235294117647, 0.54117647058823526, 0.76470588235294112),
+ (0.65098039215686276, 0.84705882352941175, 0.32941176470588235),
+ (1.0, 0.85098039215686272, 0.18431372549019609),
+ (0.89803921568627454, 0.7686274509803922, 0.58039215686274515),
+ (0.70196078431372544, 0.70196078431372544, 0.70196078431372544),
+ )
+
+_Set3_data = (
+ (0.55294117647058827, 0.82745098039215681, 0.7803921568627451 ),
+ (1.0, 1.0, 0.70196078431372544),
+ (0.74509803921568629, 0.72941176470588232, 0.85490196078431369),
+ (0.98431372549019602, 0.50196078431372548, 0.44705882352941179),
+ (0.50196078431372548, 0.69411764705882351, 0.82745098039215681),
+ (0.99215686274509807, 0.70588235294117652, 0.3843137254901961 ),
+ (0.70196078431372544, 0.87058823529411766, 0.41176470588235292),
+ (0.9882352941176471, 0.80392156862745101, 0.89803921568627454),
+ (0.85098039215686272, 0.85098039215686272, 0.85098039215686272),
+ (0.73725490196078436, 0.50196078431372548, 0.74117647058823533),
+ (0.8, 0.92156862745098034, 0.77254901960784317),
+ (1.0, 0.92941176470588238, 0.43529411764705883),
+ )
+
+
+# The next 7 palettes are from the Yorick scientific visualization package,
+# an evolution of the GIST package, both by David H. Munro.
+# They are released under a BSD-like license (see LICENSE_YORICK in
+# the license directory of the matplotlib source distribution).
+#
+# Most palette functions have been reduced to simple function descriptions
+# by Reinier Heeres, since the rgb components were mostly straight lines.
+# gist_earth_data and gist_ncar_data were simplified by a script and some
+# manual effort.
+
+_gist_earth_data = {
+ 'red': (
+ (0.0, 0.0, 0.0000),
+ (0.2824, 0.1882, 0.1882),
+ (0.4588, 0.2714, 0.2714),
+ (0.5490, 0.4719, 0.4719),
+ (0.6980, 0.7176, 0.7176),
+ (0.7882, 0.7553, 0.7553),
+ (1.0000, 0.9922, 0.9922),
+ ),
+ 'green': (
+ (0.0, 0.0, 0.0000),
+ (0.0275, 0.0000, 0.0000),
+ (0.1098, 0.1893, 0.1893),
+ (0.1647, 0.3035, 0.3035),
+ (0.2078, 0.3841, 0.3841),
+ (0.2824, 0.5020, 0.5020),
+ (0.5216, 0.6397, 0.6397),
+ (0.6980, 0.7171, 0.7171),
+ (0.7882, 0.6392, 0.6392),
+ (0.7922, 0.6413, 0.6413),
+ (0.8000, 0.6447, 0.6447),
+ (0.8078, 0.6481, 0.6481),
+ (0.8157, 0.6549, 0.6549),
+ (0.8667, 0.6991, 0.6991),
+ (0.8745, 0.7103, 0.7103),
+ (0.8824, 0.7216, 0.7216),
+ (0.8902, 0.7323, 0.7323),
+ (0.8980, 0.7430, 0.7430),
+ (0.9412, 0.8275, 0.8275),
+ (0.9569, 0.8635, 0.8635),
+ (0.9647, 0.8816, 0.8816),
+ (0.9961, 0.9733, 0.9733),
+ (1.0000, 0.9843, 0.9843),
+ ),
+ 'blue': (
+ (0.0, 0.0, 0.0000),
+ (0.0039, 0.1684, 0.1684),
+ (0.0078, 0.2212, 0.2212),
+ (0.0275, 0.4329, 0.4329),
+ (0.0314, 0.4549, 0.4549),
+ (0.2824, 0.5004, 0.5004),
+ (0.4667, 0.2748, 0.2748),
+ (0.5451, 0.3205, 0.3205),
+ (0.7843, 0.3961, 0.3961),
+ (0.8941, 0.6651, 0.6651),
+ (1.0000, 0.9843, 0.9843),
+ )
+}
+
+_gist_gray_data = {
+ 'red': gfunc[3],
+ 'green': gfunc[3],
+ 'blue': gfunc[3],
+}
+
+def _gist_heat_red(x): return 1.5 * x
+def _gist_heat_green(x): return 2 * x - 1
+def _gist_heat_blue(x): return 4 * x - 3
+_gist_heat_data = {
+ 'red': _gist_heat_red, 'green': _gist_heat_green, 'blue': _gist_heat_blue}
+
+_gist_ncar_data = {
+ 'red': (
+ (0.0, 0.0, 0.0000),
+ (0.3098, 0.0000, 0.0000),
+ (0.3725, 0.3993, 0.3993),
+ (0.4235, 0.5003, 0.5003),
+ (0.5333, 1.0000, 1.0000),
+ (0.7922, 1.0000, 1.0000),
+ (0.8471, 0.6218, 0.6218),
+ (0.8980, 0.9235, 0.9235),
+ (1.0000, 0.9961, 0.9961),
+ ),
+ 'green': (
+ (0.0, 0.0, 0.0000),
+ (0.0510, 0.3722, 0.3722),
+ (0.1059, 0.0000, 0.0000),
+ (0.1569, 0.7202, 0.7202),
+ (0.1608, 0.7537, 0.7537),
+ (0.1647, 0.7752, 0.7752),
+ (0.2157, 1.0000, 1.0000),
+ (0.2588, 0.9804, 0.9804),
+ (0.2706, 0.9804, 0.9804),
+ (0.3176, 1.0000, 1.0000),
+ (0.3686, 0.8081, 0.8081),
+ (0.4275, 1.0000, 1.0000),
+ (0.5216, 1.0000, 1.0000),
+ (0.6314, 0.7292, 0.7292),
+ (0.6863, 0.2796, 0.2796),
+ (0.7451, 0.0000, 0.0000),
+ (0.7922, 0.0000, 0.0000),
+ (0.8431, 0.1753, 0.1753),
+ (0.8980, 0.5000, 0.5000),
+ (1.0000, 0.9725, 0.9725),
+ ),
+ 'blue': (
+ (0.0, 0.5020, 0.5020),
+ (0.0510, 0.0222, 0.0222),
+ (0.1098, 1.0000, 1.0000),
+ (0.2039, 1.0000, 1.0000),
+ (0.2627, 0.6145, 0.6145),
+ (0.3216, 0.0000, 0.0000),
+ (0.4157, 0.0000, 0.0000),
+ (0.4745, 0.2342, 0.2342),
+ (0.5333, 0.0000, 0.0000),
+ (0.5804, 0.0000, 0.0000),
+ (0.6314, 0.0549, 0.0549),
+ (0.6902, 0.0000, 0.0000),
+ (0.7373, 0.0000, 0.0000),
+ (0.7922, 0.9738, 0.9738),
+ (0.8000, 1.0000, 1.0000),
+ (0.8431, 1.0000, 1.0000),
+ (0.8980, 0.9341, 0.9341),
+ (1.0000, 0.9961, 0.9961),
+ )
+}
+
+_gist_rainbow_data = (
+ (0.000, (1.00, 0.00, 0.16)),
+ (0.030, (1.00, 0.00, 0.00)),
+ (0.215, (1.00, 1.00, 0.00)),
+ (0.400, (0.00, 1.00, 0.00)),
+ (0.586, (0.00, 1.00, 1.00)),
+ (0.770, (0.00, 0.00, 1.00)),
+ (0.954, (1.00, 0.00, 1.00)),
+ (1.000, (1.00, 0.00, 0.75))
+)
+
+_gist_stern_data = {
+ 'red': (
+ (0.000, 0.000, 0.000), (0.0547, 1.000, 1.000),
+ (0.250, 0.027, 0.250), # (0.2500, 0.250, 0.250),
+ (1.000, 1.000, 1.000)),
+ 'green': ((0, 0, 0), (1, 1, 1)),
+ 'blue': (
+ (0.000, 0.000, 0.000), (0.500, 1.000, 1.000),
+ (0.735, 0.000, 0.000), (1.000, 1.000, 1.000))
+}
+
+def _gist_yarg(x): return 1 - x
+_gist_yarg_data = {'red': _gist_yarg, 'green': _gist_yarg, 'blue': _gist_yarg}
+
+# This bipolar colormap was generated from CoolWarmFloat33.csv of
+# "Diverging Color Maps for Scientific Visualization" by Kenneth Moreland.
+#
+_coolwarm_data = {
+ 'red': [
+ (0.0, 0.2298057, 0.2298057),
+ (0.03125, 0.26623388, 0.26623388),
+ (0.0625, 0.30386891, 0.30386891),
+ (0.09375, 0.342804478, 0.342804478),
+ (0.125, 0.38301334, 0.38301334),
+ (0.15625, 0.424369608, 0.424369608),
+ (0.1875, 0.46666708, 0.46666708),
+ (0.21875, 0.509635204, 0.509635204),
+ (0.25, 0.552953156, 0.552953156),
+ (0.28125, 0.596262162, 0.596262162),
+ (0.3125, 0.639176211, 0.639176211),
+ (0.34375, 0.681291281, 0.681291281),
+ (0.375, 0.722193294, 0.722193294),
+ (0.40625, 0.761464949, 0.761464949),
+ (0.4375, 0.798691636, 0.798691636),
+ (0.46875, 0.833466556, 0.833466556),
+ (0.5, 0.865395197, 0.865395197),
+ (0.53125, 0.897787179, 0.897787179),
+ (0.5625, 0.924127593, 0.924127593),
+ (0.59375, 0.944468518, 0.944468518),
+ (0.625, 0.958852946, 0.958852946),
+ (0.65625, 0.96732803, 0.96732803),
+ (0.6875, 0.969954137, 0.969954137),
+ (0.71875, 0.966811177, 0.966811177),
+ (0.75, 0.958003065, 0.958003065),
+ (0.78125, 0.943660866, 0.943660866),
+ (0.8125, 0.923944917, 0.923944917),
+ (0.84375, 0.89904617, 0.89904617),
+ (0.875, 0.869186849, 0.869186849),
+ (0.90625, 0.834620542, 0.834620542),
+ (0.9375, 0.795631745, 0.795631745),
+ (0.96875, 0.752534934, 0.752534934),
+ (1.0, 0.705673158, 0.705673158)],
+ 'green': [
+ (0.0, 0.298717966, 0.298717966),
+ (0.03125, 0.353094838, 0.353094838),
+ (0.0625, 0.406535296, 0.406535296),
+ (0.09375, 0.458757618, 0.458757618),
+ (0.125, 0.50941904, 0.50941904),
+ (0.15625, 0.558148092, 0.558148092),
+ (0.1875, 0.604562568, 0.604562568),
+ (0.21875, 0.648280772, 0.648280772),
+ (0.25, 0.688929332, 0.688929332),
+ (0.28125, 0.726149107, 0.726149107),
+ (0.3125, 0.759599947, 0.759599947),
+ (0.34375, 0.788964712, 0.788964712),
+ (0.375, 0.813952739, 0.813952739),
+ (0.40625, 0.834302879, 0.834302879),
+ (0.4375, 0.849786142, 0.849786142),
+ (0.46875, 0.860207984, 0.860207984),
+ (0.5, 0.86541021, 0.86541021),
+ (0.53125, 0.848937047, 0.848937047),
+ (0.5625, 0.827384882, 0.827384882),
+ (0.59375, 0.800927443, 0.800927443),
+ (0.625, 0.769767752, 0.769767752),
+ (0.65625, 0.734132809, 0.734132809),
+ (0.6875, 0.694266682, 0.694266682),
+ (0.71875, 0.650421156, 0.650421156),
+ (0.75, 0.602842431, 0.602842431),
+ (0.78125, 0.551750968, 0.551750968),
+ (0.8125, 0.49730856, 0.49730856),
+ (0.84375, 0.439559467, 0.439559467),
+ (0.875, 0.378313092, 0.378313092),
+ (0.90625, 0.312874446, 0.312874446),
+ (0.9375, 0.24128379, 0.24128379),
+ (0.96875, 0.157246067, 0.157246067),
+ (1.0, 0.01555616, 0.01555616)],
+ 'blue': [
+ (0.0, 0.753683153, 0.753683153),
+ (0.03125, 0.801466763, 0.801466763),
+ (0.0625, 0.84495867, 0.84495867),
+ (0.09375, 0.883725899, 0.883725899),
+ (0.125, 0.917387822, 0.917387822),
+ (0.15625, 0.945619588, 0.945619588),
+ (0.1875, 0.968154911, 0.968154911),
+ (0.21875, 0.98478814, 0.98478814),
+ (0.25, 0.995375608, 0.995375608),
+ (0.28125, 0.999836203, 0.999836203),
+ (0.3125, 0.998151185, 0.998151185),
+ (0.34375, 0.990363227, 0.990363227),
+ (0.375, 0.976574709, 0.976574709),
+ (0.40625, 0.956945269, 0.956945269),
+ (0.4375, 0.931688648, 0.931688648),
+ (0.46875, 0.901068838, 0.901068838),
+ (0.5, 0.865395561, 0.865395561),
+ (0.53125, 0.820880546, 0.820880546),
+ (0.5625, 0.774508472, 0.774508472),
+ (0.59375, 0.726736146, 0.726736146),
+ (0.625, 0.678007945, 0.678007945),
+ (0.65625, 0.628751763, 0.628751763),
+ (0.6875, 0.579375448, 0.579375448),
+ (0.71875, 0.530263762, 0.530263762),
+ (0.75, 0.481775914, 0.481775914),
+ (0.78125, 0.434243684, 0.434243684),
+ (0.8125, 0.387970225, 0.387970225),
+ (0.84375, 0.343229596, 0.343229596),
+ (0.875, 0.300267182, 0.300267182),
+ (0.90625, 0.259301199, 0.259301199),
+ (0.9375, 0.220525627, 0.220525627),
+ (0.96875, 0.184115123, 0.184115123),
+ (1.0, 0.150232812, 0.150232812)]
+ }
+
+# Implementation of Carey Rappaport's CMRmap.
+# See `A Color Map for Effective Black-and-White Rendering of Color-Scale
+# Images' by Carey Rappaport
+# https://www.mathworks.com/matlabcentral/fileexchange/2662-cmrmap-m
+_CMRmap_data = {'red': ((0.000, 0.00, 0.00),
+ (0.125, 0.15, 0.15),
+ (0.250, 0.30, 0.30),
+ (0.375, 0.60, 0.60),
+ (0.500, 1.00, 1.00),
+ (0.625, 0.90, 0.90),
+ (0.750, 0.90, 0.90),
+ (0.875, 0.90, 0.90),
+ (1.000, 1.00, 1.00)),
+ 'green': ((0.000, 0.00, 0.00),
+ (0.125, 0.15, 0.15),
+ (0.250, 0.15, 0.15),
+ (0.375, 0.20, 0.20),
+ (0.500, 0.25, 0.25),
+ (0.625, 0.50, 0.50),
+ (0.750, 0.75, 0.75),
+ (0.875, 0.90, 0.90),
+ (1.000, 1.00, 1.00)),
+ 'blue': ((0.000, 0.00, 0.00),
+ (0.125, 0.50, 0.50),
+ (0.250, 0.75, 0.75),
+ (0.375, 0.50, 0.50),
+ (0.500, 0.15, 0.15),
+ (0.625, 0.00, 0.00),
+ (0.750, 0.10, 0.10),
+ (0.875, 0.50, 0.50),
+ (1.000, 1.00, 1.00))}
+
+
+# An MIT licensed, colorblind-friendly heatmap from Wistia:
+# https://github.com/wistia/heatmap-palette
+# https://wistia.com/learn/culture/heatmaps-for-colorblindness
+#
+# >>> import matplotlib.colors as c
+# >>> colors = ["#e4ff7a", "#ffe81a", "#ffbd00", "#ffa000", "#fc7f00"]
+# >>> cm = c.LinearSegmentedColormap.from_list('wistia', colors)
+# >>> _wistia_data = cm._segmentdata
+# >>> del _wistia_data['alpha']
+#
+_wistia_data = {
+ 'red': [(0.0, 0.8941176470588236, 0.8941176470588236),
+ (0.25, 1.0, 1.0),
+ (0.5, 1.0, 1.0),
+ (0.75, 1.0, 1.0),
+ (1.0, 0.9882352941176471, 0.9882352941176471)],
+ 'green': [(0.0, 1.0, 1.0),
+ (0.25, 0.9098039215686274, 0.9098039215686274),
+ (0.5, 0.7411764705882353, 0.7411764705882353),
+ (0.75, 0.6274509803921569, 0.6274509803921569),
+ (1.0, 0.4980392156862745, 0.4980392156862745)],
+ 'blue': [(0.0, 0.47843137254901963, 0.47843137254901963),
+ (0.25, 0.10196078431372549, 0.10196078431372549),
+ (0.5, 0.0, 0.0),
+ (0.75, 0.0, 0.0),
+ (1.0, 0.0, 0.0)],
+}
+
+
+# Categorical palettes from Vega:
+# https://github.com/vega/vega/wiki/Scales
+# (divided by 255)
+#
+
+_tab10_data = (
+ (0.12156862745098039, 0.4666666666666667, 0.7058823529411765 ), # 1f77b4
+ (1.0, 0.4980392156862745, 0.054901960784313725), # ff7f0e
+ (0.17254901960784313, 0.6274509803921569, 0.17254901960784313 ), # 2ca02c
+ (0.8392156862745098, 0.15294117647058825, 0.1568627450980392 ), # d62728
+ (0.5803921568627451, 0.403921568627451, 0.7411764705882353 ), # 9467bd
+ (0.5490196078431373, 0.33725490196078434, 0.29411764705882354 ), # 8c564b
+ (0.8901960784313725, 0.4666666666666667, 0.7607843137254902 ), # e377c2
+ (0.4980392156862745, 0.4980392156862745, 0.4980392156862745 ), # 7f7f7f
+ (0.7372549019607844, 0.7411764705882353, 0.13333333333333333 ), # bcbd22
+ (0.09019607843137255, 0.7450980392156863, 0.8117647058823529), # 17becf
+)
+
+_tab20_data = (
+ (0.12156862745098039, 0.4666666666666667, 0.7058823529411765 ), # 1f77b4
+ (0.6823529411764706, 0.7803921568627451, 0.9098039215686274 ), # aec7e8
+ (1.0, 0.4980392156862745, 0.054901960784313725), # ff7f0e
+ (1.0, 0.7333333333333333, 0.47058823529411764 ), # ffbb78
+ (0.17254901960784313, 0.6274509803921569, 0.17254901960784313 ), # 2ca02c
+ (0.596078431372549, 0.8745098039215686, 0.5411764705882353 ), # 98df8a
+ (0.8392156862745098, 0.15294117647058825, 0.1568627450980392 ), # d62728
+ (1.0, 0.596078431372549, 0.5882352941176471 ), # ff9896
+ (0.5803921568627451, 0.403921568627451, 0.7411764705882353 ), # 9467bd
+ (0.7725490196078432, 0.6901960784313725, 0.8352941176470589 ), # c5b0d5
+ (0.5490196078431373, 0.33725490196078434, 0.29411764705882354 ), # 8c564b
+ (0.7686274509803922, 0.611764705882353, 0.5803921568627451 ), # c49c94
+ (0.8901960784313725, 0.4666666666666667, 0.7607843137254902 ), # e377c2
+ (0.9686274509803922, 0.7137254901960784, 0.8235294117647058 ), # f7b6d2
+ (0.4980392156862745, 0.4980392156862745, 0.4980392156862745 ), # 7f7f7f
+ (0.7803921568627451, 0.7803921568627451, 0.7803921568627451 ), # c7c7c7
+ (0.7372549019607844, 0.7411764705882353, 0.13333333333333333 ), # bcbd22
+ (0.8588235294117647, 0.8588235294117647, 0.5529411764705883 ), # dbdb8d
+ (0.09019607843137255, 0.7450980392156863, 0.8117647058823529 ), # 17becf
+ (0.6196078431372549, 0.8549019607843137, 0.8980392156862745), # 9edae5
+)
+
+_tab20b_data = (
+ (0.2235294117647059, 0.23137254901960785, 0.4745098039215686 ), # 393b79
+ (0.3215686274509804, 0.32941176470588235, 0.6392156862745098 ), # 5254a3
+ (0.4196078431372549, 0.43137254901960786, 0.8117647058823529 ), # 6b6ecf
+ (0.611764705882353, 0.6196078431372549, 0.8705882352941177 ), # 9c9ede
+ (0.38823529411764707, 0.4745098039215686, 0.2235294117647059 ), # 637939
+ (0.5490196078431373, 0.6352941176470588, 0.3215686274509804 ), # 8ca252
+ (0.7098039215686275, 0.8117647058823529, 0.4196078431372549 ), # b5cf6b
+ (0.807843137254902, 0.8588235294117647, 0.611764705882353 ), # cedb9c
+ (0.5490196078431373, 0.42745098039215684, 0.19215686274509805), # 8c6d31
+ (0.7411764705882353, 0.6196078431372549, 0.2235294117647059 ), # bd9e39
+ (0.9058823529411765, 0.7294117647058823, 0.3215686274509804 ), # e7ba52
+ (0.9058823529411765, 0.796078431372549, 0.5803921568627451 ), # e7cb94
+ (0.5176470588235295, 0.23529411764705882, 0.2235294117647059 ), # 843c39
+ (0.6784313725490196, 0.28627450980392155, 0.2901960784313726 ), # ad494a
+ (0.8392156862745098, 0.3803921568627451, 0.4196078431372549 ), # d6616b
+ (0.9058823529411765, 0.5882352941176471, 0.611764705882353 ), # e7969c
+ (0.4823529411764706, 0.2549019607843137, 0.45098039215686275), # 7b4173
+ (0.6470588235294118, 0.3176470588235294, 0.5803921568627451 ), # a55194
+ (0.807843137254902, 0.42745098039215684, 0.7411764705882353 ), # ce6dbd
+ (0.8705882352941177, 0.6196078431372549, 0.8392156862745098 ), # de9ed6
+)
+
+_tab20c_data = (
+ (0.19215686274509805, 0.5098039215686274, 0.7411764705882353 ), # 3182bd
+ (0.4196078431372549, 0.6823529411764706, 0.8392156862745098 ), # 6baed6
+ (0.6196078431372549, 0.792156862745098, 0.8823529411764706 ), # 9ecae1
+ (0.7764705882352941, 0.8588235294117647, 0.9372549019607843 ), # c6dbef
+ (0.9019607843137255, 0.3333333333333333, 0.050980392156862744), # e6550d
+ (0.9921568627450981, 0.5529411764705883, 0.23529411764705882 ), # fd8d3c
+ (0.9921568627450981, 0.6823529411764706, 0.4196078431372549 ), # fdae6b
+ (0.9921568627450981, 0.8156862745098039, 0.6352941176470588 ), # fdd0a2
+ (0.19215686274509805, 0.6392156862745098, 0.32941176470588235 ), # 31a354
+ (0.4549019607843137, 0.7686274509803922, 0.4627450980392157 ), # 74c476
+ (0.6313725490196078, 0.8509803921568627, 0.6078431372549019 ), # a1d99b
+ (0.7803921568627451, 0.9137254901960784, 0.7529411764705882 ), # c7e9c0
+ (0.4588235294117647, 0.4196078431372549, 0.6941176470588235 ), # 756bb1
+ (0.6196078431372549, 0.6039215686274509, 0.7843137254901961 ), # 9e9ac8
+ (0.7372549019607844, 0.7411764705882353, 0.8627450980392157 ), # bcbddc
+ (0.8549019607843137, 0.8549019607843137, 0.9215686274509803 ), # dadaeb
+ (0.38823529411764707, 0.38823529411764707, 0.38823529411764707 ), # 636363
+ (0.5882352941176471, 0.5882352941176471, 0.5882352941176471 ), # 969696
+ (0.7411764705882353, 0.7411764705882353, 0.7411764705882353 ), # bdbdbd
+ (0.8509803921568627, 0.8509803921568627, 0.8509803921568627 ), # d9d9d9
+)
+
+
+_petroff10_data = (
+ (0.24705882352941178, 0.5647058823529412, 0.8549019607843137), # 3f90da
+ (1.0, 0.6627450980392157, 0.054901960784313725), # ffa90e
+ (0.7411764705882353, 0.12156862745098039, 0.00392156862745098), # bd1f01
+ (0.5803921568627451, 0.6431372549019608, 0.6352941176470588), # 94a4a2
+ (0.5137254901960784, 0.17647058823529413, 0.7137254901960784), # 832db6
+ (0.6627450980392157, 0.4196078431372549, 0.34901960784313724), # a96b59
+ (0.9058823529411765, 0.38823529411764707, 0.0), # e76300
+ (0.7254901960784313, 0.6745098039215687, 0.4392156862745098), # b9ac70
+ (0.44313725490196076, 0.4588235294117647, 0.5058823529411764), # 717581
+ (0.5725490196078431, 0.8549019607843137, 0.8666666666666667), # 92dadd
+)
+
+
+datad = {
+ 'Blues': _Blues_data,
+ 'BrBG': _BrBG_data,
+ 'BuGn': _BuGn_data,
+ 'BuPu': _BuPu_data,
+ 'CMRmap': _CMRmap_data,
+ 'GnBu': _GnBu_data,
+ 'Greens': _Greens_data,
+ 'Greys': _Greys_data,
+ 'OrRd': _OrRd_data,
+ 'Oranges': _Oranges_data,
+ 'PRGn': _PRGn_data,
+ 'PiYG': _PiYG_data,
+ 'PuBu': _PuBu_data,
+ 'PuBuGn': _PuBuGn_data,
+ 'PuOr': _PuOr_data,
+ 'PuRd': _PuRd_data,
+ 'Purples': _Purples_data,
+ 'RdBu': _RdBu_data,
+ 'RdGy': _RdGy_data,
+ 'RdPu': _RdPu_data,
+ 'RdYlBu': _RdYlBu_data,
+ 'RdYlGn': _RdYlGn_data,
+ 'Reds': _Reds_data,
+ 'Spectral': _Spectral_data,
+ 'Wistia': _wistia_data,
+ 'YlGn': _YlGn_data,
+ 'YlGnBu': _YlGnBu_data,
+ 'YlOrBr': _YlOrBr_data,
+ 'YlOrRd': _YlOrRd_data,
+ 'afmhot': _afmhot_data,
+ 'autumn': _autumn_data,
+ 'binary': _binary_data,
+ 'bone': _bone_data,
+ 'brg': _brg_data,
+ 'bwr': _bwr_data,
+ 'cool': _cool_data,
+ 'coolwarm': _coolwarm_data,
+ 'copper': _copper_data,
+ 'cubehelix': _cubehelix_data,
+ 'flag': _flag_data,
+ 'gist_earth': _gist_earth_data,
+ 'gist_gray': _gist_gray_data,
+ 'gist_heat': _gist_heat_data,
+ 'gist_ncar': _gist_ncar_data,
+ 'gist_rainbow': _gist_rainbow_data,
+ 'gist_stern': _gist_stern_data,
+ 'gist_yarg': _gist_yarg_data,
+ 'gnuplot': _gnuplot_data,
+ 'gnuplot2': _gnuplot2_data,
+ 'gray': _gray_data,
+ 'hot': _hot_data,
+ 'hsv': _hsv_data,
+ 'jet': _jet_data,
+ 'nipy_spectral': _nipy_spectral_data,
+ 'ocean': _ocean_data,
+ 'pink': _pink_data,
+ 'prism': _prism_data,
+ 'rainbow': _rainbow_data,
+ 'seismic': _seismic_data,
+ 'spring': _spring_data,
+ 'summer': _summer_data,
+ 'terrain': _terrain_data,
+ 'winter': _winter_data,
+ # Qualitative
+ 'Accent': {'listed': _Accent_data},
+ 'Dark2': {'listed': _Dark2_data},
+ 'Paired': {'listed': _Paired_data},
+ 'Pastel1': {'listed': _Pastel1_data},
+ 'Pastel2': {'listed': _Pastel2_data},
+ 'Set1': {'listed': _Set1_data},
+ 'Set2': {'listed': _Set2_data},
+ 'Set3': {'listed': _Set3_data},
+ 'tab10': {'listed': _tab10_data},
+ 'tab20': {'listed': _tab20_data},
+ 'tab20b': {'listed': _tab20b_data},
+ 'tab20c': {'listed': _tab20c_data},
+}
diff --git a/lib/python3.12/site-packages/matplotlib/_cm_bivar.py b/lib/python3.12/site-packages/matplotlib/_cm_bivar.py
new file mode 100644
index 0000000000000000000000000000000000000000..53c0d48d7d6c5d3818a33df783a284e11c16662d
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_cm_bivar.py
@@ -0,0 +1,1312 @@
+# auto-generated by https://github.com/trygvrad/multivariate_colormaps
+# date: 2024-05-24
+
+import numpy as np
+from matplotlib.colors import SegmentedBivarColormap
+
+BiPeak = np.array(
+ [0.000, 0.674, 0.931, 0.000, 0.680, 0.922, 0.000, 0.685, 0.914, 0.000,
+ 0.691, 0.906, 0.000, 0.696, 0.898, 0.000, 0.701, 0.890, 0.000, 0.706,
+ 0.882, 0.000, 0.711, 0.875, 0.000, 0.715, 0.867, 0.000, 0.720, 0.860,
+ 0.000, 0.725, 0.853, 0.000, 0.729, 0.845, 0.000, 0.733, 0.838, 0.000,
+ 0.737, 0.831, 0.000, 0.741, 0.824, 0.000, 0.745, 0.816, 0.000, 0.749,
+ 0.809, 0.000, 0.752, 0.802, 0.000, 0.756, 0.794, 0.000, 0.759, 0.787,
+ 0.000, 0.762, 0.779, 0.000, 0.765, 0.771, 0.000, 0.767, 0.764, 0.000,
+ 0.770, 0.755, 0.000, 0.772, 0.747, 0.000, 0.774, 0.739, 0.000, 0.776,
+ 0.730, 0.000, 0.777, 0.721, 0.000, 0.779, 0.712, 0.021, 0.780, 0.702,
+ 0.055, 0.781, 0.693, 0.079, 0.782, 0.682, 0.097, 0.782, 0.672, 0.111,
+ 0.782, 0.661, 0.122, 0.782, 0.650, 0.132, 0.782, 0.639, 0.140, 0.781,
+ 0.627, 0.147, 0.781, 0.615, 0.154, 0.780, 0.602, 0.159, 0.778, 0.589,
+ 0.164, 0.777, 0.576, 0.169, 0.775, 0.563, 0.173, 0.773, 0.549, 0.177,
+ 0.771, 0.535, 0.180, 0.768, 0.520, 0.184, 0.766, 0.505, 0.187, 0.763,
+ 0.490, 0.190, 0.760, 0.474, 0.193, 0.756, 0.458, 0.196, 0.753, 0.442,
+ 0.200, 0.749, 0.425, 0.203, 0.745, 0.408, 0.206, 0.741, 0.391, 0.210,
+ 0.736, 0.373, 0.213, 0.732, 0.355, 0.216, 0.727, 0.337, 0.220, 0.722,
+ 0.318, 0.224, 0.717, 0.298, 0.227, 0.712, 0.278, 0.231, 0.707, 0.258,
+ 0.235, 0.701, 0.236, 0.239, 0.696, 0.214, 0.242, 0.690, 0.190, 0.246,
+ 0.684, 0.165, 0.250, 0.678, 0.136, 0.000, 0.675, 0.934, 0.000, 0.681,
+ 0.925, 0.000, 0.687, 0.917, 0.000, 0.692, 0.909, 0.000, 0.697, 0.901,
+ 0.000, 0.703, 0.894, 0.000, 0.708, 0.886, 0.000, 0.713, 0.879, 0.000,
+ 0.718, 0.872, 0.000, 0.722, 0.864, 0.000, 0.727, 0.857, 0.000, 0.731,
+ 0.850, 0.000, 0.736, 0.843, 0.000, 0.740, 0.836, 0.000, 0.744, 0.829,
+ 0.000, 0.748, 0.822, 0.000, 0.752, 0.815, 0.000, 0.755, 0.808, 0.000,
+ 0.759, 0.800, 0.000, 0.762, 0.793, 0.000, 0.765, 0.786, 0.000, 0.768,
+ 0.778, 0.000, 0.771, 0.770, 0.000, 0.773, 0.762, 0.051, 0.776, 0.754,
+ 0.087, 0.778, 0.746, 0.111, 0.780, 0.737, 0.131, 0.782, 0.728, 0.146,
+ 0.783, 0.719, 0.159, 0.784, 0.710, 0.171, 0.785, 0.700, 0.180, 0.786,
+ 0.690, 0.189, 0.786, 0.680, 0.196, 0.787, 0.669, 0.202, 0.787, 0.658,
+ 0.208, 0.786, 0.647, 0.213, 0.786, 0.635, 0.217, 0.785, 0.623, 0.221,
+ 0.784, 0.610, 0.224, 0.782, 0.597, 0.227, 0.781, 0.584, 0.230, 0.779,
+ 0.570, 0.232, 0.777, 0.556, 0.234, 0.775, 0.542, 0.236, 0.772, 0.527,
+ 0.238, 0.769, 0.512, 0.240, 0.766, 0.497, 0.242, 0.763, 0.481, 0.244,
+ 0.760, 0.465, 0.246, 0.756, 0.448, 0.248, 0.752, 0.432, 0.250, 0.748,
+ 0.415, 0.252, 0.744, 0.397, 0.254, 0.739, 0.379, 0.256, 0.735, 0.361,
+ 0.259, 0.730, 0.343, 0.261, 0.725, 0.324, 0.264, 0.720, 0.304, 0.266,
+ 0.715, 0.284, 0.269, 0.709, 0.263, 0.271, 0.704, 0.242, 0.274, 0.698,
+ 0.220, 0.277, 0.692, 0.196, 0.280, 0.686, 0.170, 0.283, 0.680, 0.143,
+ 0.000, 0.676, 0.937, 0.000, 0.682, 0.928, 0.000, 0.688, 0.920, 0.000,
+ 0.694, 0.913, 0.000, 0.699, 0.905, 0.000, 0.704, 0.897, 0.000, 0.710,
+ 0.890, 0.000, 0.715, 0.883, 0.000, 0.720, 0.876, 0.000, 0.724, 0.869,
+ 0.000, 0.729, 0.862, 0.000, 0.734, 0.855, 0.000, 0.738, 0.848, 0.000,
+ 0.743, 0.841, 0.000, 0.747, 0.834, 0.000, 0.751, 0.827, 0.000, 0.755,
+ 0.820, 0.000, 0.759, 0.813, 0.000, 0.762, 0.806, 0.003, 0.766, 0.799,
+ 0.066, 0.769, 0.792, 0.104, 0.772, 0.784, 0.131, 0.775, 0.777, 0.152,
+ 0.777, 0.769, 0.170, 0.780, 0.761, 0.185, 0.782, 0.753, 0.198, 0.784,
+ 0.744, 0.209, 0.786, 0.736, 0.219, 0.787, 0.727, 0.228, 0.788, 0.717,
+ 0.236, 0.789, 0.708, 0.243, 0.790, 0.698, 0.249, 0.791, 0.688, 0.254,
+ 0.791, 0.677, 0.259, 0.791, 0.666, 0.263, 0.791, 0.654, 0.266, 0.790,
+ 0.643, 0.269, 0.789, 0.631, 0.272, 0.788, 0.618, 0.274, 0.787, 0.605,
+ 0.276, 0.785, 0.592, 0.278, 0.783, 0.578, 0.279, 0.781, 0.564, 0.280,
+ 0.779, 0.549, 0.282, 0.776, 0.535, 0.283, 0.773, 0.519, 0.284, 0.770,
+ 0.504, 0.285, 0.767, 0.488, 0.286, 0.763, 0.472, 0.287, 0.759, 0.455,
+ 0.288, 0.756, 0.438, 0.289, 0.751, 0.421, 0.291, 0.747, 0.403, 0.292,
+ 0.742, 0.385, 0.293, 0.738, 0.367, 0.295, 0.733, 0.348, 0.296, 0.728,
+ 0.329, 0.298, 0.723, 0.310, 0.300, 0.717, 0.290, 0.302, 0.712, 0.269,
+ 0.304, 0.706, 0.247, 0.306, 0.700, 0.225, 0.308, 0.694, 0.201, 0.310,
+ 0.688, 0.176, 0.312, 0.682, 0.149, 0.000, 0.678, 0.939, 0.000, 0.683,
+ 0.931, 0.000, 0.689, 0.923, 0.000, 0.695, 0.916, 0.000, 0.701, 0.908,
+ 0.000, 0.706, 0.901, 0.000, 0.711, 0.894, 0.000, 0.717, 0.887, 0.000,
+ 0.722, 0.880, 0.000, 0.727, 0.873, 0.000, 0.732, 0.866, 0.000, 0.736,
+ 0.859, 0.000, 0.741, 0.853, 0.000, 0.745, 0.846, 0.000, 0.750, 0.839,
+ 0.000, 0.754, 0.833, 0.035, 0.758, 0.826, 0.091, 0.762, 0.819, 0.126,
+ 0.765, 0.812, 0.153, 0.769, 0.805, 0.174, 0.772, 0.798, 0.193, 0.775,
+ 0.791, 0.209, 0.778, 0.783, 0.223, 0.781, 0.776, 0.236, 0.784, 0.768,
+ 0.247, 0.786, 0.760, 0.257, 0.788, 0.752, 0.266, 0.790, 0.743, 0.273,
+ 0.791, 0.734, 0.280, 0.793, 0.725, 0.287, 0.794, 0.715, 0.292, 0.794,
+ 0.706, 0.297, 0.795, 0.695, 0.301, 0.795, 0.685, 0.305, 0.795, 0.674,
+ 0.308, 0.795, 0.662, 0.310, 0.794, 0.651, 0.312, 0.794, 0.638, 0.314,
+ 0.792, 0.626, 0.316, 0.791, 0.613, 0.317, 0.789, 0.599, 0.318, 0.787,
+ 0.586, 0.319, 0.785, 0.571, 0.320, 0.783, 0.557, 0.320, 0.780, 0.542,
+ 0.321, 0.777, 0.527, 0.321, 0.774, 0.511, 0.322, 0.770, 0.495, 0.322,
+ 0.767, 0.478, 0.323, 0.763, 0.462, 0.323, 0.759, 0.445, 0.324, 0.755,
+ 0.427, 0.325, 0.750, 0.410, 0.325, 0.745, 0.391, 0.326, 0.741, 0.373,
+ 0.327, 0.736, 0.354, 0.328, 0.730, 0.335, 0.329, 0.725, 0.315, 0.330,
+ 0.720, 0.295, 0.331, 0.714, 0.274, 0.333, 0.708, 0.253, 0.334, 0.702,
+ 0.230, 0.336, 0.696, 0.207, 0.337, 0.690, 0.182, 0.339, 0.684, 0.154,
+ 0.000, 0.679, 0.942, 0.000, 0.685, 0.934, 0.000, 0.691, 0.927, 0.000,
+ 0.696, 0.919, 0.000, 0.702, 0.912, 0.000, 0.708, 0.905, 0.000, 0.713,
+ 0.898, 0.000, 0.718, 0.891, 0.000, 0.724, 0.884, 0.000, 0.729, 0.877,
+ 0.000, 0.734, 0.871, 0.000, 0.739, 0.864, 0.000, 0.743, 0.857, 0.035,
+ 0.748, 0.851, 0.096, 0.752, 0.844, 0.133, 0.757, 0.838, 0.161, 0.761,
+ 0.831, 0.185, 0.765, 0.825, 0.205, 0.769, 0.818, 0.223, 0.772, 0.811,
+ 0.238, 0.776, 0.804, 0.252, 0.779, 0.797, 0.265, 0.782, 0.790, 0.276,
+ 0.785, 0.783, 0.286, 0.788, 0.775, 0.296, 0.790, 0.767, 0.304, 0.792,
+ 0.759, 0.311, 0.794, 0.751, 0.318, 0.796, 0.742, 0.324, 0.797, 0.733,
+ 0.329, 0.798, 0.723, 0.334, 0.799, 0.714, 0.338, 0.799, 0.703, 0.341,
+ 0.800, 0.693, 0.344, 0.800, 0.682, 0.347, 0.799, 0.670, 0.349, 0.799,
+ 0.659, 0.351, 0.798, 0.646, 0.352, 0.797, 0.634, 0.353, 0.795, 0.621,
+ 0.354, 0.794, 0.607, 0.354, 0.792, 0.593, 0.355, 0.789, 0.579, 0.355,
+ 0.787, 0.564, 0.355, 0.784, 0.549, 0.355, 0.781, 0.534, 0.355, 0.778,
+ 0.518, 0.355, 0.774, 0.502, 0.355, 0.770, 0.485, 0.355, 0.766, 0.468,
+ 0.355, 0.762, 0.451, 0.355, 0.758, 0.434, 0.355, 0.753, 0.416, 0.356,
+ 0.748, 0.397, 0.356, 0.743, 0.379, 0.356, 0.738, 0.360, 0.357, 0.733,
+ 0.340, 0.357, 0.728, 0.321, 0.358, 0.722, 0.300, 0.359, 0.716, 0.279,
+ 0.360, 0.710, 0.258, 0.361, 0.704, 0.235, 0.361, 0.698, 0.212, 0.362,
+ 0.692, 0.187, 0.363, 0.686, 0.160, 0.000, 0.680, 0.945, 0.000, 0.686,
+ 0.937, 0.000, 0.692, 0.930, 0.000, 0.698, 0.922, 0.000, 0.703, 0.915,
+ 0.000, 0.709, 0.908, 0.000, 0.715, 0.901, 0.000, 0.720, 0.894, 0.000,
+ 0.726, 0.888, 0.000, 0.731, 0.881, 0.007, 0.736, 0.875, 0.084, 0.741,
+ 0.869, 0.127, 0.746, 0.862, 0.159, 0.751, 0.856, 0.185, 0.755, 0.850,
+ 0.208, 0.760, 0.843, 0.227, 0.764, 0.837, 0.245, 0.768, 0.830, 0.260,
+ 0.772, 0.824, 0.275, 0.776, 0.817, 0.288, 0.779, 0.811, 0.300, 0.783,
+ 0.804, 0.310, 0.786, 0.797, 0.320, 0.789, 0.789, 0.329, 0.792, 0.782,
+ 0.337, 0.794, 0.774, 0.345, 0.796, 0.766, 0.351, 0.798, 0.758, 0.357,
+ 0.800, 0.749, 0.363, 0.801, 0.740, 0.367, 0.803, 0.731, 0.371, 0.803,
+ 0.721, 0.375, 0.804, 0.711, 0.378, 0.804, 0.701, 0.380, 0.804, 0.690,
+ 0.382, 0.804, 0.679, 0.384, 0.803, 0.667, 0.385, 0.802, 0.654, 0.386,
+ 0.801, 0.642, 0.386, 0.800, 0.629, 0.387, 0.798, 0.615, 0.387, 0.796,
+ 0.601, 0.387, 0.793, 0.587, 0.387, 0.791, 0.572, 0.387, 0.788, 0.557,
+ 0.386, 0.785, 0.541, 0.386, 0.781, 0.525, 0.385, 0.778, 0.509, 0.385,
+ 0.774, 0.492, 0.385, 0.770, 0.475, 0.384, 0.765, 0.457, 0.384, 0.761,
+ 0.440, 0.384, 0.756, 0.422, 0.384, 0.751, 0.403, 0.384, 0.746, 0.384,
+ 0.384, 0.741, 0.365, 0.384, 0.735, 0.346, 0.384, 0.730, 0.326, 0.384,
+ 0.724, 0.305, 0.384, 0.718, 0.284, 0.385, 0.712, 0.263, 0.385, 0.706,
+ 0.240, 0.386, 0.700, 0.217, 0.386, 0.694, 0.192, 0.387, 0.687, 0.165,
+ 0.000, 0.680, 0.948, 0.000, 0.687, 0.940, 0.000, 0.693, 0.933, 0.000,
+ 0.699, 0.925, 0.000, 0.705, 0.918, 0.000, 0.711, 0.912, 0.000, 0.716,
+ 0.905, 0.000, 0.722, 0.898, 0.050, 0.728, 0.892, 0.109, 0.733, 0.886,
+ 0.147, 0.738, 0.879, 0.177, 0.743, 0.873, 0.202, 0.748, 0.867, 0.224,
+ 0.753, 0.861, 0.243, 0.758, 0.855, 0.261, 0.763, 0.849, 0.277, 0.767,
+ 0.842, 0.292, 0.771, 0.836, 0.305, 0.775, 0.830, 0.318, 0.779, 0.823,
+ 0.329, 0.783, 0.817, 0.340, 0.787, 0.810, 0.350, 0.790, 0.803, 0.359,
+ 0.793, 0.796, 0.367, 0.796, 0.789, 0.374, 0.798, 0.782, 0.381, 0.801,
+ 0.774, 0.387, 0.803, 0.766, 0.393, 0.804, 0.757, 0.397, 0.806, 0.748,
+ 0.402, 0.807, 0.739, 0.405, 0.808, 0.729, 0.408, 0.809, 0.719, 0.411,
+ 0.809, 0.709, 0.413, 0.809, 0.698, 0.415, 0.808, 0.687, 0.416, 0.808,
+ 0.675, 0.417, 0.807, 0.663, 0.417, 0.806, 0.650, 0.417, 0.804, 0.637,
+ 0.418, 0.802, 0.623, 0.417, 0.800, 0.609, 0.417, 0.798, 0.594, 0.416,
+ 0.795, 0.579, 0.416, 0.792, 0.564, 0.415, 0.789, 0.548, 0.414, 0.785,
+ 0.532, 0.414, 0.781, 0.515, 0.413, 0.777, 0.499, 0.412, 0.773, 0.481,
+ 0.412, 0.769, 0.464, 0.411, 0.764, 0.446, 0.410, 0.759, 0.428, 0.410,
+ 0.754, 0.409, 0.409, 0.749, 0.390, 0.409, 0.743, 0.371, 0.409, 0.738,
+ 0.351, 0.409, 0.732, 0.331, 0.408, 0.726, 0.310, 0.408, 0.720, 0.289,
+ 0.408, 0.714, 0.268, 0.408, 0.708, 0.245, 0.409, 0.702, 0.222, 0.409,
+ 0.695, 0.197, 0.409, 0.689, 0.170, 0.000, 0.681, 0.950, 0.000, 0.688,
+ 0.943, 0.000, 0.694, 0.936, 0.000, 0.700, 0.929, 0.000, 0.706, 0.922,
+ 0.000, 0.712, 0.915, 0.074, 0.718, 0.908, 0.124, 0.724, 0.902, 0.159,
+ 0.730, 0.896, 0.188, 0.735, 0.890, 0.213, 0.740, 0.884, 0.235, 0.746,
+ 0.878, 0.255, 0.751, 0.872, 0.273, 0.756, 0.866, 0.289, 0.761, 0.860,
+ 0.305, 0.766, 0.854, 0.319, 0.770, 0.848, 0.332, 0.775, 0.842, 0.344,
+ 0.779, 0.836, 0.356, 0.783, 0.830, 0.366, 0.787, 0.823, 0.376, 0.790,
+ 0.817, 0.385, 0.794, 0.810, 0.394, 0.797, 0.803, 0.401, 0.800, 0.796,
+ 0.408, 0.802, 0.789, 0.414, 0.805, 0.781, 0.420, 0.807, 0.773, 0.425,
+ 0.809, 0.765, 0.430, 0.810, 0.756, 0.433, 0.812, 0.747, 0.437, 0.813,
+ 0.738, 0.440, 0.813, 0.728, 0.442, 0.814, 0.717, 0.444, 0.813, 0.706,
+ 0.445, 0.813, 0.695, 0.446, 0.812, 0.683, 0.446, 0.811, 0.671, 0.447,
+ 0.810, 0.658, 0.447, 0.809, 0.645, 0.446, 0.807, 0.631, 0.446, 0.804,
+ 0.617, 0.445, 0.802, 0.602, 0.444, 0.799, 0.587, 0.443, 0.796, 0.571,
+ 0.442, 0.792, 0.555, 0.441, 0.789, 0.539, 0.440, 0.785, 0.522, 0.439,
+ 0.781, 0.505, 0.438, 0.776, 0.488, 0.437, 0.772, 0.470, 0.436, 0.767,
+ 0.452, 0.435, 0.762, 0.433, 0.435, 0.757, 0.415, 0.434, 0.751, 0.396,
+ 0.433, 0.746, 0.376, 0.432, 0.740, 0.356, 0.432, 0.734, 0.336, 0.431,
+ 0.728, 0.315, 0.431, 0.722, 0.294, 0.431, 0.716, 0.272, 0.430, 0.710,
+ 0.250, 0.430, 0.703, 0.226, 0.430, 0.697, 0.201, 0.430, 0.690, 0.175,
+ 0.000, 0.682, 0.953, 0.000, 0.689, 0.946, 0.000, 0.695, 0.938, 0.002,
+ 0.701, 0.932, 0.086, 0.708, 0.925, 0.133, 0.714, 0.918, 0.167, 0.720,
+ 0.912, 0.196, 0.726, 0.906, 0.221, 0.731, 0.900, 0.243, 0.737, 0.894,
+ 0.263, 0.743, 0.888, 0.281, 0.748, 0.882, 0.298, 0.753, 0.876, 0.314,
+ 0.759, 0.870, 0.329, 0.764, 0.865, 0.342, 0.768, 0.859, 0.355, 0.773,
+ 0.853, 0.368, 0.778, 0.847, 0.379, 0.782, 0.842, 0.390, 0.786, 0.836,
+ 0.400, 0.790, 0.830, 0.409, 0.794, 0.823, 0.417, 0.798, 0.817, 0.425,
+ 0.801, 0.810, 0.433, 0.804, 0.803, 0.439, 0.807, 0.796, 0.445, 0.809,
+ 0.789, 0.451, 0.811, 0.781, 0.456, 0.813, 0.773, 0.460, 0.815, 0.764,
+ 0.463, 0.816, 0.755, 0.466, 0.817, 0.746, 0.469, 0.818, 0.736, 0.471,
+ 0.818, 0.725, 0.472, 0.818, 0.715, 0.473, 0.818, 0.703, 0.474, 0.817,
+ 0.691, 0.474, 0.816, 0.679, 0.474, 0.815, 0.666, 0.474, 0.813, 0.653,
+ 0.473, 0.811, 0.639, 0.473, 0.809, 0.624, 0.472, 0.806, 0.610, 0.471,
+ 0.803, 0.594, 0.469, 0.800, 0.579, 0.468, 0.796, 0.562, 0.467, 0.792,
+ 0.546, 0.466, 0.788, 0.529, 0.464, 0.784, 0.512, 0.463, 0.780, 0.494,
+ 0.462, 0.775, 0.476, 0.460, 0.770, 0.458, 0.459, 0.765, 0.439, 0.458,
+ 0.759, 0.420, 0.457, 0.754, 0.401, 0.456, 0.748, 0.381, 0.455, 0.742,
+ 0.361, 0.454, 0.736, 0.341, 0.453, 0.730, 0.320, 0.453, 0.724, 0.299,
+ 0.452, 0.718, 0.277, 0.452, 0.711, 0.254, 0.451, 0.705, 0.231, 0.451,
+ 0.698, 0.206, 0.450, 0.691, 0.179, 0.000, 0.683, 0.955, 0.013, 0.689,
+ 0.948, 0.092, 0.696, 0.941, 0.137, 0.702, 0.935, 0.171, 0.709, 0.928,
+ 0.200, 0.715, 0.922, 0.225, 0.721, 0.916, 0.247, 0.727, 0.909, 0.267,
+ 0.733, 0.904, 0.286, 0.739, 0.898, 0.303, 0.745, 0.892, 0.320, 0.750,
+ 0.886, 0.335, 0.756, 0.881, 0.350, 0.761, 0.875, 0.363, 0.766, 0.870,
+ 0.376, 0.771, 0.864, 0.388, 0.776, 0.859, 0.400, 0.781, 0.853, 0.411,
+ 0.785, 0.847, 0.421, 0.790, 0.842, 0.430, 0.794, 0.836, 0.439, 0.798,
+ 0.830, 0.448, 0.802, 0.824, 0.455, 0.805, 0.817, 0.462, 0.808, 0.810,
+ 0.469, 0.811, 0.804, 0.475, 0.814, 0.796, 0.480, 0.816, 0.789, 0.484,
+ 0.818, 0.781, 0.488, 0.820, 0.772, 0.492, 0.821, 0.763, 0.495, 0.822,
+ 0.754, 0.497, 0.823, 0.744, 0.499, 0.823, 0.734, 0.500, 0.823, 0.723,
+ 0.501, 0.823, 0.712, 0.501, 0.822, 0.700, 0.501, 0.821, 0.687, 0.501,
+ 0.819, 0.674, 0.500, 0.818, 0.661, 0.499, 0.815, 0.647, 0.498, 0.813,
+ 0.632, 0.497, 0.810, 0.617, 0.496, 0.807, 0.602, 0.494, 0.804, 0.586,
+ 0.493, 0.800, 0.569, 0.491, 0.796, 0.553, 0.490, 0.792, 0.536, 0.488,
+ 0.787, 0.518, 0.486, 0.783, 0.500, 0.485, 0.778, 0.482, 0.483, 0.773,
+ 0.463, 0.482, 0.767, 0.445, 0.480, 0.762, 0.425, 0.479, 0.756, 0.406,
+ 0.478, 0.750, 0.386, 0.477, 0.744, 0.366, 0.476, 0.738, 0.345, 0.475,
+ 0.732, 0.325, 0.474, 0.726, 0.303, 0.473, 0.719, 0.281, 0.472, 0.713,
+ 0.258, 0.471, 0.706, 0.235, 0.470, 0.699, 0.210, 0.469, 0.692, 0.184,
+ 0.095, 0.683, 0.958, 0.139, 0.690, 0.951, 0.173, 0.697, 0.944, 0.201,
+ 0.703, 0.938, 0.226, 0.710, 0.931, 0.249, 0.716, 0.925, 0.269, 0.723,
+ 0.919, 0.288, 0.729, 0.913, 0.306, 0.735, 0.907, 0.323, 0.741, 0.902,
+ 0.339, 0.747, 0.896, 0.354, 0.752, 0.891, 0.368, 0.758, 0.885, 0.382,
+ 0.764, 0.880, 0.394, 0.769, 0.875, 0.407, 0.774, 0.869, 0.418, 0.779,
+ 0.864, 0.429, 0.784, 0.859, 0.440, 0.789, 0.853, 0.450, 0.793, 0.848,
+ 0.459, 0.798, 0.842, 0.468, 0.802, 0.836, 0.476, 0.806, 0.830, 0.483,
+ 0.809, 0.824, 0.490, 0.812, 0.818, 0.496, 0.815, 0.811, 0.502, 0.818,
+ 0.804, 0.507, 0.821, 0.796, 0.512, 0.823, 0.789, 0.515, 0.825, 0.780,
+ 0.519, 0.826, 0.772, 0.521, 0.827, 0.762, 0.524, 0.828, 0.753, 0.525,
+ 0.828, 0.742, 0.526, 0.828, 0.732, 0.527, 0.828, 0.720, 0.527, 0.827,
+ 0.708, 0.527, 0.826, 0.696, 0.526, 0.824, 0.683, 0.525, 0.822, 0.669,
+ 0.524, 0.820, 0.655, 0.523, 0.817, 0.640, 0.522, 0.814, 0.625, 0.520,
+ 0.811, 0.609, 0.518, 0.808, 0.593, 0.516, 0.804, 0.576, 0.515, 0.800,
+ 0.559, 0.513, 0.795, 0.542, 0.511, 0.791, 0.524, 0.509, 0.786, 0.506,
+ 0.507, 0.781, 0.488, 0.505, 0.775, 0.469, 0.504, 0.770, 0.450, 0.502,
+ 0.764, 0.431, 0.500, 0.759, 0.411, 0.499, 0.753, 0.391, 0.497, 0.746,
+ 0.371, 0.496, 0.740, 0.350, 0.495, 0.734, 0.329, 0.494, 0.727, 0.307,
+ 0.492, 0.721, 0.285, 0.491, 0.714, 0.262, 0.490, 0.707, 0.239, 0.489,
+ 0.700, 0.214, 0.488, 0.693, 0.188, 0.172, 0.684, 0.961, 0.201, 0.691,
+ 0.954, 0.226, 0.698, 0.947, 0.248, 0.704, 0.941, 0.269, 0.711, 0.934,
+ 0.289, 0.717, 0.928, 0.307, 0.724, 0.922, 0.324, 0.730, 0.917, 0.340,
+ 0.736, 0.911, 0.356, 0.743, 0.906, 0.370, 0.749, 0.900, 0.384, 0.755,
+ 0.895, 0.398, 0.760, 0.890, 0.411, 0.766, 0.885, 0.423, 0.772, 0.880,
+ 0.435, 0.777, 0.874, 0.446, 0.782, 0.869, 0.457, 0.787, 0.864, 0.467,
+ 0.792, 0.859, 0.477, 0.797, 0.854, 0.486, 0.801, 0.848, 0.494, 0.806,
+ 0.843, 0.502, 0.810, 0.837, 0.510, 0.813, 0.831, 0.517, 0.817, 0.825,
+ 0.523, 0.820, 0.818, 0.528, 0.823, 0.811, 0.533, 0.825, 0.804, 0.538,
+ 0.828, 0.797, 0.542, 0.829, 0.788, 0.545, 0.831, 0.780, 0.547, 0.832,
+ 0.771, 0.549, 0.833, 0.761, 0.551, 0.833, 0.751, 0.552, 0.833, 0.740,
+ 0.552, 0.833, 0.729, 0.552, 0.832, 0.717, 0.551, 0.830, 0.704, 0.551,
+ 0.829, 0.691, 0.550, 0.827, 0.677, 0.548, 0.824, 0.663, 0.547, 0.822,
+ 0.648, 0.545, 0.819, 0.632, 0.543, 0.815, 0.617, 0.541, 0.812, 0.600,
+ 0.539, 0.808, 0.583, 0.537, 0.803, 0.566, 0.535, 0.799, 0.549, 0.533,
+ 0.794, 0.531, 0.531, 0.789, 0.512, 0.529, 0.784, 0.494, 0.527, 0.778,
+ 0.475, 0.525, 0.773, 0.455, 0.523, 0.767, 0.436, 0.521, 0.761, 0.416,
+ 0.519, 0.755, 0.396, 0.517, 0.748, 0.375, 0.516, 0.742, 0.354, 0.514,
+ 0.735, 0.333, 0.513, 0.729, 0.311, 0.511, 0.722, 0.289, 0.510, 0.715,
+ 0.266, 0.509, 0.708, 0.242, 0.507, 0.701, 0.218, 0.506, 0.694, 0.191,
+ 0.224, 0.684, 0.963, 0.247, 0.691, 0.956, 0.268, 0.698, 0.950, 0.287,
+ 0.705, 0.943, 0.305, 0.712, 0.937, 0.323, 0.719, 0.931, 0.339, 0.725,
+ 0.926, 0.355, 0.732, 0.920, 0.370, 0.738, 0.915, 0.385, 0.744, 0.909,
+ 0.399, 0.751, 0.904, 0.412, 0.757, 0.899, 0.425, 0.763, 0.894, 0.438,
+ 0.768, 0.889, 0.450, 0.774, 0.884, 0.461, 0.780, 0.879, 0.472, 0.785,
+ 0.875, 0.483, 0.790, 0.870, 0.493, 0.795, 0.865, 0.502, 0.800, 0.860,
+ 0.511, 0.805, 0.855, 0.520, 0.809, 0.849, 0.528, 0.814, 0.844, 0.535,
+ 0.818, 0.838, 0.542, 0.821, 0.832, 0.548, 0.824, 0.826, 0.554, 0.827,
+ 0.819, 0.559, 0.830, 0.812, 0.563, 0.832, 0.805, 0.567, 0.834, 0.797,
+ 0.570, 0.836, 0.788, 0.572, 0.837, 0.779, 0.574, 0.838, 0.770, 0.575,
+ 0.838, 0.760, 0.576, 0.838, 0.749, 0.576, 0.838, 0.737, 0.576, 0.837,
+ 0.725, 0.575, 0.835, 0.713, 0.574, 0.834, 0.699, 0.573, 0.831, 0.685,
+ 0.571, 0.829, 0.671, 0.570, 0.826, 0.656, 0.568, 0.823, 0.640, 0.566,
+ 0.819, 0.624, 0.563, 0.815, 0.607, 0.561, 0.811, 0.590, 0.559, 0.807,
+ 0.573, 0.556, 0.802, 0.555, 0.554, 0.797, 0.537, 0.552, 0.792, 0.518,
+ 0.549, 0.786, 0.499, 0.547, 0.781, 0.480, 0.545, 0.775, 0.460, 0.543,
+ 0.769, 0.441, 0.541, 0.763, 0.420, 0.539, 0.756, 0.400, 0.537, 0.750,
+ 0.379, 0.535, 0.743, 0.358, 0.533, 0.737, 0.337, 0.531, 0.730, 0.315,
+ 0.530, 0.723, 0.293, 0.528, 0.716, 0.270, 0.527, 0.709, 0.246, 0.525,
+ 0.702, 0.221, 0.524, 0.694, 0.195, 0.265, 0.685, 0.965, 0.284, 0.692,
+ 0.959, 0.303, 0.699, 0.952, 0.320, 0.706, 0.946, 0.337, 0.713, 0.940,
+ 0.353, 0.720, 0.935, 0.369, 0.726, 0.929, 0.384, 0.733, 0.924, 0.398,
+ 0.739, 0.918, 0.412, 0.746, 0.913, 0.425, 0.752, 0.908, 0.438, 0.759,
+ 0.903, 0.451, 0.765, 0.899, 0.463, 0.771, 0.894, 0.475, 0.777, 0.889,
+ 0.486, 0.782, 0.884, 0.497, 0.788, 0.880, 0.507, 0.793, 0.875, 0.517,
+ 0.799, 0.870, 0.527, 0.804, 0.866, 0.536, 0.809, 0.861, 0.544, 0.813,
+ 0.856, 0.552, 0.818, 0.850, 0.560, 0.822, 0.845, 0.566, 0.826, 0.839,
+ 0.573, 0.829, 0.833, 0.578, 0.832, 0.827, 0.583, 0.835, 0.820, 0.587,
+ 0.837, 0.813, 0.591, 0.839, 0.805, 0.594, 0.841, 0.797, 0.596, 0.842,
+ 0.788, 0.598, 0.843, 0.778, 0.599, 0.843, 0.768, 0.600, 0.843, 0.758,
+ 0.600, 0.843, 0.746, 0.599, 0.842, 0.734, 0.599, 0.840, 0.721, 0.597,
+ 0.838, 0.708, 0.596, 0.836, 0.694, 0.594, 0.834, 0.679, 0.592, 0.831,
+ 0.663, 0.590, 0.827, 0.648, 0.587, 0.823, 0.631, 0.585, 0.819, 0.614,
+ 0.582, 0.815, 0.597, 0.580, 0.810, 0.579, 0.577, 0.805, 0.561, 0.575,
+ 0.800, 0.542, 0.572, 0.795, 0.524, 0.569, 0.789, 0.504, 0.567, 0.783,
+ 0.485, 0.565, 0.777, 0.465, 0.562, 0.771, 0.445, 0.560, 0.765, 0.425,
+ 0.558, 0.758, 0.404, 0.556, 0.752, 0.383, 0.554, 0.745, 0.362, 0.552,
+ 0.738, 0.341, 0.550, 0.731, 0.319, 0.548, 0.724, 0.296, 0.546, 0.717,
+ 0.273, 0.544, 0.709, 0.249, 0.542, 0.702, 0.224, 0.541, 0.695, 0.198,
+ 0.299, 0.685, 0.968, 0.317, 0.692, 0.961, 0.334, 0.699, 0.955, 0.350,
+ 0.706, 0.949, 0.366, 0.713, 0.943, 0.381, 0.720, 0.938, 0.395, 0.727,
+ 0.932, 0.410, 0.734, 0.927, 0.423, 0.741, 0.922, 0.437, 0.747, 0.917,
+ 0.450, 0.754, 0.912, 0.463, 0.760, 0.907, 0.475, 0.767, 0.903, 0.487,
+ 0.773, 0.898, 0.498, 0.779, 0.894, 0.509, 0.785, 0.889, 0.520, 0.791,
+ 0.885, 0.531, 0.796, 0.880, 0.540, 0.802, 0.876, 0.550, 0.807, 0.871,
+ 0.559, 0.812, 0.867, 0.568, 0.817, 0.862, 0.576, 0.822, 0.857, 0.583,
+ 0.826, 0.852, 0.590, 0.830, 0.847, 0.596, 0.834, 0.841, 0.602, 0.837,
+ 0.835, 0.607, 0.840, 0.828, 0.611, 0.843, 0.821, 0.615, 0.845, 0.814,
+ 0.618, 0.846, 0.805, 0.620, 0.848, 0.797, 0.622, 0.848, 0.787, 0.623,
+ 0.849, 0.777, 0.623, 0.849, 0.766, 0.623, 0.848, 0.755, 0.622, 0.847,
+ 0.743, 0.621, 0.845, 0.730, 0.620, 0.843, 0.716, 0.618, 0.841, 0.702,
+ 0.616, 0.838, 0.687, 0.613, 0.835, 0.671, 0.611, 0.831, 0.655, 0.608,
+ 0.827, 0.638, 0.606, 0.823, 0.621, 0.603, 0.818, 0.604, 0.600, 0.814,
+ 0.585, 0.597, 0.808, 0.567, 0.594, 0.803, 0.548, 0.592, 0.797, 0.529,
+ 0.589, 0.792, 0.510, 0.586, 0.785, 0.490, 0.584, 0.779, 0.470, 0.581,
+ 0.773, 0.450, 0.579, 0.766, 0.429, 0.576, 0.760, 0.408, 0.574, 0.753,
+ 0.387, 0.572, 0.746, 0.366, 0.569, 0.739, 0.344, 0.567, 0.732, 0.322,
+ 0.565, 0.725, 0.299, 0.563, 0.717, 0.276, 0.561, 0.710, 0.252, 0.559,
+ 0.703, 0.227, 0.557, 0.695, 0.201, 0.329, 0.685, 0.970, 0.346, 0.692,
+ 0.964, 0.362, 0.699, 0.958, 0.377, 0.707, 0.952, 0.392, 0.714, 0.946,
+ 0.406, 0.721, 0.941, 0.420, 0.728, 0.935, 0.434, 0.735, 0.930, 0.447,
+ 0.742, 0.925, 0.460, 0.749, 0.920, 0.473, 0.756, 0.916, 0.485, 0.762,
+ 0.911, 0.497, 0.769, 0.907, 0.509, 0.775, 0.903, 0.521, 0.781, 0.898,
+ 0.532, 0.788, 0.894, 0.542, 0.794, 0.890, 0.553, 0.799, 0.886, 0.563,
+ 0.805, 0.882, 0.572, 0.811, 0.877, 0.581, 0.816, 0.873, 0.590, 0.821,
+ 0.868, 0.598, 0.826, 0.864, 0.606, 0.830, 0.859, 0.613, 0.834, 0.854,
+ 0.619, 0.838, 0.848, 0.625, 0.842, 0.842, 0.630, 0.845, 0.836, 0.634,
+ 0.848, 0.829, 0.638, 0.850, 0.822, 0.641, 0.852, 0.814, 0.643, 0.853,
+ 0.805, 0.645, 0.854, 0.796, 0.645, 0.854, 0.786, 0.646, 0.854, 0.775,
+ 0.645, 0.853, 0.764, 0.645, 0.852, 0.751, 0.643, 0.851, 0.738, 0.642,
+ 0.848, 0.725, 0.639, 0.846, 0.710, 0.637, 0.843, 0.695, 0.635, 0.839,
+ 0.679, 0.632, 0.836, 0.662, 0.629, 0.831, 0.645, 0.626, 0.827, 0.628,
+ 0.623, 0.822, 0.610, 0.620, 0.817, 0.592, 0.617, 0.811, 0.573, 0.614,
+ 0.806, 0.554, 0.611, 0.800, 0.534, 0.608, 0.794, 0.515, 0.605, 0.788,
+ 0.495, 0.602, 0.781, 0.474, 0.599, 0.775, 0.454, 0.597, 0.768, 0.433,
+ 0.594, 0.761, 0.412, 0.592, 0.754, 0.391, 0.589, 0.747, 0.369, 0.587,
+ 0.740, 0.347, 0.584, 0.733, 0.325, 0.582, 0.725, 0.302, 0.580, 0.718,
+ 0.279, 0.577, 0.710, 0.255, 0.575, 0.703, 0.230, 0.573, 0.695, 0.204,
+ 0.357, 0.685, 0.972, 0.372, 0.692, 0.966, 0.387, 0.700, 0.960, 0.401,
+ 0.707, 0.954, 0.416, 0.714, 0.949, 0.429, 0.722, 0.943, 0.443, 0.729,
+ 0.938, 0.456, 0.736, 0.933, 0.469, 0.743, 0.929, 0.482, 0.750, 0.924,
+ 0.494, 0.757, 0.919, 0.507, 0.764, 0.915, 0.519, 0.771, 0.911, 0.530,
+ 0.777, 0.907, 0.542, 0.784, 0.903, 0.553, 0.790, 0.899, 0.563, 0.796,
+ 0.895, 0.574, 0.802, 0.891, 0.584, 0.808, 0.887, 0.593, 0.814, 0.883,
+ 0.603, 0.820, 0.879, 0.611, 0.825, 0.875, 0.620, 0.830, 0.870, 0.627,
+ 0.835, 0.866, 0.635, 0.839, 0.861, 0.641, 0.843, 0.856, 0.647, 0.847,
+ 0.850, 0.652, 0.850, 0.844, 0.657, 0.853, 0.838, 0.660, 0.855, 0.831,
+ 0.663, 0.857, 0.823, 0.666, 0.859, 0.814, 0.667, 0.859, 0.805, 0.668,
+ 0.860, 0.795, 0.668, 0.860, 0.784, 0.667, 0.859, 0.773, 0.666, 0.858,
+ 0.760, 0.665, 0.856, 0.747, 0.663, 0.853, 0.733, 0.661, 0.851, 0.718,
+ 0.658, 0.847, 0.703, 0.655, 0.844, 0.687, 0.652, 0.840, 0.670, 0.649,
+ 0.835, 0.652, 0.646, 0.830, 0.635, 0.642, 0.825, 0.616, 0.639, 0.820,
+ 0.598, 0.636, 0.814, 0.579, 0.633, 0.808, 0.559, 0.629, 0.802, 0.539,
+ 0.626, 0.796, 0.519, 0.623, 0.790, 0.499, 0.620, 0.783, 0.479, 0.617,
+ 0.776, 0.458, 0.614, 0.769, 0.437, 0.611, 0.762, 0.416, 0.609, 0.755,
+ 0.394, 0.606, 0.748, 0.372, 0.603, 0.740, 0.350, 0.601, 0.733, 0.328,
+ 0.598, 0.726, 0.305, 0.596, 0.718, 0.282, 0.593, 0.710, 0.257, 0.591,
+ 0.703, 0.232, 0.589, 0.695, 0.206, 0.381, 0.684, 0.974, 0.396, 0.692,
+ 0.968, 0.410, 0.700, 0.962, 0.424, 0.707, 0.957, 0.438, 0.715, 0.951,
+ 0.451, 0.722, 0.946, 0.464, 0.729, 0.941, 0.477, 0.737, 0.936, 0.490,
+ 0.744, 0.932, 0.503, 0.751, 0.927, 0.515, 0.758, 0.923, 0.527, 0.765,
+ 0.919, 0.539, 0.772, 0.915, 0.550, 0.779, 0.911, 0.562, 0.786, 0.907,
+ 0.573, 0.792, 0.903, 0.584, 0.799, 0.900, 0.594, 0.805, 0.896, 0.604,
+ 0.811, 0.892, 0.614, 0.817, 0.889, 0.623, 0.823, 0.885, 0.632, 0.829,
+ 0.881, 0.641, 0.834, 0.877, 0.649, 0.839, 0.873, 0.656, 0.844, 0.868,
+ 0.663, 0.848, 0.863, 0.669, 0.852, 0.858, 0.674, 0.855, 0.852, 0.679,
+ 0.858, 0.846, 0.682, 0.861, 0.839, 0.685, 0.863, 0.832, 0.688, 0.864,
+ 0.823, 0.689, 0.865, 0.814, 0.690, 0.865, 0.804, 0.690, 0.865, 0.794,
+ 0.689, 0.864, 0.782, 0.688, 0.863, 0.769, 0.686, 0.861, 0.756, 0.684,
+ 0.858, 0.742, 0.681, 0.855, 0.726, 0.678, 0.852, 0.711, 0.675, 0.848,
+ 0.694, 0.672, 0.844, 0.677, 0.668, 0.839, 0.659, 0.665, 0.834, 0.641,
+ 0.662, 0.829, 0.622, 0.658, 0.823, 0.603, 0.655, 0.817, 0.584, 0.651,
+ 0.811, 0.564, 0.648, 0.805, 0.544, 0.644, 0.798, 0.524, 0.641, 0.791,
+ 0.503, 0.638, 0.785, 0.483, 0.635, 0.778, 0.462, 0.631, 0.770, 0.440,
+ 0.628, 0.763, 0.419, 0.625, 0.756, 0.397, 0.623, 0.748, 0.375, 0.620,
+ 0.741, 0.353, 0.617, 0.733, 0.330, 0.614, 0.726, 0.307, 0.612, 0.718,
+ 0.284, 0.609, 0.710, 0.260, 0.606, 0.702, 0.235, 0.604, 0.694, 0.208,
+ 0.404, 0.684, 0.977, 0.418, 0.692, 0.971, 0.432, 0.699, 0.965, 0.445,
+ 0.707, 0.959, 0.458, 0.715, 0.954, 0.472, 0.722, 0.949, 0.484, 0.730,
+ 0.944, 0.497, 0.737, 0.939, 0.510, 0.745, 0.935, 0.522, 0.752, 0.931,
+ 0.534, 0.759, 0.926, 0.546, 0.767, 0.922, 0.558, 0.774, 0.919, 0.569,
+ 0.781, 0.915, 0.581, 0.788, 0.911, 0.592, 0.794, 0.908, 0.603, 0.801,
+ 0.904, 0.613, 0.808, 0.901, 0.624, 0.814, 0.897, 0.633, 0.820, 0.894,
+ 0.643, 0.826, 0.891, 0.652, 0.832, 0.887, 0.661, 0.838, 0.883, 0.669,
+ 0.843, 0.879, 0.677, 0.848, 0.875, 0.684, 0.853, 0.871, 0.690, 0.857,
+ 0.866, 0.695, 0.860, 0.860, 0.700, 0.864, 0.855, 0.704, 0.866, 0.848,
+ 0.707, 0.869, 0.841, 0.709, 0.870, 0.833, 0.711, 0.871, 0.824, 0.711,
+ 0.871, 0.814, 0.711, 0.871, 0.803, 0.710, 0.870, 0.791, 0.709, 0.868,
+ 0.778, 0.707, 0.866, 0.765, 0.704, 0.864, 0.750, 0.701, 0.860, 0.735,
+ 0.698, 0.857, 0.718, 0.695, 0.852, 0.702, 0.691, 0.848, 0.684, 0.688,
+ 0.843, 0.666, 0.684, 0.837, 0.647, 0.680, 0.832, 0.628, 0.676, 0.826,
+ 0.609, 0.673, 0.820, 0.589, 0.669, 0.813, 0.569, 0.665, 0.807, 0.549,
+ 0.662, 0.800, 0.528, 0.658, 0.793, 0.507, 0.655, 0.786, 0.486, 0.651,
+ 0.779, 0.465, 0.648, 0.771, 0.444, 0.645, 0.764, 0.422, 0.642, 0.756,
+ 0.400, 0.639, 0.749, 0.378, 0.636, 0.741, 0.356, 0.633, 0.733, 0.333,
+ 0.630, 0.726, 0.310, 0.627, 0.718, 0.286, 0.624, 0.710, 0.262, 0.621,
+ 0.702, 0.237, 0.619, 0.694, 0.210, 0.425, 0.683, 0.979, 0.439, 0.691,
+ 0.973, 0.452, 0.699, 0.967, 0.465, 0.707, 0.962, 0.478, 0.715, 0.956,
+ 0.491, 0.722, 0.951, 0.503, 0.730, 0.947, 0.516, 0.738, 0.942, 0.528,
+ 0.745, 0.938, 0.540, 0.753, 0.934, 0.552, 0.760, 0.930, 0.564, 0.768,
+ 0.926, 0.576, 0.775, 0.922, 0.588, 0.782, 0.919, 0.599, 0.789, 0.915,
+ 0.610, 0.797, 0.912, 0.621, 0.803, 0.909, 0.632, 0.810, 0.906, 0.642,
+ 0.817, 0.902, 0.652, 0.823, 0.899, 0.662, 0.830, 0.896, 0.671, 0.836,
+ 0.893, 0.680, 0.842, 0.890, 0.689, 0.847, 0.886, 0.697, 0.853, 0.882,
+ 0.704, 0.857, 0.878, 0.710, 0.862, 0.874, 0.716, 0.866, 0.869, 0.721,
+ 0.869, 0.863, 0.725, 0.872, 0.857, 0.729, 0.874, 0.850, 0.731, 0.876,
+ 0.842, 0.732, 0.877, 0.833, 0.733, 0.877, 0.823, 0.732, 0.877, 0.812,
+ 0.731, 0.876, 0.800, 0.729, 0.874, 0.787, 0.727, 0.872, 0.773, 0.724,
+ 0.869, 0.759, 0.721, 0.865, 0.743, 0.718, 0.861, 0.726, 0.714, 0.857,
+ 0.709, 0.710, 0.852, 0.691, 0.706, 0.846, 0.672, 0.702, 0.841, 0.653,
+ 0.698, 0.835, 0.634, 0.694, 0.828, 0.614, 0.690, 0.822, 0.594, 0.686,
+ 0.815, 0.574, 0.683, 0.808, 0.553, 0.679, 0.801, 0.532, 0.675, 0.794,
+ 0.511, 0.672, 0.787, 0.490, 0.668, 0.779, 0.468, 0.665, 0.772, 0.446,
+ 0.661, 0.764, 0.425, 0.658, 0.757, 0.403, 0.654, 0.749, 0.380, 0.651,
+ 0.741, 0.358, 0.648, 0.733, 0.335, 0.645, 0.725, 0.312, 0.642, 0.717,
+ 0.288, 0.639, 0.709, 0.264, 0.636, 0.701, 0.238, 0.633, 0.693, 0.212,
+ 0.445, 0.682, 0.981, 0.458, 0.691, 0.975, 0.471, 0.699, 0.969, 0.484,
+ 0.707, 0.964, 0.496, 0.715, 0.959, 0.509, 0.722, 0.954, 0.521, 0.730,
+ 0.949, 0.534, 0.738, 0.945, 0.546, 0.746, 0.941, 0.558, 0.753, 0.937,
+ 0.570, 0.761, 0.933, 0.582, 0.769, 0.929, 0.593, 0.776, 0.926, 0.605,
+ 0.784, 0.922, 0.616, 0.791, 0.919, 0.628, 0.798, 0.916, 0.639, 0.806,
+ 0.913, 0.649, 0.813, 0.910, 0.660, 0.820, 0.907, 0.670, 0.826, 0.904,
+ 0.680, 0.833, 0.902, 0.690, 0.839, 0.899, 0.699, 0.846, 0.896, 0.708,
+ 0.851, 0.893, 0.716, 0.857, 0.889, 0.724, 0.862, 0.885, 0.731, 0.867,
+ 0.881, 0.737, 0.871, 0.877, 0.742, 0.875, 0.872, 0.746, 0.878, 0.866,
+ 0.750, 0.880, 0.859, 0.752, 0.882, 0.851, 0.753, 0.883, 0.843, 0.754,
+ 0.883, 0.833, 0.753, 0.883, 0.822, 0.752, 0.882, 0.810, 0.750, 0.880,
+ 0.797, 0.747, 0.877, 0.782, 0.744, 0.874, 0.767, 0.740, 0.870, 0.751,
+ 0.737, 0.866, 0.734, 0.733, 0.861, 0.716, 0.729, 0.855, 0.697, 0.724,
+ 0.850, 0.678, 0.720, 0.844, 0.659, 0.716, 0.837, 0.639, 0.712, 0.831,
+ 0.619, 0.708, 0.824, 0.598, 0.704, 0.817, 0.578, 0.699, 0.810, 0.557,
+ 0.696, 0.803, 0.535, 0.692, 0.795, 0.514, 0.688, 0.788, 0.493, 0.684,
+ 0.780, 0.471, 0.680, 0.772, 0.449, 0.677, 0.765, 0.427, 0.673, 0.757,
+ 0.405, 0.670, 0.749, 0.382, 0.666, 0.741, 0.360, 0.663, 0.733, 0.337,
+ 0.660, 0.725, 0.313, 0.657, 0.716, 0.289, 0.653, 0.708, 0.265, 0.650,
+ 0.700, 0.240, 0.647, 0.692, 0.213, 0.464, 0.681, 0.982, 0.476, 0.690,
+ 0.977, 0.489, 0.698, 0.971, 0.501, 0.706, 0.966, 0.514, 0.714, 0.961,
+ 0.526, 0.722, 0.956, 0.538, 0.730, 0.952, 0.550, 0.738, 0.947, 0.562,
+ 0.746, 0.943, 0.574, 0.754, 0.939, 0.586, 0.762, 0.936, 0.598, 0.769,
+ 0.932, 0.610, 0.777, 0.929, 0.621, 0.785, 0.926, 0.633, 0.792, 0.923,
+ 0.644, 0.800, 0.920, 0.655, 0.807, 0.917, 0.666, 0.815, 0.915, 0.677,
+ 0.822, 0.912, 0.688, 0.829, 0.909, 0.698, 0.836, 0.907, 0.708, 0.843,
+ 0.904, 0.717, 0.849, 0.902, 0.727, 0.855, 0.899, 0.735, 0.861, 0.896,
+ 0.743, 0.867, 0.893, 0.750, 0.872, 0.889, 0.757, 0.877, 0.885, 0.762,
+ 0.881, 0.880, 0.767, 0.884, 0.875, 0.770, 0.887, 0.868, 0.773, 0.888,
+ 0.861, 0.774, 0.889, 0.852, 0.774, 0.890, 0.842, 0.774, 0.889, 0.831,
+ 0.772, 0.888, 0.819, 0.770, 0.885, 0.806, 0.767, 0.883, 0.791, 0.763,
+ 0.879, 0.775, 0.759, 0.875, 0.759, 0.755, 0.870, 0.741, 0.751, 0.865,
+ 0.723, 0.747, 0.859, 0.704, 0.742, 0.853, 0.684, 0.738, 0.847, 0.664,
+ 0.733, 0.840, 0.644, 0.729, 0.833, 0.623, 0.724, 0.826, 0.603, 0.720,
+ 0.819, 0.581, 0.716, 0.811, 0.560, 0.712, 0.804, 0.539, 0.708, 0.796,
+ 0.517, 0.704, 0.788, 0.495, 0.700, 0.780, 0.473, 0.696, 0.772, 0.451,
+ 0.692, 0.764, 0.429, 0.688, 0.756, 0.407, 0.685, 0.748, 0.384, 0.681,
+ 0.740, 0.361, 0.678, 0.732, 0.338, 0.674, 0.724, 0.315, 0.671, 0.715,
+ 0.291, 0.667, 0.707, 0.266, 0.664, 0.699, 0.241, 0.661, 0.691, 0.214,
+ 0.481, 0.680, 0.984, 0.494, 0.689, 0.978, 0.506, 0.697, 0.973, 0.518,
+ 0.705, 0.968, 0.530, 0.713, 0.963, 0.542, 0.722, 0.958, 0.554, 0.730,
+ 0.954, 0.566, 0.738, 0.950, 0.578, 0.746, 0.946, 0.590, 0.754, 0.942,
+ 0.602, 0.762, 0.939, 0.614, 0.770, 0.935, 0.626, 0.778, 0.932, 0.637,
+ 0.786, 0.929, 0.649, 0.794, 0.926, 0.660, 0.801, 0.924, 0.671, 0.809,
+ 0.921, 0.683, 0.817, 0.919, 0.694, 0.824, 0.916, 0.704, 0.832, 0.914,
+ 0.715, 0.839, 0.912, 0.725, 0.846, 0.910, 0.735, 0.853, 0.908, 0.744,
+ 0.859, 0.905, 0.753, 0.866, 0.903, 0.762, 0.872, 0.900, 0.770, 0.877,
+ 0.897, 0.776, 0.882, 0.893, 0.782, 0.886, 0.889, 0.787, 0.890, 0.884,
+ 0.791, 0.893, 0.878, 0.794, 0.895, 0.871, 0.795, 0.896, 0.862, 0.795,
+ 0.896, 0.852, 0.794, 0.895, 0.841, 0.792, 0.894, 0.829, 0.789, 0.891,
+ 0.815, 0.786, 0.888, 0.800, 0.782, 0.884, 0.783, 0.778, 0.879, 0.766,
+ 0.774, 0.874, 0.748, 0.769, 0.868, 0.729, 0.764, 0.862, 0.710, 0.760,
+ 0.856, 0.690, 0.755, 0.849, 0.669, 0.750, 0.842, 0.649, 0.745, 0.835,
+ 0.628, 0.741, 0.827, 0.606, 0.736, 0.820, 0.585, 0.732, 0.812, 0.563,
+ 0.728, 0.804, 0.542, 0.723, 0.796, 0.520, 0.719, 0.788, 0.498, 0.715,
+ 0.780, 0.475, 0.711, 0.772, 0.453, 0.707, 0.764, 0.431, 0.703, 0.756,
+ 0.408, 0.699, 0.748, 0.386, 0.696, 0.739, 0.363, 0.692, 0.731, 0.339,
+ 0.688, 0.723, 0.316, 0.685, 0.714, 0.292, 0.681, 0.706, 0.267, 0.678,
+ 0.697, 0.242, 0.674, 0.689, 0.215, 0.498, 0.679, 0.986, 0.510, 0.687,
+ 0.980, 0.522, 0.696, 0.975, 0.534, 0.704, 0.970, 0.546, 0.712, 0.965,
+ 0.558, 0.721, 0.961, 0.570, 0.729, 0.956, 0.581, 0.737, 0.952, 0.593,
+ 0.746, 0.948, 0.605, 0.754, 0.945, 0.617, 0.762, 0.941, 0.629, 0.770,
+ 0.938, 0.640, 0.778, 0.935, 0.652, 0.786, 0.932, 0.664, 0.794, 0.930,
+ 0.675, 0.802, 0.927, 0.687, 0.810, 0.925, 0.698, 0.818, 0.923, 0.709,
+ 0.826, 0.921, 0.720, 0.834, 0.919, 0.731, 0.841, 0.917, 0.742, 0.849,
+ 0.915, 0.752, 0.856, 0.913, 0.762, 0.863, 0.911, 0.771, 0.870, 0.909,
+ 0.780, 0.876, 0.907, 0.788, 0.882, 0.904, 0.796, 0.887, 0.901, 0.802,
+ 0.892, 0.897, 0.807, 0.896, 0.893, 0.811, 0.899, 0.887, 0.814, 0.902,
+ 0.880, 0.815, 0.903, 0.872, 0.815, 0.903, 0.862, 0.814, 0.902, 0.851,
+ 0.812, 0.900, 0.838, 0.809, 0.897, 0.824, 0.805, 0.893, 0.808, 0.801,
+ 0.889, 0.791, 0.796, 0.884, 0.774, 0.791, 0.878, 0.755, 0.786, 0.872,
+ 0.735, 0.781, 0.865, 0.715, 0.776, 0.858, 0.695, 0.771, 0.851, 0.674,
+ 0.767, 0.844, 0.653, 0.762, 0.836, 0.631, 0.757, 0.829, 0.610, 0.752,
+ 0.821, 0.588, 0.748, 0.813, 0.566, 0.743, 0.805, 0.544, 0.739, 0.796,
+ 0.522, 0.734, 0.788, 0.500, 0.730, 0.780, 0.477, 0.726, 0.772, 0.455,
+ 0.722, 0.763, 0.432, 0.718, 0.755, 0.410, 0.714, 0.746, 0.387, 0.710,
+ 0.738, 0.364, 0.706, 0.730, 0.340, 0.702, 0.721, 0.317, 0.698, 0.713,
+ 0.293, 0.694, 0.704, 0.268, 0.691, 0.696, 0.243, 0.687, 0.687, 0.216,
+ 0.513, 0.677, 0.987, 0.525, 0.686, 0.982, 0.537, 0.694, 0.977, 0.549,
+ 0.703, 0.972, 0.561, 0.711, 0.967, 0.572, 0.720, 0.962, 0.584, 0.728,
+ 0.958, 0.596, 0.737, 0.954, 0.608, 0.745, 0.951, 0.619, 0.753, 0.947,
+ 0.631, 0.762, 0.944, 0.643, 0.770, 0.941, 0.655, 0.778, 0.938, 0.666,
+ 0.787, 0.935, 0.678, 0.795, 0.933, 0.689, 0.803, 0.930, 0.701, 0.811,
+ 0.928, 0.713, 0.820, 0.926, 0.724, 0.828, 0.925, 0.735, 0.836, 0.923,
+ 0.746, 0.844, 0.921, 0.757, 0.852, 0.920, 0.768, 0.859, 0.918, 0.778,
+ 0.867, 0.917, 0.788, 0.874, 0.915, 0.797, 0.881, 0.913, 0.806, 0.887,
+ 0.911, 0.814, 0.893, 0.909, 0.821, 0.898, 0.906, 0.827, 0.902, 0.902,
+ 0.831, 0.906, 0.897, 0.834, 0.908, 0.890, 0.836, 0.910, 0.882, 0.836,
+ 0.910, 0.873, 0.834, 0.909, 0.861, 0.832, 0.906, 0.848, 0.828, 0.903,
+ 0.833, 0.824, 0.899, 0.817, 0.819, 0.894, 0.799, 0.814, 0.888, 0.781,
+ 0.809, 0.882, 0.761, 0.804, 0.875, 0.741, 0.798, 0.868, 0.720, 0.793,
+ 0.861, 0.699, 0.788, 0.853, 0.678, 0.783, 0.845, 0.656, 0.777, 0.837,
+ 0.635, 0.772, 0.829, 0.613, 0.768, 0.821, 0.590, 0.763, 0.813, 0.568,
+ 0.758, 0.804, 0.546, 0.753, 0.796, 0.524, 0.749, 0.788, 0.501, 0.744,
+ 0.779, 0.479, 0.740, 0.771, 0.456, 0.736, 0.762, 0.433, 0.731, 0.754,
+ 0.411, 0.727, 0.745, 0.388, 0.723, 0.736, 0.365, 0.719, 0.728, 0.341,
+ 0.715, 0.719, 0.317, 0.711, 0.711, 0.293, 0.707, 0.702, 0.268, 0.704,
+ 0.694, 0.243, 0.700, 0.685, 0.216, 0.528, 0.675, 0.989, 0.540, 0.684,
+ 0.983, 0.551, 0.693, 0.978, 0.563, 0.701, 0.973, 0.575, 0.710, 0.969,
+ 0.586, 0.718, 0.964, 0.598, 0.727, 0.960, 0.610, 0.736, 0.956, 0.621,
+ 0.744, 0.953, 0.633, 0.753, 0.949, 0.645, 0.761, 0.946, 0.656, 0.770,
+ 0.943, 0.668, 0.778, 0.940, 0.680, 0.787, 0.938, 0.691, 0.795, 0.936,
+ 0.703, 0.804, 0.933, 0.715, 0.812, 0.932, 0.726, 0.821, 0.930, 0.738,
+ 0.829, 0.928, 0.749, 0.837, 0.927, 0.761, 0.846, 0.926, 0.772, 0.854,
+ 0.924, 0.783, 0.862, 0.923, 0.794, 0.870, 0.922, 0.804, 0.877, 0.921,
+ 0.814, 0.885, 0.920, 0.824, 0.892, 0.918, 0.832, 0.898, 0.917, 0.840,
+ 0.904, 0.914, 0.846, 0.909, 0.911, 0.851, 0.913, 0.906, 0.855, 0.915,
+ 0.901, 0.856, 0.917, 0.893, 0.856, 0.917, 0.883, 0.854, 0.915, 0.871,
+ 0.851, 0.913, 0.858, 0.847, 0.909, 0.842, 0.842, 0.904, 0.825, 0.837,
+ 0.898, 0.806, 0.831, 0.892, 0.787, 0.826, 0.885, 0.767, 0.820, 0.878,
+ 0.746, 0.814, 0.870, 0.725, 0.809, 0.862, 0.703, 0.803, 0.854, 0.681,
+ 0.798, 0.846, 0.659, 0.793, 0.838, 0.637, 0.788, 0.829, 0.615, 0.782,
+ 0.821, 0.592, 0.777, 0.812, 0.570, 0.773, 0.804, 0.548, 0.768, 0.795,
+ 0.525, 0.763, 0.787, 0.502, 0.758, 0.778, 0.480, 0.754, 0.769, 0.457,
+ 0.749, 0.761, 0.434, 0.745, 0.752, 0.411, 0.741, 0.743, 0.388, 0.737,
+ 0.735, 0.365, 0.732, 0.726, 0.342, 0.728, 0.717, 0.318, 0.724, 0.709,
+ 0.293, 0.720, 0.700, 0.269, 0.716, 0.691, 0.243, 0.712, 0.683, 0.216,
+ 0.542, 0.673, 0.990, 0.554, 0.682, 0.985, 0.565, 0.691, 0.980, 0.577,
+ 0.700, 0.975, 0.588, 0.708, 0.970, 0.600, 0.717, 0.966, 0.611, 0.726,
+ 0.962, 0.623, 0.734, 0.958, 0.634, 0.743, 0.955, 0.646, 0.752, 0.951,
+ 0.657, 0.760, 0.948, 0.669, 0.769, 0.945, 0.681, 0.778, 0.943, 0.692,
+ 0.786, 0.940, 0.704, 0.795, 0.938, 0.716, 0.804, 0.936, 0.728, 0.812,
+ 0.934, 0.739, 0.821, 0.933, 0.751, 0.830, 0.932, 0.763, 0.838, 0.930,
+ 0.774, 0.847, 0.929, 0.786, 0.856, 0.929, 0.797, 0.864, 0.928, 0.809,
+ 0.873, 0.927, 0.819, 0.881, 0.927, 0.830, 0.889, 0.926, 0.840, 0.896,
+ 0.925, 0.850, 0.903, 0.924, 0.858, 0.910, 0.922, 0.865, 0.915, 0.920,
+ 0.871, 0.920, 0.916, 0.875, 0.923, 0.911, 0.876, 0.924, 0.903, 0.876,
+ 0.924, 0.894, 0.873, 0.922, 0.882, 0.870, 0.919, 0.867, 0.865, 0.914,
+ 0.851, 0.860, 0.909, 0.832, 0.854, 0.902, 0.813, 0.848, 0.895, 0.793,
+ 0.842, 0.888, 0.772, 0.836, 0.880, 0.750, 0.830, 0.872, 0.729, 0.824,
+ 0.864, 0.707, 0.819, 0.855, 0.684, 0.813, 0.847, 0.662, 0.808, 0.838,
+ 0.639, 0.802, 0.829, 0.617, 0.797, 0.820, 0.594, 0.792, 0.812, 0.571,
+ 0.787, 0.803, 0.549, 0.782, 0.794, 0.526, 0.777, 0.785, 0.503, 0.772,
+ 0.776, 0.480, 0.767, 0.768, 0.458, 0.763, 0.759, 0.435, 0.758, 0.750,
+ 0.412, 0.754, 0.741, 0.388, 0.749, 0.732, 0.365, 0.745, 0.724, 0.342,
+ 0.741, 0.715, 0.318, 0.737, 0.706, 0.293, 0.732, 0.697, 0.269, 0.728,
+ 0.689, 0.243, 0.724, 0.680, 0.216, 0.556, 0.671, 0.992, 0.567, 0.680,
+ 0.986, 0.578, 0.689, 0.981, 0.590, 0.697, 0.976, 0.601, 0.706, 0.972,
+ 0.612, 0.715, 0.968, 0.624, 0.724, 0.964, 0.635, 0.733, 0.960, 0.646,
+ 0.741, 0.956, 0.658, 0.750, 0.953, 0.670, 0.759, 0.950, 0.681, 0.768,
+ 0.947, 0.693, 0.777, 0.945, 0.704, 0.786, 0.943, 0.716, 0.794, 0.941,
+ 0.728, 0.803, 0.939, 0.740, 0.812, 0.937, 0.752, 0.821, 0.936, 0.763,
+ 0.830, 0.935, 0.775, 0.839, 0.934, 0.787, 0.848, 0.933, 0.799, 0.857,
+ 0.932, 0.811, 0.866, 0.932, 0.822, 0.875, 0.932, 0.834, 0.883, 0.932,
+ 0.845, 0.892, 0.931, 0.856, 0.900, 0.931, 0.866, 0.908, 0.931, 0.876,
+ 0.915, 0.930, 0.884, 0.922, 0.929, 0.890, 0.927, 0.926, 0.895, 0.930,
+ 0.921, 0.896, 0.932, 0.914, 0.896, 0.932, 0.905, 0.893, 0.929, 0.892,
+ 0.888, 0.925, 0.876, 0.883, 0.920, 0.859, 0.877, 0.913, 0.840, 0.871,
+ 0.906, 0.819, 0.864, 0.898, 0.798, 0.858, 0.890, 0.776, 0.852, 0.882,
+ 0.754, 0.845, 0.873, 0.732, 0.839, 0.864, 0.709, 0.833, 0.855, 0.686,
+ 0.828, 0.846, 0.664, 0.822, 0.837, 0.641, 0.816, 0.828, 0.618, 0.811,
+ 0.819, 0.595, 0.806, 0.810, 0.572, 0.800, 0.801, 0.549, 0.795, 0.792,
+ 0.526, 0.790, 0.783, 0.504, 0.785, 0.774, 0.481, 0.781, 0.765, 0.458,
+ 0.776, 0.756, 0.435, 0.771, 0.748, 0.412, 0.766, 0.739, 0.388, 0.762,
+ 0.730, 0.365, 0.757, 0.721, 0.341, 0.753, 0.712, 0.318, 0.749, 0.703,
+ 0.293, 0.744, 0.695, 0.268, 0.740, 0.686, 0.243, 0.736, 0.677, 0.216,
+ 0.569, 0.668, 0.993, 0.580, 0.677, 0.987, 0.591, 0.686, 0.982, 0.602,
+ 0.695, 0.978, 0.613, 0.704, 0.973, 0.624, 0.713, 0.969, 0.635, 0.722,
+ 0.965, 0.647, 0.731, 0.961, 0.658, 0.740, 0.958, 0.670, 0.748, 0.955,
+ 0.681, 0.757, 0.952, 0.693, 0.766, 0.949, 0.704, 0.775, 0.947, 0.716,
+ 0.784, 0.945, 0.728, 0.793, 0.943, 0.739, 0.802, 0.941, 0.751, 0.812,
+ 0.939, 0.763, 0.821, 0.938, 0.775, 0.830, 0.937, 0.787, 0.839, 0.936,
+ 0.799, 0.848, 0.936, 0.811, 0.858, 0.936, 0.823, 0.867, 0.935, 0.835,
+ 0.876, 0.936, 0.847, 0.886, 0.936, 0.859, 0.895, 0.936, 0.870, 0.904,
+ 0.937, 0.882, 0.912, 0.937, 0.892, 0.920, 0.937, 0.901, 0.928, 0.937,
+ 0.909, 0.934, 0.936, 0.914, 0.938, 0.932, 0.917, 0.940, 0.926, 0.915,
+ 0.940, 0.916, 0.912, 0.936, 0.902, 0.906, 0.931, 0.885, 0.900, 0.925,
+ 0.866, 0.893, 0.917, 0.846, 0.887, 0.909, 0.824, 0.880, 0.900, 0.802,
+ 0.873, 0.891, 0.780, 0.867, 0.882, 0.757, 0.860, 0.873, 0.734, 0.854,
+ 0.864, 0.711, 0.848, 0.855, 0.688, 0.842, 0.845, 0.665, 0.836, 0.836,
+ 0.642, 0.830, 0.827, 0.619, 0.824, 0.818, 0.596, 0.819, 0.808, 0.573,
+ 0.814, 0.799, 0.549, 0.808, 0.790, 0.527, 0.803, 0.781, 0.504, 0.798,
+ 0.772, 0.481, 0.793, 0.763, 0.458, 0.788, 0.754, 0.434, 0.783, 0.745,
+ 0.411, 0.779, 0.736, 0.388, 0.774, 0.727, 0.365, 0.769, 0.718, 0.341,
+ 0.765, 0.709, 0.317, 0.760, 0.700, 0.293, 0.756, 0.691, 0.268, 0.751,
+ 0.683, 0.242, 0.747, 0.674, 0.215, 0.581, 0.665, 0.994, 0.592, 0.674,
+ 0.989, 0.603, 0.683, 0.984, 0.614, 0.692, 0.979, 0.625, 0.701, 0.974,
+ 0.636, 0.710, 0.970, 0.647, 0.719, 0.966, 0.658, 0.728, 0.963, 0.669,
+ 0.737, 0.959, 0.681, 0.746, 0.956, 0.692, 0.755, 0.953, 0.703, 0.765,
+ 0.951, 0.715, 0.774, 0.948, 0.727, 0.783, 0.946, 0.738, 0.792, 0.944,
+ 0.750, 0.801, 0.943, 0.762, 0.810, 0.941, 0.774, 0.820, 0.940, 0.786,
+ 0.829, 0.939, 0.798, 0.839, 0.939, 0.810, 0.848, 0.938, 0.822, 0.858,
+ 0.938, 0.834, 0.867, 0.939, 0.847, 0.877, 0.939, 0.859, 0.887, 0.940,
+ 0.871, 0.897, 0.940, 0.883, 0.906, 0.942, 0.896, 0.916, 0.943, 0.907,
+ 0.925, 0.944, 0.918, 0.933, 0.945, 0.927, 0.941, 0.945, 0.934, 0.946,
+ 0.943, 0.937, 0.949, 0.937, 0.935, 0.948, 0.927, 0.930, 0.943, 0.912,
+ 0.924, 0.937, 0.893, 0.916, 0.929, 0.872, 0.909, 0.920, 0.850, 0.902,
+ 0.911, 0.828, 0.895, 0.901, 0.805, 0.888, 0.892, 0.782, 0.881, 0.882,
+ 0.759, 0.874, 0.872, 0.735, 0.868, 0.863, 0.712, 0.861, 0.853, 0.689,
+ 0.855, 0.844, 0.665, 0.849, 0.834, 0.642, 0.843, 0.825, 0.619, 0.838,
+ 0.815, 0.596, 0.832, 0.806, 0.572, 0.826, 0.797, 0.549, 0.821, 0.787,
+ 0.526, 0.816, 0.778, 0.503, 0.811, 0.769, 0.480, 0.805, 0.760, 0.457,
+ 0.800, 0.751, 0.434, 0.795, 0.742, 0.411, 0.791, 0.733, 0.387, 0.786,
+ 0.724, 0.364, 0.781, 0.715, 0.340, 0.776, 0.706, 0.316, 0.772, 0.697,
+ 0.292, 0.767, 0.688, 0.267, 0.762, 0.679, 0.241, 0.758, 0.670, 0.215,
+ 0.593, 0.662, 0.995, 0.603, 0.671, 0.990, 0.614, 0.680, 0.985, 0.625,
+ 0.689, 0.980, 0.636, 0.699, 0.975, 0.647, 0.708, 0.971, 0.658, 0.717,
+ 0.967, 0.669, 0.726, 0.964, 0.680, 0.735, 0.960, 0.691, 0.744, 0.957,
+ 0.702, 0.753, 0.955, 0.714, 0.762, 0.952, 0.725, 0.771, 0.950, 0.737,
+ 0.781, 0.948, 0.748, 0.790, 0.946, 0.760, 0.799, 0.944, 0.772, 0.809,
+ 0.943, 0.784, 0.818, 0.942, 0.796, 0.828, 0.941, 0.808, 0.837, 0.941,
+ 0.820, 0.847, 0.940, 0.832, 0.857, 0.941, 0.844, 0.867, 0.941, 0.857,
+ 0.877, 0.942, 0.869, 0.887, 0.943, 0.882, 0.897, 0.944, 0.895, 0.908,
+ 0.945, 0.908, 0.918, 0.947, 0.920, 0.928, 0.949, 0.933, 0.938, 0.951,
+ 0.944, 0.947, 0.953, 0.953, 0.955, 0.954, 0.957, 0.958, 0.950, 0.954,
+ 0.956, 0.938, 0.948, 0.949, 0.920, 0.940, 0.941, 0.899, 0.932, 0.931,
+ 0.877, 0.924, 0.921, 0.854, 0.916, 0.911, 0.830, 0.909, 0.901, 0.807,
+ 0.901, 0.891, 0.783, 0.894, 0.881, 0.759, 0.887, 0.871, 0.736, 0.881,
+ 0.861, 0.712, 0.874, 0.851, 0.688, 0.868, 0.841, 0.665, 0.862, 0.832,
+ 0.642, 0.856, 0.822, 0.618, 0.850, 0.812, 0.595, 0.844, 0.803, 0.572,
+ 0.839, 0.793, 0.549, 0.833, 0.784, 0.525, 0.828, 0.775, 0.502, 0.822,
+ 0.766, 0.479, 0.817, 0.756, 0.456, 0.812, 0.747, 0.433, 0.807, 0.738,
+ 0.410, 0.802, 0.729, 0.387, 0.797, 0.720, 0.363, 0.792, 0.711, 0.339,
+ 0.787, 0.702, 0.315, 0.782, 0.693, 0.291, 0.778, 0.684, 0.266, 0.773,
+ 0.675, 0.240, 0.768, 0.666, 0.214, 0.604, 0.659, 0.996, 0.614, 0.668,
+ 0.990, 0.625, 0.677, 0.985, 0.636, 0.686, 0.981, 0.646, 0.695, 0.976,
+ 0.657, 0.704, 0.972, 0.668, 0.714, 0.968, 0.679, 0.723, 0.965, 0.690,
+ 0.732, 0.961, 0.701, 0.741, 0.958, 0.712, 0.750, 0.956, 0.723, 0.759,
+ 0.953, 0.735, 0.769, 0.951, 0.746, 0.778, 0.949, 0.758, 0.787, 0.947,
+ 0.769, 0.797, 0.945, 0.781, 0.806, 0.944, 0.793, 0.816, 0.943, 0.805,
+ 0.826, 0.943, 0.817, 0.836, 0.942, 0.829, 0.845, 0.942, 0.841, 0.855,
+ 0.942, 0.853, 0.866, 0.943, 0.866, 0.876, 0.943, 0.879, 0.886, 0.945,
+ 0.892, 0.897, 0.946, 0.905, 0.907, 0.948, 0.918, 0.918, 0.950, 0.931,
+ 0.930, 0.953, 0.945, 0.941, 0.956, 0.958, 0.952, 0.960, 0.971, 0.963,
+ 0.963, 0.978, 0.968, 0.963, 0.972, 0.963, 0.948, 0.963, 0.954, 0.926,
+ 0.954, 0.943, 0.903, 0.945, 0.931, 0.879, 0.937, 0.921, 0.855, 0.929,
+ 0.910, 0.831, 0.921, 0.899, 0.807, 0.914, 0.889, 0.783, 0.907, 0.878,
+ 0.759, 0.900, 0.868, 0.735, 0.893, 0.858, 0.711, 0.887, 0.848, 0.688,
+ 0.880, 0.838, 0.664, 0.874, 0.828, 0.641, 0.868, 0.818, 0.617, 0.862,
+ 0.809, 0.594, 0.856, 0.799, 0.571, 0.850, 0.790, 0.547, 0.845, 0.780,
+ 0.524, 0.839, 0.771, 0.501, 0.834, 0.762, 0.478, 0.828, 0.752, 0.455,
+ 0.823, 0.743, 0.432, 0.818, 0.734, 0.409, 0.813, 0.725, 0.385, 0.808,
+ 0.716, 0.362, 0.803, 0.707, 0.338, 0.798, 0.698, 0.314, 0.793, 0.689,
+ 0.290, 0.788, 0.680, 0.265, 0.783, 0.671, 0.239, 0.778, 0.662, 0.213,
+ 0.615, 0.655, 0.996, 0.625, 0.664, 0.991, 0.635, 0.673, 0.986, 0.646,
+ 0.683, 0.982, 0.656, 0.692, 0.977, 0.667, 0.701, 0.973, 0.678, 0.710,
+ 0.969, 0.688, 0.719, 0.966, 0.699, 0.729, 0.962, 0.710, 0.738, 0.959,
+ 0.721, 0.747, 0.956, 0.732, 0.756, 0.954, 0.744, 0.766, 0.952, 0.755,
+ 0.775, 0.950, 0.766, 0.784, 0.948, 0.778, 0.794, 0.946, 0.789, 0.804,
+ 0.945, 0.801, 0.813, 0.944, 0.813, 0.823, 0.943, 0.825, 0.833, 0.943,
+ 0.837, 0.843, 0.943, 0.849, 0.853, 0.943, 0.861, 0.863, 0.944, 0.874,
+ 0.873, 0.944, 0.886, 0.884, 0.946, 0.899, 0.895, 0.947, 0.912, 0.906,
+ 0.949, 0.926, 0.917, 0.952, 0.939, 0.928, 0.955, 0.953, 0.940, 0.958,
+ 0.967, 0.953, 0.963, 0.982, 0.966, 0.969, 0.994, 0.976, 0.972, 0.986,
+ 0.966, 0.952, 0.976, 0.953, 0.928, 0.966, 0.941, 0.903, 0.957, 0.929,
+ 0.878, 0.949, 0.918, 0.854, 0.941, 0.906, 0.830, 0.933, 0.896, 0.806,
+ 0.926, 0.885, 0.782, 0.918, 0.874, 0.758, 0.911, 0.864, 0.734, 0.905,
+ 0.854, 0.710, 0.898, 0.844, 0.686, 0.892, 0.834, 0.663, 0.885, 0.824,
+ 0.639, 0.879, 0.814, 0.616, 0.873, 0.804, 0.592, 0.867, 0.795, 0.569,
+ 0.861, 0.785, 0.546, 0.856, 0.776, 0.523, 0.850, 0.766, 0.500, 0.845,
+ 0.757, 0.477, 0.839, 0.748, 0.454, 0.834, 0.739, 0.430, 0.829, 0.729,
+ 0.407, 0.823, 0.720, 0.384, 0.818, 0.711, 0.361, 0.813, 0.702, 0.337,
+ 0.808, 0.693, 0.313, 0.803, 0.684, 0.289, 0.798, 0.675, 0.264, 0.793,
+ 0.666, 0.238, 0.788, 0.657, 0.211, 0.625, 0.651, 0.997, 0.635, 0.660,
+ 0.992, 0.645, 0.669, 0.987, 0.656, 0.679, 0.982, 0.666, 0.688, 0.978,
+ 0.676, 0.697, 0.974, 0.687, 0.706, 0.970, 0.698, 0.716, 0.966, 0.708,
+ 0.725, 0.963, 0.719, 0.734, 0.960, 0.730, 0.743, 0.957, 0.741, 0.753,
+ 0.954, 0.752, 0.762, 0.952, 0.763, 0.771, 0.950, 0.774, 0.781, 0.948,
+ 0.786, 0.790, 0.947, 0.797, 0.800, 0.945, 0.809, 0.810, 0.945, 0.820,
+ 0.819, 0.944, 0.832, 0.829, 0.943, 0.844, 0.839, 0.943, 0.856, 0.849,
+ 0.943, 0.868, 0.860, 0.944, 0.880, 0.870, 0.945, 0.893, 0.880, 0.946,
+ 0.905, 0.891, 0.947, 0.918, 0.902, 0.949, 0.931, 0.913, 0.951, 0.944,
+ 0.924, 0.954, 0.957, 0.936, 0.957, 0.971, 0.947, 0.961, 0.983, 0.958,
+ 0.964, 0.991, 0.963, 0.962, 0.990, 0.957, 0.946, 0.983, 0.946, 0.924,
+ 0.975, 0.935, 0.900, 0.967, 0.923, 0.876, 0.959, 0.912, 0.851, 0.951,
+ 0.901, 0.827, 0.943, 0.890, 0.803, 0.936, 0.880, 0.779, 0.929, 0.869,
+ 0.755, 0.922, 0.859, 0.732, 0.915, 0.849, 0.708, 0.909, 0.839, 0.684,
+ 0.902, 0.829, 0.661, 0.896, 0.819, 0.637, 0.890, 0.809, 0.614, 0.884,
+ 0.800, 0.591, 0.878, 0.790, 0.567, 0.872, 0.780, 0.544, 0.866, 0.771,
+ 0.521, 0.861, 0.762, 0.498, 0.855, 0.752, 0.475, 0.850, 0.743, 0.452,
+ 0.844, 0.734, 0.429, 0.839, 0.725, 0.406, 0.834, 0.715, 0.382, 0.828,
+ 0.706, 0.359, 0.823, 0.697, 0.335, 0.818, 0.688, 0.311, 0.813, 0.679,
+ 0.287, 0.808, 0.670, 0.262, 0.803, 0.662, 0.236, 0.798, 0.653, 0.210,
+ 0.635, 0.646, 0.998, 0.645, 0.656, 0.992, 0.655, 0.665, 0.987, 0.665,
+ 0.674, 0.983, 0.675, 0.684, 0.978, 0.685, 0.693, 0.974, 0.696, 0.702,
+ 0.970, 0.706, 0.711, 0.966, 0.717, 0.721, 0.963, 0.727, 0.730, 0.960,
+ 0.738, 0.739, 0.957, 0.749, 0.748, 0.955, 0.760, 0.758, 0.952, 0.771,
+ 0.767, 0.950, 0.782, 0.777, 0.948, 0.793, 0.786, 0.947, 0.804, 0.796,
+ 0.946, 0.816, 0.805, 0.945, 0.827, 0.815, 0.944, 0.839, 0.825, 0.943,
+ 0.850, 0.835, 0.943, 0.862, 0.845, 0.943, 0.874, 0.855, 0.943, 0.886,
+ 0.865, 0.944, 0.898, 0.875, 0.945, 0.910, 0.886, 0.946, 0.923, 0.896,
+ 0.948, 0.935, 0.907, 0.949, 0.947, 0.917, 0.951, 0.959, 0.927, 0.953,
+ 0.970, 0.937, 0.955, 0.980, 0.944, 0.955, 0.987, 0.946, 0.949, 0.989,
+ 0.942, 0.936, 0.985, 0.935, 0.916, 0.980, 0.925, 0.894, 0.973, 0.915,
+ 0.871, 0.966, 0.904, 0.847, 0.959, 0.894, 0.824, 0.952, 0.883, 0.800,
+ 0.945, 0.873, 0.776, 0.938, 0.863, 0.752, 0.932, 0.853, 0.729, 0.925,
+ 0.843, 0.705, 0.919, 0.833, 0.682, 0.912, 0.823, 0.658, 0.906, 0.813,
+ 0.635, 0.900, 0.803, 0.611, 0.894, 0.794, 0.588, 0.888, 0.784, 0.565,
+ 0.882, 0.775, 0.542, 0.876, 0.765, 0.519, 0.871, 0.756, 0.496, 0.865,
+ 0.747, 0.473, 0.859, 0.738, 0.450, 0.854, 0.728, 0.427, 0.848, 0.719,
+ 0.404, 0.843, 0.710, 0.380, 0.838, 0.701, 0.357, 0.833, 0.692, 0.333,
+ 0.827, 0.683, 0.310, 0.822, 0.674, 0.285, 0.817, 0.665, 0.260, 0.812,
+ 0.656, 0.235, 0.807, 0.648, 0.208, 0.644, 0.642, 0.998, 0.654, 0.651,
+ 0.993, 0.664, 0.660, 0.988, 0.674, 0.670, 0.983, 0.684, 0.679, 0.978,
+ 0.694, 0.688, 0.974, 0.704, 0.697, 0.970, 0.715, 0.707, 0.967, 0.725,
+ 0.716, 0.963, 0.735, 0.725, 0.960, 0.746, 0.735, 0.957, 0.757, 0.744,
+ 0.955, 0.767, 0.753, 0.952, 0.778, 0.763, 0.950, 0.789, 0.772, 0.948,
+ 0.800, 0.781, 0.947, 0.811, 0.791, 0.945, 0.822, 0.801, 0.944, 0.833,
+ 0.810, 0.943, 0.845, 0.820, 0.943, 0.856, 0.830, 0.942, 0.868, 0.839,
+ 0.942, 0.879, 0.849, 0.942, 0.891, 0.859, 0.943, 0.902, 0.869, 0.943,
+ 0.914, 0.879, 0.944, 0.926, 0.889, 0.945, 0.937, 0.899, 0.946, 0.949,
+ 0.908, 0.947, 0.959, 0.917, 0.948, 0.969, 0.924, 0.947, 0.978, 0.929,
+ 0.944, 0.984, 0.930, 0.937, 0.986, 0.927, 0.924, 0.986, 0.921, 0.907,
+ 0.982, 0.913, 0.887, 0.978, 0.904, 0.865, 0.972, 0.895, 0.842, 0.966,
+ 0.885, 0.819, 0.959, 0.875, 0.795, 0.953, 0.865, 0.772, 0.946, 0.855,
+ 0.749, 0.940, 0.846, 0.725, 0.934, 0.836, 0.702, 0.927, 0.826, 0.678,
+ 0.921, 0.816, 0.655, 0.915, 0.807, 0.632, 0.909, 0.797, 0.609, 0.903,
+ 0.788, 0.586, 0.897, 0.778, 0.562, 0.891, 0.769, 0.539, 0.886, 0.759,
+ 0.516, 0.880, 0.750, 0.493, 0.874, 0.741, 0.471, 0.869, 0.732, 0.448,
+ 0.863, 0.723, 0.425, 0.858, 0.713, 0.402, 0.852, 0.704, 0.378, 0.847,
+ 0.695, 0.355, 0.842, 0.686, 0.331, 0.836, 0.677, 0.308, 0.831, 0.669,
+ 0.283, 0.826, 0.660, 0.258, 0.821, 0.651, 0.233, 0.815, 0.642, 0.206,
+ 0.653, 0.636, 0.998, 0.663, 0.646, 0.993, 0.673, 0.655, 0.988, 0.682,
+ 0.665, 0.983, 0.692, 0.674, 0.979, 0.702, 0.683, 0.974, 0.712, 0.692,
+ 0.970, 0.722, 0.702, 0.967, 0.733, 0.711, 0.963, 0.743, 0.720, 0.960,
+ 0.753, 0.730, 0.957, 0.764, 0.739, 0.954, 0.774, 0.748, 0.952, 0.785,
+ 0.757, 0.950, 0.796, 0.767, 0.948, 0.806, 0.776, 0.946, 0.817, 0.786,
+ 0.945, 0.828, 0.795, 0.943, 0.839, 0.804, 0.942, 0.850, 0.814, 0.941,
+ 0.861, 0.824, 0.941, 0.872, 0.833, 0.940, 0.884, 0.843, 0.940, 0.895,
+ 0.852, 0.940, 0.906, 0.862, 0.940, 0.917, 0.871, 0.941, 0.928, 0.880,
+ 0.941, 0.939, 0.889, 0.941, 0.949, 0.897, 0.941, 0.959, 0.904, 0.940,
+ 0.968, 0.910, 0.938, 0.975, 0.914, 0.933, 0.981, 0.914, 0.925, 0.984,
+ 0.912, 0.913, 0.985, 0.907, 0.897, 0.983, 0.900, 0.878, 0.980, 0.893,
+ 0.857, 0.976, 0.884, 0.836, 0.971, 0.875, 0.813, 0.965, 0.866, 0.790,
+ 0.959, 0.856, 0.767, 0.954, 0.847, 0.744, 0.947, 0.837, 0.721, 0.941,
+ 0.828, 0.698, 0.935, 0.818, 0.675, 0.929, 0.809, 0.652, 0.923, 0.800,
+ 0.629, 0.917, 0.790, 0.605, 0.912, 0.781, 0.582, 0.906, 0.771, 0.560,
+ 0.900, 0.762, 0.537, 0.894, 0.753, 0.514, 0.889, 0.744, 0.491, 0.883,
+ 0.735, 0.468, 0.877, 0.725, 0.445, 0.872, 0.716, 0.422, 0.866, 0.707,
+ 0.399, 0.861, 0.698, 0.376, 0.856, 0.689, 0.353, 0.850, 0.680, 0.329,
+ 0.845, 0.672, 0.305, 0.840, 0.663, 0.281, 0.834, 0.654, 0.256, 0.829,
+ 0.645, 0.231, 0.824, 0.636, 0.204, 0.662, 0.631, 0.998, 0.672, 0.641,
+ 0.993, 0.681, 0.650, 0.988, 0.691, 0.659, 0.983, 0.700, 0.669, 0.979,
+ 0.710, 0.678, 0.974, 0.720, 0.687, 0.970, 0.730, 0.696, 0.966, 0.740,
+ 0.706, 0.963, 0.750, 0.715, 0.960, 0.760, 0.724, 0.957, 0.771, 0.733,
+ 0.954, 0.781, 0.742, 0.951, 0.791, 0.752, 0.949, 0.802, 0.761, 0.947,
+ 0.812, 0.770, 0.945, 0.823, 0.779, 0.943, 0.834, 0.789, 0.942, 0.844,
+ 0.798, 0.941, 0.855, 0.807, 0.940, 0.866, 0.817, 0.939, 0.877, 0.826,
+ 0.938, 0.887, 0.835, 0.938, 0.898, 0.844, 0.937, 0.909, 0.853, 0.937,
+ 0.919, 0.862, 0.937, 0.930, 0.870, 0.936, 0.940, 0.878, 0.936, 0.950,
+ 0.885, 0.934, 0.958, 0.891, 0.932, 0.967, 0.896, 0.928, 0.974, 0.898,
+ 0.922, 0.979, 0.899, 0.914, 0.982, 0.897, 0.902, 0.984, 0.893, 0.886,
+ 0.984, 0.887, 0.869, 0.982, 0.880, 0.849, 0.979, 0.872, 0.828, 0.975,
+ 0.864, 0.807, 0.970, 0.856, 0.785, 0.965, 0.847, 0.762, 0.959, 0.838,
+ 0.739, 0.954, 0.829, 0.717, 0.948, 0.819, 0.694, 0.943, 0.810, 0.671,
+ 0.937, 0.801, 0.648, 0.931, 0.792, 0.625, 0.925, 0.782, 0.602, 0.919,
+ 0.773, 0.579, 0.914, 0.764, 0.556, 0.908, 0.755, 0.533, 0.902, 0.746,
+ 0.511, 0.897, 0.737, 0.488, 0.891, 0.728, 0.465, 0.886, 0.719, 0.442,
+ 0.880, 0.710, 0.420, 0.875, 0.701, 0.397, 0.869, 0.692, 0.374, 0.864,
+ 0.683, 0.350, 0.858, 0.674, 0.327, 0.853, 0.665, 0.303, 0.848, 0.657,
+ 0.279, 0.842, 0.648, 0.254, 0.837, 0.639, 0.229, 0.832, 0.630, 0.202,
+ 0.671, 0.625, 0.998, 0.680, 0.635, 0.993, 0.689, 0.644, 0.988, 0.698,
+ 0.654, 0.983, 0.708, 0.663, 0.978, 0.718, 0.672, 0.974, 0.727, 0.681,
+ 0.970, 0.737, 0.691, 0.966, 0.747, 0.700, 0.962, 0.757, 0.709, 0.959,
+ 0.767, 0.718, 0.956, 0.777, 0.727, 0.953, 0.787, 0.736, 0.950, 0.797,
+ 0.745, 0.948, 0.807, 0.755, 0.946, 0.818, 0.764, 0.944, 0.828, 0.773,
+ 0.942, 0.839, 0.782, 0.940, 0.849, 0.791, 0.939, 0.859, 0.800, 0.938,
+ 0.870, 0.809, 0.937, 0.880, 0.818, 0.936, 0.891, 0.827, 0.935, 0.901,
+ 0.835, 0.934, 0.911, 0.844, 0.933, 0.921, 0.852, 0.932, 0.931, 0.859,
+ 0.931, 0.941, 0.866, 0.929, 0.950, 0.873, 0.927, 0.958, 0.878, 0.923,
+ 0.966, 0.881, 0.919, 0.972, 0.883, 0.912, 0.977, 0.883, 0.903, 0.981,
+ 0.882, 0.891, 0.983, 0.878, 0.876, 0.984, 0.873, 0.859, 0.983, 0.867,
+ 0.841, 0.980, 0.860, 0.821, 0.977, 0.853, 0.800, 0.974, 0.845, 0.778,
+ 0.969, 0.836, 0.756, 0.964, 0.828, 0.734, 0.959, 0.819, 0.712, 0.954,
+ 0.810, 0.689, 0.949, 0.801, 0.666, 0.943, 0.792, 0.644, 0.938, 0.783,
+ 0.621, 0.932, 0.774, 0.598, 0.927, 0.765, 0.575, 0.921, 0.756, 0.553,
+ 0.916, 0.747, 0.530, 0.910, 0.738, 0.507, 0.904, 0.729, 0.485, 0.899,
+ 0.721, 0.462, 0.893, 0.712, 0.439, 0.888, 0.703, 0.417, 0.882, 0.694,
+ 0.394, 0.877, 0.685, 0.371, 0.871, 0.676, 0.348, 0.866, 0.668, 0.324,
+ 0.861, 0.659, 0.301, 0.855, 0.650, 0.277, 0.850, 0.641, 0.252, 0.845,
+ 0.633, 0.226, 0.839, 0.624, 0.200, 0.679, 0.619, 0.998, 0.688, 0.629,
+ 0.993, 0.697, 0.638, 0.988, 0.706, 0.648, 0.983, 0.715, 0.657, 0.978,
+ 0.725, 0.666, 0.974, 0.734, 0.675, 0.969, 0.744, 0.684, 0.965, 0.754,
+ 0.693, 0.962, 0.763, 0.703, 0.958, 0.773, 0.712, 0.955, 0.783, 0.721,
+ 0.952, 0.793, 0.730, 0.949, 0.803, 0.739, 0.947, 0.813, 0.748, 0.944,
+ 0.823, 0.757, 0.942, 0.833, 0.766, 0.940, 0.843, 0.774, 0.938, 0.853,
+ 0.783, 0.937, 0.863, 0.792, 0.935, 0.874, 0.801, 0.934, 0.884, 0.809,
+ 0.932, 0.894, 0.818, 0.931, 0.904, 0.826, 0.930, 0.913, 0.833, 0.928,
+ 0.923, 0.841, 0.927, 0.932, 0.848, 0.925, 0.941, 0.854, 0.922, 0.950,
+ 0.859, 0.919, 0.957, 0.864, 0.915, 0.965, 0.867, 0.909, 0.971, 0.868,
+ 0.901, 0.976, 0.868, 0.892, 0.980, 0.867, 0.880, 0.982, 0.863, 0.866,
+ 0.983, 0.859, 0.849, 0.983, 0.854, 0.832, 0.982, 0.847, 0.812, 0.979,
+ 0.840, 0.792, 0.976, 0.833, 0.771, 0.973, 0.825, 0.750, 0.969, 0.817,
+ 0.728, 0.964, 0.809, 0.706, 0.959, 0.800, 0.684, 0.954, 0.792, 0.661,
+ 0.949, 0.783, 0.639, 0.944, 0.774, 0.617, 0.939, 0.766, 0.594, 0.933,
+ 0.757, 0.572, 0.928, 0.748, 0.549, 0.922, 0.739, 0.527, 0.917, 0.731,
+ 0.504, 0.911, 0.722, 0.481, 0.906, 0.713, 0.459, 0.901, 0.704, 0.436,
+ 0.895, 0.695, 0.414, 0.890, 0.687, 0.391, 0.884, 0.678, 0.368, 0.879,
+ 0.669, 0.345, 0.873, 0.661, 0.322, 0.868, 0.652, 0.298, 0.863, 0.643,
+ 0.274, 0.857, 0.635, 0.249, 0.852, 0.626, 0.224, 0.846, 0.617, 0.197,
+ 0.686, 0.613, 0.998, 0.695, 0.622, 0.993, 0.704, 0.632, 0.987, 0.713,
+ 0.641, 0.982, 0.722, 0.650, 0.977, 0.732, 0.660, 0.973, 0.741, 0.669,
+ 0.969, 0.750, 0.678, 0.965, 0.760, 0.687, 0.961, 0.769, 0.696, 0.957,
+ 0.779, 0.705, 0.954, 0.789, 0.714, 0.951, 0.798, 0.723, 0.948, 0.808,
+ 0.731, 0.945, 0.818, 0.740, 0.943, 0.828, 0.749, 0.940, 0.838, 0.758,
+ 0.938, 0.847, 0.766, 0.936, 0.857, 0.775, 0.934, 0.867, 0.783, 0.932,
+ 0.877, 0.792, 0.930, 0.887, 0.800, 0.929, 0.896, 0.808, 0.927, 0.906,
+ 0.815, 0.925, 0.915, 0.823, 0.923, 0.924, 0.829, 0.921, 0.933, 0.836,
+ 0.918, 0.942, 0.841, 0.915, 0.950, 0.846, 0.911, 0.957, 0.850, 0.906,
+ 0.964, 0.852, 0.899, 0.970, 0.853, 0.891, 0.975, 0.853, 0.881, 0.979,
+ 0.852, 0.869, 0.981, 0.849, 0.855, 0.983, 0.845, 0.840, 0.983, 0.840,
+ 0.822, 0.982, 0.834, 0.804, 0.981, 0.828, 0.784, 0.978, 0.821, 0.764,
+ 0.975, 0.814, 0.743, 0.972, 0.806, 0.722, 0.968, 0.798, 0.700, 0.964,
+ 0.790, 0.678, 0.959, 0.782, 0.656, 0.954, 0.773, 0.634, 0.949, 0.765,
+ 0.612, 0.944, 0.757, 0.590, 0.939, 0.748, 0.567, 0.934, 0.739, 0.545,
+ 0.929, 0.731, 0.523, 0.923, 0.722, 0.500, 0.918, 0.714, 0.478, 0.913,
+ 0.705, 0.456, 0.907, 0.696, 0.433, 0.902, 0.688, 0.411, 0.896, 0.679,
+ 0.388, 0.891, 0.670, 0.365, 0.886, 0.662, 0.342, 0.880, 0.653, 0.319,
+ 0.875, 0.645, 0.295, 0.869, 0.636, 0.271, 0.864, 0.628, 0.247, 0.859,
+ 0.619, 0.221, 0.853, 0.611, 0.195, 0.694, 0.606, 0.998, 0.703, 0.616,
+ 0.992, 0.711, 0.625, 0.987, 0.720, 0.634, 0.982, 0.729, 0.644, 0.977,
+ 0.738, 0.653, 0.972, 0.747, 0.662, 0.968, 0.757, 0.671, 0.964, 0.766,
+ 0.680, 0.960, 0.775, 0.689, 0.956, 0.785, 0.698, 0.953, 0.794, 0.706,
+ 0.949, 0.804, 0.715, 0.946, 0.813, 0.724, 0.943, 0.823, 0.732, 0.941,
+ 0.832, 0.741, 0.938, 0.842, 0.749, 0.936, 0.851, 0.758, 0.933, 0.861,
+ 0.766, 0.931, 0.870, 0.774, 0.929, 0.880, 0.782, 0.927, 0.889, 0.790,
+ 0.924, 0.899, 0.797, 0.922, 0.908, 0.805, 0.920, 0.917, 0.811, 0.917,
+ 0.925, 0.818, 0.914, 0.934, 0.823, 0.911, 0.942, 0.828, 0.907, 0.950,
+ 0.832, 0.902, 0.957, 0.836, 0.896, 0.963, 0.838, 0.889, 0.969, 0.839,
+ 0.881, 0.974, 0.838, 0.871, 0.978, 0.837, 0.859, 0.980, 0.834, 0.845,
+ 0.982, 0.831, 0.830, 0.983, 0.826, 0.813, 0.983, 0.821, 0.795, 0.982,
+ 0.815, 0.776, 0.980, 0.809, 0.757, 0.978, 0.802, 0.736, 0.975, 0.794,
+ 0.715, 0.971, 0.787, 0.694, 0.967, 0.779, 0.673, 0.963, 0.771, 0.651,
+ 0.959, 0.763, 0.629, 0.954, 0.755, 0.607, 0.949, 0.747, 0.585, 0.944,
+ 0.739, 0.563, 0.939, 0.730, 0.541, 0.934, 0.722, 0.519, 0.929, 0.714,
+ 0.496, 0.924, 0.705, 0.474, 0.919, 0.697, 0.452, 0.913, 0.688, 0.430,
+ 0.908, 0.680, 0.407, 0.903, 0.671, 0.385, 0.897, 0.663, 0.362, 0.892,
+ 0.654, 0.339, 0.887, 0.646, 0.316, 0.881, 0.637, 0.293, 0.876, 0.629,
+ 0.269, 0.870, 0.620, 0.244, 0.865, 0.612, 0.219, 0.860, 0.604, 0.192,
+ 0.701, 0.599, 0.997, 0.710, 0.609, 0.992, 0.718, 0.618, 0.986, 0.727,
+ 0.627, 0.981, 0.736, 0.636, 0.976, 0.745, 0.645, 0.971, 0.754, 0.655,
+ 0.967, 0.763, 0.663, 0.963, 0.772, 0.672, 0.959, 0.781, 0.681, 0.955,
+ 0.790, 0.690, 0.951, 0.799, 0.699, 0.948, 0.808, 0.707, 0.944, 0.818,
+ 0.716, 0.941, 0.827, 0.724, 0.938, 0.836, 0.732, 0.935, 0.846, 0.741,
+ 0.933, 0.855, 0.749, 0.930, 0.864, 0.757, 0.928, 0.874, 0.765, 0.925,
+ 0.883, 0.772, 0.923, 0.892, 0.780, 0.920, 0.901, 0.787, 0.917, 0.910,
+ 0.793, 0.914, 0.918, 0.800, 0.911, 0.927, 0.805, 0.908, 0.935, 0.811,
+ 0.904, 0.942, 0.815, 0.899, 0.950, 0.819, 0.894, 0.956, 0.821, 0.887,
+ 0.963, 0.823, 0.880, 0.968, 0.824, 0.871, 0.973, 0.824, 0.860, 0.977,
+ 0.822, 0.849, 0.980, 0.820, 0.835, 0.982, 0.817, 0.820, 0.983, 0.812,
+ 0.804, 0.983, 0.808, 0.786, 0.983, 0.802, 0.768, 0.981, 0.796, 0.749,
+ 0.979, 0.789, 0.729, 0.977, 0.783, 0.709, 0.974, 0.776, 0.688, 0.970,
+ 0.768, 0.667, 0.967, 0.761, 0.645, 0.963, 0.753, 0.624, 0.958, 0.745,
+ 0.602, 0.954, 0.737, 0.580, 0.949, 0.729, 0.558, 0.944, 0.721, 0.536,
+ 0.939, 0.713, 0.514, 0.934, 0.704, 0.492, 0.929, 0.696, 0.470, 0.924,
+ 0.688, 0.448, 0.919, 0.680, 0.426, 0.914, 0.671, 0.404, 0.908, 0.663,
+ 0.381, 0.903, 0.655, 0.359, 0.898, 0.646, 0.336, 0.893, 0.638, 0.313,
+ 0.887, 0.629, 0.290, 0.882, 0.621, 0.266, 0.876, 0.613, 0.241, 0.871,
+ 0.604, 0.216, 0.866, 0.596, 0.189, 0.708, 0.592, 0.997, 0.716, 0.601,
+ 0.991, 0.725, 0.611, 0.985, 0.733, 0.620, 0.980, 0.742, 0.629, 0.975,
+ 0.751, 0.638, 0.970, 0.759, 0.647, 0.966, 0.768, 0.656, 0.961, 0.777,
+ 0.665, 0.957, 0.786, 0.673, 0.953, 0.795, 0.682, 0.949, 0.804, 0.690,
+ 0.946, 0.813, 0.699, 0.942, 0.822, 0.707, 0.939, 0.831, 0.715, 0.936,
+ 0.840, 0.723, 0.933, 0.849, 0.731, 0.930, 0.859, 0.739, 0.927, 0.868,
+ 0.747, 0.924, 0.876, 0.754, 0.921, 0.885, 0.762, 0.918, 0.894, 0.769,
+ 0.915, 0.903, 0.775, 0.912, 0.911, 0.782, 0.909, 0.920, 0.787, 0.905,
+ 0.928, 0.793, 0.901, 0.935, 0.798, 0.896, 0.943, 0.802, 0.891, 0.950,
+ 0.805, 0.885, 0.956, 0.807, 0.878, 0.962, 0.809, 0.870, 0.967, 0.809,
+ 0.861, 0.972, 0.809, 0.850, 0.976, 0.808, 0.838, 0.979, 0.805, 0.825,
+ 0.981, 0.802, 0.810, 0.983, 0.799, 0.795, 0.983, 0.794, 0.778, 0.983,
+ 0.789, 0.760, 0.982, 0.783, 0.741, 0.981, 0.777, 0.721, 0.979, 0.771,
+ 0.701, 0.976, 0.764, 0.681, 0.973, 0.757, 0.660, 0.970, 0.750, 0.639,
+ 0.966, 0.742, 0.618, 0.962, 0.735, 0.597, 0.958, 0.727, 0.575, 0.953,
+ 0.719, 0.553, 0.949, 0.711, 0.532, 0.944, 0.703, 0.510, 0.939, 0.695,
+ 0.488, 0.934, 0.687, 0.466, 0.929, 0.679, 0.444, 0.924, 0.671, 0.422,
+ 0.919, 0.663, 0.400, 0.914, 0.654, 0.378, 0.909, 0.646, 0.355, 0.903,
+ 0.638, 0.333, 0.898, 0.630, 0.310, 0.893, 0.621, 0.287, 0.887, 0.613,
+ 0.263, 0.882, 0.605, 0.238, 0.877, 0.597, 0.213, 0.871, 0.589, 0.186,
+ 0.715, 0.584, 0.996, 0.723, 0.593, 0.990, 0.731, 0.603, 0.984, 0.739,
+ 0.612, 0.979, 0.748, 0.621, 0.974, 0.756, 0.630, 0.969, 0.765, 0.639,
+ 0.964, 0.774, 0.648, 0.960, 0.782, 0.656, 0.955, 0.791, 0.665, 0.951,
+ 0.800, 0.673, 0.947, 0.809, 0.682, 0.943, 0.818, 0.690, 0.940, 0.826,
+ 0.698, 0.936, 0.835, 0.706, 0.933, 0.844, 0.714, 0.930, 0.853, 0.722,
+ 0.926, 0.862, 0.729, 0.923, 0.871, 0.737, 0.920, 0.879, 0.744, 0.917,
+ 0.888, 0.751, 0.913, 0.896, 0.758, 0.910, 0.905, 0.764, 0.906, 0.913,
+ 0.770, 0.903, 0.921, 0.775, 0.898, 0.929, 0.780, 0.894, 0.936, 0.784,
+ 0.889, 0.943, 0.788, 0.883, 0.950, 0.791, 0.877, 0.956, 0.793, 0.869,
+ 0.962, 0.794, 0.861, 0.967, 0.795, 0.851, 0.971, 0.794, 0.841, 0.975,
+ 0.793, 0.829, 0.978, 0.791, 0.815, 0.981, 0.788, 0.801, 0.982, 0.785,
+ 0.785, 0.983, 0.780, 0.769, 0.983, 0.776, 0.751, 0.983, 0.770, 0.733,
+ 0.982, 0.764, 0.714, 0.980, 0.758, 0.694, 0.978, 0.752, 0.674, 0.975,
+ 0.745, 0.654, 0.972, 0.738, 0.633, 0.969, 0.731, 0.612, 0.965, 0.724,
+ 0.591, 0.961, 0.716, 0.570, 0.957, 0.709, 0.548, 0.953, 0.701, 0.527,
+ 0.948, 0.693, 0.505, 0.943, 0.685, 0.484, 0.939, 0.678, 0.462, 0.934,
+ 0.670, 0.440, 0.929, 0.662, 0.418, 0.924, 0.654, 0.396, 0.919, 0.646,
+ 0.374, 0.914, 0.637, 0.352, 0.908, 0.629, 0.329, 0.903, 0.621, 0.307,
+ 0.898, 0.613, 0.283, 0.893, 0.605, 0.260, 0.887, 0.597, 0.235, 0.882,
+ 0.589, 0.210, 0.876, 0.581, 0.183, 0.721, 0.576, 0.995, 0.729, 0.585,
+ 0.989, 0.737, 0.595, 0.983, 0.745, 0.604, 0.978, 0.754, 0.613, 0.973,
+ 0.762, 0.622, 0.968, 0.770, 0.631, 0.963, 0.779, 0.639, 0.958, 0.787,
+ 0.648, 0.954, 0.796, 0.656, 0.949, 0.805, 0.665, 0.945, 0.813, 0.673,
+ 0.941, 0.822, 0.681, 0.937, 0.830, 0.689, 0.933, 0.839, 0.697, 0.930,
+ 0.848, 0.704, 0.926, 0.856, 0.712, 0.923, 0.865, 0.719, 0.919, 0.873,
+ 0.726, 0.916, 0.882, 0.733, 0.912, 0.890, 0.740, 0.908, 0.898, 0.746,
+ 0.905, 0.906, 0.752, 0.901, 0.914, 0.757, 0.896, 0.922, 0.762, 0.892,
+ 0.929, 0.767, 0.887, 0.937, 0.771, 0.881, 0.943, 0.774, 0.875, 0.950,
+ 0.777, 0.868, 0.956, 0.779, 0.860, 0.961, 0.780, 0.851, 0.966, 0.780,
+ 0.842, 0.971, 0.780, 0.831, 0.975, 0.779, 0.819, 0.978, 0.777, 0.806,
+ 0.980, 0.774, 0.791, 0.982, 0.771, 0.776, 0.983, 0.767, 0.760, 0.984,
+ 0.762, 0.742, 0.983, 0.757, 0.725, 0.983, 0.752, 0.706, 0.981, 0.746,
+ 0.687, 0.979, 0.740, 0.667, 0.977, 0.733, 0.647, 0.974, 0.727, 0.627,
+ 0.971, 0.720, 0.606, 0.968, 0.713, 0.585, 0.964, 0.706, 0.564, 0.960,
+ 0.698, 0.543, 0.956, 0.691, 0.522, 0.952, 0.683, 0.501, 0.947, 0.676,
+ 0.479, 0.943, 0.668, 0.458, 0.938, 0.660, 0.436, 0.933, 0.652, 0.414,
+ 0.928, 0.644, 0.392, 0.923, 0.636, 0.370, 0.918, 0.629, 0.348, 0.913,
+ 0.621, 0.326, 0.908, 0.613, 0.303, 0.903, 0.605, 0.280, 0.897, 0.597,
+ 0.257, 0.892, 0.589, 0.232, 0.887, 0.581, 0.207, 0.881, 0.573, 0.180,
+ 0.727, 0.568, 0.994, 0.735, 0.577, 0.988, 0.743, 0.586, 0.982, 0.751,
+ 0.595, 0.977, 0.759, 0.604, 0.971, 0.767, 0.613, 0.966, 0.776, 0.622,
+ 0.961, 0.784, 0.630, 0.956, 0.792, 0.639, 0.951, 0.801, 0.647, 0.947,
+ 0.809, 0.655, 0.943, 0.817, 0.663, 0.938, 0.826, 0.671, 0.934, 0.834,
+ 0.679, 0.930, 0.843, 0.687, 0.927, 0.851, 0.694, 0.923, 0.859, 0.702,
+ 0.919, 0.868, 0.709, 0.915, 0.876, 0.715, 0.911, 0.884, 0.722, 0.907,
+ 0.892, 0.728, 0.903, 0.900, 0.734, 0.899, 0.908, 0.740, 0.895, 0.916,
+ 0.745, 0.890, 0.923, 0.750, 0.885, 0.930, 0.754, 0.879, 0.937, 0.758,
+ 0.873, 0.944, 0.761, 0.867, 0.950, 0.763, 0.859, 0.956, 0.765, 0.851,
+ 0.961, 0.766, 0.842, 0.966, 0.766, 0.832, 0.970, 0.766, 0.821, 0.974,
+ 0.764, 0.809, 0.977, 0.762, 0.796, 0.980, 0.760, 0.782, 0.982, 0.757,
+ 0.767, 0.983, 0.753, 0.751, 0.984, 0.749, 0.734, 0.984, 0.744, 0.716,
+ 0.983, 0.739, 0.698, 0.982, 0.733, 0.679, 0.980, 0.727, 0.660, 0.978,
+ 0.721, 0.640, 0.976, 0.715, 0.620, 0.973, 0.708, 0.600, 0.970, 0.701,
+ 0.579, 0.967, 0.694, 0.559, 0.963, 0.687, 0.538, 0.959, 0.680, 0.517,
+ 0.955, 0.673, 0.496, 0.951, 0.665, 0.474, 0.946, 0.658, 0.453, 0.942,
+ 0.650, 0.432, 0.937, 0.643, 0.410, 0.932, 0.635, 0.388, 0.927, 0.627,
+ 0.367, 0.922, 0.619, 0.345, 0.917, 0.612, 0.322, 0.912, 0.604, 0.300,
+ 0.907, 0.596, 0.277, 0.902, 0.588, 0.253, 0.897, 0.580, 0.229, 0.891,
+ 0.572, 0.204, 0.886, 0.564, 0.177, 0.733, 0.559, 0.993, 0.741, 0.568,
+ 0.987, 0.749, 0.577, 0.981, 0.757, 0.587, 0.975, 0.765, 0.595, 0.970,
+ 0.773, 0.604, 0.964, 0.781, 0.613, 0.959, 0.789, 0.621, 0.954, 0.797,
+ 0.630, 0.949, 0.805, 0.638, 0.945, 0.813, 0.646, 0.940, 0.821, 0.654,
+ 0.936, 0.830, 0.662, 0.931, 0.838, 0.669, 0.927, 0.846, 0.677, 0.923,
+ 0.854, 0.684, 0.919, 0.862, 0.691, 0.915, 0.870, 0.698, 0.911, 0.879,
+ 0.704, 0.907, 0.886, 0.711, 0.902, 0.894, 0.717, 0.898, 0.902, 0.722,
+ 0.893, 0.910, 0.727, 0.889, 0.917, 0.732, 0.883, 0.924, 0.737, 0.878,
+ 0.931, 0.741, 0.872, 0.938, 0.744, 0.866, 0.944, 0.747, 0.859, 0.950,
+ 0.749, 0.851, 0.956, 0.751, 0.842, 0.961, 0.751, 0.833, 0.966, 0.752,
+ 0.823, 0.970, 0.751, 0.812, 0.974, 0.750, 0.800, 0.977, 0.748, 0.787,
+ 0.979, 0.746, 0.773, 0.981, 0.743, 0.758, 0.983, 0.739, 0.742, 0.984,
+ 0.735, 0.725, 0.984, 0.731, 0.708, 0.983, 0.726, 0.690, 0.983, 0.721,
+ 0.672, 0.981, 0.715, 0.653, 0.980, 0.709, 0.633, 0.977, 0.703, 0.614,
+ 0.975, 0.697, 0.594, 0.972, 0.690, 0.573, 0.969, 0.683, 0.553, 0.965,
+ 0.676, 0.532, 0.962, 0.669, 0.512, 0.958, 0.662, 0.491, 0.954, 0.655,
+ 0.470, 0.949, 0.648, 0.448, 0.945, 0.640, 0.427, 0.941, 0.633, 0.406,
+ 0.936, 0.625, 0.384, 0.931, 0.618, 0.363, 0.926, 0.610, 0.341, 0.921,
+ 0.602, 0.319, 0.916, 0.595, 0.296, 0.911, 0.587, 0.273, 0.906, 0.579,
+ 0.250, 0.901, 0.571, 0.226, 0.896, 0.563, 0.201, 0.890, 0.556, 0.174,
+ 0.739, 0.550, 0.992, 0.747, 0.559, 0.986, 0.754, 0.568, 0.980, 0.762,
+ 0.577, 0.974, 0.770, 0.586, 0.968, 0.778, 0.595, 0.962, 0.785, 0.603,
+ 0.957, 0.793, 0.612, 0.952, 0.801, 0.620, 0.947, 0.809, 0.628, 0.942,
+ 0.817, 0.636, 0.937, 0.825, 0.644, 0.933, 0.833, 0.651, 0.928, 0.841,
+ 0.659, 0.924, 0.849, 0.666, 0.919, 0.857, 0.673, 0.915, 0.865, 0.680,
+ 0.911, 0.873, 0.686, 0.906, 0.881, 0.693, 0.902, 0.889, 0.699, 0.897,
+ 0.896, 0.705, 0.892, 0.904, 0.710, 0.887, 0.911, 0.715, 0.882, 0.918,
+ 0.720, 0.877, 0.925, 0.724, 0.871, 0.932, 0.727, 0.865, 0.938, 0.730,
+ 0.858, 0.944, 0.733, 0.850, 0.950, 0.735, 0.842, 0.956, 0.736, 0.834,
+ 0.961, 0.737, 0.824, 0.965, 0.737, 0.814, 0.970, 0.737, 0.802, 0.973,
+ 0.736, 0.790, 0.976, 0.734, 0.777, 0.979, 0.732, 0.763, 0.981, 0.729,
+ 0.749, 0.982, 0.726, 0.733, 0.983, 0.722, 0.717, 0.984, 0.717, 0.700,
+ 0.984, 0.713, 0.682, 0.983, 0.708, 0.664, 0.982, 0.702, 0.645, 0.980,
+ 0.697, 0.626, 0.979, 0.691, 0.607, 0.976, 0.685, 0.587, 0.974, 0.678,
+ 0.567, 0.971, 0.672, 0.547, 0.967, 0.665, 0.527, 0.964, 0.658, 0.506,
+ 0.960, 0.651, 0.485, 0.956, 0.644, 0.465, 0.952, 0.637, 0.444, 0.948,
+ 0.630, 0.423, 0.944, 0.623, 0.401, 0.939, 0.615, 0.380, 0.934, 0.608,
+ 0.358, 0.930, 0.600, 0.337, 0.925, 0.593, 0.315, 0.920, 0.585, 0.292,
+ 0.915, 0.578, 0.270, 0.910, 0.570, 0.246, 0.905, 0.562, 0.222, 0.899,
+ 0.555, 0.197, 0.894, 0.547, 0.171, 0.745, 0.540, 0.991, 0.752, 0.550,
+ 0.984, 0.760, 0.559, 0.978, 0.767, 0.568, 0.972, 0.775, 0.577, 0.966,
+ 0.782, 0.585, 0.960, 0.790, 0.594, 0.955, 0.798, 0.602, 0.950, 0.806,
+ 0.610, 0.944, 0.813, 0.618, 0.939, 0.821, 0.626, 0.934, 0.829, 0.634,
+ 0.930, 0.837, 0.641, 0.925, 0.845, 0.648, 0.920, 0.852, 0.655, 0.915,
+ 0.860, 0.662, 0.911, 0.868, 0.669, 0.906, 0.876, 0.675, 0.901, 0.883,
+ 0.681, 0.897, 0.891, 0.687, 0.892, 0.898, 0.692, 0.887, 0.905, 0.697,
+ 0.881, 0.912, 0.702, 0.876, 0.919, 0.707, 0.870, 0.926, 0.710, 0.864,
+ 0.932, 0.714, 0.857, 0.939, 0.717, 0.850, 0.945, 0.719, 0.842, 0.950,
+ 0.721, 0.834, 0.956, 0.722, 0.825, 0.961, 0.723, 0.815, 0.965, 0.723,
+ 0.804, 0.969, 0.723, 0.793, 0.973, 0.722, 0.781, 0.976, 0.720, 0.768,
+ 0.978, 0.718, 0.754, 0.981, 0.715, 0.739, 0.982, 0.712, 0.724, 0.983,
+ 0.708, 0.708, 0.984, 0.704, 0.691, 0.984, 0.700, 0.674, 0.983, 0.695,
+ 0.656, 0.982, 0.690, 0.638, 0.981, 0.684, 0.619, 0.979, 0.679, 0.600,
+ 0.977, 0.673, 0.581, 0.975, 0.666, 0.561, 0.972, 0.660, 0.541, 0.969,
+ 0.654, 0.521, 0.966, 0.647, 0.501, 0.962, 0.640, 0.480, 0.959, 0.634,
+ 0.459, 0.955, 0.627, 0.439, 0.951, 0.620, 0.418, 0.946, 0.612, 0.397,
+ 0.942, 0.605, 0.376, 0.937, 0.598, 0.354, 0.933, 0.591, 0.333, 0.928,
+ 0.583, 0.311, 0.923, 0.576, 0.289, 0.918, 0.568, 0.266, 0.913, 0.561,
+ 0.243, 0.908, 0.553, 0.219, 0.903, 0.546, 0.194, 0.898, 0.538, 0.167,
+ 0.750, 0.531, 0.989, 0.757, 0.540, 0.983, 0.765, 0.549, 0.976, 0.772,
+ 0.558, 0.970, 0.779, 0.567, 0.964, 0.787, 0.575, 0.958, 0.794, 0.584,
+ 0.953, 0.802, 0.592, 0.947, 0.810, 0.600, 0.942, 0.817, 0.608, 0.936,
+ 0.825, 0.615, 0.931, 0.833, 0.623, 0.926, 0.840, 0.630, 0.921, 0.848,
+ 0.637, 0.916, 0.855, 0.644, 0.911, 0.863, 0.651, 0.907, 0.870, 0.657,
+ 0.902, 0.878, 0.663, 0.897, 0.885, 0.669, 0.891, 0.893, 0.675, 0.886,
+ 0.900, 0.680, 0.881, 0.907, 0.685, 0.875, 0.914, 0.689, 0.869, 0.920,
+ 0.693, 0.863, 0.927, 0.697, 0.857, 0.933, 0.700, 0.850, 0.939, 0.703,
+ 0.842, 0.945, 0.705, 0.834, 0.950, 0.707, 0.825, 0.956, 0.708, 0.816,
+ 0.960, 0.709, 0.806, 0.965, 0.709, 0.795, 0.969, 0.708, 0.784, 0.972,
+ 0.707, 0.772, 0.975, 0.706, 0.759, 0.978, 0.704, 0.745, 0.980, 0.701,
+ 0.731, 0.982, 0.698, 0.715, 0.983, 0.694, 0.699, 0.984, 0.691, 0.683,
+ 0.984, 0.686, 0.666, 0.983, 0.682, 0.648, 0.983, 0.677, 0.630, 0.982,
+ 0.672, 0.612, 0.980, 0.666, 0.593, 0.978, 0.660, 0.574, 0.976, 0.655,
+ 0.554, 0.973, 0.648, 0.535, 0.971, 0.642, 0.515, 0.967, 0.636, 0.495,
+ 0.964, 0.629, 0.475, 0.961, 0.623, 0.454, 0.957, 0.616, 0.434, 0.953,
+ 0.609, 0.413, 0.949, 0.602, 0.392, 0.944, 0.595, 0.371, 0.940, 0.588,
+ 0.350, 0.936, 0.580, 0.328, 0.931, 0.573, 0.307, 0.926, 0.566, 0.285,
+ 0.921, 0.559, 0.262, 0.916, 0.551, 0.239, 0.911, 0.544, 0.215, 0.906,
+ 0.536, 0.190, 0.901, 0.529, 0.164, 0.755, 0.521, 0.988, 0.762, 0.530,
+ 0.981, 0.770, 0.539, 0.975, 0.777, 0.548, 0.968, 0.784, 0.557, 0.962,
+ 0.791, 0.565, 0.956, 0.799, 0.573, 0.950, 0.806, 0.582, 0.944, 0.814,
+ 0.589, 0.939, 0.821, 0.597, 0.933, 0.828, 0.605, 0.928, 0.836, 0.612,
+ 0.923, 0.843, 0.619, 0.918, 0.851, 0.626, 0.912, 0.858, 0.633, 0.907,
+ 0.866, 0.639, 0.902, 0.873, 0.645, 0.897, 0.880, 0.651, 0.892, 0.887,
+ 0.657, 0.886, 0.894, 0.662, 0.881, 0.901, 0.667, 0.875, 0.908, 0.672,
+ 0.869, 0.915, 0.676, 0.863, 0.921, 0.680, 0.856, 0.928, 0.684, 0.849,
+ 0.934, 0.687, 0.842, 0.940, 0.689, 0.834, 0.945, 0.691, 0.826, 0.951,
+ 0.693, 0.817, 0.956, 0.694, 0.807, 0.960, 0.695, 0.797, 0.964, 0.695,
+ 0.787, 0.968, 0.694, 0.775, 0.972, 0.693, 0.763, 0.975, 0.692, 0.750,
+ 0.977, 0.690, 0.736, 0.980, 0.687, 0.722, 0.981, 0.684, 0.707, 0.982,
+ 0.681, 0.691, 0.983, 0.677, 0.675, 0.984, 0.673, 0.658, 0.983, 0.669,
+ 0.641, 0.983, 0.664, 0.623, 0.982, 0.659, 0.605, 0.980, 0.654, 0.586,
+ 0.979, 0.648, 0.567, 0.977, 0.642, 0.548, 0.974, 0.637, 0.529, 0.972,
+ 0.630, 0.509, 0.969, 0.624, 0.489, 0.966, 0.618, 0.469, 0.962, 0.611,
+ 0.449, 0.959, 0.605, 0.429, 0.955, 0.598, 0.408, 0.951, 0.591, 0.387,
+ 0.947, 0.584, 0.367, 0.942, 0.577, 0.346, 0.938, 0.570, 0.324, 0.933,
+ 0.563, 0.303, 0.929, 0.556, 0.281, 0.924, 0.549, 0.258, 0.919, 0.541,
+ 0.235, 0.914, 0.534, 0.212, 0.909, 0.527, 0.187, 0.904, 0.519, 0.160,
+ 0.760, 0.510, 0.986, 0.767, 0.520, 0.979, 0.774, 0.529, 0.973, 0.781,
+ 0.538, 0.966, 0.788, 0.546, 0.960, 0.796, 0.555, 0.954, 0.803, 0.563,
+ 0.948, 0.810, 0.571, 0.942, 0.817, 0.579, 0.936, 0.825, 0.586, 0.930,
+ 0.832, 0.594, 0.925, 0.839, 0.601, 0.919, 0.846, 0.608, 0.914, 0.854,
+ 0.615, 0.908, 0.861, 0.621, 0.903, 0.868, 0.627, 0.897, 0.875, 0.633,
+ 0.892, 0.882, 0.639, 0.886, 0.889, 0.645, 0.881, 0.896, 0.650, 0.875,
+ 0.903, 0.655, 0.869, 0.909, 0.659, 0.863, 0.916, 0.663, 0.856, 0.922,
+ 0.667, 0.849, 0.928, 0.670, 0.842, 0.934, 0.673, 0.834, 0.940, 0.675,
+ 0.826, 0.945, 0.677, 0.818, 0.951, 0.679, 0.809, 0.955, 0.680, 0.799,
+ 0.960, 0.680, 0.789, 0.964, 0.680, 0.778, 0.968, 0.680, 0.766, 0.971,
+ 0.679, 0.754, 0.974, 0.677, 0.741, 0.977, 0.676, 0.727, 0.979, 0.673,
+ 0.713, 0.981, 0.670, 0.698, 0.982, 0.667, 0.682, 0.983, 0.664, 0.666,
+ 0.983, 0.660, 0.650, 0.983, 0.655, 0.633, 0.983, 0.651, 0.615, 0.982,
+ 0.646, 0.597, 0.981, 0.641, 0.579, 0.979, 0.636, 0.560, 0.977, 0.630,
+ 0.541, 0.975, 0.625, 0.522, 0.973, 0.619, 0.503, 0.970, 0.613, 0.483,
+ 0.967, 0.606, 0.463, 0.964, 0.600, 0.443, 0.960, 0.594, 0.423, 0.956,
+ 0.587, 0.403, 0.953, 0.580, 0.383, 0.949, 0.574, 0.362, 0.944, 0.567,
+ 0.341, 0.940, 0.560, 0.320, 0.936, 0.553, 0.298, 0.931, 0.546, 0.277,
+ 0.926, 0.539, 0.254, 0.922, 0.532, 0.232, 0.917, 0.524, 0.208, 0.912,
+ 0.517, 0.183, 0.906, 0.510, 0.156, 0.765, 0.499, 0.985, 0.772, 0.509,
+ 0.978, 0.779, 0.518, 0.971, 0.786, 0.527, 0.964, 0.793, 0.535, 0.957,
+ 0.800, 0.544, 0.951, 0.807, 0.552, 0.945, 0.814, 0.560, 0.939, 0.821,
+ 0.568, 0.933, 0.828, 0.575, 0.927, 0.835, 0.582, 0.921, 0.842, 0.589,
+ 0.915, 0.849, 0.596, 0.910, 0.856, 0.603, 0.904, 0.863, 0.609, 0.898,
+ 0.870, 0.615, 0.893, 0.877, 0.621, 0.887, 0.884, 0.627, 0.881, 0.891,
+ 0.632, 0.875, 0.898, 0.637, 0.869, 0.904, 0.642, 0.863, 0.911, 0.646,
+ 0.856, 0.917, 0.650, 0.849, 0.923, 0.653, 0.842, 0.929, 0.657, 0.835,
+ 0.935, 0.659, 0.827, 0.940, 0.662, 0.818, 0.946, 0.663, 0.810, 0.951,
+ 0.665, 0.800, 0.955, 0.666, 0.790, 0.960, 0.666, 0.780, 0.964, 0.666,
+ 0.769, 0.967, 0.666, 0.757, 0.971, 0.665, 0.745, 0.974, 0.663, 0.732,
+ 0.976, 0.662, 0.718, 0.978, 0.659, 0.704, 0.980, 0.657, 0.689, 0.981,
+ 0.654, 0.674, 0.982, 0.650, 0.658, 0.983, 0.646, 0.642, 0.983, 0.642,
+ 0.625, 0.983, 0.638, 0.608, 0.982, 0.633, 0.590, 0.981, 0.628, 0.572,
+ 0.979, 0.623, 0.553, 0.978, 0.618, 0.535, 0.976, 0.612, 0.516, 0.973,
+ 0.607, 0.497, 0.971, 0.601, 0.477, 0.968, 0.595, 0.458, 0.965, 0.589,
+ 0.438, 0.961, 0.582, 0.418, 0.958, 0.576, 0.398, 0.954, 0.569, 0.378,
+ 0.950, 0.563, 0.357, 0.946, 0.556, 0.336, 0.942, 0.549, 0.315, 0.938,
+ 0.542, 0.294, 0.933, 0.536, 0.273, 0.928, 0.529, 0.250, 0.924, 0.522,
+ 0.228, 0.919, 0.514, 0.204, 0.914, 0.507, 0.179, 0.909, 0.500, 0.153,
+ 0.770, 0.488, 0.983, 0.777, 0.498, 0.976, 0.783, 0.507, 0.969, 0.790,
+ 0.516, 0.962, 0.797, 0.524, 0.955, 0.804, 0.533, 0.948, 0.811, 0.541,
+ 0.942, 0.817, 0.549, 0.936, 0.824, 0.556, 0.930, 0.831, 0.564, 0.924,
+ 0.838, 0.571, 0.918, 0.845, 0.578, 0.912, 0.852, 0.584, 0.906, 0.859,
+ 0.591, 0.900, 0.866, 0.597, 0.894, 0.873, 0.603, 0.888, 0.879, 0.609,
+ 0.882, 0.886, 0.614, 0.876, 0.893, 0.619, 0.869, 0.899, 0.624, 0.863,
+ 0.906, 0.629, 0.856, 0.912, 0.633, 0.850, 0.918, 0.637, 0.843, 0.924,
+ 0.640, 0.835, 0.930, 0.643, 0.827, 0.935, 0.646, 0.819, 0.941, 0.648,
+ 0.811, 0.946, 0.649, 0.802, 0.951, 0.651, 0.792, 0.955, 0.652, 0.782,
+ 0.959, 0.652, 0.771, 0.963, 0.652, 0.760, 0.967, 0.652, 0.749, 0.970,
+ 0.651, 0.736, 0.973, 0.649, 0.723, 0.976, 0.647, 0.710, 0.978, 0.645,
+ 0.696, 0.980, 0.643, 0.681, 0.981, 0.640, 0.666, 0.982, 0.637, 0.650,
+ 0.982, 0.633, 0.634, 0.983, 0.629, 0.617, 0.982, 0.625, 0.600, 0.982,
+ 0.620, 0.582, 0.981, 0.616, 0.565, 0.979, 0.611, 0.546, 0.978, 0.605,
+ 0.528, 0.976, 0.600, 0.509, 0.974, 0.595, 0.490, 0.971, 0.589, 0.471,
+ 0.969, 0.583, 0.452, 0.966, 0.577, 0.432, 0.962, 0.571, 0.413, 0.959,
+ 0.565, 0.393, 0.955, 0.558, 0.373, 0.952, 0.552, 0.352, 0.948, 0.545,
+ 0.332, 0.943, 0.539, 0.311, 0.939, 0.532, 0.290, 0.935, 0.525, 0.268,
+ 0.930, 0.518, 0.246, 0.926, 0.511, 0.224, 0.921, 0.504, 0.200, 0.916,
+ 0.497, 0.175, 0.911, 0.490, 0.149, 0.775, 0.477, 0.981, 0.781, 0.486,
+ 0.974, 0.788, 0.495, 0.966, 0.794, 0.504, 0.959, 0.801, 0.513, 0.952,
+ 0.808, 0.521, 0.946, 0.814, 0.529, 0.939, 0.821, 0.537, 0.933, 0.828,
+ 0.545, 0.926, 0.835, 0.552, 0.920, 0.841, 0.559, 0.914, 0.848, 0.566,
+ 0.908, 0.855, 0.572, 0.901, 0.862, 0.579, 0.895, 0.868, 0.585, 0.889,
+ 0.875, 0.591, 0.883, 0.881, 0.596, 0.877, 0.888, 0.601, 0.870, 0.894,
+ 0.606, 0.864, 0.901, 0.611, 0.857, 0.907, 0.615, 0.850, 0.913, 0.619,
+ 0.843, 0.919, 0.623, 0.836, 0.925, 0.626, 0.828, 0.930, 0.629, 0.820,
+ 0.936, 0.632, 0.812, 0.941, 0.634, 0.803, 0.946, 0.635, 0.794, 0.951,
+ 0.637, 0.784, 0.955, 0.637, 0.774, 0.959, 0.638, 0.763, 0.963, 0.638,
+ 0.752, 0.967, 0.637, 0.740, 0.970, 0.636, 0.728, 0.973, 0.635, 0.715,
+ 0.975, 0.633, 0.701, 0.977, 0.631, 0.687, 0.979, 0.629, 0.672, 0.980,
+ 0.626, 0.657, 0.981, 0.623, 0.642, 0.982, 0.619, 0.626, 0.982, 0.616,
+ 0.609, 0.982, 0.612, 0.592, 0.981, 0.607, 0.575, 0.981, 0.603, 0.557,
+ 0.979, 0.598, 0.540, 0.978, 0.593, 0.521, 0.976, 0.588, 0.503, 0.974,
+ 0.582, 0.484, 0.972, 0.577, 0.465, 0.969, 0.571, 0.446, 0.966, 0.565,
+ 0.427, 0.963, 0.559, 0.407, 0.960, 0.553, 0.387, 0.956, 0.547, 0.368,
+ 0.953, 0.541, 0.347, 0.949, 0.534, 0.327, 0.945, 0.528, 0.306, 0.941,
+ 0.521, 0.285, 0.936, 0.514, 0.264, 0.932, 0.508, 0.242, 0.927, 0.501,
+ 0.220, 0.922, 0.494, 0.196, 0.918, 0.487, 0.172, 0.913, 0.480, 0.145,
+ 0.779, 0.465, 0.979, 0.785, 0.474, 0.971, 0.792, 0.484, 0.964, 0.798,
+ 0.492, 0.957, 0.805, 0.501, 0.950, 0.811, 0.509, 0.943, 0.818, 0.517,
+ 0.936, 0.824, 0.525, 0.929, 0.831, 0.533, 0.923, 0.838, 0.540, 0.916,
+ 0.844, 0.547, 0.910, 0.851, 0.554, 0.904, 0.857, 0.560, 0.897, 0.864,
+ 0.566, 0.891, 0.870, 0.572, 0.884, 0.877, 0.578, 0.878, 0.883, 0.583,
+ 0.871, 0.890, 0.589, 0.865, 0.896, 0.593, 0.858, 0.902, 0.598, 0.851,
+ 0.908, 0.602, 0.844, 0.914, 0.606, 0.837, 0.920, 0.609, 0.829, 0.925,
+ 0.613, 0.821, 0.931, 0.615, 0.813, 0.936, 0.618, 0.804, 0.941, 0.620,
+ 0.795, 0.946, 0.621, 0.786, 0.950, 0.622, 0.776, 0.955, 0.623, 0.765,
+ 0.959, 0.624, 0.755, 0.963, 0.624, 0.743, 0.966, 0.623, 0.731, 0.969,
+ 0.622, 0.719, 0.972, 0.621, 0.706, 0.974, 0.619, 0.693, 0.976, 0.617,
+ 0.679, 0.978, 0.615, 0.664, 0.979, 0.612, 0.649, 0.980, 0.609, 0.634,
+ 0.981, 0.606, 0.618, 0.981, 0.602, 0.601, 0.981, 0.598, 0.585, 0.981,
+ 0.594, 0.568, 0.980, 0.590, 0.550, 0.979, 0.585, 0.533, 0.978, 0.580,
+ 0.515, 0.976, 0.575, 0.496, 0.974, 0.570, 0.478, 0.972, 0.565, 0.459,
+ 0.969, 0.559, 0.440, 0.967, 0.553, 0.421, 0.964, 0.547, 0.402, 0.960,
+ 0.542, 0.382, 0.957, 0.535, 0.362, 0.953, 0.529, 0.342, 0.950, 0.523,
+ 0.322, 0.946, 0.517, 0.302, 0.942, 0.510, 0.281, 0.937, 0.504, 0.260,
+ 0.933, 0.497, 0.238, 0.929, 0.490, 0.216, 0.924, 0.484, 0.192, 0.919,
+ 0.477, 0.168, 0.914, 0.470, 0.141, 0.783, 0.453, 0.977, 0.789, 0.462,
+ 0.969, 0.796, 0.471, 0.962, 0.802, 0.480, 0.954, 0.808, 0.489, 0.947,
+ 0.815, 0.497, 0.940, 0.821, 0.505, 0.933, 0.828, 0.513, 0.926, 0.834,
+ 0.520, 0.919, 0.840, 0.527, 0.913, 0.847, 0.534, 0.906, 0.853, 0.541,
+ 0.899, 0.860, 0.548, 0.893, 0.866, 0.554, 0.886, 0.873, 0.560, 0.880,
+ 0.879, 0.565, 0.873, 0.885, 0.570, 0.866, 0.891, 0.575, 0.859, 0.897,
+ 0.580, 0.852, 0.903, 0.585, 0.845, 0.909, 0.589, 0.838, 0.915, 0.592,
+ 0.830, 0.921, 0.596, 0.822, 0.926, 0.599, 0.814, 0.931, 0.601, 0.805,
+ 0.936, 0.604, 0.797, 0.941, 0.606, 0.787, 0.946, 0.607, 0.778, 0.950,
+ 0.608, 0.768, 0.955, 0.609, 0.757, 0.958, 0.609, 0.746, 0.962, 0.609,
+ 0.735, 0.965, 0.609, 0.723, 0.968, 0.608, 0.710, 0.971, 0.607, 0.698,
+ 0.974, 0.605, 0.684, 0.976, 0.603, 0.670, 0.977, 0.601, 0.656, 0.979,
+ 0.598, 0.641, 0.980, 0.596, 0.626, 0.980, 0.592, 0.610, 0.981, 0.589,
+ 0.594, 0.981, 0.585, 0.577, 0.980, 0.581, 0.560, 0.980, 0.577, 0.543,
+ 0.979, 0.572, 0.526, 0.977, 0.568, 0.508, 0.976, 0.563, 0.490, 0.974,
+ 0.558, 0.471, 0.972, 0.552, 0.453, 0.969, 0.547, 0.434, 0.967, 0.541,
+ 0.415, 0.964, 0.536, 0.396, 0.961, 0.530, 0.377, 0.958, 0.524, 0.357,
+ 0.954, 0.518, 0.337, 0.950, 0.512, 0.317, 0.947, 0.505, 0.297, 0.943,
+ 0.499, 0.276, 0.938, 0.493, 0.255, 0.934, 0.486, 0.234, 0.930, 0.480,
+ 0.211, 0.925, 0.473, 0.188, 0.920, 0.466, 0.164, 0.916, 0.459, 0.137,
+ 0.787, 0.440, 0.975, 0.793, 0.450, 0.967, 0.799, 0.459, 0.959, 0.806,
+ 0.468, 0.952, 0.812, 0.476, 0.944, 0.818, 0.485, 0.937, 0.824, 0.493,
+ 0.930, 0.831, 0.500, 0.923, 0.837, 0.508, 0.916, 0.843, 0.515, 0.909,
+ 0.850, 0.522, 0.902, 0.856, 0.528, 0.895, 0.862, 0.535, 0.888, 0.868,
+ 0.541, 0.881, 0.874, 0.547, 0.875, 0.881, 0.552, 0.868, 0.887, 0.557,
+ 0.861, 0.893, 0.562, 0.853, 0.899, 0.567, 0.846, 0.904, 0.571, 0.839,
+ 0.910, 0.575, 0.831, 0.916, 0.579, 0.823, 0.921, 0.582, 0.815, 0.926,
+ 0.585, 0.807, 0.932, 0.587, 0.798, 0.937, 0.590, 0.789, 0.941, 0.591,
+ 0.780, 0.946, 0.593, 0.770, 0.950, 0.594, 0.760, 0.954, 0.595, 0.749,
+ 0.958, 0.595, 0.738, 0.962, 0.595, 0.727, 0.965, 0.595, 0.715, 0.968,
+ 0.594, 0.702, 0.970, 0.593, 0.689, 0.973, 0.591, 0.676, 0.975, 0.589,
+ 0.662, 0.976, 0.587, 0.648, 0.978, 0.585, 0.633, 0.979, 0.582, 0.618,
+ 0.980, 0.579, 0.602, 0.980, 0.575, 0.586, 0.980, 0.572, 0.570, 0.980,
+ 0.568, 0.553, 0.979, 0.564, 0.536, 0.978, 0.559, 0.518, 0.977, 0.555,
+ 0.501, 0.975, 0.550, 0.483, 0.974, 0.545, 0.465, 0.972, 0.540, 0.447,
+ 0.969, 0.535, 0.428, 0.967, 0.529, 0.409, 0.964, 0.524, 0.390, 0.961,
+ 0.518, 0.371, 0.958, 0.512, 0.352, 0.954, 0.506, 0.332, 0.951, 0.500,
+ 0.312, 0.947, 0.494, 0.292, 0.943, 0.488, 0.272, 0.939, 0.481, 0.251,
+ 0.935, 0.475, 0.229, 0.931, 0.469, 0.207, 0.926, 0.462, 0.184, 0.921,
+ 0.455, 0.159, 0.917, 0.449, 0.133, 0.791, 0.427, 0.973, 0.797, 0.437,
+ 0.964, 0.803, 0.446, 0.957, 0.809, 0.455, 0.949, 0.815, 0.464, 0.941,
+ 0.821, 0.472, 0.934, 0.827, 0.480, 0.926, 0.834, 0.488, 0.919, 0.840,
+ 0.495, 0.912, 0.846, 0.502, 0.905, 0.852, 0.509, 0.898, 0.858, 0.515,
+ 0.891, 0.864, 0.522, 0.884, 0.870, 0.528, 0.877, 0.876, 0.533, 0.870,
+ 0.882, 0.539, 0.862, 0.888, 0.544, 0.855, 0.894, 0.549, 0.848, 0.900,
+ 0.553, 0.840, 0.906, 0.557, 0.833, 0.911, 0.561, 0.825, 0.916, 0.565,
+ 0.817, 0.922, 0.568, 0.808, 0.927, 0.571, 0.800, 0.932, 0.573, 0.791,
+ 0.937, 0.575, 0.782, 0.941, 0.577, 0.772, 0.946, 0.579, 0.762, 0.950,
+ 0.580, 0.752, 0.954, 0.580, 0.741, 0.958, 0.581, 0.730, 0.961, 0.581,
+ 0.718, 0.964, 0.580, 0.706, 0.967, 0.580, 0.694, 0.970, 0.578, 0.681,
+ 0.972, 0.577, 0.667, 0.974, 0.575, 0.654, 0.976, 0.573, 0.639, 0.977,
+ 0.571, 0.625, 0.978, 0.568, 0.610, 0.979, 0.565, 0.594, 0.979, 0.562,
+ 0.578, 0.979, 0.558, 0.562, 0.979, 0.554, 0.545, 0.978, 0.550, 0.529,
+ 0.977, 0.546, 0.511, 0.976, 0.542, 0.494, 0.975, 0.537, 0.476, 0.973,
+ 0.532, 0.458, 0.971, 0.527, 0.440, 0.969, 0.522, 0.422, 0.967, 0.517,
+ 0.403, 0.964, 0.511, 0.385, 0.961, 0.506, 0.366, 0.958, 0.500, 0.347,
+ 0.955, 0.494, 0.327, 0.951, 0.488, 0.307, 0.947, 0.482, 0.287, 0.944,
+ 0.476, 0.267, 0.940, 0.470, 0.246, 0.935, 0.464, 0.225, 0.931, 0.458,
+ 0.203, 0.927, 0.451, 0.180, 0.922, 0.445, 0.155, 0.917, 0.438, 0.129,
+ 0.795, 0.413, 0.970, 0.801, 0.423, 0.962, 0.807, 0.433, 0.954, 0.813,
+ 0.442, 0.946, 0.818, 0.450, 0.938, 0.824, 0.459, 0.930, 0.830, 0.467,
+ 0.923, 0.836, 0.474, 0.915, 0.842, 0.482, 0.908, 0.848, 0.489, 0.901,
+ 0.854, 0.496, 0.894, 0.860, 0.502, 0.886, 0.866, 0.508, 0.879, 0.872,
+ 0.514, 0.872, 0.878, 0.520, 0.864, 0.884, 0.525, 0.857, 0.890, 0.530,
+ 0.850, 0.895, 0.535, 0.842, 0.901, 0.539, 0.834, 0.906, 0.543, 0.826,
+ 0.912, 0.547, 0.818, 0.917, 0.551, 0.810, 0.922, 0.554, 0.801, 0.927,
+ 0.557, 0.793, 0.932, 0.559, 0.783, 0.937, 0.561, 0.774, 0.941, 0.563,
+ 0.764, 0.946, 0.564, 0.754, 0.950, 0.565, 0.744, 0.953, 0.566, 0.733,
+ 0.957, 0.566, 0.722, 0.960, 0.566, 0.710, 0.963, 0.566, 0.698, 0.966,
+ 0.565, 0.685, 0.969, 0.564, 0.673, 0.971, 0.563, 0.659, 0.973, 0.561,
+ 0.645, 0.975, 0.559, 0.631, 0.976, 0.557, 0.617, 0.977, 0.554, 0.602,
+ 0.978, 0.551, 0.586, 0.978, 0.548, 0.571, 0.978, 0.545, 0.554, 0.978,
+ 0.541, 0.538, 0.977, 0.537, 0.521, 0.977, 0.533, 0.504, 0.976, 0.529,
+ 0.487, 0.974, 0.524, 0.470, 0.973, 0.519, 0.452, 0.971, 0.515, 0.434,
+ 0.969, 0.510, 0.416, 0.966, 0.504, 0.398, 0.964, 0.499, 0.379, 0.961,
+ 0.494, 0.360, 0.958, 0.488, 0.341, 0.955, 0.482, 0.322, 0.951, 0.477,
+ 0.302, 0.948, 0.471, 0.283, 0.944, 0.465, 0.262, 0.940, 0.459, 0.242,
+ 0.936, 0.452, 0.220, 0.932, 0.446, 0.198, 0.927, 0.440, 0.175, 0.923,
+ 0.434, 0.151, 0.918, 0.427, 0.124, 0.799, 0.399, 0.968, 0.804, 0.409,
+ 0.959, 0.810, 0.419, 0.951, 0.816, 0.428, 0.943, 0.822, 0.437, 0.935,
+ 0.827, 0.445, 0.927, 0.833, 0.453, 0.919, 0.839, 0.461, 0.912, 0.845,
+ 0.468, 0.904, 0.851, 0.475, 0.897, 0.857, 0.482, 0.889, 0.862, 0.489,
+ 0.882, 0.868, 0.495, 0.874, 0.874, 0.501, 0.867, 0.880, 0.506, 0.859,
+ 0.885, 0.511, 0.852, 0.891, 0.516, 0.844, 0.897, 0.521, 0.836, 0.902,
+ 0.525, 0.828, 0.907, 0.529, 0.820, 0.913, 0.533, 0.812, 0.918, 0.537,
+ 0.803, 0.923, 0.540, 0.794, 0.928, 0.542, 0.785, 0.932, 0.545, 0.776,
+ 0.937, 0.547, 0.767, 0.941, 0.549, 0.757, 0.945, 0.550, 0.747, 0.949,
+ 0.551, 0.736, 0.953, 0.552, 0.725, 0.956, 0.552, 0.714, 0.960, 0.552,
+ 0.702, 0.963, 0.552, 0.690, 0.965, 0.551, 0.677, 0.968, 0.550, 0.664,
+ 0.970, 0.549, 0.651, 0.972, 0.547, 0.637, 0.974, 0.545, 0.623, 0.975,
+ 0.543, 0.609, 0.976, 0.540, 0.594, 0.977, 0.537, 0.578, 0.977, 0.534,
+ 0.563, 0.977, 0.531, 0.547, 0.977, 0.527, 0.531, 0.976, 0.524, 0.514,
+ 0.976, 0.520, 0.497, 0.975, 0.516, 0.480, 0.973, 0.511, 0.463, 0.972,
+ 0.507, 0.446, 0.970, 0.502, 0.428, 0.968, 0.497, 0.410, 0.966, 0.492,
+ 0.392, 0.963, 0.487, 0.373, 0.960, 0.481, 0.355, 0.957, 0.476, 0.336,
+ 0.954, 0.470, 0.317, 0.951, 0.465, 0.297, 0.947, 0.459, 0.278, 0.944,
+ 0.453, 0.258, 0.940, 0.447, 0.237, 0.936, 0.441, 0.216, 0.932, 0.435,
+ 0.194, 0.927, 0.429, 0.171, 0.923, 0.422, 0.147, 0.918, 0.416, 0.120,
+ 0.802, 0.385, 0.965, 0.808, 0.395, 0.957, 0.813, 0.405, 0.948, 0.819,
+ 0.414, 0.940, 0.825, 0.423, 0.932, 0.830, 0.431, 0.924, 0.836, 0.439,
+ 0.916, 0.842, 0.447, 0.908, 0.847, 0.454, 0.900, 0.853, 0.462, 0.892,
+ 0.859, 0.468, 0.885, 0.864, 0.475, 0.877, 0.870, 0.481, 0.869, 0.876,
+ 0.487, 0.862, 0.881, 0.492, 0.854, 0.887, 0.498, 0.846, 0.892, 0.502,
+ 0.838, 0.898, 0.507, 0.830, 0.903, 0.511, 0.822, 0.908, 0.515, 0.814,
+ 0.913, 0.519, 0.805, 0.918, 0.522, 0.797, 0.923, 0.525, 0.788, 0.928,
+ 0.528, 0.778, 0.932, 0.530, 0.769, 0.937, 0.532, 0.759, 0.941, 0.534,
+ 0.749, 0.945, 0.535, 0.739, 0.949, 0.536, 0.728, 0.952, 0.537, 0.717,
+ 0.956, 0.537, 0.706, 0.959, 0.537, 0.694, 0.962, 0.537, 0.682, 0.964,
+ 0.536, 0.669, 0.967, 0.536, 0.656, 0.969, 0.534, 0.643, 0.971, 0.533,
+ 0.629, 0.972, 0.531, 0.615, 0.974, 0.529, 0.601, 0.975, 0.526, 0.586,
+ 0.975, 0.523, 0.571, 0.976, 0.521, 0.555, 0.976, 0.517, 0.540, 0.976,
+ 0.514, 0.523, 0.975, 0.510, 0.507, 0.975, 0.506, 0.490, 0.974, 0.502,
+ 0.474, 0.972, 0.498, 0.456, 0.971, 0.494, 0.439, 0.969, 0.489, 0.421,
+ 0.967, 0.484, 0.404, 0.965, 0.479, 0.386, 0.963, 0.474, 0.367, 0.960,
+ 0.469, 0.349, 0.957, 0.464, 0.330, 0.954, 0.458, 0.311, 0.951, 0.453,
+ 0.292, 0.947, 0.447, 0.273, 0.944, 0.441, 0.253, 0.940, 0.435, 0.232,
+ 0.936, 0.429, 0.211, 0.932, 0.423, 0.190, 0.927, 0.417, 0.167, 0.923,
+ 0.411, 0.142, 0.919, 0.405, 0.116, 0.806, 0.370, 0.963, 0.811, 0.380,
+ 0.954, 0.816, 0.390, 0.945, 0.822, 0.399, 0.937, 0.827, 0.408, 0.929,
+ 0.833, 0.417, 0.920, 0.838, 0.425, 0.912, 0.844, 0.433, 0.904, 0.850,
+ 0.440, 0.896, 0.855, 0.447, 0.888, 0.861, 0.454, 0.880, 0.866, 0.461,
+ 0.872, 0.872, 0.467, 0.865, 0.877, 0.473, 0.857, 0.883, 0.478, 0.849,
+ 0.888, 0.483, 0.841, 0.893, 0.488, 0.833, 0.899, 0.493, 0.824, 0.904,
+ 0.497, 0.816, 0.909, 0.501, 0.807, 0.914, 0.505, 0.799, 0.919, 0.508,
+ 0.790, 0.923, 0.511, 0.781, 0.928, 0.514, 0.771, 0.932, 0.516, 0.762,
+ 0.937, 0.518, 0.752, 0.941, 0.520, 0.742, 0.945, 0.521, 0.731, 0.948,
+ 0.522, 0.720, 0.952, 0.523, 0.709, 0.955, 0.523, 0.698, 0.958, 0.523,
+ 0.686, 0.961, 0.523, 0.674, 0.964, 0.522, 0.661, 0.966, 0.521, 0.648,
+ 0.968, 0.520, 0.635, 0.970, 0.518, 0.621, 0.971, 0.517, 0.607, 0.972,
+ 0.514, 0.593, 0.973, 0.512, 0.578, 0.974, 0.509, 0.563, 0.975, 0.507,
+ 0.548, 0.975, 0.503, 0.532, 0.975, 0.500, 0.516, 0.974, 0.497, 0.500,
+ 0.974, 0.493, 0.483, 0.973, 0.489, 0.467, 0.971, 0.485, 0.450, 0.970,
+ 0.480, 0.433, 0.968, 0.476, 0.415, 0.966, 0.471, 0.397, 0.964, 0.466,
+ 0.380, 0.962, 0.461, 0.362, 0.959, 0.456, 0.343, 0.956, 0.451, 0.325,
+ 0.953, 0.446, 0.306, 0.950, 0.440, 0.287, 0.947, 0.435, 0.268, 0.943,
+ 0.429, 0.248, 0.939, 0.423, 0.228, 0.936, 0.417, 0.207, 0.931, 0.411,
+ 0.185, 0.927, 0.405, 0.162, 0.923, 0.399, 0.138, 0.918, 0.393, 0.111,
+ 0.809, 0.354, 0.960, 0.814, 0.364, 0.951, 0.819, 0.375, 0.942, 0.825,
+ 0.384, 0.934, 0.830, 0.393, 0.925, 0.835, 0.402, 0.917, 0.841, 0.410,
+ 0.908, 0.846, 0.418, 0.900, 0.852, 0.426, 0.892, 0.857, 0.433, 0.884,
+ 0.863, 0.440, 0.876, 0.868, 0.446, 0.868, 0.873, 0.452, 0.860, 0.879,
+ 0.458, 0.852, 0.884, 0.464, 0.843, 0.889, 0.469, 0.835, 0.894, 0.474,
+ 0.827, 0.899, 0.478, 0.818, 0.904, 0.483, 0.810, 0.909, 0.486, 0.801,
+ 0.914, 0.490, 0.792, 0.919, 0.493, 0.783, 0.923, 0.496, 0.774, 0.928,
+ 0.499, 0.764, 0.932, 0.501, 0.755, 0.936, 0.503, 0.745, 0.940, 0.505,
+ 0.734, 0.944, 0.506, 0.724, 0.948, 0.507, 0.713, 0.951, 0.508, 0.701,
+ 0.954, 0.508, 0.690, 0.957, 0.508, 0.678, 0.960, 0.508, 0.666, 0.962,
+ 0.507, 0.653, 0.965, 0.507, 0.640, 0.967, 0.505, 0.627, 0.968, 0.504,
+ 0.613, 0.970, 0.502, 0.599, 0.971, 0.500, 0.585, 0.972, 0.498, 0.570,
+ 0.973, 0.495, 0.555, 0.973, 0.493, 0.540, 0.973, 0.490, 0.525, 0.973,
+ 0.486, 0.509, 0.973, 0.483, 0.493, 0.972, 0.479, 0.476, 0.971, 0.475,
+ 0.460, 0.970, 0.471, 0.443, 0.969, 0.467, 0.426, 0.967, 0.463, 0.409,
+ 0.965, 0.458, 0.391, 0.963, 0.453, 0.374, 0.961, 0.449, 0.356, 0.958,
+ 0.444, 0.338, 0.956, 0.438, 0.319, 0.953, 0.433, 0.301, 0.949, 0.428,
+ 0.282, 0.946, 0.422, 0.263, 0.943, 0.417, 0.243, 0.939, 0.411, 0.223,
+ 0.935, 0.405, 0.202, 0.931, 0.399, 0.181, 0.927, 0.393, 0.158, 0.923,
+ 0.387, 0.134, 0.918, 0.381, 0.107,
+ ]).reshape((65, 65, 3))
+
+BiOrangeBlue = np.array(
+ [0.000, 0.000, 0.000, 0.000, 0.062, 0.125, 0.000, 0.125, 0.250, 0.000,
+ 0.188, 0.375, 0.000, 0.250, 0.500, 0.000, 0.312, 0.625, 0.000, 0.375,
+ 0.750, 0.000, 0.438, 0.875, 0.000, 0.500, 1.000, 0.125, 0.062, 0.000,
+ 0.125, 0.125, 0.125, 0.125, 0.188, 0.250, 0.125, 0.250, 0.375, 0.125,
+ 0.312, 0.500, 0.125, 0.375, 0.625, 0.125, 0.438, 0.750, 0.125, 0.500,
+ 0.875, 0.125, 0.562, 1.000, 0.250, 0.125, 0.000, 0.250, 0.188, 0.125,
+ 0.250, 0.250, 0.250, 0.250, 0.312, 0.375, 0.250, 0.375, 0.500, 0.250,
+ 0.438, 0.625, 0.250, 0.500, 0.750, 0.250, 0.562, 0.875, 0.250, 0.625,
+ 1.000, 0.375, 0.188, 0.000, 0.375, 0.250, 0.125, 0.375, 0.312, 0.250,
+ 0.375, 0.375, 0.375, 0.375, 0.438, 0.500, 0.375, 0.500, 0.625, 0.375,
+ 0.562, 0.750, 0.375, 0.625, 0.875, 0.375, 0.688, 1.000, 0.500, 0.250,
+ 0.000, 0.500, 0.312, 0.125, 0.500, 0.375, 0.250, 0.500, 0.438, 0.375,
+ 0.500, 0.500, 0.500, 0.500, 0.562, 0.625, 0.500, 0.625, 0.750, 0.500,
+ 0.688, 0.875, 0.500, 0.750, 1.000, 0.625, 0.312, 0.000, 0.625, 0.375,
+ 0.125, 0.625, 0.438, 0.250, 0.625, 0.500, 0.375, 0.625, 0.562, 0.500,
+ 0.625, 0.625, 0.625, 0.625, 0.688, 0.750, 0.625, 0.750, 0.875, 0.625,
+ 0.812, 1.000, 0.750, 0.375, 0.000, 0.750, 0.438, 0.125, 0.750, 0.500,
+ 0.250, 0.750, 0.562, 0.375, 0.750, 0.625, 0.500, 0.750, 0.688, 0.625,
+ 0.750, 0.750, 0.750, 0.750, 0.812, 0.875, 0.750, 0.875, 1.000, 0.875,
+ 0.438, 0.000, 0.875, 0.500, 0.125, 0.875, 0.562, 0.250, 0.875, 0.625,
+ 0.375, 0.875, 0.688, 0.500, 0.875, 0.750, 0.625, 0.875, 0.812, 0.750,
+ 0.875, 0.875, 0.875, 0.875, 0.938, 1.000, 1.000, 0.500, 0.000, 1.000,
+ 0.562, 0.125, 1.000, 0.625, 0.250, 1.000, 0.688, 0.375, 1.000, 0.750,
+ 0.500, 1.000, 0.812, 0.625, 1.000, 0.875, 0.750, 1.000, 0.938, 0.875,
+ 1.000, 1.000, 1.000,
+ ]).reshape((9, 9, 3))
+
+cmaps = {
+ "BiPeak": SegmentedBivarColormap(
+ BiPeak, 256, "square", (.5, .5), name="BiPeak"),
+ "BiOrangeBlue": SegmentedBivarColormap(
+ BiOrangeBlue, 256, "square", (0, 0), name="BiOrangeBlue"),
+ "BiCone": SegmentedBivarColormap(BiPeak, 256, "circle", (.5, .5), name="BiCone"),
+}
diff --git a/lib/python3.12/site-packages/matplotlib/_cm_multivar.py b/lib/python3.12/site-packages/matplotlib/_cm_multivar.py
new file mode 100644
index 0000000000000000000000000000000000000000..610d7c40935b0999fe7de38515f316ce816023f7
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_cm_multivar.py
@@ -0,0 +1,166 @@
+# auto-generated by https://github.com/trygvrad/multivariate_colormaps
+# date: 2024-05-28
+
+from .colors import LinearSegmentedColormap, MultivarColormap
+import matplotlib as mpl
+_LUTSIZE = mpl.rcParams['image.lut']
+
+_2VarAddA0_data = [[0.000, 0.000, 0.000],
+ [0.020, 0.026, 0.031],
+ [0.049, 0.068, 0.085],
+ [0.075, 0.107, 0.135],
+ [0.097, 0.144, 0.183],
+ [0.116, 0.178, 0.231],
+ [0.133, 0.212, 0.279],
+ [0.148, 0.244, 0.326],
+ [0.161, 0.276, 0.374],
+ [0.173, 0.308, 0.422],
+ [0.182, 0.339, 0.471],
+ [0.190, 0.370, 0.521],
+ [0.197, 0.400, 0.572],
+ [0.201, 0.431, 0.623],
+ [0.204, 0.461, 0.675],
+ [0.204, 0.491, 0.728],
+ [0.202, 0.520, 0.783],
+ [0.197, 0.549, 0.838],
+ [0.187, 0.577, 0.895]]
+
+_2VarAddA1_data = [[0.000, 0.000, 0.000],
+ [0.030, 0.023, 0.018],
+ [0.079, 0.060, 0.043],
+ [0.125, 0.093, 0.065],
+ [0.170, 0.123, 0.083],
+ [0.213, 0.151, 0.098],
+ [0.255, 0.177, 0.110],
+ [0.298, 0.202, 0.120],
+ [0.341, 0.226, 0.128],
+ [0.384, 0.249, 0.134],
+ [0.427, 0.271, 0.138],
+ [0.472, 0.292, 0.141],
+ [0.517, 0.313, 0.142],
+ [0.563, 0.333, 0.141],
+ [0.610, 0.353, 0.139],
+ [0.658, 0.372, 0.134],
+ [0.708, 0.390, 0.127],
+ [0.759, 0.407, 0.118],
+ [0.813, 0.423, 0.105]]
+
+_2VarSubA0_data = [[1.000, 1.000, 1.000],
+ [0.959, 0.973, 0.986],
+ [0.916, 0.948, 0.974],
+ [0.874, 0.923, 0.965],
+ [0.832, 0.899, 0.956],
+ [0.790, 0.875, 0.948],
+ [0.748, 0.852, 0.940],
+ [0.707, 0.829, 0.934],
+ [0.665, 0.806, 0.927],
+ [0.624, 0.784, 0.921],
+ [0.583, 0.762, 0.916],
+ [0.541, 0.740, 0.910],
+ [0.500, 0.718, 0.905],
+ [0.457, 0.697, 0.901],
+ [0.414, 0.675, 0.896],
+ [0.369, 0.652, 0.892],
+ [0.320, 0.629, 0.888],
+ [0.266, 0.604, 0.884],
+ [0.199, 0.574, 0.881]]
+
+_2VarSubA1_data = [[1.000, 1.000, 1.000],
+ [0.982, 0.967, 0.955],
+ [0.966, 0.935, 0.908],
+ [0.951, 0.902, 0.860],
+ [0.937, 0.870, 0.813],
+ [0.923, 0.838, 0.765],
+ [0.910, 0.807, 0.718],
+ [0.898, 0.776, 0.671],
+ [0.886, 0.745, 0.624],
+ [0.874, 0.714, 0.577],
+ [0.862, 0.683, 0.530],
+ [0.851, 0.653, 0.483],
+ [0.841, 0.622, 0.435],
+ [0.831, 0.592, 0.388],
+ [0.822, 0.561, 0.340],
+ [0.813, 0.530, 0.290],
+ [0.806, 0.498, 0.239],
+ [0.802, 0.464, 0.184],
+ [0.801, 0.426, 0.119]]
+
+_3VarAddA0_data = [[0.000, 0.000, 0.000],
+ [0.018, 0.023, 0.028],
+ [0.040, 0.056, 0.071],
+ [0.059, 0.087, 0.110],
+ [0.074, 0.114, 0.147],
+ [0.086, 0.139, 0.183],
+ [0.095, 0.163, 0.219],
+ [0.101, 0.187, 0.255],
+ [0.105, 0.209, 0.290],
+ [0.107, 0.230, 0.326],
+ [0.105, 0.251, 0.362],
+ [0.101, 0.271, 0.398],
+ [0.091, 0.291, 0.434],
+ [0.075, 0.309, 0.471],
+ [0.046, 0.325, 0.507],
+ [0.021, 0.341, 0.546],
+ [0.021, 0.363, 0.584],
+ [0.022, 0.385, 0.622],
+ [0.023, 0.408, 0.661]]
+
+_3VarAddA1_data = [[0.000, 0.000, 0.000],
+ [0.020, 0.024, 0.016],
+ [0.047, 0.058, 0.034],
+ [0.072, 0.088, 0.048],
+ [0.093, 0.116, 0.059],
+ [0.113, 0.142, 0.067],
+ [0.131, 0.167, 0.071],
+ [0.149, 0.190, 0.074],
+ [0.166, 0.213, 0.074],
+ [0.182, 0.235, 0.072],
+ [0.198, 0.256, 0.068],
+ [0.215, 0.276, 0.061],
+ [0.232, 0.296, 0.051],
+ [0.249, 0.314, 0.037],
+ [0.270, 0.330, 0.018],
+ [0.288, 0.347, 0.000],
+ [0.302, 0.369, 0.000],
+ [0.315, 0.391, 0.000],
+ [0.328, 0.414, 0.000]]
+
+_3VarAddA2_data = [[0.000, 0.000, 0.000],
+ [0.029, 0.020, 0.023],
+ [0.072, 0.045, 0.055],
+ [0.111, 0.067, 0.084],
+ [0.148, 0.085, 0.109],
+ [0.184, 0.101, 0.133],
+ [0.219, 0.115, 0.155],
+ [0.254, 0.127, 0.176],
+ [0.289, 0.138, 0.195],
+ [0.323, 0.147, 0.214],
+ [0.358, 0.155, 0.232],
+ [0.393, 0.161, 0.250],
+ [0.429, 0.166, 0.267],
+ [0.467, 0.169, 0.283],
+ [0.507, 0.168, 0.298],
+ [0.546, 0.168, 0.313],
+ [0.580, 0.172, 0.328],
+ [0.615, 0.175, 0.341],
+ [0.649, 0.178, 0.355]]
+
+cmaps = {
+ name: LinearSegmentedColormap.from_list(name, data, _LUTSIZE) for name, data in [
+ ('2VarAddA0', _2VarAddA0_data),
+ ('2VarAddA1', _2VarAddA1_data),
+ ('2VarSubA0', _2VarSubA0_data),
+ ('2VarSubA1', _2VarSubA1_data),
+ ('3VarAddA0', _3VarAddA0_data),
+ ('3VarAddA1', _3VarAddA1_data),
+ ('3VarAddA2', _3VarAddA2_data),
+ ]}
+
+cmap_families = {
+ '2VarAddA': MultivarColormap([cmaps[f'2VarAddA{i}'] for i in range(2)],
+ 'sRGB_add', name='2VarAddA'),
+ '2VarSubA': MultivarColormap([cmaps[f'2VarSubA{i}'] for i in range(2)],
+ 'sRGB_sub', name='2VarSubA'),
+ '3VarAddA': MultivarColormap([cmaps[f'3VarAddA{i}'] for i in range(3)],
+ 'sRGB_add', name='3VarAddA'),
+}
diff --git a/lib/python3.12/site-packages/matplotlib/_color_data.pyi b/lib/python3.12/site-packages/matplotlib/_color_data.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..feb3de9c3043d55910e2649804352ae96ccbd1ec
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_color_data.pyi
@@ -0,0 +1,6 @@
+from .typing import ColorType
+
+BASE_COLORS: dict[str, ColorType]
+TABLEAU_COLORS: dict[str, ColorType]
+XKCD_COLORS: dict[str, ColorType]
+CSS4_COLORS: dict[str, ColorType]
diff --git a/lib/python3.12/site-packages/matplotlib/_constrained_layout.py b/lib/python3.12/site-packages/matplotlib/_constrained_layout.py
new file mode 100644
index 0000000000000000000000000000000000000000..5623e12a3c41d0d0d35041fd1dd9fb23e9938e51
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_constrained_layout.py
@@ -0,0 +1,801 @@
+"""
+Adjust subplot layouts so that there are no overlapping Axes or Axes
+decorations. All Axes decorations are dealt with (labels, ticks, titles,
+ticklabels) and some dependent artists are also dealt with (colorbar,
+suptitle).
+
+Layout is done via `~matplotlib.gridspec`, with one constraint per gridspec,
+so it is possible to have overlapping Axes if the gridspecs overlap (i.e.
+using `~matplotlib.gridspec.GridSpecFromSubplotSpec`). Axes placed using
+``figure.subplots()`` or ``figure.add_subplots()`` will participate in the
+layout. Axes manually placed via ``figure.add_axes()`` will not.
+
+See Tutorial: :ref:`constrainedlayout_guide`
+
+General idea:
+-------------
+
+First, a figure has a gridspec that divides the figure into nrows and ncols,
+with heights and widths set by ``height_ratios`` and ``width_ratios``,
+often just set to 1 for an equal grid.
+
+Subplotspecs that are derived from this gridspec can contain either a
+``SubPanel``, a ``GridSpecFromSubplotSpec``, or an ``Axes``. The ``SubPanel``
+and ``GridSpecFromSubplotSpec`` are dealt with recursively and each contain an
+analogous layout.
+
+Each ``GridSpec`` has a ``_layoutgrid`` attached to it. The ``_layoutgrid``
+has the same logical layout as the ``GridSpec``. Each row of the grid spec
+has a top and bottom "margin" and each column has a left and right "margin".
+The "inner" height of each row is constrained to be the same (or as modified
+by ``height_ratio``), and the "inner" width of each column is
+constrained to be the same (as modified by ``width_ratio``), where "inner"
+is the width or height of each column/row minus the size of the margins.
+
+Then the size of the margins for each row and column are determined as the
+max width of the decorators on each Axes that has decorators in that margin.
+For instance, a normal Axes would have a left margin that includes the
+left ticklabels, and the ylabel if it exists. The right margin may include a
+colorbar, the bottom margin the xaxis decorations, and the top margin the
+title.
+
+With these constraints, the solver then finds appropriate bounds for the
+columns and rows. It's possible that the margins take up the whole figure,
+in which case the algorithm is not applied and a warning is raised.
+
+See the tutorial :ref:`constrainedlayout_guide`
+for more discussion of the algorithm with examples.
+"""
+
+import logging
+
+import numpy as np
+
+from matplotlib import _api, artist as martist
+import matplotlib.transforms as mtransforms
+import matplotlib._layoutgrid as mlayoutgrid
+
+
+_log = logging.getLogger(__name__)
+
+
+######################################################
+def do_constrained_layout(fig, h_pad, w_pad,
+ hspace=None, wspace=None, rect=(0, 0, 1, 1),
+ compress=False):
+ """
+ Do the constrained_layout. Called at draw time in
+ ``figure.constrained_layout()``
+
+ Parameters
+ ----------
+ fig : `~matplotlib.figure.Figure`
+ `.Figure` instance to do the layout in.
+
+ h_pad, w_pad : float
+ Padding around the Axes elements in figure-normalized units.
+
+ hspace, wspace : float
+ Fraction of the figure to dedicate to space between the
+ Axes. These are evenly spread between the gaps between the Axes.
+ A value of 0.2 for a three-column layout would have a space
+ of 0.1 of the figure width between each column.
+ If h/wspace < h/w_pad, then the pads are used instead.
+
+ rect : tuple of 4 floats
+ Rectangle in figure coordinates to perform constrained layout in
+ [left, bottom, width, height], each from 0-1.
+
+ compress : bool
+ Whether to shift Axes so that white space in between them is
+ removed. This is useful for simple grids of fixed-aspect Axes (e.g.
+ a grid of images).
+
+ Returns
+ -------
+ layoutgrid : private debugging structure
+ """
+
+ renderer = fig._get_renderer()
+ # make layoutgrid tree...
+ layoutgrids = make_layoutgrids(fig, None, rect=rect)
+ if not layoutgrids['hasgrids']:
+ _api.warn_external('There are no gridspecs with layoutgrids. '
+ 'Possibly did not call parent GridSpec with the'
+ ' "figure" keyword')
+ return
+
+ for _ in range(2):
+ # do the algorithm twice. This has to be done because decorations
+ # change size after the first re-position (i.e. x/yticklabels get
+ # larger/smaller). This second reposition tends to be much milder,
+ # so doing twice makes things work OK.
+
+ # make margins for all the Axes and subfigures in the
+ # figure. Add margins for colorbars...
+ make_layout_margins(layoutgrids, fig, renderer, h_pad=h_pad,
+ w_pad=w_pad, hspace=hspace, wspace=wspace)
+ make_margin_suptitles(layoutgrids, fig, renderer, h_pad=h_pad,
+ w_pad=w_pad)
+
+ # if a layout is such that a columns (or rows) margin has no
+ # constraints, we need to make all such instances in the grid
+ # match in margin size.
+ match_submerged_margins(layoutgrids, fig)
+
+ # update all the variables in the layout.
+ layoutgrids[fig].update_variables()
+
+ warn_collapsed = ('constrained_layout not applied because '
+ 'axes sizes collapsed to zero. Try making '
+ 'figure larger or Axes decorations smaller.')
+ if check_no_collapsed_axes(layoutgrids, fig):
+ reposition_axes(layoutgrids, fig, renderer, h_pad=h_pad,
+ w_pad=w_pad, hspace=hspace, wspace=wspace)
+ if compress:
+ layoutgrids = compress_fixed_aspect(layoutgrids, fig)
+ layoutgrids[fig].update_variables()
+ if check_no_collapsed_axes(layoutgrids, fig):
+ reposition_axes(layoutgrids, fig, renderer, h_pad=h_pad,
+ w_pad=w_pad, hspace=hspace, wspace=wspace)
+ else:
+ _api.warn_external(warn_collapsed)
+
+ if ((suptitle := fig._suptitle) is not None and
+ suptitle.get_in_layout() and suptitle._autopos):
+ x, _ = suptitle.get_position()
+ suptitle.set_position(
+ (x, layoutgrids[fig].get_inner_bbox().y1 + h_pad))
+ suptitle.set_verticalalignment('bottom')
+ else:
+ _api.warn_external(warn_collapsed)
+ reset_margins(layoutgrids, fig)
+ return layoutgrids
+
+
+def make_layoutgrids(fig, layoutgrids, rect=(0, 0, 1, 1)):
+ """
+ Make the layoutgrid tree.
+
+ (Sub)Figures get a layoutgrid so we can have figure margins.
+
+ Gridspecs that are attached to Axes get a layoutgrid so Axes
+ can have margins.
+ """
+
+ if layoutgrids is None:
+ layoutgrids = dict()
+ layoutgrids['hasgrids'] = False
+ if not hasattr(fig, '_parent'):
+ # top figure; pass rect as parent to allow user-specified
+ # margins
+ layoutgrids[fig] = mlayoutgrid.LayoutGrid(parent=rect, name='figlb')
+ else:
+ # subfigure
+ gs = fig._subplotspec.get_gridspec()
+ # it is possible the gridspec containing this subfigure hasn't
+ # been added to the tree yet:
+ layoutgrids = make_layoutgrids_gs(layoutgrids, gs)
+ # add the layoutgrid for the subfigure:
+ parentlb = layoutgrids[gs]
+ layoutgrids[fig] = mlayoutgrid.LayoutGrid(
+ parent=parentlb,
+ name='panellb',
+ parent_inner=True,
+ nrows=1, ncols=1,
+ parent_pos=(fig._subplotspec.rowspan,
+ fig._subplotspec.colspan))
+ # recursively do all subfigures in this figure...
+ for sfig in fig.subfigs:
+ layoutgrids = make_layoutgrids(sfig, layoutgrids)
+
+ # for each Axes at the local level add its gridspec:
+ for ax in fig._localaxes:
+ gs = ax.get_gridspec()
+ if gs is not None:
+ layoutgrids = make_layoutgrids_gs(layoutgrids, gs)
+
+ return layoutgrids
+
+
+def make_layoutgrids_gs(layoutgrids, gs):
+ """
+ Make the layoutgrid for a gridspec (and anything nested in the gridspec)
+ """
+
+ if gs in layoutgrids or gs.figure is None:
+ return layoutgrids
+ # in order to do constrained_layout there has to be at least *one*
+ # gridspec in the tree:
+ layoutgrids['hasgrids'] = True
+ if not hasattr(gs, '_subplot_spec'):
+ # normal gridspec
+ parent = layoutgrids[gs.figure]
+ layoutgrids[gs] = mlayoutgrid.LayoutGrid(
+ parent=parent,
+ parent_inner=True,
+ name='gridspec',
+ ncols=gs._ncols, nrows=gs._nrows,
+ width_ratios=gs.get_width_ratios(),
+ height_ratios=gs.get_height_ratios())
+ else:
+ # this is a gridspecfromsubplotspec:
+ subplot_spec = gs._subplot_spec
+ parentgs = subplot_spec.get_gridspec()
+ # if a nested gridspec it is possible the parent is not in there yet:
+ if parentgs not in layoutgrids:
+ layoutgrids = make_layoutgrids_gs(layoutgrids, parentgs)
+ subspeclb = layoutgrids[parentgs]
+ # gridspecfromsubplotspec need an outer container:
+ # get a unique representation:
+ rep = (gs, 'top')
+ if rep not in layoutgrids:
+ layoutgrids[rep] = mlayoutgrid.LayoutGrid(
+ parent=subspeclb,
+ name='top',
+ nrows=1, ncols=1,
+ parent_pos=(subplot_spec.rowspan, subplot_spec.colspan))
+ layoutgrids[gs] = mlayoutgrid.LayoutGrid(
+ parent=layoutgrids[rep],
+ name='gridspec',
+ nrows=gs._nrows, ncols=gs._ncols,
+ width_ratios=gs.get_width_ratios(),
+ height_ratios=gs.get_height_ratios())
+ return layoutgrids
+
+
+def check_no_collapsed_axes(layoutgrids, fig):
+ """
+ Check that no Axes have collapsed to zero size.
+ """
+ for sfig in fig.subfigs:
+ ok = check_no_collapsed_axes(layoutgrids, sfig)
+ if not ok:
+ return False
+ for ax in fig.axes:
+ gs = ax.get_gridspec()
+ if gs in layoutgrids: # also implies gs is not None.
+ lg = layoutgrids[gs]
+ for i in range(gs.nrows):
+ for j in range(gs.ncols):
+ bb = lg.get_inner_bbox(i, j)
+ if bb.width <= 0 or bb.height <= 0:
+ return False
+ return True
+
+
+def compress_fixed_aspect(layoutgrids, fig):
+ gs = None
+ for ax in fig.axes:
+ if ax.get_subplotspec() is None:
+ continue
+ ax.apply_aspect()
+ sub = ax.get_subplotspec()
+ _gs = sub.get_gridspec()
+ if gs is None:
+ gs = _gs
+ extraw = np.zeros(gs.ncols)
+ extrah = np.zeros(gs.nrows)
+ elif _gs != gs:
+ raise ValueError('Cannot do compressed layout if Axes are not'
+ 'all from the same gridspec')
+ orig = ax.get_position(original=True)
+ actual = ax.get_position(original=False)
+ dw = orig.width - actual.width
+ if dw > 0:
+ extraw[sub.colspan] = np.maximum(extraw[sub.colspan], dw)
+ dh = orig.height - actual.height
+ if dh > 0:
+ extrah[sub.rowspan] = np.maximum(extrah[sub.rowspan], dh)
+
+ if gs is None:
+ raise ValueError('Cannot do compressed layout if no Axes '
+ 'are part of a gridspec.')
+ w = np.sum(extraw) / 2
+ layoutgrids[fig].edit_margin_min('left', w)
+ layoutgrids[fig].edit_margin_min('right', w)
+
+ h = np.sum(extrah) / 2
+ layoutgrids[fig].edit_margin_min('top', h)
+ layoutgrids[fig].edit_margin_min('bottom', h)
+ return layoutgrids
+
+
+def get_margin_from_padding(obj, *, w_pad=0, h_pad=0,
+ hspace=0, wspace=0):
+
+ ss = obj._subplotspec
+ gs = ss.get_gridspec()
+
+ if hasattr(gs, 'hspace'):
+ _hspace = (gs.hspace if gs.hspace is not None else hspace)
+ _wspace = (gs.wspace if gs.wspace is not None else wspace)
+ else:
+ _hspace = (gs._hspace if gs._hspace is not None else hspace)
+ _wspace = (gs._wspace if gs._wspace is not None else wspace)
+
+ _wspace = _wspace / 2
+ _hspace = _hspace / 2
+
+ nrows, ncols = gs.get_geometry()
+ # there are two margins for each direction. The "cb"
+ # margins are for pads and colorbars, the non-"cb" are
+ # for the Axes decorations (labels etc).
+ margin = {'leftcb': w_pad, 'rightcb': w_pad,
+ 'bottomcb': h_pad, 'topcb': h_pad,
+ 'left': 0, 'right': 0,
+ 'top': 0, 'bottom': 0}
+ if _wspace / ncols > w_pad:
+ if ss.colspan.start > 0:
+ margin['leftcb'] = _wspace / ncols
+ if ss.colspan.stop < ncols:
+ margin['rightcb'] = _wspace / ncols
+ if _hspace / nrows > h_pad:
+ if ss.rowspan.stop < nrows:
+ margin['bottomcb'] = _hspace / nrows
+ if ss.rowspan.start > 0:
+ margin['topcb'] = _hspace / nrows
+
+ return margin
+
+
+def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0,
+ hspace=0, wspace=0):
+ """
+ For each Axes, make a margin between the *pos* layoutbox and the
+ *axes* layoutbox be a minimum size that can accommodate the
+ decorations on the axis.
+
+ Then make room for colorbars.
+
+ Parameters
+ ----------
+ layoutgrids : dict
+ fig : `~matplotlib.figure.Figure`
+ `.Figure` instance to do the layout in.
+ renderer : `~matplotlib.backend_bases.RendererBase` subclass.
+ The renderer to use.
+ w_pad, h_pad : float, default: 0
+ Width and height padding (in fraction of figure).
+ hspace, wspace : float, default: 0
+ Width and height padding as fraction of figure size divided by
+ number of columns or rows.
+ """
+ for sfig in fig.subfigs: # recursively make child panel margins
+ ss = sfig._subplotspec
+ gs = ss.get_gridspec()
+
+ make_layout_margins(layoutgrids, sfig, renderer,
+ w_pad=w_pad, h_pad=h_pad,
+ hspace=hspace, wspace=wspace)
+
+ margins = get_margin_from_padding(sfig, w_pad=0, h_pad=0,
+ hspace=hspace, wspace=wspace)
+ layoutgrids[gs].edit_outer_margin_mins(margins, ss)
+
+ for ax in fig._localaxes:
+ if not ax.get_subplotspec() or not ax.get_in_layout():
+ continue
+
+ ss = ax.get_subplotspec()
+ gs = ss.get_gridspec()
+
+ if gs not in layoutgrids:
+ return
+
+ margin = get_margin_from_padding(ax, w_pad=w_pad, h_pad=h_pad,
+ hspace=hspace, wspace=wspace)
+ pos, bbox = get_pos_and_bbox(ax, renderer)
+ # the margin is the distance between the bounding box of the Axes
+ # and its position (plus the padding from above)
+ margin['left'] += pos.x0 - bbox.x0
+ margin['right'] += bbox.x1 - pos.x1
+ # remember that rows are ordered from top:
+ margin['bottom'] += pos.y0 - bbox.y0
+ margin['top'] += bbox.y1 - pos.y1
+
+ # make margin for colorbars. These margins go in the
+ # padding margin, versus the margin for Axes decorators.
+ for cbax in ax._colorbars:
+ # note pad is a fraction of the parent width...
+ pad = colorbar_get_pad(layoutgrids, cbax)
+ # colorbars can be child of more than one subplot spec:
+ cbp_rspan, cbp_cspan = get_cb_parent_spans(cbax)
+ loc = cbax._colorbar_info['location']
+ cbpos, cbbbox = get_pos_and_bbox(cbax, renderer)
+ if loc == 'right':
+ if cbp_cspan.stop == ss.colspan.stop:
+ # only increase if the colorbar is on the right edge
+ margin['rightcb'] += cbbbox.width + pad
+ elif loc == 'left':
+ if cbp_cspan.start == ss.colspan.start:
+ # only increase if the colorbar is on the left edge
+ margin['leftcb'] += cbbbox.width + pad
+ elif loc == 'top':
+ if cbp_rspan.start == ss.rowspan.start:
+ margin['topcb'] += cbbbox.height + pad
+ else:
+ if cbp_rspan.stop == ss.rowspan.stop:
+ margin['bottomcb'] += cbbbox.height + pad
+ # If the colorbars are wider than the parent box in the
+ # cross direction
+ if loc in ['top', 'bottom']:
+ if (cbp_cspan.start == ss.colspan.start and
+ cbbbox.x0 < bbox.x0):
+ margin['left'] += bbox.x0 - cbbbox.x0
+ if (cbp_cspan.stop == ss.colspan.stop and
+ cbbbox.x1 > bbox.x1):
+ margin['right'] += cbbbox.x1 - bbox.x1
+ # or taller:
+ if loc in ['left', 'right']:
+ if (cbp_rspan.stop == ss.rowspan.stop and
+ cbbbox.y0 < bbox.y0):
+ margin['bottom'] += bbox.y0 - cbbbox.y0
+ if (cbp_rspan.start == ss.rowspan.start and
+ cbbbox.y1 > bbox.y1):
+ margin['top'] += cbbbox.y1 - bbox.y1
+ # pass the new margins down to the layout grid for the solution...
+ layoutgrids[gs].edit_outer_margin_mins(margin, ss)
+
+ # make margins for figure-level legends:
+ for leg in fig.legends:
+ inv_trans_fig = None
+ if leg._outside_loc and leg._bbox_to_anchor is None:
+ if inv_trans_fig is None:
+ inv_trans_fig = fig.transFigure.inverted().transform_bbox
+ bbox = inv_trans_fig(leg.get_tightbbox(renderer))
+ w = bbox.width + 2 * w_pad
+ h = bbox.height + 2 * h_pad
+ legendloc = leg._outside_loc
+ if legendloc == 'lower':
+ layoutgrids[fig].edit_margin_min('bottom', h)
+ elif legendloc == 'upper':
+ layoutgrids[fig].edit_margin_min('top', h)
+ if legendloc == 'right':
+ layoutgrids[fig].edit_margin_min('right', w)
+ elif legendloc == 'left':
+ layoutgrids[fig].edit_margin_min('left', w)
+
+
+def make_margin_suptitles(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0):
+ # Figure out how large the suptitle is and make the
+ # top level figure margin larger.
+
+ inv_trans_fig = fig.transFigure.inverted().transform_bbox
+ # get the h_pad and w_pad as distances in the local subfigure coordinates:
+ padbox = mtransforms.Bbox([[0, 0], [w_pad, h_pad]])
+ padbox = (fig.transFigure -
+ fig.transSubfigure).transform_bbox(padbox)
+ h_pad_local = padbox.height
+ w_pad_local = padbox.width
+
+ for sfig in fig.subfigs:
+ make_margin_suptitles(layoutgrids, sfig, renderer,
+ w_pad=w_pad, h_pad=h_pad)
+
+ if fig._suptitle is not None and fig._suptitle.get_in_layout():
+ p = fig._suptitle.get_position()
+ if getattr(fig._suptitle, '_autopos', False):
+ fig._suptitle.set_position((p[0], 1 - h_pad_local))
+ bbox = inv_trans_fig(fig._suptitle.get_tightbbox(renderer))
+ layoutgrids[fig].edit_margin_min('top', bbox.height + 2 * h_pad)
+
+ if fig._supxlabel is not None and fig._supxlabel.get_in_layout():
+ p = fig._supxlabel.get_position()
+ if getattr(fig._supxlabel, '_autopos', False):
+ fig._supxlabel.set_position((p[0], h_pad_local))
+ bbox = inv_trans_fig(fig._supxlabel.get_tightbbox(renderer))
+ layoutgrids[fig].edit_margin_min('bottom',
+ bbox.height + 2 * h_pad)
+
+ if fig._supylabel is not None and fig._supylabel.get_in_layout():
+ p = fig._supylabel.get_position()
+ if getattr(fig._supylabel, '_autopos', False):
+ fig._supylabel.set_position((w_pad_local, p[1]))
+ bbox = inv_trans_fig(fig._supylabel.get_tightbbox(renderer))
+ layoutgrids[fig].edit_margin_min('left', bbox.width + 2 * w_pad)
+
+
+def match_submerged_margins(layoutgrids, fig):
+ """
+ Make the margins that are submerged inside an Axes the same size.
+
+ This allows Axes that span two columns (or rows) that are offset
+ from one another to have the same size.
+
+ This gives the proper layout for something like::
+ fig = plt.figure(constrained_layout=True)
+ axs = fig.subplot_mosaic("AAAB\nCCDD")
+
+ Without this routine, the Axes D will be wider than C, because the
+ margin width between the two columns in C has no width by default,
+ whereas the margins between the two columns of D are set by the
+ width of the margin between A and B. However, obviously the user would
+ like C and D to be the same size, so we need to add constraints to these
+ "submerged" margins.
+
+ This routine makes all the interior margins the same, and the spacing
+ between the three columns in A and the two column in C are all set to the
+ margins between the two columns of D.
+
+ See test_constrained_layout::test_constrained_layout12 for an example.
+ """
+
+ for sfig in fig.subfigs:
+ match_submerged_margins(layoutgrids, sfig)
+
+ axs = [a for a in fig.get_axes()
+ if a.get_subplotspec() is not None and a.get_in_layout()]
+
+ for ax1 in axs:
+ ss1 = ax1.get_subplotspec()
+ if ss1.get_gridspec() not in layoutgrids:
+ axs.remove(ax1)
+ continue
+ lg1 = layoutgrids[ss1.get_gridspec()]
+
+ # interior columns:
+ if len(ss1.colspan) > 1:
+ maxsubl = np.max(
+ lg1.margin_vals['left'][ss1.colspan[1:]] +
+ lg1.margin_vals['leftcb'][ss1.colspan[1:]]
+ )
+ maxsubr = np.max(
+ lg1.margin_vals['right'][ss1.colspan[:-1]] +
+ lg1.margin_vals['rightcb'][ss1.colspan[:-1]]
+ )
+ for ax2 in axs:
+ ss2 = ax2.get_subplotspec()
+ lg2 = layoutgrids[ss2.get_gridspec()]
+ if lg2 is not None and len(ss2.colspan) > 1:
+ maxsubl2 = np.max(
+ lg2.margin_vals['left'][ss2.colspan[1:]] +
+ lg2.margin_vals['leftcb'][ss2.colspan[1:]])
+ if maxsubl2 > maxsubl:
+ maxsubl = maxsubl2
+ maxsubr2 = np.max(
+ lg2.margin_vals['right'][ss2.colspan[:-1]] +
+ lg2.margin_vals['rightcb'][ss2.colspan[:-1]])
+ if maxsubr2 > maxsubr:
+ maxsubr = maxsubr2
+ for i in ss1.colspan[1:]:
+ lg1.edit_margin_min('left', maxsubl, cell=i)
+ for i in ss1.colspan[:-1]:
+ lg1.edit_margin_min('right', maxsubr, cell=i)
+
+ # interior rows:
+ if len(ss1.rowspan) > 1:
+ maxsubt = np.max(
+ lg1.margin_vals['top'][ss1.rowspan[1:]] +
+ lg1.margin_vals['topcb'][ss1.rowspan[1:]]
+ )
+ maxsubb = np.max(
+ lg1.margin_vals['bottom'][ss1.rowspan[:-1]] +
+ lg1.margin_vals['bottomcb'][ss1.rowspan[:-1]]
+ )
+
+ for ax2 in axs:
+ ss2 = ax2.get_subplotspec()
+ lg2 = layoutgrids[ss2.get_gridspec()]
+ if lg2 is not None:
+ if len(ss2.rowspan) > 1:
+ maxsubt = np.max([np.max(
+ lg2.margin_vals['top'][ss2.rowspan[1:]] +
+ lg2.margin_vals['topcb'][ss2.rowspan[1:]]
+ ), maxsubt])
+ maxsubb = np.max([np.max(
+ lg2.margin_vals['bottom'][ss2.rowspan[:-1]] +
+ lg2.margin_vals['bottomcb'][ss2.rowspan[:-1]]
+ ), maxsubb])
+ for i in ss1.rowspan[1:]:
+ lg1.edit_margin_min('top', maxsubt, cell=i)
+ for i in ss1.rowspan[:-1]:
+ lg1.edit_margin_min('bottom', maxsubb, cell=i)
+
+
+def get_cb_parent_spans(cbax):
+ """
+ Figure out which subplotspecs this colorbar belongs to.
+
+ Parameters
+ ----------
+ cbax : `~matplotlib.axes.Axes`
+ Axes for the colorbar.
+ """
+ rowstart = np.inf
+ rowstop = -np.inf
+ colstart = np.inf
+ colstop = -np.inf
+ for parent in cbax._colorbar_info['parents']:
+ ss = parent.get_subplotspec()
+ rowstart = min(ss.rowspan.start, rowstart)
+ rowstop = max(ss.rowspan.stop, rowstop)
+ colstart = min(ss.colspan.start, colstart)
+ colstop = max(ss.colspan.stop, colstop)
+
+ rowspan = range(rowstart, rowstop)
+ colspan = range(colstart, colstop)
+ return rowspan, colspan
+
+
+def get_pos_and_bbox(ax, renderer):
+ """
+ Get the position and the bbox for the Axes.
+
+ Parameters
+ ----------
+ ax : `~matplotlib.axes.Axes`
+ renderer : `~matplotlib.backend_bases.RendererBase` subclass.
+
+ Returns
+ -------
+ pos : `~matplotlib.transforms.Bbox`
+ Position in figure coordinates.
+ bbox : `~matplotlib.transforms.Bbox`
+ Tight bounding box in figure coordinates.
+ """
+ fig = ax.get_figure(root=False)
+ pos = ax.get_position(original=True)
+ # pos is in panel co-ords, but we need in figure for the layout
+ pos = pos.transformed(fig.transSubfigure - fig.transFigure)
+ tightbbox = martist._get_tightbbox_for_layout_only(ax, renderer)
+ if tightbbox is None:
+ bbox = pos
+ else:
+ bbox = tightbbox.transformed(fig.transFigure.inverted())
+ return pos, bbox
+
+
+def reposition_axes(layoutgrids, fig, renderer, *,
+ w_pad=0, h_pad=0, hspace=0, wspace=0):
+ """
+ Reposition all the Axes based on the new inner bounding box.
+ """
+ trans_fig_to_subfig = fig.transFigure - fig.transSubfigure
+ for sfig in fig.subfigs:
+ bbox = layoutgrids[sfig].get_outer_bbox()
+ sfig._redo_transform_rel_fig(
+ bbox=bbox.transformed(trans_fig_to_subfig))
+ reposition_axes(layoutgrids, sfig, renderer,
+ w_pad=w_pad, h_pad=h_pad,
+ wspace=wspace, hspace=hspace)
+
+ for ax in fig._localaxes:
+ if ax.get_subplotspec() is None or not ax.get_in_layout():
+ continue
+
+ # grid bbox is in Figure coordinates, but we specify in panel
+ # coordinates...
+ ss = ax.get_subplotspec()
+ gs = ss.get_gridspec()
+ if gs not in layoutgrids:
+ return
+
+ bbox = layoutgrids[gs].get_inner_bbox(rows=ss.rowspan,
+ cols=ss.colspan)
+
+ # transform from figure to panel for set_position:
+ newbbox = trans_fig_to_subfig.transform_bbox(bbox)
+ ax._set_position(newbbox)
+
+ # move the colorbars:
+ # we need to keep track of oldw and oldh if there is more than
+ # one colorbar:
+ offset = {'left': 0, 'right': 0, 'bottom': 0, 'top': 0}
+ for nn, cbax in enumerate(ax._colorbars[::-1]):
+ if ax == cbax._colorbar_info['parents'][0]:
+ reposition_colorbar(layoutgrids, cbax, renderer,
+ offset=offset)
+
+
+def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None):
+ """
+ Place the colorbar in its new place.
+
+ Parameters
+ ----------
+ layoutgrids : dict
+ cbax : `~matplotlib.axes.Axes`
+ Axes for the colorbar.
+ renderer : `~matplotlib.backend_bases.RendererBase` subclass.
+ The renderer to use.
+ offset : array-like
+ Offset the colorbar needs to be pushed to in order to
+ account for multiple colorbars.
+ """
+
+ parents = cbax._colorbar_info['parents']
+ gs = parents[0].get_gridspec()
+ fig = cbax.get_figure(root=False)
+ trans_fig_to_subfig = fig.transFigure - fig.transSubfigure
+
+ cb_rspans, cb_cspans = get_cb_parent_spans(cbax)
+ bboxparent = layoutgrids[gs].get_bbox_for_cb(rows=cb_rspans,
+ cols=cb_cspans)
+ pb = layoutgrids[gs].get_inner_bbox(rows=cb_rspans, cols=cb_cspans)
+
+ location = cbax._colorbar_info['location']
+ anchor = cbax._colorbar_info['anchor']
+ fraction = cbax._colorbar_info['fraction']
+ aspect = cbax._colorbar_info['aspect']
+ shrink = cbax._colorbar_info['shrink']
+
+ cbpos, cbbbox = get_pos_and_bbox(cbax, renderer)
+
+ # Colorbar gets put at extreme edge of outer bbox of the subplotspec
+ # It needs to be moved in by: 1) a pad 2) its "margin" 3) by
+ # any colorbars already added at this location:
+ cbpad = colorbar_get_pad(layoutgrids, cbax)
+ if location in ('left', 'right'):
+ # fraction and shrink are fractions of parent
+ pbcb = pb.shrunk(fraction, shrink).anchored(anchor, pb)
+ # The colorbar is at the left side of the parent. Need
+ # to translate to right (or left)
+ if location == 'right':
+ lmargin = cbpos.x0 - cbbbox.x0
+ dx = bboxparent.x1 - pbcb.x0 + offset['right']
+ dx += cbpad + lmargin
+ offset['right'] += cbbbox.width + cbpad
+ pbcb = pbcb.translated(dx, 0)
+ else:
+ lmargin = cbpos.x0 - cbbbox.x0
+ dx = bboxparent.x0 - pbcb.x0 # edge of parent
+ dx += -cbbbox.width - cbpad + lmargin - offset['left']
+ offset['left'] += cbbbox.width + cbpad
+ pbcb = pbcb.translated(dx, 0)
+ else: # horizontal axes:
+ pbcb = pb.shrunk(shrink, fraction).anchored(anchor, pb)
+ if location == 'top':
+ bmargin = cbpos.y0 - cbbbox.y0
+ dy = bboxparent.y1 - pbcb.y0 + offset['top']
+ dy += cbpad + bmargin
+ offset['top'] += cbbbox.height + cbpad
+ pbcb = pbcb.translated(0, dy)
+ else:
+ bmargin = cbpos.y0 - cbbbox.y0
+ dy = bboxparent.y0 - pbcb.y0
+ dy += -cbbbox.height - cbpad + bmargin - offset['bottom']
+ offset['bottom'] += cbbbox.height + cbpad
+ pbcb = pbcb.translated(0, dy)
+
+ pbcb = trans_fig_to_subfig.transform_bbox(pbcb)
+ cbax.set_transform(fig.transSubfigure)
+ cbax._set_position(pbcb)
+ cbax.set_anchor(anchor)
+ if location in ['bottom', 'top']:
+ aspect = 1 / aspect
+ cbax.set_box_aspect(aspect)
+ cbax.set_aspect('auto')
+ return offset
+
+
+def reset_margins(layoutgrids, fig):
+ """
+ Reset the margins in the layoutboxes of *fig*.
+
+ Margins are usually set as a minimum, so if the figure gets smaller
+ the minimum needs to be zero in order for it to grow again.
+ """
+ for sfig in fig.subfigs:
+ reset_margins(layoutgrids, sfig)
+ for ax in fig.axes:
+ if ax.get_in_layout():
+ gs = ax.get_gridspec()
+ if gs in layoutgrids: # also implies gs is not None.
+ layoutgrids[gs].reset_margins()
+ layoutgrids[fig].reset_margins()
+
+
+def colorbar_get_pad(layoutgrids, cax):
+ parents = cax._colorbar_info['parents']
+ gs = parents[0].get_gridspec()
+
+ cb_rspans, cb_cspans = get_cb_parent_spans(cax)
+ bboxouter = layoutgrids[gs].get_inner_bbox(rows=cb_rspans, cols=cb_cspans)
+
+ if cax._colorbar_info['location'] in ['right', 'left']:
+ size = bboxouter.width
+ else:
+ size = bboxouter.height
+
+ return cax._colorbar_info['pad'] * size
diff --git a/lib/python3.12/site-packages/matplotlib/_enums.pyi b/lib/python3.12/site-packages/matplotlib/_enums.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..714e6cfe03faab19b2a3f939a6be4ac95415e061
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_enums.pyi
@@ -0,0 +1,19 @@
+from typing import cast
+from enum import Enum
+
+
+class JoinStyle(str, Enum):
+ miter = "miter"
+ round = "round"
+ bevel = "bevel"
+ @staticmethod
+ def demo() -> None: ...
+
+
+class CapStyle(str, Enum):
+ butt = "butt"
+ projecting = "projecting"
+ round = "round"
+
+ @staticmethod
+ def demo() -> None: ...
diff --git a/lib/python3.12/site-packages/matplotlib/_fontconfig_pattern.py b/lib/python3.12/site-packages/matplotlib/_fontconfig_pattern.py
new file mode 100644
index 0000000000000000000000000000000000000000..a1341c633243905be30141ecb7273d0fb325f2de
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_fontconfig_pattern.py
@@ -0,0 +1,111 @@
+"""
+A module for parsing and generating `fontconfig patterns`_.
+
+.. _fontconfig patterns:
+ https://www.freedesktop.org/software/fontconfig/fontconfig-user.html
+"""
+
+# This class logically belongs in `matplotlib.font_manager`, but placing it
+# there would have created cyclical dependency problems, because it also needs
+# to be available from `matplotlib.rcsetup` (for parsing matplotlibrc files).
+
+from functools import lru_cache, partial
+import re
+
+from pyparsing import (
+ Group, Optional, ParseException, Regex, StringEnd, Suppress, ZeroOrMore, oneOf)
+
+
+_family_punc = r'\\\-:,'
+_family_unescape = partial(re.compile(r'\\(?=[%s])' % _family_punc).sub, '')
+_family_escape = partial(re.compile(r'(?=[%s])' % _family_punc).sub, r'\\')
+_value_punc = r'\\=_:,'
+_value_unescape = partial(re.compile(r'\\(?=[%s])' % _value_punc).sub, '')
+_value_escape = partial(re.compile(r'(?=[%s])' % _value_punc).sub, r'\\')
+
+
+_CONSTANTS = {
+ 'thin': ('weight', 'light'),
+ 'extralight': ('weight', 'light'),
+ 'ultralight': ('weight', 'light'),
+ 'light': ('weight', 'light'),
+ 'book': ('weight', 'book'),
+ 'regular': ('weight', 'regular'),
+ 'normal': ('weight', 'normal'),
+ 'medium': ('weight', 'medium'),
+ 'demibold': ('weight', 'demibold'),
+ 'semibold': ('weight', 'semibold'),
+ 'bold': ('weight', 'bold'),
+ 'extrabold': ('weight', 'extra bold'),
+ 'black': ('weight', 'black'),
+ 'heavy': ('weight', 'heavy'),
+ 'roman': ('slant', 'normal'),
+ 'italic': ('slant', 'italic'),
+ 'oblique': ('slant', 'oblique'),
+ 'ultracondensed': ('width', 'ultra-condensed'),
+ 'extracondensed': ('width', 'extra-condensed'),
+ 'condensed': ('width', 'condensed'),
+ 'semicondensed': ('width', 'semi-condensed'),
+ 'expanded': ('width', 'expanded'),
+ 'extraexpanded': ('width', 'extra-expanded'),
+ 'ultraexpanded': ('width', 'ultra-expanded'),
+}
+
+
+@lru_cache # The parser instance is a singleton.
+def _make_fontconfig_parser():
+ def comma_separated(elem):
+ return elem + ZeroOrMore(Suppress(",") + elem)
+
+ family = Regex(fr"([^{_family_punc}]|(\\[{_family_punc}]))*")
+ size = Regex(r"([0-9]+\.?[0-9]*|\.[0-9]+)")
+ name = Regex(r"[a-z]+")
+ value = Regex(fr"([^{_value_punc}]|(\\[{_value_punc}]))*")
+ prop = Group((name + Suppress("=") + comma_separated(value)) | oneOf(_CONSTANTS))
+ return (
+ Optional(comma_separated(family)("families"))
+ + Optional("-" + comma_separated(size)("sizes"))
+ + ZeroOrMore(":" + prop("properties*"))
+ + StringEnd()
+ )
+
+
+# `parse_fontconfig_pattern` is a bottleneck during the tests because it is
+# repeatedly called when the rcParams are reset (to validate the default
+# fonts). In practice, the cache size doesn't grow beyond a few dozen entries
+# during the test suite.
+@lru_cache
+def parse_fontconfig_pattern(pattern):
+ """
+ Parse a fontconfig *pattern* into a dict that can initialize a
+ `.font_manager.FontProperties` object.
+ """
+ parser = _make_fontconfig_parser()
+ try:
+ parse = parser.parseString(pattern)
+ except ParseException as err:
+ # explain becomes a plain method on pyparsing 3 (err.explain(0)).
+ raise ValueError("\n" + ParseException.explain(err, 0)) from None
+ parser.resetCache()
+ props = {}
+ if "families" in parse:
+ props["family"] = [*map(_family_unescape, parse["families"])]
+ if "sizes" in parse:
+ props["size"] = [*parse["sizes"]]
+ for prop in parse.get("properties", []):
+ if len(prop) == 1:
+ prop = _CONSTANTS[prop[0]]
+ k, *v = prop
+ props.setdefault(k, []).extend(map(_value_unescape, v))
+ return props
+
+
+def generate_fontconfig_pattern(d):
+ """Convert a `.FontProperties` to a fontconfig pattern string."""
+ kvs = [(k, getattr(d, f"get_{k}")())
+ for k in ["style", "variant", "weight", "stretch", "file", "size"]]
+ # Families is given first without a leading keyword. Other entries (which
+ # are necessarily scalar) are given as key=value, skipping Nones.
+ return (",".join(_family_escape(f) for f in d.get_family())
+ + "".join(f":{k}={_value_escape(str(v))}"
+ for k, v in kvs if v is not None))
diff --git a/lib/python3.12/site-packages/matplotlib/_image.pyi b/lib/python3.12/site-packages/matplotlib/_image.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/lib/python3.12/site-packages/matplotlib/_internal_utils.py b/lib/python3.12/site-packages/matplotlib/_internal_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..0223aa593bb2cb20b58f2b9e41bdc0dfa5ceed35
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_internal_utils.py
@@ -0,0 +1,64 @@
+"""
+Internal debugging utilities, that are not expected to be used in the rest of
+the codebase.
+
+WARNING: Code in this module may change without prior notice!
+"""
+
+from io import StringIO
+from pathlib import Path
+import subprocess
+
+from matplotlib.transforms import TransformNode
+
+
+def graphviz_dump_transform(transform, dest, *, highlight=None):
+ """
+ Generate a graphical representation of the transform tree for *transform*
+ using the :program:`dot` program (which this function depends on). The
+ output format (png, dot, etc.) is determined from the suffix of *dest*.
+
+ Parameters
+ ----------
+ transform : `~matplotlib.transform.Transform`
+ The represented transform.
+ dest : str
+ Output filename. The extension must be one of the formats supported
+ by :program:`dot`, e.g. png, svg, dot, ...
+ (see https://www.graphviz.org/doc/info/output.html).
+ highlight : list of `~matplotlib.transform.Transform` or None
+ The transforms in the tree to be drawn in bold.
+ If *None*, *transform* is highlighted.
+ """
+
+ if highlight is None:
+ highlight = [transform]
+ seen = set()
+
+ def recurse(root, buf):
+ if id(root) in seen:
+ return
+ seen.add(id(root))
+ props = {}
+ label = type(root).__name__
+ if root._invalid:
+ label = f'[{label}]'
+ if root in highlight:
+ props['style'] = 'bold'
+ props['shape'] = 'box'
+ props['label'] = '"%s"' % label
+ props = ' '.join(map('{0[0]}={0[1]}'.format, props.items()))
+ buf.write(f'{id(root)} [{props}];\n')
+ for key, val in vars(root).items():
+ if isinstance(val, TransformNode) and id(root) in val._parents:
+ buf.write(f'"{id(root)}" -> "{id(val)}" '
+ f'[label="{key}", fontsize=10];\n')
+ recurse(val, buf)
+
+ buf = StringIO()
+ buf.write('digraph G {\n')
+ recurse(transform, buf)
+ buf.write('}\n')
+ subprocess.run(
+ ['dot', '-T', Path(dest).suffix[1:], '-o', dest],
+ input=buf.getvalue().encode('utf-8'), check=True)
diff --git a/lib/python3.12/site-packages/matplotlib/_mathtext.py b/lib/python3.12/site-packages/matplotlib/_mathtext.py
new file mode 100644
index 0000000000000000000000000000000000000000..7085a986414e74c046998ebc5925e803656074e7
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_mathtext.py
@@ -0,0 +1,2861 @@
+"""
+Implementation details for :mod:`.mathtext`.
+"""
+
+from __future__ import annotations
+
+import abc
+import copy
+import enum
+import functools
+import logging
+import os
+import re
+import types
+import unicodedata
+import string
+import typing as T
+from typing import NamedTuple
+
+import numpy as np
+from pyparsing import (
+ Empty, Forward, Literal, NotAny, oneOf, OneOrMore, Optional,
+ ParseBaseException, ParseException, ParseExpression, ParseFatalException,
+ ParserElement, ParseResults, QuotedString, Regex, StringEnd, ZeroOrMore,
+ pyparsing_common, Group)
+
+import matplotlib as mpl
+from . import cbook
+from ._mathtext_data import (
+ latex_to_bakoma, stix_glyph_fixes, stix_virtual_fonts, tex2uni)
+from .font_manager import FontProperties, findfont, get_font
+from .ft2font import FT2Font, FT2Image, Kerning, LoadFlags
+
+from packaging.version import parse as parse_version
+from pyparsing import __version__ as pyparsing_version
+if parse_version(pyparsing_version).major < 3:
+ from pyparsing import nestedExpr as nested_expr
+else:
+ from pyparsing import nested_expr
+
+if T.TYPE_CHECKING:
+ from collections.abc import Iterable
+ from .ft2font import Glyph
+
+ParserElement.enablePackrat()
+_log = logging.getLogger("matplotlib.mathtext")
+
+
+##############################################################################
+# FONTS
+
+
+def get_unicode_index(symbol: str) -> int: # Publicly exported.
+ r"""
+ Return the integer index (from the Unicode table) of *symbol*.
+
+ Parameters
+ ----------
+ symbol : str
+ A single (Unicode) character, a TeX command (e.g. r'\pi') or a Type1
+ symbol name (e.g. 'phi').
+ """
+ try: # This will succeed if symbol is a single Unicode char
+ return ord(symbol)
+ except TypeError:
+ pass
+ try: # Is symbol a TeX symbol (i.e. \alpha)
+ return tex2uni[symbol.strip("\\")]
+ except KeyError as err:
+ raise ValueError(
+ f"{symbol!r} is not a valid Unicode character or TeX/Type1 symbol"
+ ) from err
+
+
+class VectorParse(NamedTuple):
+ """
+ The namedtuple type returned by ``MathTextParser("path").parse(...)``.
+
+ Attributes
+ ----------
+ width, height, depth : float
+ The global metrics.
+ glyphs : list
+ The glyphs including their positions.
+ rect : list
+ The list of rectangles.
+ """
+ width: float
+ height: float
+ depth: float
+ glyphs: list[tuple[FT2Font, float, int, float, float]]
+ rects: list[tuple[float, float, float, float]]
+
+VectorParse.__module__ = "matplotlib.mathtext"
+
+
+class RasterParse(NamedTuple):
+ """
+ The namedtuple type returned by ``MathTextParser("agg").parse(...)``.
+
+ Attributes
+ ----------
+ ox, oy : float
+ The offsets are always zero.
+ width, height, depth : float
+ The global metrics.
+ image : FT2Image
+ A raster image.
+ """
+ ox: float
+ oy: float
+ width: float
+ height: float
+ depth: float
+ image: FT2Image
+
+RasterParse.__module__ = "matplotlib.mathtext"
+
+
+class Output:
+ r"""
+ Result of `ship`\ping a box: lists of positioned glyphs and rectangles.
+
+ This class is not exposed to end users, but converted to a `VectorParse` or
+ a `RasterParse` by `.MathTextParser.parse`.
+ """
+
+ def __init__(self, box: Box):
+ self.box = box
+ self.glyphs: list[tuple[float, float, FontInfo]] = [] # (ox, oy, info)
+ self.rects: list[tuple[float, float, float, float]] = [] # (x1, y1, x2, y2)
+
+ def to_vector(self) -> VectorParse:
+ w, h, d = map(
+ np.ceil, [self.box.width, self.box.height, self.box.depth])
+ gs = [(info.font, info.fontsize, info.num, ox, h - oy + info.offset)
+ for ox, oy, info in self.glyphs]
+ rs = [(x1, h - y2, x2 - x1, y2 - y1)
+ for x1, y1, x2, y2 in self.rects]
+ return VectorParse(w, h + d, d, gs, rs)
+
+ def to_raster(self, *, antialiased: bool) -> RasterParse:
+ # Metrics y's and mathtext y's are oriented in opposite directions,
+ # hence the switch between ymin and ymax.
+ xmin = min([*[ox + info.metrics.xmin for ox, oy, info in self.glyphs],
+ *[x1 for x1, y1, x2, y2 in self.rects], 0]) - 1
+ ymin = min([*[oy - info.metrics.ymax for ox, oy, info in self.glyphs],
+ *[y1 for x1, y1, x2, y2 in self.rects], 0]) - 1
+ xmax = max([*[ox + info.metrics.xmax for ox, oy, info in self.glyphs],
+ *[x2 for x1, y1, x2, y2 in self.rects], 0]) + 1
+ ymax = max([*[oy - info.metrics.ymin for ox, oy, info in self.glyphs],
+ *[y2 for x1, y1, x2, y2 in self.rects], 0]) + 1
+ w = xmax - xmin
+ h = ymax - ymin - self.box.depth
+ d = ymax - ymin - self.box.height
+ image = FT2Image(int(np.ceil(w)), int(np.ceil(h + max(d, 0))))
+
+ # Ideally, we could just use self.glyphs and self.rects here, shifting
+ # their coordinates by (-xmin, -ymin), but this yields slightly
+ # different results due to floating point slop; shipping twice is the
+ # old approach and keeps baseline images backcompat.
+ shifted = ship(self.box, (-xmin, -ymin))
+
+ for ox, oy, info in shifted.glyphs:
+ info.font.draw_glyph_to_bitmap(
+ image, int(ox), int(oy - info.metrics.iceberg), info.glyph,
+ antialiased=antialiased)
+ for x1, y1, x2, y2 in shifted.rects:
+ height = max(int(y2 - y1) - 1, 0)
+ if height == 0:
+ center = (y2 + y1) / 2
+ y = int(center - (height + 1) / 2)
+ else:
+ y = int(y1)
+ image.draw_rect_filled(int(x1), y, int(np.ceil(x2)), y + height)
+ return RasterParse(0, 0, w, h + d, d, image)
+
+
+class FontMetrics(NamedTuple):
+ """
+ Metrics of a font.
+
+ Attributes
+ ----------
+ advance : float
+ The advance distance (in points) of the glyph.
+ height : float
+ The height of the glyph in points.
+ width : float
+ The width of the glyph in points.
+ xmin, xmax, ymin, ymax : float
+ The ink rectangle of the glyph.
+ iceberg : float
+ The distance from the baseline to the top of the glyph. (This corresponds to
+ TeX's definition of "height".)
+ slanted : bool
+ Whether the glyph should be considered as "slanted" (currently used for kerning
+ sub/superscripts).
+ """
+ advance: float
+ height: float
+ width: float
+ xmin: float
+ xmax: float
+ ymin: float
+ ymax: float
+ iceberg: float
+ slanted: bool
+
+
+class FontInfo(NamedTuple):
+ font: FT2Font
+ fontsize: float
+ postscript_name: str
+ metrics: FontMetrics
+ num: int
+ glyph: Glyph
+ offset: float
+
+
+class Fonts(abc.ABC):
+ """
+ An abstract base class for a system of fonts to use for mathtext.
+
+ The class must be able to take symbol keys and font file names and
+ return the character metrics. It also delegates to a backend class
+ to do the actual drawing.
+ """
+
+ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
+ """
+ Parameters
+ ----------
+ default_font_prop : `~.font_manager.FontProperties`
+ The default non-math font, or the base font for Unicode (generic)
+ font rendering.
+ load_glyph_flags : `.ft2font.LoadFlags`
+ Flags passed to the glyph loader (e.g. ``FT_Load_Glyph`` and
+ ``FT_Load_Char`` for FreeType-based fonts).
+ """
+ self.default_font_prop = default_font_prop
+ self.load_glyph_flags = load_glyph_flags
+
+ def get_kern(self, font1: str, fontclass1: str, sym1: str, fontsize1: float,
+ font2: str, fontclass2: str, sym2: str, fontsize2: float,
+ dpi: float) -> float:
+ """
+ Get the kerning distance for font between *sym1* and *sym2*.
+
+ See `~.Fonts.get_metrics` for a detailed description of the parameters.
+ """
+ return 0.
+
+ def _get_font(self, font: str) -> FT2Font:
+ raise NotImplementedError
+
+ def _get_info(self, font: str, font_class: str, sym: str, fontsize: float,
+ dpi: float) -> FontInfo:
+ raise NotImplementedError
+
+ def get_metrics(self, font: str, font_class: str, sym: str, fontsize: float,
+ dpi: float) -> FontMetrics:
+ r"""
+ Parameters
+ ----------
+ font : str
+ One of the TeX font names: "tt", "it", "rm", "cal", "sf", "bf",
+ "default", "regular", "bb", "frak", "scr". "default" and "regular"
+ are synonyms and use the non-math font.
+ font_class : str
+ One of the TeX font names (as for *font*), but **not** "bb",
+ "frak", or "scr". This is used to combine two font classes. The
+ only supported combination currently is ``get_metrics("frak", "bf",
+ ...)``.
+ sym : str
+ A symbol in raw TeX form, e.g., "1", "x", or "\sigma".
+ fontsize : float
+ Font size in points.
+ dpi : float
+ Rendering dots-per-inch.
+
+ Returns
+ -------
+ FontMetrics
+ """
+ info = self._get_info(font, font_class, sym, fontsize, dpi)
+ return info.metrics
+
+ def render_glyph(self, output: Output, ox: float, oy: float, font: str,
+ font_class: str, sym: str, fontsize: float, dpi: float) -> None:
+ """
+ At position (*ox*, *oy*), draw the glyph specified by the remaining
+ parameters (see `get_metrics` for their detailed description).
+ """
+ info = self._get_info(font, font_class, sym, fontsize, dpi)
+ output.glyphs.append((ox, oy, info))
+
+ def render_rect_filled(self, output: Output,
+ x1: float, y1: float, x2: float, y2: float) -> None:
+ """
+ Draw a filled rectangle from (*x1*, *y1*) to (*x2*, *y2*).
+ """
+ output.rects.append((x1, y1, x2, y2))
+
+ def get_xheight(self, font: str, fontsize: float, dpi: float) -> float:
+ """
+ Get the xheight for the given *font* and *fontsize*.
+ """
+ raise NotImplementedError()
+
+ def get_underline_thickness(self, font: str, fontsize: float, dpi: float) -> float:
+ """
+ Get the line thickness that matches the given font. Used as a
+ base unit for drawing lines such as in a fraction or radical.
+ """
+ raise NotImplementedError()
+
+ def get_sized_alternatives_for_symbol(self, fontname: str,
+ sym: str) -> list[tuple[str, str]]:
+ """
+ Override if your font provides multiple sizes of the same
+ symbol. Should return a list of symbols matching *sym* in
+ various sizes. The expression renderer will select the most
+ appropriate size for a given situation from this list.
+ """
+ return [(fontname, sym)]
+
+
+class TruetypeFonts(Fonts, metaclass=abc.ABCMeta):
+ """
+ A generic base class for all font setups that use Truetype fonts
+ (through FT2Font).
+ """
+
+ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
+ super().__init__(default_font_prop, load_glyph_flags)
+ # Per-instance cache.
+ self._get_info = functools.cache(self._get_info) # type: ignore[method-assign]
+ self._fonts = {}
+ self.fontmap: dict[str | int, str] = {}
+
+ filename = findfont(self.default_font_prop)
+ default_font = get_font(filename)
+ self._fonts['default'] = default_font
+ self._fonts['regular'] = default_font
+
+ def _get_font(self, font: str | int) -> FT2Font:
+ if font in self.fontmap:
+ basename = self.fontmap[font]
+ else:
+ # NOTE: An int is only passed by subclasses which have placed int keys into
+ # `self.fontmap`, so we must cast this to confirm it to typing.
+ basename = T.cast(str, font)
+ cached_font = self._fonts.get(basename)
+ if cached_font is None and os.path.exists(basename):
+ cached_font = get_font(basename)
+ self._fonts[basename] = cached_font
+ self._fonts[cached_font.postscript_name] = cached_font
+ self._fonts[cached_font.postscript_name.lower()] = cached_font
+ return T.cast(FT2Font, cached_font) # FIXME: Not sure this is guaranteed.
+
+ def _get_offset(self, font: FT2Font, glyph: Glyph, fontsize: float,
+ dpi: float) -> float:
+ if font.postscript_name == 'Cmex10':
+ return (glyph.height / 64 / 2) + (fontsize/3 * dpi/72)
+ return 0.
+
+ def _get_glyph(self, fontname: str, font_class: str,
+ sym: str) -> tuple[FT2Font, int, bool]:
+ raise NotImplementedError
+
+ # The return value of _get_info is cached per-instance.
+ def _get_info(self, fontname: str, font_class: str, sym: str, fontsize: float,
+ dpi: float) -> FontInfo:
+ font, num, slanted = self._get_glyph(fontname, font_class, sym)
+ font.set_size(fontsize, dpi)
+ glyph = font.load_char(num, flags=self.load_glyph_flags)
+
+ xmin, ymin, xmax, ymax = (val / 64 for val in glyph.bbox)
+ offset = self._get_offset(font, glyph, fontsize, dpi)
+ metrics = FontMetrics(
+ advance=glyph.linearHoriAdvance / 65536,
+ height=glyph.height / 64,
+ width=glyph.width / 64,
+ xmin=xmin,
+ xmax=xmax,
+ ymin=ymin + offset,
+ ymax=ymax + offset,
+ # iceberg is the equivalent of TeX's "height"
+ iceberg=glyph.horiBearingY / 64 + offset,
+ slanted=slanted
+ )
+
+ return FontInfo(
+ font=font,
+ fontsize=fontsize,
+ postscript_name=font.postscript_name,
+ metrics=metrics,
+ num=num,
+ glyph=glyph,
+ offset=offset
+ )
+
+ def get_xheight(self, fontname: str, fontsize: float, dpi: float) -> float:
+ font = self._get_font(fontname)
+ font.set_size(fontsize, dpi)
+ pclt = font.get_sfnt_table('pclt')
+ if pclt is None:
+ # Some fonts don't store the xHeight, so we do a poor man's xHeight
+ metrics = self.get_metrics(
+ fontname, mpl.rcParams['mathtext.default'], 'x', fontsize, dpi)
+ return metrics.iceberg
+ xHeight = (pclt['xHeight'] / 64.0) * (fontsize / 12.0) * (dpi / 100.0)
+ return xHeight
+
+ def get_underline_thickness(self, font: str, fontsize: float, dpi: float) -> float:
+ # This function used to grab underline thickness from the font
+ # metrics, but that information is just too un-reliable, so it
+ # is now hardcoded.
+ return ((0.75 / 12.0) * fontsize * dpi) / 72.0
+
+ def get_kern(self, font1: str, fontclass1: str, sym1: str, fontsize1: float,
+ font2: str, fontclass2: str, sym2: str, fontsize2: float,
+ dpi: float) -> float:
+ if font1 == font2 and fontsize1 == fontsize2:
+ info1 = self._get_info(font1, fontclass1, sym1, fontsize1, dpi)
+ info2 = self._get_info(font2, fontclass2, sym2, fontsize2, dpi)
+ font = info1.font
+ return font.get_kerning(info1.num, info2.num, Kerning.DEFAULT) / 64
+ return super().get_kern(font1, fontclass1, sym1, fontsize1,
+ font2, fontclass2, sym2, fontsize2, dpi)
+
+
+class BakomaFonts(TruetypeFonts):
+ """
+ Use the Bakoma TrueType fonts for rendering.
+
+ Symbols are strewn about a number of font files, each of which has
+ its own proprietary 8-bit encoding.
+ """
+ _fontmap = {
+ 'cal': 'cmsy10',
+ 'rm': 'cmr10',
+ 'tt': 'cmtt10',
+ 'it': 'cmmi10',
+ 'bf': 'cmb10',
+ 'sf': 'cmss10',
+ 'ex': 'cmex10',
+ }
+
+ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
+ self._stix_fallback = StixFonts(default_font_prop, load_glyph_flags)
+
+ super().__init__(default_font_prop, load_glyph_flags)
+ for key, val in self._fontmap.items():
+ fullpath = findfont(val)
+ self.fontmap[key] = fullpath
+ self.fontmap[val] = fullpath
+
+ _slanted_symbols = set(r"\int \oint".split())
+
+ def _get_glyph(self, fontname: str, font_class: str,
+ sym: str) -> tuple[FT2Font, int, bool]:
+ font = None
+ if fontname in self.fontmap and sym in latex_to_bakoma:
+ basename, num = latex_to_bakoma[sym]
+ slanted = (basename == "cmmi10") or sym in self._slanted_symbols
+ font = self._get_font(basename)
+ elif len(sym) == 1:
+ slanted = (fontname == "it")
+ font = self._get_font(fontname)
+ if font is not None:
+ num = ord(sym)
+ if font is not None and font.get_char_index(num) != 0:
+ return font, num, slanted
+ else:
+ return self._stix_fallback._get_glyph(fontname, font_class, sym)
+
+ # The Bakoma fonts contain many pre-sized alternatives for the
+ # delimiters. The AutoSizedChar class will use these alternatives
+ # and select the best (closest sized) glyph.
+ _size_alternatives = {
+ '(': [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'),
+ ('ex', '\xb5'), ('ex', '\xc3')],
+ ')': [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'),
+ ('ex', '\xb6'), ('ex', '\x21')],
+ '{': [('cal', '{'), ('ex', '\xa9'), ('ex', '\x6e'),
+ ('ex', '\xbd'), ('ex', '\x28')],
+ '}': [('cal', '}'), ('ex', '\xaa'), ('ex', '\x6f'),
+ ('ex', '\xbe'), ('ex', '\x29')],
+ # The fourth size of '[' is mysteriously missing from the BaKoMa
+ # font, so I've omitted it for both '[' and ']'
+ '[': [('rm', '['), ('ex', '\xa3'), ('ex', '\x68'),
+ ('ex', '\x22')],
+ ']': [('rm', ']'), ('ex', '\xa4'), ('ex', '\x69'),
+ ('ex', '\x23')],
+ r'\lfloor': [('ex', '\xa5'), ('ex', '\x6a'),
+ ('ex', '\xb9'), ('ex', '\x24')],
+ r'\rfloor': [('ex', '\xa6'), ('ex', '\x6b'),
+ ('ex', '\xba'), ('ex', '\x25')],
+ r'\lceil': [('ex', '\xa7'), ('ex', '\x6c'),
+ ('ex', '\xbb'), ('ex', '\x26')],
+ r'\rceil': [('ex', '\xa8'), ('ex', '\x6d'),
+ ('ex', '\xbc'), ('ex', '\x27')],
+ r'\langle': [('ex', '\xad'), ('ex', '\x44'),
+ ('ex', '\xbf'), ('ex', '\x2a')],
+ r'\rangle': [('ex', '\xae'), ('ex', '\x45'),
+ ('ex', '\xc0'), ('ex', '\x2b')],
+ r'\__sqrt__': [('ex', '\x70'), ('ex', '\x71'),
+ ('ex', '\x72'), ('ex', '\x73')],
+ r'\backslash': [('ex', '\xb2'), ('ex', '\x2f'),
+ ('ex', '\xc2'), ('ex', '\x2d')],
+ r'/': [('rm', '/'), ('ex', '\xb1'), ('ex', '\x2e'),
+ ('ex', '\xcb'), ('ex', '\x2c')],
+ r'\widehat': [('rm', '\x5e'), ('ex', '\x62'), ('ex', '\x63'),
+ ('ex', '\x64')],
+ r'\widetilde': [('rm', '\x7e'), ('ex', '\x65'), ('ex', '\x66'),
+ ('ex', '\x67')],
+ r'<': [('cal', 'h'), ('ex', 'D')],
+ r'>': [('cal', 'i'), ('ex', 'E')]
+ }
+
+ for alias, target in [(r'\leftparen', '('),
+ (r'\rightparen', ')'),
+ (r'\leftbrace', '{'),
+ (r'\rightbrace', '}'),
+ (r'\leftbracket', '['),
+ (r'\rightbracket', ']'),
+ (r'\{', '{'),
+ (r'\}', '}'),
+ (r'\[', '['),
+ (r'\]', ']')]:
+ _size_alternatives[alias] = _size_alternatives[target]
+
+ def get_sized_alternatives_for_symbol(self, fontname: str,
+ sym: str) -> list[tuple[str, str]]:
+ return self._size_alternatives.get(sym, [(fontname, sym)])
+
+
+class UnicodeFonts(TruetypeFonts):
+ """
+ An abstract base class for handling Unicode fonts.
+
+ While some reasonably complete Unicode fonts (such as DejaVu) may
+ work in some situations, the only Unicode font I'm aware of with a
+ complete set of math symbols is STIX.
+
+ This class will "fallback" on the Bakoma fonts when a required
+ symbol cannot be found in the font.
+ """
+
+ # Some glyphs are not present in the `cmr10` font, and must be brought in
+ # from `cmsy10`. Map the Unicode indices of those glyphs to the indices at
+ # which they are found in `cmsy10`.
+ _cmr10_substitutions = {
+ 0x00D7: 0x00A3, # Multiplication sign.
+ 0x2212: 0x00A1, # Minus sign.
+ }
+
+ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
+ # This must come first so the backend's owner is set correctly
+ fallback_rc = mpl.rcParams['mathtext.fallback']
+ font_cls: type[TruetypeFonts] | None = {
+ 'stix': StixFonts,
+ 'stixsans': StixSansFonts,
+ 'cm': BakomaFonts
+ }.get(fallback_rc)
+ self._fallback_font = (font_cls(default_font_prop, load_glyph_flags)
+ if font_cls else None)
+
+ super().__init__(default_font_prop, load_glyph_flags)
+ for texfont in "cal rm tt it bf sf bfit".split():
+ prop = mpl.rcParams['mathtext.' + texfont]
+ font = findfont(prop)
+ self.fontmap[texfont] = font
+ prop = FontProperties('cmex10')
+ font = findfont(prop)
+ self.fontmap['ex'] = font
+
+ # include STIX sized alternatives for glyphs if fallback is STIX
+ if isinstance(self._fallback_font, StixFonts):
+ stixsizedaltfonts = {
+ 0: 'STIXGeneral',
+ 1: 'STIXSizeOneSym',
+ 2: 'STIXSizeTwoSym',
+ 3: 'STIXSizeThreeSym',
+ 4: 'STIXSizeFourSym',
+ 5: 'STIXSizeFiveSym'}
+
+ for size, name in stixsizedaltfonts.items():
+ fullpath = findfont(name)
+ self.fontmap[size] = fullpath
+ self.fontmap[name] = fullpath
+
+ _slanted_symbols = set(r"\int \oint".split())
+
+ def _map_virtual_font(self, fontname: str, font_class: str,
+ uniindex: int) -> tuple[str, int]:
+ return fontname, uniindex
+
+ def _get_glyph(self, fontname: str, font_class: str,
+ sym: str) -> tuple[FT2Font, int, bool]:
+ try:
+ uniindex = get_unicode_index(sym)
+ found_symbol = True
+ except ValueError:
+ uniindex = ord('?')
+ found_symbol = False
+ _log.warning("No TeX to Unicode mapping for %a.", sym)
+
+ fontname, uniindex = self._map_virtual_font(
+ fontname, font_class, uniindex)
+
+ new_fontname = fontname
+
+ # Only characters in the "Letter" class should be italicized in 'it'
+ # mode. Greek capital letters should be Roman.
+ if found_symbol:
+ if fontname == 'it' and uniindex < 0x10000:
+ char = chr(uniindex)
+ if (unicodedata.category(char)[0] != "L"
+ or unicodedata.name(char).startswith("GREEK CAPITAL")):
+ new_fontname = 'rm'
+
+ slanted = (new_fontname == 'it') or sym in self._slanted_symbols
+ found_symbol = False
+ font = self._get_font(new_fontname)
+ if font is not None:
+ if (uniindex in self._cmr10_substitutions
+ and font.family_name == "cmr10"):
+ font = get_font(
+ cbook._get_data_path("fonts/ttf/cmsy10.ttf"))
+ uniindex = self._cmr10_substitutions[uniindex]
+ glyphindex = font.get_char_index(uniindex)
+ if glyphindex != 0:
+ found_symbol = True
+
+ if not found_symbol:
+ if self._fallback_font:
+ if (fontname in ('it', 'regular')
+ and isinstance(self._fallback_font, StixFonts)):
+ fontname = 'rm'
+
+ g = self._fallback_font._get_glyph(fontname, font_class, sym)
+ family = g[0].family_name
+ if family in list(BakomaFonts._fontmap.values()):
+ family = "Computer Modern"
+ _log.info("Substituting symbol %s from %s", sym, family)
+ return g
+
+ else:
+ if (fontname in ('it', 'regular')
+ and isinstance(self, StixFonts)):
+ return self._get_glyph('rm', font_class, sym)
+ _log.warning("Font %r does not have a glyph for %a [U+%x], "
+ "substituting with a dummy symbol.",
+ new_fontname, sym, uniindex)
+ font = self._get_font('rm')
+ uniindex = 0xA4 # currency char, for lack of anything better
+ slanted = False
+
+ return font, uniindex, slanted
+
+ def get_sized_alternatives_for_symbol(self, fontname: str,
+ sym: str) -> list[tuple[str, str]]:
+ if self._fallback_font:
+ return self._fallback_font.get_sized_alternatives_for_symbol(
+ fontname, sym)
+ return [(fontname, sym)]
+
+
+class DejaVuFonts(UnicodeFonts, metaclass=abc.ABCMeta):
+ _fontmap: dict[str | int, str] = {}
+
+ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
+ # This must come first so the backend's owner is set correctly
+ if isinstance(self, DejaVuSerifFonts):
+ self._fallback_font = StixFonts(default_font_prop, load_glyph_flags)
+ else:
+ self._fallback_font = StixSansFonts(default_font_prop, load_glyph_flags)
+ self.bakoma = BakomaFonts(default_font_prop, load_glyph_flags)
+ TruetypeFonts.__init__(self, default_font_prop, load_glyph_flags)
+ # Include Stix sized alternatives for glyphs
+ self._fontmap.update({
+ 1: 'STIXSizeOneSym',
+ 2: 'STIXSizeTwoSym',
+ 3: 'STIXSizeThreeSym',
+ 4: 'STIXSizeFourSym',
+ 5: 'STIXSizeFiveSym',
+ })
+ for key, name in self._fontmap.items():
+ fullpath = findfont(name)
+ self.fontmap[key] = fullpath
+ self.fontmap[name] = fullpath
+
+ def _get_glyph(self, fontname: str, font_class: str,
+ sym: str) -> tuple[FT2Font, int, bool]:
+ # Override prime symbol to use Bakoma.
+ if sym == r'\prime':
+ return self.bakoma._get_glyph(fontname, font_class, sym)
+ else:
+ # check whether the glyph is available in the display font
+ uniindex = get_unicode_index(sym)
+ font = self._get_font('ex')
+ if font is not None:
+ glyphindex = font.get_char_index(uniindex)
+ if glyphindex != 0:
+ return super()._get_glyph('ex', font_class, sym)
+ # otherwise return regular glyph
+ return super()._get_glyph(fontname, font_class, sym)
+
+
+class DejaVuSerifFonts(DejaVuFonts):
+ """
+ A font handling class for the DejaVu Serif fonts
+
+ If a glyph is not found it will fallback to Stix Serif
+ """
+ _fontmap = {
+ 'rm': 'DejaVu Serif',
+ 'it': 'DejaVu Serif:italic',
+ 'bf': 'DejaVu Serif:weight=bold',
+ 'bfit': 'DejaVu Serif:italic:bold',
+ 'sf': 'DejaVu Sans',
+ 'tt': 'DejaVu Sans Mono',
+ 'ex': 'DejaVu Serif Display',
+ 0: 'DejaVu Serif',
+ }
+
+
+class DejaVuSansFonts(DejaVuFonts):
+ """
+ A font handling class for the DejaVu Sans fonts
+
+ If a glyph is not found it will fallback to Stix Sans
+ """
+ _fontmap = {
+ 'rm': 'DejaVu Sans',
+ 'it': 'DejaVu Sans:italic',
+ 'bf': 'DejaVu Sans:weight=bold',
+ 'bfit': 'DejaVu Sans:italic:bold',
+ 'sf': 'DejaVu Sans',
+ 'tt': 'DejaVu Sans Mono',
+ 'ex': 'DejaVu Sans Display',
+ 0: 'DejaVu Sans',
+ }
+
+
+class StixFonts(UnicodeFonts):
+ """
+ A font handling class for the STIX fonts.
+
+ In addition to what UnicodeFonts provides, this class:
+
+ - supports "virtual fonts" which are complete alpha numeric
+ character sets with different font styles at special Unicode
+ code points, such as "Blackboard".
+
+ - handles sized alternative characters for the STIXSizeX fonts.
+ """
+ _fontmap: dict[str | int, str] = {
+ 'rm': 'STIXGeneral',
+ 'it': 'STIXGeneral:italic',
+ 'bf': 'STIXGeneral:weight=bold',
+ 'bfit': 'STIXGeneral:italic:bold',
+ 'nonunirm': 'STIXNonUnicode',
+ 'nonuniit': 'STIXNonUnicode:italic',
+ 'nonunibf': 'STIXNonUnicode:weight=bold',
+ 0: 'STIXGeneral',
+ 1: 'STIXSizeOneSym',
+ 2: 'STIXSizeTwoSym',
+ 3: 'STIXSizeThreeSym',
+ 4: 'STIXSizeFourSym',
+ 5: 'STIXSizeFiveSym',
+ }
+ _fallback_font = None
+ _sans = False
+
+ def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags):
+ TruetypeFonts.__init__(self, default_font_prop, load_glyph_flags)
+ for key, name in self._fontmap.items():
+ fullpath = findfont(name)
+ self.fontmap[key] = fullpath
+ self.fontmap[name] = fullpath
+
+ def _map_virtual_font(self, fontname: str, font_class: str,
+ uniindex: int) -> tuple[str, int]:
+ # Handle these "fonts" that are actually embedded in
+ # other fonts.
+ font_mapping = stix_virtual_fonts.get(fontname)
+ if (self._sans and font_mapping is None
+ and fontname not in ('regular', 'default')):
+ font_mapping = stix_virtual_fonts['sf']
+ doing_sans_conversion = True
+ else:
+ doing_sans_conversion = False
+
+ if isinstance(font_mapping, dict):
+ try:
+ mapping = font_mapping[font_class]
+ except KeyError:
+ mapping = font_mapping['rm']
+ elif isinstance(font_mapping, list):
+ mapping = font_mapping
+ else:
+ mapping = None
+
+ if mapping is not None:
+ # Binary search for the source glyph
+ lo = 0
+ hi = len(mapping)
+ while lo < hi:
+ mid = (lo+hi)//2
+ range = mapping[mid]
+ if uniindex < range[0]:
+ hi = mid
+ elif uniindex <= range[1]:
+ break
+ else:
+ lo = mid + 1
+
+ if range[0] <= uniindex <= range[1]:
+ uniindex = uniindex - range[0] + range[3]
+ fontname = range[2]
+ elif not doing_sans_conversion:
+ # This will generate a dummy character
+ uniindex = 0x1
+ fontname = mpl.rcParams['mathtext.default']
+
+ # Fix some incorrect glyphs.
+ if fontname in ('rm', 'it'):
+ uniindex = stix_glyph_fixes.get(uniindex, uniindex)
+
+ # Handle private use area glyphs
+ if fontname in ('it', 'rm', 'bf', 'bfit') and 0xe000 <= uniindex <= 0xf8ff:
+ fontname = 'nonuni' + fontname
+
+ return fontname, uniindex
+
+ @functools.cache
+ def get_sized_alternatives_for_symbol( # type: ignore[override]
+ self,
+ fontname: str,
+ sym: str) -> list[tuple[str, str]] | list[tuple[int, str]]:
+ fixes = {
+ '\\{': '{', '\\}': '}', '\\[': '[', '\\]': ']',
+ '<': '\N{MATHEMATICAL LEFT ANGLE BRACKET}',
+ '>': '\N{MATHEMATICAL RIGHT ANGLE BRACKET}',
+ }
+ sym = fixes.get(sym, sym)
+ try:
+ uniindex = get_unicode_index(sym)
+ except ValueError:
+ return [(fontname, sym)]
+ alternatives = [(i, chr(uniindex)) for i in range(6)
+ if self._get_font(i).get_char_index(uniindex) != 0]
+ # The largest size of the radical symbol in STIX has incorrect
+ # metrics that cause it to be disconnected from the stem.
+ if sym == r'\__sqrt__':
+ alternatives = alternatives[:-1]
+ return alternatives
+
+
+class StixSansFonts(StixFonts):
+ """
+ A font handling class for the STIX fonts (that uses sans-serif
+ characters by default).
+ """
+ _sans = True
+
+
+##############################################################################
+# TeX-LIKE BOX MODEL
+
+# The following is based directly on the document 'woven' from the
+# TeX82 source code. This information is also available in printed
+# form:
+#
+# Knuth, Donald E.. 1986. Computers and Typesetting, Volume B:
+# TeX: The Program. Addison-Wesley Professional.
+#
+# The most relevant "chapters" are:
+# Data structures for boxes and their friends
+# Shipping pages out (ship())
+# Packaging (hpack() and vpack())
+# Data structures for math mode
+# Subroutines for math mode
+# Typesetting math formulas
+#
+# Many of the docstrings below refer to a numbered "node" in that
+# book, e.g., node123
+#
+# Note that (as TeX) y increases downward, unlike many other parts of
+# matplotlib.
+
+# How much text shrinks when going to the next-smallest level.
+SHRINK_FACTOR = 0.7
+# The number of different sizes of chars to use, beyond which they will not
+# get any smaller
+NUM_SIZE_LEVELS = 6
+
+
+class FontConstantsBase:
+ """
+ A set of constants that controls how certain things, such as sub-
+ and superscripts are laid out. These are all metrics that can't
+ be reliably retrieved from the font metrics in the font itself.
+ """
+ # Percentage of x-height of additional horiz. space after sub/superscripts
+ script_space: T.ClassVar[float] = 0.05
+
+ # Percentage of x-height that sub/superscripts drop below the baseline
+ subdrop: T.ClassVar[float] = 0.4
+
+ # Percentage of x-height that superscripts are raised from the baseline
+ sup1: T.ClassVar[float] = 0.7
+
+ # Percentage of x-height that subscripts drop below the baseline
+ sub1: T.ClassVar[float] = 0.3
+
+ # Percentage of x-height that subscripts drop below the baseline when a
+ # superscript is present
+ sub2: T.ClassVar[float] = 0.5
+
+ # Percentage of x-height that sub/superscripts are offset relative to the
+ # nucleus edge for non-slanted nuclei
+ delta: T.ClassVar[float] = 0.025
+
+ # Additional percentage of last character height above 2/3 of the
+ # x-height that superscripts are offset relative to the subscript
+ # for slanted nuclei
+ delta_slanted: T.ClassVar[float] = 0.2
+
+ # Percentage of x-height that superscripts and subscripts are offset for
+ # integrals
+ delta_integral: T.ClassVar[float] = 0.1
+
+
+class ComputerModernFontConstants(FontConstantsBase):
+ script_space = 0.075
+ subdrop = 0.2
+ sup1 = 0.45
+ sub1 = 0.2
+ sub2 = 0.3
+ delta = 0.075
+ delta_slanted = 0.3
+ delta_integral = 0.3
+
+
+class STIXFontConstants(FontConstantsBase):
+ script_space = 0.1
+ sup1 = 0.8
+ sub2 = 0.6
+ delta = 0.05
+ delta_slanted = 0.3
+ delta_integral = 0.3
+
+
+class STIXSansFontConstants(FontConstantsBase):
+ script_space = 0.05
+ sup1 = 0.8
+ delta_slanted = 0.6
+ delta_integral = 0.3
+
+
+class DejaVuSerifFontConstants(FontConstantsBase):
+ pass
+
+
+class DejaVuSansFontConstants(FontConstantsBase):
+ pass
+
+
+# Maps font family names to the FontConstantBase subclass to use
+_font_constant_mapping = {
+ 'DejaVu Sans': DejaVuSansFontConstants,
+ 'DejaVu Sans Mono': DejaVuSansFontConstants,
+ 'DejaVu Serif': DejaVuSerifFontConstants,
+ 'cmb10': ComputerModernFontConstants,
+ 'cmex10': ComputerModernFontConstants,
+ 'cmmi10': ComputerModernFontConstants,
+ 'cmr10': ComputerModernFontConstants,
+ 'cmss10': ComputerModernFontConstants,
+ 'cmsy10': ComputerModernFontConstants,
+ 'cmtt10': ComputerModernFontConstants,
+ 'STIXGeneral': STIXFontConstants,
+ 'STIXNonUnicode': STIXFontConstants,
+ 'STIXSizeFiveSym': STIXFontConstants,
+ 'STIXSizeFourSym': STIXFontConstants,
+ 'STIXSizeThreeSym': STIXFontConstants,
+ 'STIXSizeTwoSym': STIXFontConstants,
+ 'STIXSizeOneSym': STIXFontConstants,
+ # Map the fonts we used to ship, just for good measure
+ 'Bitstream Vera Sans': DejaVuSansFontConstants,
+ 'Bitstream Vera': DejaVuSansFontConstants,
+ }
+
+
+def _get_font_constant_set(state: ParserState) -> type[FontConstantsBase]:
+ constants = _font_constant_mapping.get(
+ state.fontset._get_font(state.font).family_name, FontConstantsBase)
+ # STIX sans isn't really its own fonts, just different code points
+ # in the STIX fonts, so we have to detect this one separately.
+ if (constants is STIXFontConstants and
+ isinstance(state.fontset, StixSansFonts)):
+ return STIXSansFontConstants
+ return constants
+
+
+class Node:
+ """A node in the TeX box model."""
+
+ def __init__(self) -> None:
+ self.size = 0
+
+ def __repr__(self) -> str:
+ return type(self).__name__
+
+ def get_kerning(self, next: Node | None) -> float:
+ return 0.0
+
+ def shrink(self) -> None:
+ """
+ Shrinks one level smaller. There are only three levels of
+ sizes, after which things will no longer get smaller.
+ """
+ self.size += 1
+
+ def render(self, output: Output, x: float, y: float) -> None:
+ """Render this node."""
+
+
+class Box(Node):
+ """A node with a physical location."""
+
+ def __init__(self, width: float, height: float, depth: float) -> None:
+ super().__init__()
+ self.width = width
+ self.height = height
+ self.depth = depth
+
+ def shrink(self) -> None:
+ super().shrink()
+ if self.size < NUM_SIZE_LEVELS:
+ self.width *= SHRINK_FACTOR
+ self.height *= SHRINK_FACTOR
+ self.depth *= SHRINK_FACTOR
+
+ def render(self, output: Output, # type: ignore[override]
+ x1: float, y1: float, x2: float, y2: float) -> None:
+ pass
+
+
+class Vbox(Box):
+ """A box with only height (zero width)."""
+
+ def __init__(self, height: float, depth: float):
+ super().__init__(0., height, depth)
+
+
+class Hbox(Box):
+ """A box with only width (zero height and depth)."""
+
+ def __init__(self, width: float):
+ super().__init__(width, 0., 0.)
+
+
+class Char(Node):
+ """
+ A single character.
+
+ Unlike TeX, the font information and metrics are stored with each `Char`
+ to make it easier to lookup the font metrics when needed. Note that TeX
+ boxes have a width, height, and depth, unlike Type1 and TrueType which use
+ a full bounding box and an advance in the x-direction. The metrics must
+ be converted to the TeX model, and the advance (if different from width)
+ must be converted into a `Kern` node when the `Char` is added to its parent
+ `Hlist`.
+ """
+
+ def __init__(self, c: str, state: ParserState):
+ super().__init__()
+ self.c = c
+ self.fontset = state.fontset
+ self.font = state.font
+ self.font_class = state.font_class
+ self.fontsize = state.fontsize
+ self.dpi = state.dpi
+ # The real width, height and depth will be set during the
+ # pack phase, after we know the real fontsize
+ self._update_metrics()
+
+ def __repr__(self) -> str:
+ return '`%s`' % self.c
+
+ def _update_metrics(self) -> None:
+ metrics = self._metrics = self.fontset.get_metrics(
+ self.font, self.font_class, self.c, self.fontsize, self.dpi)
+ if self.c == ' ':
+ self.width = metrics.advance
+ else:
+ self.width = metrics.width
+ self.height = metrics.iceberg
+ self.depth = -(metrics.iceberg - metrics.height)
+
+ def is_slanted(self) -> bool:
+ return self._metrics.slanted
+
+ def get_kerning(self, next: Node | None) -> float:
+ """
+ Return the amount of kerning between this and the given character.
+
+ This method is called when characters are strung together into `Hlist`
+ to create `Kern` nodes.
+ """
+ advance = self._metrics.advance - self.width
+ kern = 0.
+ if isinstance(next, Char):
+ kern = self.fontset.get_kern(
+ self.font, self.font_class, self.c, self.fontsize,
+ next.font, next.font_class, next.c, next.fontsize,
+ self.dpi)
+ return advance + kern
+
+ def render(self, output: Output, x: float, y: float) -> None:
+ self.fontset.render_glyph(
+ output, x, y,
+ self.font, self.font_class, self.c, self.fontsize, self.dpi)
+
+ def shrink(self) -> None:
+ super().shrink()
+ if self.size < NUM_SIZE_LEVELS:
+ self.fontsize *= SHRINK_FACTOR
+ self.width *= SHRINK_FACTOR
+ self.height *= SHRINK_FACTOR
+ self.depth *= SHRINK_FACTOR
+
+
+class Accent(Char):
+ """
+ The font metrics need to be dealt with differently for accents,
+ since they are already offset correctly from the baseline in
+ TrueType fonts.
+ """
+ def _update_metrics(self) -> None:
+ metrics = self._metrics = self.fontset.get_metrics(
+ self.font, self.font_class, self.c, self.fontsize, self.dpi)
+ self.width = metrics.xmax - metrics.xmin
+ self.height = metrics.ymax - metrics.ymin
+ self.depth = 0
+
+ def shrink(self) -> None:
+ super().shrink()
+ self._update_metrics()
+
+ def render(self, output: Output, x: float, y: float) -> None:
+ self.fontset.render_glyph(
+ output, x - self._metrics.xmin, y + self._metrics.ymin,
+ self.font, self.font_class, self.c, self.fontsize, self.dpi)
+
+
+class List(Box):
+ """A list of nodes (either horizontal or vertical)."""
+
+ def __init__(self, elements: T.Sequence[Node]):
+ super().__init__(0., 0., 0.)
+ self.shift_amount = 0. # An arbitrary offset
+ self.children = [*elements] # The child nodes of this list
+ # The following parameters are set in the vpack and hpack functions
+ self.glue_set = 0. # The glue setting of this list
+ self.glue_sign = 0 # 0: normal, -1: shrinking, 1: stretching
+ self.glue_order = 0 # The order of infinity (0 - 3) for the glue
+
+ def __repr__(self) -> str:
+ return '{}[{}]'.format(
+ super().__repr__(),
+ self.width, self.height,
+ self.depth, self.shift_amount,
+ ', '.join([repr(x) for x in self.children]))
+
+ def _set_glue(self, x: float, sign: int, totals: list[float],
+ error_type: str) -> None:
+ self.glue_order = o = next(
+ # Highest order of glue used by the members of this list.
+ (i for i in range(len(totals))[::-1] if totals[i] != 0), 0)
+ self.glue_sign = sign
+ if totals[o] != 0.:
+ self.glue_set = x / totals[o]
+ else:
+ self.glue_sign = 0
+ self.glue_ratio = 0.
+ if o == 0:
+ if len(self.children):
+ _log.warning("%s %s: %r",
+ error_type, type(self).__name__, self)
+
+ def shrink(self) -> None:
+ for child in self.children:
+ child.shrink()
+ super().shrink()
+ if self.size < NUM_SIZE_LEVELS:
+ self.shift_amount *= SHRINK_FACTOR
+ self.glue_set *= SHRINK_FACTOR
+
+
+class Hlist(List):
+ """A horizontal list of boxes."""
+
+ def __init__(self, elements: T.Sequence[Node], w: float = 0.0,
+ m: T.Literal['additional', 'exactly'] = 'additional',
+ do_kern: bool = True):
+ super().__init__(elements)
+ if do_kern:
+ self.kern()
+ self.hpack(w=w, m=m)
+
+ def kern(self) -> None:
+ """
+ Insert `Kern` nodes between `Char` nodes to set kerning.
+
+ The `Char` nodes themselves determine the amount of kerning they need
+ (in `~Char.get_kerning`), and this function just creates the correct
+ linked list.
+ """
+ new_children = []
+ num_children = len(self.children)
+ if num_children:
+ for i in range(num_children):
+ elem = self.children[i]
+ if i < num_children - 1:
+ next = self.children[i + 1]
+ else:
+ next = None
+
+ new_children.append(elem)
+ kerning_distance = elem.get_kerning(next)
+ if kerning_distance != 0.:
+ kern = Kern(kerning_distance)
+ new_children.append(kern)
+ self.children = new_children
+
+ def hpack(self, w: float = 0.0,
+ m: T.Literal['additional', 'exactly'] = 'additional') -> None:
+ r"""
+ Compute the dimensions of the resulting boxes, and adjust the glue if
+ one of those dimensions is pre-specified. The computed sizes normally
+ enclose all of the material inside the new box; but some items may
+ stick out if negative glue is used, if the box is overfull, or if a
+ ``\vbox`` includes other boxes that have been shifted left.
+
+ Parameters
+ ----------
+ w : float, default: 0
+ A width.
+ m : {'exactly', 'additional'}, default: 'additional'
+ Whether to produce a box whose width is 'exactly' *w*; or a box
+ with the natural width of the contents, plus *w* ('additional').
+
+ Notes
+ -----
+ The defaults produce a box with the natural width of the contents.
+ """
+ # I don't know why these get reset in TeX. Shift_amount is pretty
+ # much useless if we do.
+ # self.shift_amount = 0.
+ h = 0.
+ d = 0.
+ x = 0.
+ total_stretch = [0.] * 4
+ total_shrink = [0.] * 4
+ for p in self.children:
+ if isinstance(p, Char):
+ x += p.width
+ h = max(h, p.height)
+ d = max(d, p.depth)
+ elif isinstance(p, Box):
+ x += p.width
+ if not np.isinf(p.height) and not np.isinf(p.depth):
+ s = getattr(p, 'shift_amount', 0.)
+ h = max(h, p.height - s)
+ d = max(d, p.depth + s)
+ elif isinstance(p, Glue):
+ glue_spec = p.glue_spec
+ x += glue_spec.width
+ total_stretch[glue_spec.stretch_order] += glue_spec.stretch
+ total_shrink[glue_spec.shrink_order] += glue_spec.shrink
+ elif isinstance(p, Kern):
+ x += p.width
+ self.height = h
+ self.depth = d
+
+ if m == 'additional':
+ w += x
+ self.width = w
+ x = w - x
+
+ if x == 0.:
+ self.glue_sign = 0
+ self.glue_order = 0
+ self.glue_ratio = 0.
+ return
+ if x > 0.:
+ self._set_glue(x, 1, total_stretch, "Overful")
+ else:
+ self._set_glue(x, -1, total_shrink, "Underful")
+
+
+class Vlist(List):
+ """A vertical list of boxes."""
+
+ def __init__(self, elements: T.Sequence[Node], h: float = 0.0,
+ m: T.Literal['additional', 'exactly'] = 'additional'):
+ super().__init__(elements)
+ self.vpack(h=h, m=m)
+
+ def vpack(self, h: float = 0.0,
+ m: T.Literal['additional', 'exactly'] = 'additional',
+ l: float = np.inf) -> None:
+ """
+ Compute the dimensions of the resulting boxes, and to adjust the glue
+ if one of those dimensions is pre-specified.
+
+ Parameters
+ ----------
+ h : float, default: 0
+ A height.
+ m : {'exactly', 'additional'}, default: 'additional'
+ Whether to produce a box whose height is 'exactly' *h*; or a box
+ with the natural height of the contents, plus *h* ('additional').
+ l : float, default: np.inf
+ The maximum height.
+
+ Notes
+ -----
+ The defaults produce a box with the natural height of the contents.
+ """
+ # I don't know why these get reset in TeX. Shift_amount is pretty
+ # much useless if we do.
+ # self.shift_amount = 0.
+ w = 0.
+ d = 0.
+ x = 0.
+ total_stretch = [0.] * 4
+ total_shrink = [0.] * 4
+ for p in self.children:
+ if isinstance(p, Box):
+ x += d + p.height
+ d = p.depth
+ if not np.isinf(p.width):
+ s = getattr(p, 'shift_amount', 0.)
+ w = max(w, p.width + s)
+ elif isinstance(p, Glue):
+ x += d
+ d = 0.
+ glue_spec = p.glue_spec
+ x += glue_spec.width
+ total_stretch[glue_spec.stretch_order] += glue_spec.stretch
+ total_shrink[glue_spec.shrink_order] += glue_spec.shrink
+ elif isinstance(p, Kern):
+ x += d + p.width
+ d = 0.
+ elif isinstance(p, Char):
+ raise RuntimeError(
+ "Internal mathtext error: Char node found in Vlist")
+
+ self.width = w
+ if d > l:
+ x += d - l
+ self.depth = l
+ else:
+ self.depth = d
+
+ if m == 'additional':
+ h += x
+ self.height = h
+ x = h - x
+
+ if x == 0:
+ self.glue_sign = 0
+ self.glue_order = 0
+ self.glue_ratio = 0.
+ return
+
+ if x > 0.:
+ self._set_glue(x, 1, total_stretch, "Overful")
+ else:
+ self._set_glue(x, -1, total_shrink, "Underful")
+
+
+class Rule(Box):
+ """
+ A solid black rectangle.
+
+ It has *width*, *depth*, and *height* fields just as in an `Hlist`.
+ However, if any of these dimensions is inf, the actual value will be
+ determined by running the rule up to the boundary of the innermost
+ enclosing box. This is called a "running dimension". The width is never
+ running in an `Hlist`; the height and depth are never running in a `Vlist`.
+ """
+
+ def __init__(self, width: float, height: float, depth: float, state: ParserState):
+ super().__init__(width, height, depth)
+ self.fontset = state.fontset
+
+ def render(self, output: Output, # type: ignore[override]
+ x: float, y: float, w: float, h: float) -> None:
+ self.fontset.render_rect_filled(output, x, y, x + w, y + h)
+
+
+class Hrule(Rule):
+ """Convenience class to create a horizontal rule."""
+
+ def __init__(self, state: ParserState, thickness: float | None = None):
+ if thickness is None:
+ thickness = state.get_current_underline_thickness()
+ height = depth = thickness * 0.5
+ super().__init__(np.inf, height, depth, state)
+
+
+class Vrule(Rule):
+ """Convenience class to create a vertical rule."""
+
+ def __init__(self, state: ParserState):
+ thickness = state.get_current_underline_thickness()
+ super().__init__(thickness, np.inf, np.inf, state)
+
+
+class _GlueSpec(NamedTuple):
+ width: float
+ stretch: float
+ stretch_order: int
+ shrink: float
+ shrink_order: int
+
+
+_GlueSpec._named = { # type: ignore[attr-defined]
+ 'fil': _GlueSpec(0., 1., 1, 0., 0),
+ 'fill': _GlueSpec(0., 1., 2, 0., 0),
+ 'filll': _GlueSpec(0., 1., 3, 0., 0),
+ 'neg_fil': _GlueSpec(0., 0., 0, 1., 1),
+ 'neg_fill': _GlueSpec(0., 0., 0, 1., 2),
+ 'neg_filll': _GlueSpec(0., 0., 0, 1., 3),
+ 'empty': _GlueSpec(0., 0., 0, 0., 0),
+ 'ss': _GlueSpec(0., 1., 1, -1., 1),
+}
+
+
+class Glue(Node):
+ """
+ Most of the information in this object is stored in the underlying
+ ``_GlueSpec`` class, which is shared between multiple glue objects.
+ (This is a memory optimization which probably doesn't matter anymore, but
+ it's easier to stick to what TeX does.)
+ """
+
+ def __init__(self,
+ glue_type: _GlueSpec | T.Literal["fil", "fill", "filll",
+ "neg_fil", "neg_fill", "neg_filll",
+ "empty", "ss"]):
+ super().__init__()
+ if isinstance(glue_type, str):
+ glue_spec = _GlueSpec._named[glue_type] # type: ignore[attr-defined]
+ elif isinstance(glue_type, _GlueSpec):
+ glue_spec = glue_type
+ else:
+ raise ValueError("glue_type must be a glue spec name or instance")
+ self.glue_spec = glue_spec
+
+ def shrink(self) -> None:
+ super().shrink()
+ if self.size < NUM_SIZE_LEVELS:
+ g = self.glue_spec
+ self.glue_spec = g._replace(width=g.width * SHRINK_FACTOR)
+
+
+class HCentered(Hlist):
+ """
+ A convenience class to create an `Hlist` whose contents are
+ centered within its enclosing box.
+ """
+
+ def __init__(self, elements: list[Node]):
+ super().__init__([Glue('ss'), *elements, Glue('ss')], do_kern=False)
+
+
+class VCentered(Vlist):
+ """
+ A convenience class to create a `Vlist` whose contents are
+ centered within its enclosing box.
+ """
+
+ def __init__(self, elements: list[Node]):
+ super().__init__([Glue('ss'), *elements, Glue('ss')])
+
+
+class Kern(Node):
+ """
+ A `Kern` node has a width field to specify a (normally
+ negative) amount of spacing. This spacing correction appears in
+ horizontal lists between letters like A and V when the font
+ designer said that it looks better to move them closer together or
+ further apart. A kern node can also appear in a vertical list,
+ when its *width* denotes additional spacing in the vertical
+ direction.
+ """
+
+ height = 0
+ depth = 0
+
+ def __init__(self, width: float):
+ super().__init__()
+ self.width = width
+
+ def __repr__(self) -> str:
+ return "k%.02f" % self.width
+
+ def shrink(self) -> None:
+ super().shrink()
+ if self.size < NUM_SIZE_LEVELS:
+ self.width *= SHRINK_FACTOR
+
+
+class AutoHeightChar(Hlist):
+ """
+ A character as close to the given height and depth as possible.
+
+ When using a font with multiple height versions of some characters (such as
+ the BaKoMa fonts), the correct glyph will be selected, otherwise this will
+ always just return a scaled version of the glyph.
+ """
+
+ def __init__(self, c: str, height: float, depth: float, state: ParserState,
+ always: bool = False, factor: float | None = None):
+ alternatives = state.fontset.get_sized_alternatives_for_symbol(
+ state.font, c)
+
+ xHeight = state.fontset.get_xheight(
+ state.font, state.fontsize, state.dpi)
+
+ state = state.copy()
+ target_total = height + depth
+ for fontname, sym in alternatives:
+ state.font = fontname
+ char = Char(sym, state)
+ # Ensure that size 0 is chosen when the text is regular sized but
+ # with descender glyphs by subtracting 0.2 * xHeight
+ if char.height + char.depth >= target_total - 0.2 * xHeight:
+ break
+
+ shift = 0.0
+ if state.font != 0 or len(alternatives) == 1:
+ if factor is None:
+ factor = target_total / (char.height + char.depth)
+ state.fontsize *= factor
+ char = Char(sym, state)
+
+ shift = (depth - char.depth)
+
+ super().__init__([char])
+ self.shift_amount = shift
+
+
+class AutoWidthChar(Hlist):
+ """
+ A character as close to the given width as possible.
+
+ When using a font with multiple width versions of some characters (such as
+ the BaKoMa fonts), the correct glyph will be selected, otherwise this will
+ always just return a scaled version of the glyph.
+ """
+
+ def __init__(self, c: str, width: float, state: ParserState, always: bool = False,
+ char_class: type[Char] = Char):
+ alternatives = state.fontset.get_sized_alternatives_for_symbol(
+ state.font, c)
+
+ state = state.copy()
+ for fontname, sym in alternatives:
+ state.font = fontname
+ char = char_class(sym, state)
+ if char.width >= width:
+ break
+
+ factor = width / char.width
+ state.fontsize *= factor
+ char = char_class(sym, state)
+
+ super().__init__([char])
+ self.width = char.width
+
+
+def ship(box: Box, xy: tuple[float, float] = (0, 0)) -> Output:
+ """
+ Ship out *box* at offset *xy*, converting it to an `Output`.
+
+ Since boxes can be inside of boxes inside of boxes, the main work of `ship`
+ is done by two mutually recursive routines, `hlist_out` and `vlist_out`,
+ which traverse the `Hlist` nodes and `Vlist` nodes inside of horizontal
+ and vertical boxes. The global variables used in TeX to store state as it
+ processes have become local variables here.
+ """
+ ox, oy = xy
+ cur_v = 0.
+ cur_h = 0.
+ off_h = ox
+ off_v = oy + box.height
+ output = Output(box)
+
+ def clamp(value: float) -> float:
+ return -1e9 if value < -1e9 else +1e9 if value > +1e9 else value
+
+ def hlist_out(box: Hlist) -> None:
+ nonlocal cur_v, cur_h, off_h, off_v
+
+ cur_g = 0
+ cur_glue = 0.
+ glue_order = box.glue_order
+ glue_sign = box.glue_sign
+ base_line = cur_v
+ left_edge = cur_h
+
+ for p in box.children:
+ if isinstance(p, Char):
+ p.render(output, cur_h + off_h, cur_v + off_v)
+ cur_h += p.width
+ elif isinstance(p, Kern):
+ cur_h += p.width
+ elif isinstance(p, List):
+ # node623
+ if len(p.children) == 0:
+ cur_h += p.width
+ else:
+ edge = cur_h
+ cur_v = base_line + p.shift_amount
+ if isinstance(p, Hlist):
+ hlist_out(p)
+ elif isinstance(p, Vlist):
+ # p.vpack(box.height + box.depth, 'exactly')
+ vlist_out(p)
+ else:
+ assert False, "unreachable code"
+ cur_h = edge + p.width
+ cur_v = base_line
+ elif isinstance(p, Box):
+ # node624
+ rule_height = p.height
+ rule_depth = p.depth
+ rule_width = p.width
+ if np.isinf(rule_height):
+ rule_height = box.height
+ if np.isinf(rule_depth):
+ rule_depth = box.depth
+ if rule_height > 0 and rule_width > 0:
+ cur_v = base_line + rule_depth
+ p.render(output,
+ cur_h + off_h, cur_v + off_v,
+ rule_width, rule_height)
+ cur_v = base_line
+ cur_h += rule_width
+ elif isinstance(p, Glue):
+ # node625
+ glue_spec = p.glue_spec
+ rule_width = glue_spec.width - cur_g
+ if glue_sign != 0: # normal
+ if glue_sign == 1: # stretching
+ if glue_spec.stretch_order == glue_order:
+ cur_glue += glue_spec.stretch
+ cur_g = round(clamp(box.glue_set * cur_glue))
+ elif glue_spec.shrink_order == glue_order:
+ cur_glue += glue_spec.shrink
+ cur_g = round(clamp(box.glue_set * cur_glue))
+ rule_width += cur_g
+ cur_h += rule_width
+
+ def vlist_out(box: Vlist) -> None:
+ nonlocal cur_v, cur_h, off_h, off_v
+
+ cur_g = 0
+ cur_glue = 0.
+ glue_order = box.glue_order
+ glue_sign = box.glue_sign
+ left_edge = cur_h
+ cur_v -= box.height
+ top_edge = cur_v
+
+ for p in box.children:
+ if isinstance(p, Kern):
+ cur_v += p.width
+ elif isinstance(p, List):
+ if len(p.children) == 0:
+ cur_v += p.height + p.depth
+ else:
+ cur_v += p.height
+ cur_h = left_edge + p.shift_amount
+ save_v = cur_v
+ p.width = box.width
+ if isinstance(p, Hlist):
+ hlist_out(p)
+ elif isinstance(p, Vlist):
+ vlist_out(p)
+ else:
+ assert False, "unreachable code"
+ cur_v = save_v + p.depth
+ cur_h = left_edge
+ elif isinstance(p, Box):
+ rule_height = p.height
+ rule_depth = p.depth
+ rule_width = p.width
+ if np.isinf(rule_width):
+ rule_width = box.width
+ rule_height += rule_depth
+ if rule_height > 0 and rule_depth > 0:
+ cur_v += rule_height
+ p.render(output,
+ cur_h + off_h, cur_v + off_v,
+ rule_width, rule_height)
+ elif isinstance(p, Glue):
+ glue_spec = p.glue_spec
+ rule_height = glue_spec.width - cur_g
+ if glue_sign != 0: # normal
+ if glue_sign == 1: # stretching
+ if glue_spec.stretch_order == glue_order:
+ cur_glue += glue_spec.stretch
+ cur_g = round(clamp(box.glue_set * cur_glue))
+ elif glue_spec.shrink_order == glue_order: # shrinking
+ cur_glue += glue_spec.shrink
+ cur_g = round(clamp(box.glue_set * cur_glue))
+ rule_height += cur_g
+ cur_v += rule_height
+ elif isinstance(p, Char):
+ raise RuntimeError(
+ "Internal mathtext error: Char node found in vlist")
+
+ assert isinstance(box, Hlist)
+ hlist_out(box)
+ return output
+
+
+##############################################################################
+# PARSER
+
+
+def Error(msg: str) -> ParserElement:
+ """Helper class to raise parser errors."""
+ def raise_error(s: str, loc: int, toks: ParseResults) -> T.Any:
+ raise ParseFatalException(s, loc, msg)
+
+ return Empty().setParseAction(raise_error)
+
+
+class ParserState:
+ """
+ Parser state.
+
+ States are pushed and popped from a stack as necessary, and the "current"
+ state is always at the top of the stack.
+
+ Upon entering and leaving a group { } or math/non-math, the stack is pushed
+ and popped accordingly.
+ """
+
+ def __init__(self, fontset: Fonts, font: str, font_class: str, fontsize: float,
+ dpi: float):
+ self.fontset = fontset
+ self._font = font
+ self.font_class = font_class
+ self.fontsize = fontsize
+ self.dpi = dpi
+
+ def copy(self) -> ParserState:
+ return copy.copy(self)
+
+ @property
+ def font(self) -> str:
+ return self._font
+
+ @font.setter
+ def font(self, name: str) -> None:
+ if name in ('rm', 'it', 'bf', 'bfit'):
+ self.font_class = name
+ self._font = name
+
+ def get_current_underline_thickness(self) -> float:
+ """Return the underline thickness for this state."""
+ return self.fontset.get_underline_thickness(
+ self.font, self.fontsize, self.dpi)
+
+
+def cmd(expr: str, args: ParserElement) -> ParserElement:
+ r"""
+ Helper to define TeX commands.
+
+ ``cmd("\cmd", args)`` is equivalent to
+ ``"\cmd" - (args | Error("Expected \cmd{arg}{...}"))`` where the names in
+ the error message are taken from element names in *args*. If *expr*
+ already includes arguments (e.g. "\cmd{arg}{...}"), then they are stripped
+ when constructing the parse element, but kept (and *expr* is used as is) in
+ the error message.
+ """
+
+ def names(elt: ParserElement) -> T.Generator[str, None, None]:
+ if isinstance(elt, ParseExpression):
+ for expr in elt.exprs:
+ yield from names(expr)
+ elif elt.resultsName:
+ yield elt.resultsName
+
+ csname = expr.split("{", 1)[0]
+ err = (csname + "".join("{%s}" % name for name in names(args))
+ if expr == csname else expr)
+ return csname - (args | Error(f"Expected {err}"))
+
+
+class Parser:
+ """
+ A pyparsing-based parser for strings containing math expressions.
+
+ Raw text may also appear outside of pairs of ``$``.
+
+ The grammar is based directly on that in TeX, though it cuts a few corners.
+ """
+
+ class _MathStyle(enum.Enum):
+ DISPLAYSTYLE = 0
+ TEXTSTYLE = 1
+ SCRIPTSTYLE = 2
+ SCRIPTSCRIPTSTYLE = 3
+
+ _binary_operators = set(
+ '+ * - \N{MINUS SIGN}'
+ r'''
+ \pm \sqcap \rhd
+ \mp \sqcup \unlhd
+ \times \vee \unrhd
+ \div \wedge \oplus
+ \ast \setminus \ominus
+ \star \wr \otimes
+ \circ \diamond \oslash
+ \bullet \bigtriangleup \odot
+ \cdot \bigtriangledown \bigcirc
+ \cap \triangleleft \dagger
+ \cup \triangleright \ddagger
+ \uplus \lhd \amalg
+ \dotplus \dotminus \Cap
+ \Cup \barwedge \boxdot
+ \boxminus \boxplus \boxtimes
+ \curlyvee \curlywedge \divideontimes
+ \doublebarwedge \leftthreetimes \rightthreetimes
+ \slash \veebar \barvee
+ \cupdot \intercal \amalg
+ \circledcirc \circleddash \circledast
+ \boxbar \obar \merge
+ \minuscolon \dotsminusdots
+ '''.split())
+
+ _relation_symbols = set(r'''
+ = < > :
+ \leq \geq \equiv \models
+ \prec \succ \sim \perp
+ \preceq \succeq \simeq \mid
+ \ll \gg \asymp \parallel
+ \subset \supset \approx \bowtie
+ \subseteq \supseteq \cong \Join
+ \sqsubset \sqsupset \neq \smile
+ \sqsubseteq \sqsupseteq \doteq \frown
+ \in \ni \propto \vdash
+ \dashv \dots \doteqdot \leqq
+ \geqq \lneqq \gneqq \lessgtr
+ \leqslant \geqslant \eqgtr \eqless
+ \eqslantless \eqslantgtr \lesseqgtr \backsim
+ \backsimeq \lesssim \gtrsim \precsim
+ \precnsim \gnsim \lnsim \succsim
+ \succnsim \nsim \lesseqqgtr \gtreqqless
+ \gtreqless \subseteqq \supseteqq \subsetneqq
+ \supsetneqq \lessapprox \approxeq \gtrapprox
+ \precapprox \succapprox \precnapprox \succnapprox
+ \npreccurlyeq \nsucccurlyeq \nsqsubseteq \nsqsupseteq
+ \sqsubsetneq \sqsupsetneq \nlesssim \ngtrsim
+ \nlessgtr \ngtrless \lnapprox \gnapprox
+ \napprox \approxeq \approxident \lll
+ \ggg \nparallel \Vdash \Vvdash
+ \nVdash \nvdash \vDash \nvDash
+ \nVDash \oequal \simneqq \triangle
+ \triangleq \triangleeq \triangleleft
+ \triangleright \ntriangleleft \ntriangleright
+ \trianglelefteq \ntrianglelefteq \trianglerighteq
+ \ntrianglerighteq \blacktriangleleft \blacktriangleright
+ \equalparallel \measuredrightangle \varlrtriangle
+ \Doteq \Bumpeq \Subset \Supset
+ \backepsilon \because \therefore \bot
+ \top \bumpeq \circeq \coloneq
+ \curlyeqprec \curlyeqsucc \eqcirc \eqcolon
+ \eqsim \fallingdotseq \gtrdot \gtrless
+ \ltimes \rtimes \lessdot \ne
+ \ncong \nequiv \ngeq \ngtr
+ \nleq \nless \nmid \notin
+ \nprec \nsubset \nsubseteq \nsucc
+ \nsupset \nsupseteq \pitchfork \preccurlyeq
+ \risingdotseq \subsetneq \succcurlyeq \supsetneq
+ \varpropto \vartriangleleft \scurel
+ \vartriangleright \rightangle \equal \backcong
+ \eqdef \wedgeq \questeq \between
+ \veeeq \disin \varisins \isins
+ \isindot \varisinobar \isinobar \isinvb
+ \isinE \nisd \varnis \nis
+ \varniobar \niobar \bagmember \ratio
+ \Equiv \stareq \measeq \arceq
+ \rightassert \rightModels \smallin \smallowns
+ \notsmallowns \nsimeq'''.split())
+
+ _arrow_symbols = set(r"""
+ \leftarrow \longleftarrow \uparrow \Leftarrow \Longleftarrow
+ \Uparrow \rightarrow \longrightarrow \downarrow \Rightarrow
+ \Longrightarrow \Downarrow \leftrightarrow \updownarrow
+ \longleftrightarrow \updownarrow \Leftrightarrow
+ \Longleftrightarrow \Updownarrow \mapsto \longmapsto \nearrow
+ \hookleftarrow \hookrightarrow \searrow \leftharpoonup
+ \rightharpoonup \swarrow \leftharpoondown \rightharpoondown
+ \nwarrow \rightleftharpoons \leadsto \dashrightarrow
+ \dashleftarrow \leftleftarrows \leftrightarrows \Lleftarrow
+ \Rrightarrow \twoheadleftarrow \leftarrowtail \looparrowleft
+ \leftrightharpoons \curvearrowleft \circlearrowleft \Lsh
+ \upuparrows \upharpoonleft \downharpoonleft \multimap
+ \leftrightsquigarrow \rightrightarrows \rightleftarrows
+ \rightrightarrows \rightleftarrows \twoheadrightarrow
+ \rightarrowtail \looparrowright \rightleftharpoons
+ \curvearrowright \circlearrowright \Rsh \downdownarrows
+ \upharpoonright \downharpoonright \rightsquigarrow \nleftarrow
+ \nrightarrow \nLeftarrow \nRightarrow \nleftrightarrow
+ \nLeftrightarrow \to \Swarrow \Searrow \Nwarrow \Nearrow
+ \leftsquigarrow \overleftarrow \overleftrightarrow \cwopencirclearrow
+ \downzigzagarrow \cupleftarrow \rightzigzagarrow \twoheaddownarrow
+ \updownarrowbar \twoheaduparrow \rightarrowbar \updownarrows
+ \barleftarrow \mapsfrom \mapsdown \mapsup \Ldsh \Rdsh
+ """.split())
+
+ _spaced_symbols = _binary_operators | _relation_symbols | _arrow_symbols
+
+ _punctuation_symbols = set(r', ; . ! \ldotp \cdotp'.split())
+
+ _overunder_symbols = set(r'''
+ \sum \prod \coprod \bigcap \bigcup \bigsqcup \bigvee
+ \bigwedge \bigodot \bigotimes \bigoplus \biguplus
+ '''.split())
+
+ _overunder_functions = set("lim liminf limsup sup max min".split())
+
+ _dropsub_symbols = set(r'\int \oint \iint \oiint \iiint \oiiint \iiiint'.split())
+
+ _fontnames = set("rm cal it tt sf bf bfit "
+ "default bb frak scr regular".split())
+
+ _function_names = set("""
+ arccos csc ker min arcsin deg lg Pr arctan det lim sec arg dim
+ liminf sin cos exp limsup sinh cosh gcd ln sup cot hom log tan
+ coth inf max tanh""".split())
+
+ _ambi_delims = set(r"""
+ | \| / \backslash \uparrow \downarrow \updownarrow \Uparrow
+ \Downarrow \Updownarrow . \vert \Vert""".split())
+ _left_delims = set(r"""
+ ( [ \{ < \lfloor \langle \lceil \lbrace \leftbrace \lbrack \leftparen \lgroup
+ """.split())
+ _right_delims = set(r"""
+ ) ] \} > \rfloor \rangle \rceil \rbrace \rightbrace \rbrack \rightparen \rgroup
+ """.split())
+ _delims = _left_delims | _right_delims | _ambi_delims
+
+ _small_greek = set([unicodedata.name(chr(i)).split()[-1].lower() for i in
+ range(ord('\N{GREEK SMALL LETTER ALPHA}'),
+ ord('\N{GREEK SMALL LETTER OMEGA}') + 1)])
+ _latin_alphabets = set(string.ascii_letters)
+
+ def __init__(self) -> None:
+ p = types.SimpleNamespace()
+
+ def set_names_and_parse_actions() -> None:
+ for key, val in vars(p).items():
+ if not key.startswith('_'):
+ # Set names on (almost) everything -- very useful for debugging
+ # token, placeable, and auto_delim are forward references which
+ # are left without names to ensure useful error messages
+ if key not in ("token", "placeable", "auto_delim"):
+ val.setName(key)
+ # Set actions
+ if hasattr(self, key):
+ val.setParseAction(getattr(self, key))
+
+ # Root definitions.
+
+ # In TeX parlance, a csname is a control sequence name (a "\foo").
+ def csnames(group: str, names: Iterable[str]) -> Regex:
+ ends_with_alpha = []
+ ends_with_nonalpha = []
+ for name in names:
+ if name[-1].isalpha():
+ ends_with_alpha.append(name)
+ else:
+ ends_with_nonalpha.append(name)
+ return Regex(
+ r"\\(?P<{group}>(?:{alpha})(?![A-Za-z]){additional}{nonalpha})".format(
+ group=group,
+ alpha="|".join(map(re.escape, ends_with_alpha)),
+ additional="|" if ends_with_nonalpha else "",
+ nonalpha="|".join(map(re.escape, ends_with_nonalpha)),
+ )
+ )
+
+ p.float_literal = Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)")
+ p.space = oneOf(self._space_widths)("space")
+
+ p.style_literal = oneOf(
+ [str(e.value) for e in self._MathStyle])("style_literal")
+
+ p.symbol = Regex(
+ r"[a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|\U00000080-\U0001ffff]"
+ r"|\\[%${}\[\]_|]"
+ + r"|\\(?:{})(?![A-Za-z])".format(
+ "|".join(map(re.escape, tex2uni)))
+ )("sym").leaveWhitespace()
+ p.unknown_symbol = Regex(r"\\[A-Za-z]+")("name")
+
+ p.font = csnames("font", self._fontnames)
+ p.start_group = Optional(r"\math" + oneOf(self._fontnames)("font")) + "{"
+ p.end_group = Literal("}")
+
+ p.delim = oneOf(self._delims)
+
+ # Mutually recursive definitions. (Minimizing the number of Forward
+ # elements is important for speed.)
+ p.auto_delim = Forward()
+ p.placeable = Forward()
+ p.named_placeable = Forward()
+ p.required_group = Forward()
+ p.optional_group = Forward()
+ p.token = Forward()
+
+ # Workaround for placable being part of a cycle of definitions
+ # calling `p.placeable("name")` results in a copy, so not guaranteed
+ # to get the definition added after it is used.
+ # ref https://github.com/matplotlib/matplotlib/issues/25204
+ # xref https://github.com/pyparsing/pyparsing/issues/95
+ p.named_placeable <<= p.placeable
+
+ set_names_and_parse_actions() # for mutually recursive definitions.
+
+ p.optional_group <<= "{" + ZeroOrMore(p.token)("group") + "}"
+ p.required_group <<= "{" + OneOrMore(p.token)("group") + "}"
+
+ p.customspace = cmd(r"\hspace", "{" + p.float_literal("space") + "}")
+
+ p.accent = (
+ csnames("accent", [*self._accent_map, *self._wide_accents])
+ - p.named_placeable("sym"))
+
+ p.function = csnames("name", self._function_names)
+
+ p.group = p.start_group + ZeroOrMore(p.token)("group") + p.end_group
+ p.unclosed_group = (p.start_group + ZeroOrMore(p.token)("group") + StringEnd())
+
+ p.frac = cmd(r"\frac", p.required_group("num") + p.required_group("den"))
+ p.dfrac = cmd(r"\dfrac", p.required_group("num") + p.required_group("den"))
+ p.binom = cmd(r"\binom", p.required_group("num") + p.required_group("den"))
+
+ p.genfrac = cmd(
+ r"\genfrac",
+ "{" + Optional(p.delim)("ldelim") + "}"
+ + "{" + Optional(p.delim)("rdelim") + "}"
+ + "{" + p.float_literal("rulesize") + "}"
+ + "{" + Optional(p.style_literal)("style") + "}"
+ + p.required_group("num")
+ + p.required_group("den"))
+
+ p.sqrt = cmd(
+ r"\sqrt{value}",
+ Optional("[" + OneOrMore(NotAny("]") + p.token)("root") + "]")
+ + p.required_group("value"))
+
+ p.overline = cmd(r"\overline", p.required_group("body"))
+
+ p.overset = cmd(
+ r"\overset",
+ p.optional_group("annotation") + p.optional_group("body"))
+ p.underset = cmd(
+ r"\underset",
+ p.optional_group("annotation") + p.optional_group("body"))
+
+ p.text = cmd(r"\text", QuotedString('{', '\\', endQuoteChar="}"))
+
+ p.substack = cmd(r"\substack",
+ nested_expr(opener="{", closer="}",
+ content=Group(OneOrMore(p.token)) +
+ ZeroOrMore(Literal("\\\\").suppress()))("parts"))
+
+ p.subsuper = (
+ (Optional(p.placeable)("nucleus")
+ + OneOrMore(oneOf(["_", "^"]) - p.placeable)("subsuper")
+ + Regex("'*")("apostrophes"))
+ | Regex("'+")("apostrophes")
+ | (p.named_placeable("nucleus") + Regex("'*")("apostrophes"))
+ )
+
+ p.simple = p.space | p.customspace | p.font | p.subsuper
+
+ p.token <<= (
+ p.simple
+ | p.auto_delim
+ | p.unclosed_group
+ | p.unknown_symbol # Must be last
+ )
+
+ p.operatorname = cmd(r"\operatorname", "{" + ZeroOrMore(p.simple)("name") + "}")
+
+ p.boldsymbol = cmd(
+ r"\boldsymbol", "{" + ZeroOrMore(p.simple)("value") + "}")
+
+ p.placeable <<= (
+ p.accent # Must be before symbol as all accents are symbols
+ | p.symbol # Must be second to catch all named symbols and single
+ # chars not in a group
+ | p.function
+ | p.operatorname
+ | p.group
+ | p.frac
+ | p.dfrac
+ | p.binom
+ | p.genfrac
+ | p.overset
+ | p.underset
+ | p.sqrt
+ | p.overline
+ | p.text
+ | p.boldsymbol
+ | p.substack
+ )
+
+ mdelim = r"\middle" - (p.delim("mdelim") | Error("Expected a delimiter"))
+ p.auto_delim <<= (
+ r"\left" - (p.delim("left") | Error("Expected a delimiter"))
+ + ZeroOrMore(p.simple | p.auto_delim | mdelim)("mid")
+ + r"\right" - (p.delim("right") | Error("Expected a delimiter"))
+ )
+
+ # Leaf definitions.
+ p.math = OneOrMore(p.token)
+ p.math_string = QuotedString('$', '\\', unquoteResults=False)
+ p.non_math = Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace()
+ p.main = (
+ p.non_math + ZeroOrMore(p.math_string + p.non_math) + StringEnd()
+ )
+ set_names_and_parse_actions() # for leaf definitions.
+
+ self._expression = p.main
+ self._math_expression = p.math
+
+ # To add space to nucleus operators after sub/superscripts
+ self._in_subscript_or_superscript = False
+
+ def parse(self, s: str, fonts_object: Fonts, fontsize: float, dpi: float) -> Hlist:
+ """
+ Parse expression *s* using the given *fonts_object* for
+ output, at the given *fontsize* and *dpi*.
+
+ Returns the parse tree of `Node` instances.
+ """
+ self._state_stack = [
+ ParserState(fonts_object, 'default', 'rm', fontsize, dpi)]
+ self._em_width_cache: dict[tuple[str, float, float], float] = {}
+ try:
+ result = self._expression.parseString(s)
+ except ParseBaseException as err:
+ # explain becomes a plain method on pyparsing 3 (err.explain(0)).
+ raise ValueError("\n" + ParseException.explain(err, 0)) from None
+ self._state_stack = []
+ self._in_subscript_or_superscript = False
+ # prevent operator spacing from leaking into a new expression
+ self._em_width_cache = {}
+ ParserElement.resetCache()
+ return T.cast(Hlist, result[0]) # Known return type from main.
+
+ def get_state(self) -> ParserState:
+ """Get the current `State` of the parser."""
+ return self._state_stack[-1]
+
+ def pop_state(self) -> None:
+ """Pop a `State` off of the stack."""
+ self._state_stack.pop()
+
+ def push_state(self) -> None:
+ """Push a new `State` onto the stack, copying the current state."""
+ self._state_stack.append(self.get_state().copy())
+
+ def main(self, toks: ParseResults) -> list[Hlist]:
+ return [Hlist(toks.asList())]
+
+ def math_string(self, toks: ParseResults) -> ParseResults:
+ return self._math_expression.parseString(toks[0][1:-1], parseAll=True)
+
+ def math(self, toks: ParseResults) -> T.Any:
+ hlist = Hlist(toks.asList())
+ self.pop_state()
+ return [hlist]
+
+ def non_math(self, toks: ParseResults) -> T.Any:
+ s = toks[0].replace(r'\$', '$')
+ symbols = [Char(c, self.get_state()) for c in s]
+ hlist = Hlist(symbols)
+ # We're going into math now, so set font to 'it'
+ self.push_state()
+ self.get_state().font = mpl.rcParams['mathtext.default']
+ return [hlist]
+
+ float_literal = staticmethod(pyparsing_common.convertToFloat)
+
+ def text(self, toks: ParseResults) -> T.Any:
+ self.push_state()
+ state = self.get_state()
+ state.font = 'rm'
+ hlist = Hlist([Char(c, state) for c in toks[1]])
+ self.pop_state()
+ return [hlist]
+
+ def _make_space(self, percentage: float) -> Kern:
+ # In TeX, an em (the unit usually used to measure horizontal lengths)
+ # is not the width of the character 'm'; it is the same in different
+ # font styles (e.g. roman or italic). Mathtext, however, uses 'm' in
+ # the italic style so that horizontal spaces don't depend on the
+ # current font style.
+ state = self.get_state()
+ key = (state.font, state.fontsize, state.dpi)
+ width = self._em_width_cache.get(key)
+ if width is None:
+ metrics = state.fontset.get_metrics(
+ 'it', mpl.rcParams['mathtext.default'], 'm',
+ state.fontsize, state.dpi)
+ width = metrics.advance
+ self._em_width_cache[key] = width
+ return Kern(width * percentage)
+
+ _space_widths = {
+ r'\,': 0.16667, # 3/18 em = 3 mu
+ r'\thinspace': 0.16667, # 3/18 em = 3 mu
+ r'\/': 0.16667, # 3/18 em = 3 mu
+ r'\>': 0.22222, # 4/18 em = 4 mu
+ r'\:': 0.22222, # 4/18 em = 4 mu
+ r'\;': 0.27778, # 5/18 em = 5 mu
+ r'\ ': 0.33333, # 6/18 em = 6 mu
+ r'~': 0.33333, # 6/18 em = 6 mu, nonbreakable
+ r'\enspace': 0.5, # 9/18 em = 9 mu
+ r'\quad': 1, # 1 em = 18 mu
+ r'\qquad': 2, # 2 em = 36 mu
+ r'\!': -0.16667, # -3/18 em = -3 mu
+ }
+
+ def space(self, toks: ParseResults) -> T.Any:
+ num = self._space_widths[toks["space"]]
+ box = self._make_space(num)
+ return [box]
+
+ def customspace(self, toks: ParseResults) -> T.Any:
+ return [self._make_space(toks["space"])]
+
+ def symbol(self, s: str, loc: int,
+ toks: ParseResults | dict[str, str]) -> T.Any:
+ c = toks["sym"]
+ if c == "-":
+ # "U+2212 minus sign is the preferred representation of the unary
+ # and binary minus sign rather than the ASCII-derived U+002D
+ # hyphen-minus, because minus sign is unambiguous and because it
+ # is rendered with a more desirable length, usually longer than a
+ # hyphen." (https://www.unicode.org/reports/tr25/)
+ c = "\N{MINUS SIGN}"
+ try:
+ char = Char(c, self.get_state())
+ except ValueError as err:
+ raise ParseFatalException(s, loc,
+ "Unknown symbol: %s" % c) from err
+
+ if c in self._spaced_symbols:
+ # iterate until we find previous character, needed for cases
+ # such as $=-2$, ${ -2}$, $ -2$, or $ -2$.
+ prev_char = next((c for c in s[:loc][::-1] if c != ' '), '')
+ # Binary operators at start of string should not be spaced
+ # Also, operators in sub- or superscripts should not be spaced
+ if (self._in_subscript_or_superscript or (
+ c in self._binary_operators and (
+ len(s[:loc].split()) == 0 or prev_char in {
+ '{', *self._left_delims, *self._relation_symbols}))):
+ return [char]
+ else:
+ return [Hlist([self._make_space(0.2),
+ char,
+ self._make_space(0.2)],
+ do_kern=True)]
+ elif c in self._punctuation_symbols:
+ prev_char = next((c for c in s[:loc][::-1] if c != ' '), '')
+ next_char = next((c for c in s[loc + 1:] if c != ' '), '')
+
+ # Do not space commas between brackets
+ if c == ',':
+ if prev_char == '{' and next_char == '}':
+ return [char]
+
+ # Do not space dots as decimal separators
+ if c == '.' and prev_char.isdigit() and next_char.isdigit():
+ return [char]
+ else:
+ return [Hlist([char, self._make_space(0.2)], do_kern=True)]
+ return [char]
+
+ def unknown_symbol(self, s: str, loc: int, toks: ParseResults) -> T.Any:
+ raise ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}")
+
+ _accent_map = {
+ r'hat': r'\circumflexaccent',
+ r'breve': r'\combiningbreve',
+ r'bar': r'\combiningoverline',
+ r'grave': r'\combininggraveaccent',
+ r'acute': r'\combiningacuteaccent',
+ r'tilde': r'\combiningtilde',
+ r'dot': r'\combiningdotabove',
+ r'ddot': r'\combiningdiaeresis',
+ r'dddot': r'\combiningthreedotsabove',
+ r'ddddot': r'\combiningfourdotsabove',
+ r'vec': r'\combiningrightarrowabove',
+ r'"': r'\combiningdiaeresis',
+ r"`": r'\combininggraveaccent',
+ r"'": r'\combiningacuteaccent',
+ r'~': r'\combiningtilde',
+ r'.': r'\combiningdotabove',
+ r'^': r'\circumflexaccent',
+ r'overrightarrow': r'\rightarrow',
+ r'overleftarrow': r'\leftarrow',
+ r'mathring': r'\circ',
+ }
+
+ _wide_accents = set(r"widehat widetilde widebar".split())
+
+ def accent(self, toks: ParseResults) -> T.Any:
+ state = self.get_state()
+ thickness = state.get_current_underline_thickness()
+ accent = toks["accent"]
+ sym = toks["sym"]
+ accent_box: Node
+ if accent in self._wide_accents:
+ accent_box = AutoWidthChar(
+ '\\' + accent, sym.width, state, char_class=Accent)
+ else:
+ accent_box = Accent(self._accent_map[accent], state)
+ if accent == 'mathring':
+ accent_box.shrink()
+ accent_box.shrink()
+ centered = HCentered([Hbox(sym.width / 4.0), accent_box])
+ centered.hpack(sym.width, 'exactly')
+ return Vlist([
+ centered,
+ Vbox(0., thickness * 2.0),
+ Hlist([sym])
+ ])
+
+ def function(self, s: str, loc: int, toks: ParseResults) -> T.Any:
+ hlist = self.operatorname(s, loc, toks)
+ hlist.function_name = toks["name"]
+ return hlist
+
+ def operatorname(self, s: str, loc: int, toks: ParseResults) -> T.Any:
+ self.push_state()
+ state = self.get_state()
+ state.font = 'rm'
+ hlist_list: list[Node] = []
+ # Change the font of Chars, but leave Kerns alone
+ name = toks["name"]
+ for c in name:
+ if isinstance(c, Char):
+ c.font = 'rm'
+ c._update_metrics()
+ hlist_list.append(c)
+ elif isinstance(c, str):
+ hlist_list.append(Char(c, state))
+ else:
+ hlist_list.append(c)
+ next_char_loc = loc + len(name) + 1
+ if isinstance(name, ParseResults):
+ next_char_loc += len('operatorname{}')
+ next_char = next((c for c in s[next_char_loc:] if c != ' '), '')
+ delimiters = self._delims | {'^', '_'}
+ if (next_char not in delimiters and
+ name not in self._overunder_functions):
+ # Add thin space except when followed by parenthesis, bracket, etc.
+ hlist_list += [self._make_space(self._space_widths[r'\,'])]
+ self.pop_state()
+ # if followed by a super/subscript, set flag to true
+ # This flag tells subsuper to add space after this operator
+ if next_char in {'^', '_'}:
+ self._in_subscript_or_superscript = True
+ else:
+ self._in_subscript_or_superscript = False
+
+ return Hlist(hlist_list)
+
+ def start_group(self, toks: ParseResults) -> T.Any:
+ self.push_state()
+ # Deal with LaTeX-style font tokens
+ if toks.get("font"):
+ self.get_state().font = toks.get("font")
+ return []
+
+ def group(self, toks: ParseResults) -> T.Any:
+ grp = Hlist(toks.get("group", []))
+ return [grp]
+
+ def required_group(self, toks: ParseResults) -> T.Any:
+ return Hlist(toks.get("group", []))
+
+ optional_group = required_group
+
+ def end_group(self) -> T.Any:
+ self.pop_state()
+ return []
+
+ def unclosed_group(self, s: str, loc: int, toks: ParseResults) -> T.Any:
+ raise ParseFatalException(s, len(s), "Expected '}'")
+
+ def font(self, toks: ParseResults) -> T.Any:
+ self.get_state().font = toks["font"]
+ return []
+
+ def is_overunder(self, nucleus: Node) -> bool:
+ if isinstance(nucleus, Char):
+ return nucleus.c in self._overunder_symbols
+ elif isinstance(nucleus, Hlist) and hasattr(nucleus, 'function_name'):
+ return nucleus.function_name in self._overunder_functions
+ return False
+
+ def is_dropsub(self, nucleus: Node) -> bool:
+ if isinstance(nucleus, Char):
+ return nucleus.c in self._dropsub_symbols
+ return False
+
+ def is_slanted(self, nucleus: Node) -> bool:
+ if isinstance(nucleus, Char):
+ return nucleus.is_slanted()
+ return False
+
+ def subsuper(self, s: str, loc: int, toks: ParseResults) -> T.Any:
+ nucleus = toks.get("nucleus", Hbox(0))
+ subsuper = toks.get("subsuper", [])
+ napostrophes = len(toks.get("apostrophes", []))
+
+ if not subsuper and not napostrophes:
+ return nucleus
+
+ sub = super = None
+ while subsuper:
+ op, arg, *subsuper = subsuper
+ if op == '_':
+ if sub is not None:
+ raise ParseFatalException("Double subscript")
+ sub = arg
+ else:
+ if super is not None:
+ raise ParseFatalException("Double superscript")
+ super = arg
+
+ state = self.get_state()
+ rule_thickness = state.fontset.get_underline_thickness(
+ state.font, state.fontsize, state.dpi)
+ xHeight = state.fontset.get_xheight(
+ state.font, state.fontsize, state.dpi)
+
+ if napostrophes:
+ if super is None:
+ super = Hlist([])
+ for i in range(napostrophes):
+ super.children.extend(self.symbol(s, loc, {"sym": "\\prime"}))
+ # kern() and hpack() needed to get the metrics right after
+ # extending
+ super.kern()
+ super.hpack()
+
+ # Handle over/under symbols, such as sum or prod
+ if self.is_overunder(nucleus):
+ vlist = []
+ shift = 0.
+ width = nucleus.width
+ if super is not None:
+ super.shrink()
+ width = max(width, super.width)
+ if sub is not None:
+ sub.shrink()
+ width = max(width, sub.width)
+
+ vgap = rule_thickness * 3.0
+ if super is not None:
+ hlist = HCentered([super])
+ hlist.hpack(width, 'exactly')
+ vlist.extend([hlist, Vbox(0, vgap)])
+ hlist = HCentered([nucleus])
+ hlist.hpack(width, 'exactly')
+ vlist.append(hlist)
+ if sub is not None:
+ hlist = HCentered([sub])
+ hlist.hpack(width, 'exactly')
+ vlist.extend([Vbox(0, vgap), hlist])
+ shift = hlist.height + vgap + nucleus.depth
+ vlt = Vlist(vlist)
+ vlt.shift_amount = shift
+ result = Hlist([vlt])
+ return [result]
+
+ # We remove kerning on the last character for consistency (otherwise
+ # it will compute kerning based on non-shrunk characters and may put
+ # them too close together when superscripted)
+ # We change the width of the last character to match the advance to
+ # consider some fonts with weird metrics: e.g. stix's f has a width of
+ # 7.75 and a kerning of -4.0 for an advance of 3.72, and we want to put
+ # the superscript at the advance
+ last_char = nucleus
+ if isinstance(nucleus, Hlist):
+ new_children = nucleus.children
+ if len(new_children):
+ # remove last kern
+ if (isinstance(new_children[-1], Kern) and
+ hasattr(new_children[-2], '_metrics')):
+ new_children = new_children[:-1]
+ last_char = new_children[-1]
+ if hasattr(last_char, '_metrics'):
+ last_char.width = last_char._metrics.advance
+ # create new Hlist without kerning
+ nucleus = Hlist(new_children, do_kern=False)
+ else:
+ if isinstance(nucleus, Char):
+ last_char.width = last_char._metrics.advance
+ nucleus = Hlist([nucleus])
+
+ # Handle regular sub/superscripts
+ constants = _get_font_constant_set(state)
+ lc_height = last_char.height
+ lc_baseline = 0
+ if self.is_dropsub(last_char):
+ lc_baseline = last_char.depth
+
+ # Compute kerning for sub and super
+ superkern = constants.delta * xHeight
+ subkern = constants.delta * xHeight
+ if self.is_slanted(last_char):
+ superkern += constants.delta * xHeight
+ superkern += (constants.delta_slanted *
+ (lc_height - xHeight * 2. / 3.))
+ if self.is_dropsub(last_char):
+ subkern = (3 * constants.delta -
+ constants.delta_integral) * lc_height
+ superkern = (3 * constants.delta +
+ constants.delta_integral) * lc_height
+ else:
+ subkern = 0
+
+ x: List
+ if super is None:
+ # node757
+ # Note: One of super or sub must be a Node if we're in this function, but
+ # mypy can't know this, since it can't interpret pyparsing expressions,
+ # hence the cast.
+ x = Hlist([Kern(subkern), T.cast(Node, sub)])
+ x.shrink()
+ if self.is_dropsub(last_char):
+ shift_down = lc_baseline + constants.subdrop * xHeight
+ else:
+ shift_down = constants.sub1 * xHeight
+ x.shift_amount = shift_down
+ else:
+ x = Hlist([Kern(superkern), super])
+ x.shrink()
+ if self.is_dropsub(last_char):
+ shift_up = lc_height - constants.subdrop * xHeight
+ else:
+ shift_up = constants.sup1 * xHeight
+ if sub is None:
+ x.shift_amount = -shift_up
+ else: # Both sub and superscript
+ y = Hlist([Kern(subkern), sub])
+ y.shrink()
+ if self.is_dropsub(last_char):
+ shift_down = lc_baseline + constants.subdrop * xHeight
+ else:
+ shift_down = constants.sub2 * xHeight
+ # If sub and superscript collide, move super up
+ clr = (2.0 * rule_thickness -
+ ((shift_up - x.depth) - (y.height - shift_down)))
+ if clr > 0.:
+ shift_up += clr
+ x = Vlist([
+ x,
+ Kern((shift_up - x.depth) - (y.height - shift_down)),
+ y])
+ x.shift_amount = shift_down
+
+ if not self.is_dropsub(last_char):
+ x.width += constants.script_space * xHeight
+
+ # Do we need to add a space after the nucleus?
+ # To find out, check the flag set by operatorname
+ spaced_nucleus = [nucleus, x]
+ if self._in_subscript_or_superscript:
+ spaced_nucleus += [self._make_space(self._space_widths[r'\,'])]
+ self._in_subscript_or_superscript = False
+
+ result = Hlist(spaced_nucleus)
+ return [result]
+
+ def _genfrac(self, ldelim: str, rdelim: str, rule: float | None, style: _MathStyle,
+ num: Hlist, den: Hlist) -> T.Any:
+ state = self.get_state()
+ thickness = state.get_current_underline_thickness()
+
+ for _ in range(style.value):
+ num.shrink()
+ den.shrink()
+ cnum = HCentered([num])
+ cden = HCentered([den])
+ width = max(num.width, den.width)
+ cnum.hpack(width, 'exactly')
+ cden.hpack(width, 'exactly')
+ vlist = Vlist([cnum, # numerator
+ Vbox(0, thickness * 2.0), # space
+ Hrule(state, rule), # rule
+ Vbox(0, thickness * 2.0), # space
+ cden # denominator
+ ])
+
+ # Shift so the fraction line sits in the middle of the
+ # equals sign
+ metrics = state.fontset.get_metrics(
+ state.font, mpl.rcParams['mathtext.default'],
+ '=', state.fontsize, state.dpi)
+ shift = (cden.height -
+ ((metrics.ymax + metrics.ymin) / 2 -
+ thickness * 3.0))
+ vlist.shift_amount = shift
+
+ result = [Hlist([vlist, Hbox(thickness * 2.)])]
+ if ldelim or rdelim:
+ if ldelim == '':
+ ldelim = '.'
+ if rdelim == '':
+ rdelim = '.'
+ return self._auto_sized_delimiter(ldelim,
+ T.cast(list[Box | Char | str],
+ result),
+ rdelim)
+ return result
+
+ def style_literal(self, toks: ParseResults) -> T.Any:
+ return self._MathStyle(int(toks["style_literal"]))
+
+ def genfrac(self, toks: ParseResults) -> T.Any:
+ return self._genfrac(
+ toks.get("ldelim", ""), toks.get("rdelim", ""),
+ toks["rulesize"], toks.get("style", self._MathStyle.TEXTSTYLE),
+ toks["num"], toks["den"])
+
+ def frac(self, toks: ParseResults) -> T.Any:
+ return self._genfrac(
+ "", "", self.get_state().get_current_underline_thickness(),
+ self._MathStyle.TEXTSTYLE, toks["num"], toks["den"])
+
+ def dfrac(self, toks: ParseResults) -> T.Any:
+ return self._genfrac(
+ "", "", self.get_state().get_current_underline_thickness(),
+ self._MathStyle.DISPLAYSTYLE, toks["num"], toks["den"])
+
+ def binom(self, toks: ParseResults) -> T.Any:
+ return self._genfrac(
+ "(", ")", 0,
+ self._MathStyle.TEXTSTYLE, toks["num"], toks["den"])
+
+ def _genset(self, s: str, loc: int, toks: ParseResults) -> T.Any:
+ annotation = toks["annotation"]
+ body = toks["body"]
+ thickness = self.get_state().get_current_underline_thickness()
+
+ annotation.shrink()
+ centered_annotation = HCentered([annotation])
+ centered_body = HCentered([body])
+ width = max(centered_annotation.width, centered_body.width)
+ centered_annotation.hpack(width, 'exactly')
+ centered_body.hpack(width, 'exactly')
+
+ vgap = thickness * 3
+ if s[loc + 1] == "u": # \underset
+ vlist = Vlist([
+ centered_body, # body
+ Vbox(0, vgap), # space
+ centered_annotation # annotation
+ ])
+ # Shift so the body sits in the same vertical position
+ vlist.shift_amount = centered_body.depth + centered_annotation.height + vgap
+ else: # \overset
+ vlist = Vlist([
+ centered_annotation, # annotation
+ Vbox(0, vgap), # space
+ centered_body # body
+ ])
+
+ # To add horizontal gap between symbols: wrap the Vlist into
+ # an Hlist and extend it with an Hbox(0, horizontal_gap)
+ return vlist
+
+ overset = underset = _genset
+
+ def sqrt(self, toks: ParseResults) -> T.Any:
+ root = toks.get("root")
+ body = toks["value"]
+ state = self.get_state()
+ thickness = state.get_current_underline_thickness()
+
+ # Determine the height of the body, and add a little extra to
+ # the height so it doesn't seem cramped
+ height = body.height - body.shift_amount + thickness * 5.0
+ depth = body.depth + body.shift_amount
+ check = AutoHeightChar(r'\__sqrt__', height, depth, state, always=True)
+ height = check.height - check.shift_amount
+ depth = check.depth + check.shift_amount
+
+ # Put a little extra space to the left and right of the body
+ padded_body = Hlist([Hbox(2 * thickness), body, Hbox(2 * thickness)])
+ rightside = Vlist([Hrule(state), Glue('fill'), padded_body])
+ # Stretch the glue between the hrule and the body
+ rightside.vpack(height + (state.fontsize * state.dpi) / (100.0 * 12.0),
+ 'exactly', depth)
+
+ # Add the root and shift it upward so it is above the tick.
+ # The value of 0.6 is a hard-coded hack ;)
+ if not root:
+ root = Box(check.width * 0.5, 0., 0.)
+ else:
+ root = Hlist(root)
+ root.shrink()
+ root.shrink()
+
+ root_vlist = Vlist([Hlist([root])])
+ root_vlist.shift_amount = -height * 0.6
+
+ hlist = Hlist([root_vlist, # Root
+ # Negative kerning to put root over tick
+ Kern(-check.width * 0.5),
+ check, # Check
+ rightside]) # Body
+ return [hlist]
+
+ def overline(self, toks: ParseResults) -> T.Any:
+ body = toks["body"]
+
+ state = self.get_state()
+ thickness = state.get_current_underline_thickness()
+
+ height = body.height - body.shift_amount + thickness * 3.0
+ depth = body.depth + body.shift_amount
+
+ # Place overline above body
+ rightside = Vlist([Hrule(state), Glue('fill'), Hlist([body])])
+
+ # Stretch the glue between the hrule and the body
+ rightside.vpack(height + (state.fontsize * state.dpi) / (100.0 * 12.0),
+ 'exactly', depth)
+
+ hlist = Hlist([rightside])
+ return [hlist]
+
+ def _auto_sized_delimiter(self, front: str,
+ middle: list[Box | Char | str],
+ back: str) -> T.Any:
+ state = self.get_state()
+ if len(middle):
+ height = max([x.height for x in middle if not isinstance(x, str)])
+ depth = max([x.depth for x in middle if not isinstance(x, str)])
+ factor = None
+ for idx, el in enumerate(middle):
+ if el == r'\middle':
+ c = T.cast(str, middle[idx + 1]) # Should be one of p.delims.
+ if c != '.':
+ middle[idx + 1] = AutoHeightChar(
+ c, height, depth, state, factor=factor)
+ else:
+ middle.remove(c)
+ del middle[idx]
+ # There should only be \middle and its delimiter as str, which have
+ # just been removed.
+ middle_part = T.cast(list[Box | Char], middle)
+ else:
+ height = 0
+ depth = 0
+ factor = 1.0
+ middle_part = []
+
+ parts: list[Node] = []
+ # \left. and \right. aren't supposed to produce any symbols
+ if front != '.':
+ parts.append(
+ AutoHeightChar(front, height, depth, state, factor=factor))
+ parts.extend(middle_part)
+ if back != '.':
+ parts.append(
+ AutoHeightChar(back, height, depth, state, factor=factor))
+ hlist = Hlist(parts)
+ return hlist
+
+ def auto_delim(self, toks: ParseResults) -> T.Any:
+ return self._auto_sized_delimiter(
+ toks["left"],
+ # if "mid" in toks ... can be removed when requiring pyparsing 3.
+ toks["mid"].asList() if "mid" in toks else [],
+ toks["right"])
+
+ def boldsymbol(self, toks: ParseResults) -> T.Any:
+ self.push_state()
+ state = self.get_state()
+ hlist: list[Node] = []
+ name = toks["value"]
+ for c in name:
+ if isinstance(c, Hlist):
+ k = c.children[1]
+ if isinstance(k, Char):
+ k.font = "bf"
+ k._update_metrics()
+ hlist.append(c)
+ elif isinstance(c, Char):
+ c.font = "bf"
+ if (c.c in self._latin_alphabets or
+ c.c[1:] in self._small_greek):
+ c.font = "bfit"
+ c._update_metrics()
+ c._update_metrics()
+ hlist.append(c)
+ else:
+ hlist.append(c)
+ self.pop_state()
+
+ return Hlist(hlist)
+
+ def substack(self, toks: ParseResults) -> T.Any:
+ parts = toks["parts"]
+ state = self.get_state()
+ thickness = state.get_current_underline_thickness()
+
+ hlist = [Hlist(k) for k in parts[0]]
+ max_width = max(map(lambda c: c.width, hlist))
+
+ vlist = []
+ for sub in hlist:
+ cp = HCentered([sub])
+ cp.hpack(max_width, 'exactly')
+ vlist.append(cp)
+
+ stack = [val
+ for pair in zip(vlist, [Vbox(0, thickness * 2)] * len(vlist))
+ for val in pair]
+ del stack[-1]
+ vlt = Vlist(stack)
+ result = [Hlist([vlt])]
+ return result
diff --git a/lib/python3.12/site-packages/matplotlib/_mathtext_data.py b/lib/python3.12/site-packages/matplotlib/_mathtext_data.py
new file mode 100644
index 0000000000000000000000000000000000000000..5819ee7430447f9ef5f6e760b65cdd5933ef9395
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_mathtext_data.py
@@ -0,0 +1,1742 @@
+"""
+font data tables for truetype and afm computer modern fonts
+"""
+
+from __future__ import annotations
+from typing import overload
+
+latex_to_bakoma = {
+ '\\__sqrt__' : ('cmex10', 0x70),
+ '\\bigcap' : ('cmex10', 0x5c),
+ '\\bigcup' : ('cmex10', 0x5b),
+ '\\bigodot' : ('cmex10', 0x4b),
+ '\\bigoplus' : ('cmex10', 0x4d),
+ '\\bigotimes' : ('cmex10', 0x4f),
+ '\\biguplus' : ('cmex10', 0x5d),
+ '\\bigvee' : ('cmex10', 0x5f),
+ '\\bigwedge' : ('cmex10', 0x5e),
+ '\\coprod' : ('cmex10', 0x61),
+ '\\int' : ('cmex10', 0x5a),
+ '\\langle' : ('cmex10', 0xad),
+ '\\leftangle' : ('cmex10', 0xad),
+ '\\leftbrace' : ('cmex10', 0xa9),
+ '\\oint' : ('cmex10', 0x49),
+ '\\prod' : ('cmex10', 0x59),
+ '\\rangle' : ('cmex10', 0xae),
+ '\\rightangle' : ('cmex10', 0xae),
+ '\\rightbrace' : ('cmex10', 0xaa),
+ '\\sum' : ('cmex10', 0x58),
+ '\\widehat' : ('cmex10', 0x62),
+ '\\widetilde' : ('cmex10', 0x65),
+ '\\{' : ('cmex10', 0xa9),
+ '\\}' : ('cmex10', 0xaa),
+ '{' : ('cmex10', 0xa9),
+ '}' : ('cmex10', 0xaa),
+
+ ',' : ('cmmi10', 0x3b),
+ '.' : ('cmmi10', 0x3a),
+ '/' : ('cmmi10', 0x3d),
+ '<' : ('cmmi10', 0x3c),
+ '>' : ('cmmi10', 0x3e),
+ '\\alpha' : ('cmmi10', 0xae),
+ '\\beta' : ('cmmi10', 0xaf),
+ '\\chi' : ('cmmi10', 0xc2),
+ '\\combiningrightarrowabove' : ('cmmi10', 0x7e),
+ '\\delta' : ('cmmi10', 0xb1),
+ '\\ell' : ('cmmi10', 0x60),
+ '\\epsilon' : ('cmmi10', 0xb2),
+ '\\eta' : ('cmmi10', 0xb4),
+ '\\flat' : ('cmmi10', 0x5b),
+ '\\frown' : ('cmmi10', 0x5f),
+ '\\gamma' : ('cmmi10', 0xb0),
+ '\\imath' : ('cmmi10', 0x7b),
+ '\\iota' : ('cmmi10', 0xb6),
+ '\\jmath' : ('cmmi10', 0x7c),
+ '\\kappa' : ('cmmi10', 0x2219),
+ '\\lambda' : ('cmmi10', 0xb8),
+ '\\leftharpoondown' : ('cmmi10', 0x29),
+ '\\leftharpoonup' : ('cmmi10', 0x28),
+ '\\mu' : ('cmmi10', 0xb9),
+ '\\natural' : ('cmmi10', 0x5c),
+ '\\nu' : ('cmmi10', 0xba),
+ '\\omega' : ('cmmi10', 0x21),
+ '\\phi' : ('cmmi10', 0xc1),
+ '\\pi' : ('cmmi10', 0xbc),
+ '\\psi' : ('cmmi10', 0xc3),
+ '\\rho' : ('cmmi10', 0xbd),
+ '\\rightharpoondown' : ('cmmi10', 0x2b),
+ '\\rightharpoonup' : ('cmmi10', 0x2a),
+ '\\sharp' : ('cmmi10', 0x5d),
+ '\\sigma' : ('cmmi10', 0xbe),
+ '\\smile' : ('cmmi10', 0x5e),
+ '\\tau' : ('cmmi10', 0xbf),
+ '\\theta' : ('cmmi10', 0xb5),
+ '\\triangleleft' : ('cmmi10', 0x2f),
+ '\\triangleright' : ('cmmi10', 0x2e),
+ '\\upsilon' : ('cmmi10', 0xc0),
+ '\\varepsilon' : ('cmmi10', 0x22),
+ '\\varphi' : ('cmmi10', 0x27),
+ '\\varrho' : ('cmmi10', 0x25),
+ '\\varsigma' : ('cmmi10', 0x26),
+ '\\vartheta' : ('cmmi10', 0x23),
+ '\\wp' : ('cmmi10', 0x7d),
+ '\\xi' : ('cmmi10', 0xbb),
+ '\\zeta' : ('cmmi10', 0xb3),
+
+ '!' : ('cmr10', 0x21),
+ '%' : ('cmr10', 0x25),
+ '&' : ('cmr10', 0x26),
+ '(' : ('cmr10', 0x28),
+ ')' : ('cmr10', 0x29),
+ '+' : ('cmr10', 0x2b),
+ '0' : ('cmr10', 0x30),
+ '1' : ('cmr10', 0x31),
+ '2' : ('cmr10', 0x32),
+ '3' : ('cmr10', 0x33),
+ '4' : ('cmr10', 0x34),
+ '5' : ('cmr10', 0x35),
+ '6' : ('cmr10', 0x36),
+ '7' : ('cmr10', 0x37),
+ '8' : ('cmr10', 0x38),
+ '9' : ('cmr10', 0x39),
+ ':' : ('cmr10', 0x3a),
+ ';' : ('cmr10', 0x3b),
+ '=' : ('cmr10', 0x3d),
+ '?' : ('cmr10', 0x3f),
+ '@' : ('cmr10', 0x40),
+ '[' : ('cmr10', 0x5b),
+ '\\#' : ('cmr10', 0x23),
+ '\\$' : ('cmr10', 0x24),
+ '\\%' : ('cmr10', 0x25),
+ '\\Delta' : ('cmr10', 0xa2),
+ '\\Gamma' : ('cmr10', 0xa1),
+ '\\Lambda' : ('cmr10', 0xa4),
+ '\\Omega' : ('cmr10', 0xad),
+ '\\Phi' : ('cmr10', 0xa9),
+ '\\Pi' : ('cmr10', 0xa6),
+ '\\Psi' : ('cmr10', 0xaa),
+ '\\Sigma' : ('cmr10', 0xa7),
+ '\\Theta' : ('cmr10', 0xa3),
+ '\\Upsilon' : ('cmr10', 0xa8),
+ '\\Xi' : ('cmr10', 0xa5),
+ '\\circumflexaccent' : ('cmr10', 0x5e),
+ '\\combiningacuteaccent' : ('cmr10', 0xb6),
+ '\\combiningbreve' : ('cmr10', 0xb8),
+ '\\combiningdiaeresis' : ('cmr10', 0xc4),
+ '\\combiningdotabove' : ('cmr10', 0x5f),
+ '\\combininggraveaccent' : ('cmr10', 0xb5),
+ '\\combiningoverline' : ('cmr10', 0xb9),
+ '\\combiningtilde' : ('cmr10', 0x7e),
+ '\\leftbracket' : ('cmr10', 0x5b),
+ '\\leftparen' : ('cmr10', 0x28),
+ '\\rightbracket' : ('cmr10', 0x5d),
+ '\\rightparen' : ('cmr10', 0x29),
+ '\\widebar' : ('cmr10', 0xb9),
+ ']' : ('cmr10', 0x5d),
+
+ '*' : ('cmsy10', 0xa4),
+ '\N{MINUS SIGN}' : ('cmsy10', 0xa1),
+ '\\Downarrow' : ('cmsy10', 0x2b),
+ '\\Im' : ('cmsy10', 0x3d),
+ '\\Leftarrow' : ('cmsy10', 0x28),
+ '\\Leftrightarrow' : ('cmsy10', 0x2c),
+ '\\P' : ('cmsy10', 0x7b),
+ '\\Re' : ('cmsy10', 0x3c),
+ '\\Rightarrow' : ('cmsy10', 0x29),
+ '\\S' : ('cmsy10', 0x78),
+ '\\Uparrow' : ('cmsy10', 0x2a),
+ '\\Updownarrow' : ('cmsy10', 0x6d),
+ '\\Vert' : ('cmsy10', 0x6b),
+ '\\aleph' : ('cmsy10', 0x40),
+ '\\approx' : ('cmsy10', 0xbc),
+ '\\ast' : ('cmsy10', 0xa4),
+ '\\asymp' : ('cmsy10', 0xb3),
+ '\\backslash' : ('cmsy10', 0x6e),
+ '\\bigcirc' : ('cmsy10', 0xb0),
+ '\\bigtriangledown' : ('cmsy10', 0x35),
+ '\\bigtriangleup' : ('cmsy10', 0x34),
+ '\\bot' : ('cmsy10', 0x3f),
+ '\\bullet' : ('cmsy10', 0xb2),
+ '\\cap' : ('cmsy10', 0x5c),
+ '\\cdot' : ('cmsy10', 0xa2),
+ '\\circ' : ('cmsy10', 0xb1),
+ '\\clubsuit' : ('cmsy10', 0x7c),
+ '\\cup' : ('cmsy10', 0x5b),
+ '\\dag' : ('cmsy10', 0x79),
+ '\\dashv' : ('cmsy10', 0x61),
+ '\\ddag' : ('cmsy10', 0x7a),
+ '\\diamond' : ('cmsy10', 0xa6),
+ '\\diamondsuit' : ('cmsy10', 0x7d),
+ '\\div' : ('cmsy10', 0xa5),
+ '\\downarrow' : ('cmsy10', 0x23),
+ '\\emptyset' : ('cmsy10', 0x3b),
+ '\\equiv' : ('cmsy10', 0xb4),
+ '\\exists' : ('cmsy10', 0x39),
+ '\\forall' : ('cmsy10', 0x38),
+ '\\geq' : ('cmsy10', 0xb8),
+ '\\gg' : ('cmsy10', 0xc0),
+ '\\heartsuit' : ('cmsy10', 0x7e),
+ '\\in' : ('cmsy10', 0x32),
+ '\\infty' : ('cmsy10', 0x31),
+ '\\lbrace' : ('cmsy10', 0x66),
+ '\\lceil' : ('cmsy10', 0x64),
+ '\\leftarrow' : ('cmsy10', 0xc3),
+ '\\leftrightarrow' : ('cmsy10', 0x24),
+ '\\leq' : ('cmsy10', 0x2219),
+ '\\lfloor' : ('cmsy10', 0x62),
+ '\\ll' : ('cmsy10', 0xbf),
+ '\\mid' : ('cmsy10', 0x6a),
+ '\\mp' : ('cmsy10', 0xa8),
+ '\\nabla' : ('cmsy10', 0x72),
+ '\\nearrow' : ('cmsy10', 0x25),
+ '\\neg' : ('cmsy10', 0x3a),
+ '\\ni' : ('cmsy10', 0x33),
+ '\\nwarrow' : ('cmsy10', 0x2d),
+ '\\odot' : ('cmsy10', 0xaf),
+ '\\ominus' : ('cmsy10', 0xaa),
+ '\\oplus' : ('cmsy10', 0xa9),
+ '\\oslash' : ('cmsy10', 0xae),
+ '\\otimes' : ('cmsy10', 0xad),
+ '\\pm' : ('cmsy10', 0xa7),
+ '\\prec' : ('cmsy10', 0xc1),
+ '\\preceq' : ('cmsy10', 0xb9),
+ '\\prime' : ('cmsy10', 0x30),
+ '\\propto' : ('cmsy10', 0x2f),
+ '\\rbrace' : ('cmsy10', 0x67),
+ '\\rceil' : ('cmsy10', 0x65),
+ '\\rfloor' : ('cmsy10', 0x63),
+ '\\rightarrow' : ('cmsy10', 0x21),
+ '\\searrow' : ('cmsy10', 0x26),
+ '\\sim' : ('cmsy10', 0xbb),
+ '\\simeq' : ('cmsy10', 0x27),
+ '\\slash' : ('cmsy10', 0x36),
+ '\\spadesuit' : ('cmsy10', 0xc4),
+ '\\sqcap' : ('cmsy10', 0x75),
+ '\\sqcup' : ('cmsy10', 0x74),
+ '\\sqsubseteq' : ('cmsy10', 0x76),
+ '\\sqsupseteq' : ('cmsy10', 0x77),
+ '\\subset' : ('cmsy10', 0xbd),
+ '\\subseteq' : ('cmsy10', 0xb5),
+ '\\succ' : ('cmsy10', 0xc2),
+ '\\succeq' : ('cmsy10', 0xba),
+ '\\supset' : ('cmsy10', 0xbe),
+ '\\supseteq' : ('cmsy10', 0xb6),
+ '\\swarrow' : ('cmsy10', 0x2e),
+ '\\times' : ('cmsy10', 0xa3),
+ '\\to' : ('cmsy10', 0x21),
+ '\\top' : ('cmsy10', 0x3e),
+ '\\uparrow' : ('cmsy10', 0x22),
+ '\\updownarrow' : ('cmsy10', 0x6c),
+ '\\uplus' : ('cmsy10', 0x5d),
+ '\\vdash' : ('cmsy10', 0x60),
+ '\\vee' : ('cmsy10', 0x5f),
+ '\\vert' : ('cmsy10', 0x6a),
+ '\\wedge' : ('cmsy10', 0x5e),
+ '\\wr' : ('cmsy10', 0x6f),
+ '\\|' : ('cmsy10', 0x6b),
+ '|' : ('cmsy10', 0x6a),
+
+ '\\_' : ('cmtt10', 0x5f)
+}
+
+# Automatically generated.
+
+type12uni = {
+ 'aring' : 229,
+ 'quotedblright' : 8221,
+ 'V' : 86,
+ 'dollar' : 36,
+ 'four' : 52,
+ 'Yacute' : 221,
+ 'P' : 80,
+ 'underscore' : 95,
+ 'p' : 112,
+ 'Otilde' : 213,
+ 'perthousand' : 8240,
+ 'zero' : 48,
+ 'dotlessi' : 305,
+ 'Scaron' : 352,
+ 'zcaron' : 382,
+ 'egrave' : 232,
+ 'section' : 167,
+ 'Icircumflex' : 206,
+ 'ntilde' : 241,
+ 'ampersand' : 38,
+ 'dotaccent' : 729,
+ 'degree' : 176,
+ 'K' : 75,
+ 'acircumflex' : 226,
+ 'Aring' : 197,
+ 'k' : 107,
+ 'smalltilde' : 732,
+ 'Agrave' : 192,
+ 'divide' : 247,
+ 'ocircumflex' : 244,
+ 'asciitilde' : 126,
+ 'two' : 50,
+ 'E' : 69,
+ 'scaron' : 353,
+ 'F' : 70,
+ 'bracketleft' : 91,
+ 'asciicircum' : 94,
+ 'f' : 102,
+ 'ordmasculine' : 186,
+ 'mu' : 181,
+ 'paragraph' : 182,
+ 'nine' : 57,
+ 'v' : 118,
+ 'guilsinglleft' : 8249,
+ 'backslash' : 92,
+ 'six' : 54,
+ 'A' : 65,
+ 'icircumflex' : 238,
+ 'a' : 97,
+ 'ogonek' : 731,
+ 'q' : 113,
+ 'oacute' : 243,
+ 'ograve' : 242,
+ 'edieresis' : 235,
+ 'comma' : 44,
+ 'otilde' : 245,
+ 'guillemotright' : 187,
+ 'ecircumflex' : 234,
+ 'greater' : 62,
+ 'uacute' : 250,
+ 'L' : 76,
+ 'bullet' : 8226,
+ 'cedilla' : 184,
+ 'ydieresis' : 255,
+ 'l' : 108,
+ 'logicalnot' : 172,
+ 'exclamdown' : 161,
+ 'endash' : 8211,
+ 'agrave' : 224,
+ 'Adieresis' : 196,
+ 'germandbls' : 223,
+ 'Odieresis' : 214,
+ 'space' : 32,
+ 'quoteright' : 8217,
+ 'ucircumflex' : 251,
+ 'G' : 71,
+ 'quoteleft' : 8216,
+ 'W' : 87,
+ 'Q' : 81,
+ 'g' : 103,
+ 'w' : 119,
+ 'question' : 63,
+ 'one' : 49,
+ 'ring' : 730,
+ 'figuredash' : 8210,
+ 'B' : 66,
+ 'iacute' : 237,
+ 'Ydieresis' : 376,
+ 'R' : 82,
+ 'b' : 98,
+ 'r' : 114,
+ 'Ccedilla' : 199,
+ 'minus' : 8722,
+ 'Lslash' : 321,
+ 'Uacute' : 218,
+ 'yacute' : 253,
+ 'Ucircumflex' : 219,
+ 'quotedbl' : 34,
+ 'onehalf' : 189,
+ 'Thorn' : 222,
+ 'M' : 77,
+ 'eight' : 56,
+ 'multiply' : 215,
+ 'grave' : 96,
+ 'Ocircumflex' : 212,
+ 'm' : 109,
+ 'Ugrave' : 217,
+ 'guilsinglright' : 8250,
+ 'Ntilde' : 209,
+ 'questiondown' : 191,
+ 'Atilde' : 195,
+ 'ccedilla' : 231,
+ 'Z' : 90,
+ 'copyright' : 169,
+ 'yen' : 165,
+ 'Eacute' : 201,
+ 'H' : 72,
+ 'X' : 88,
+ 'Idieresis' : 207,
+ 'bar' : 124,
+ 'h' : 104,
+ 'x' : 120,
+ 'udieresis' : 252,
+ 'ordfeminine' : 170,
+ 'braceleft' : 123,
+ 'macron' : 175,
+ 'atilde' : 227,
+ 'Acircumflex' : 194,
+ 'Oslash' : 216,
+ 'C' : 67,
+ 'quotedblleft' : 8220,
+ 'S' : 83,
+ 'exclam' : 33,
+ 'Zcaron' : 381,
+ 'equal' : 61,
+ 's' : 115,
+ 'eth' : 240,
+ 'Egrave' : 200,
+ 'hyphen' : 45,
+ 'period' : 46,
+ 'igrave' : 236,
+ 'colon' : 58,
+ 'Ecircumflex' : 202,
+ 'trademark' : 8482,
+ 'Aacute' : 193,
+ 'cent' : 162,
+ 'lslash' : 322,
+ 'c' : 99,
+ 'N' : 78,
+ 'breve' : 728,
+ 'Oacute' : 211,
+ 'guillemotleft' : 171,
+ 'n' : 110,
+ 'idieresis' : 239,
+ 'braceright' : 125,
+ 'seven' : 55,
+ 'brokenbar' : 166,
+ 'ugrave' : 249,
+ 'periodcentered' : 183,
+ 'sterling' : 163,
+ 'I' : 73,
+ 'Y' : 89,
+ 'Eth' : 208,
+ 'emdash' : 8212,
+ 'i' : 105,
+ 'daggerdbl' : 8225,
+ 'y' : 121,
+ 'plusminus' : 177,
+ 'less' : 60,
+ 'Udieresis' : 220,
+ 'D' : 68,
+ 'five' : 53,
+ 'T' : 84,
+ 'oslash' : 248,
+ 'acute' : 180,
+ 'd' : 100,
+ 'OE' : 338,
+ 'Igrave' : 204,
+ 't' : 116,
+ 'parenright' : 41,
+ 'adieresis' : 228,
+ 'quotesingle' : 39,
+ 'twodotenleader' : 8229,
+ 'slash' : 47,
+ 'ellipsis' : 8230,
+ 'numbersign' : 35,
+ 'odieresis' : 246,
+ 'O' : 79,
+ 'oe' : 339,
+ 'o' : 111,
+ 'Edieresis' : 203,
+ 'plus' : 43,
+ 'dagger' : 8224,
+ 'three' : 51,
+ 'hungarumlaut' : 733,
+ 'parenleft' : 40,
+ 'fraction' : 8260,
+ 'registered' : 174,
+ 'J' : 74,
+ 'dieresis' : 168,
+ 'Ograve' : 210,
+ 'j' : 106,
+ 'z' : 122,
+ 'ae' : 230,
+ 'semicolon' : 59,
+ 'at' : 64,
+ 'Iacute' : 205,
+ 'percent' : 37,
+ 'bracketright' : 93,
+ 'AE' : 198,
+ 'asterisk' : 42,
+ 'aacute' : 225,
+ 'U' : 85,
+ 'eacute' : 233,
+ 'e' : 101,
+ 'thorn' : 254,
+ 'u' : 117,
+}
+
+uni2type1 = {v: k for k, v in type12uni.items()}
+
+# The script below is to sort and format the tex2uni dict
+
+## For decimal values: int(hex(v), 16)
+# newtex = {k: hex(v) for k, v in tex2uni.items()}
+# sd = dict(sorted(newtex.items(), key=lambda item: item[0]))
+#
+## For formatting the sorted dictionary with proper spacing
+## the value '24' comes from finding the longest string in
+## the newtex keys with len(max(newtex, key=len))
+# for key in sd:
+# print("{0:24} : {1: _EntryTypeOut: ...
+
+
+@overload
+def _normalize_stix_fontcodes(d: list[_EntryTypeIn]) -> list[_EntryTypeOut]: ...
+
+
+@overload
+def _normalize_stix_fontcodes(d: dict[str, list[_EntryTypeIn] |
+ dict[str, list[_EntryTypeIn]]]
+ ) -> dict[str, list[_EntryTypeOut] |
+ dict[str, list[_EntryTypeOut]]]: ...
+
+
+def _normalize_stix_fontcodes(d):
+ if isinstance(d, tuple):
+ return tuple(ord(x) if isinstance(x, str) and len(x) == 1 else x for x in d)
+ elif isinstance(d, list):
+ return [_normalize_stix_fontcodes(x) for x in d]
+ elif isinstance(d, dict):
+ return {k: _normalize_stix_fontcodes(v) for k, v in d.items()}
+
+
+stix_virtual_fonts: dict[str, dict[str, list[_EntryTypeOut]] | list[_EntryTypeOut]]
+stix_virtual_fonts = _normalize_stix_fontcodes(_stix_virtual_fonts)
+
+# Free redundant list now that it has been normalized
+del _stix_virtual_fonts
+
+# Fix some incorrect glyphs.
+stix_glyph_fixes = {
+ # Cap and Cup glyphs are swapped.
+ 0x22d2: 0x22d3,
+ 0x22d3: 0x22d2,
+}
diff --git a/lib/python3.12/site-packages/matplotlib/_pylab_helpers.py b/lib/python3.12/site-packages/matplotlib/_pylab_helpers.py
new file mode 100644
index 0000000000000000000000000000000000000000..a3861aef592008a84ffddadb7a0c76c8833a30af
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_pylab_helpers.py
@@ -0,0 +1,134 @@
+"""
+Manage figures for the pyplot interface.
+"""
+
+import atexit
+from collections import OrderedDict
+
+
+class Gcf:
+ """
+ Singleton to maintain the relation between figures and their managers, and
+ keep track of and "active" figure and manager.
+
+ The canvas of a figure created through pyplot is associated with a figure
+ manager, which handles the interaction between the figure and the backend.
+ pyplot keeps track of figure managers using an identifier, the "figure
+ number" or "manager number" (which can actually be any hashable value);
+ this number is available as the :attr:`number` attribute of the manager.
+
+ This class is never instantiated; it consists of an `OrderedDict` mapping
+ figure/manager numbers to managers, and a set of class methods that
+ manipulate this `OrderedDict`.
+
+ Attributes
+ ----------
+ figs : OrderedDict
+ `OrderedDict` mapping numbers to managers; the active manager is at the
+ end.
+ """
+
+ figs = OrderedDict()
+
+ @classmethod
+ def get_fig_manager(cls, num):
+ """
+ If manager number *num* exists, make it the active one and return it;
+ otherwise return *None*.
+ """
+ manager = cls.figs.get(num, None)
+ if manager is not None:
+ cls.set_active(manager)
+ return manager
+
+ @classmethod
+ def destroy(cls, num):
+ """
+ Destroy manager *num* -- either a manager instance or a manager number.
+
+ In the interactive backends, this is bound to the window "destroy" and
+ "delete" events.
+
+ It is recommended to pass a manager instance, to avoid confusion when
+ two managers share the same number.
+ """
+ if all(hasattr(num, attr) for attr in ["num", "destroy"]):
+ manager = num
+ if cls.figs.get(manager.num) is manager:
+ cls.figs.pop(manager.num)
+ else:
+ try:
+ manager = cls.figs.pop(num)
+ except KeyError:
+ return
+ if hasattr(manager, "_cidgcf"):
+ manager.canvas.mpl_disconnect(manager._cidgcf)
+ manager.destroy()
+
+ @classmethod
+ def destroy_fig(cls, fig):
+ """Destroy figure *fig*."""
+ num = next((manager.num for manager in cls.figs.values()
+ if manager.canvas.figure == fig), None)
+ if num is not None:
+ cls.destroy(num)
+
+ @classmethod
+ def destroy_all(cls):
+ """Destroy all figures."""
+ for manager in list(cls.figs.values()):
+ manager.canvas.mpl_disconnect(manager._cidgcf)
+ manager.destroy()
+ cls.figs.clear()
+
+ @classmethod
+ def has_fignum(cls, num):
+ """Return whether figure number *num* exists."""
+ return num in cls.figs
+
+ @classmethod
+ def get_all_fig_managers(cls):
+ """Return a list of figure managers."""
+ return list(cls.figs.values())
+
+ @classmethod
+ def get_num_fig_managers(cls):
+ """Return the number of figures being managed."""
+ return len(cls.figs)
+
+ @classmethod
+ def get_active(cls):
+ """Return the active manager, or *None* if there is no manager."""
+ return next(reversed(cls.figs.values())) if cls.figs else None
+
+ @classmethod
+ def _set_new_active_manager(cls, manager):
+ """Adopt *manager* into pyplot and make it the active manager."""
+ if not hasattr(manager, "_cidgcf"):
+ manager._cidgcf = manager.canvas.mpl_connect(
+ "button_press_event", lambda event: cls.set_active(manager))
+ fig = manager.canvas.figure
+ fig._number = manager.num
+ label = fig.get_label()
+ if label:
+ manager.set_window_title(label)
+ cls.set_active(manager)
+
+ @classmethod
+ def set_active(cls, manager):
+ """Make *manager* the active manager."""
+ cls.figs[manager.num] = manager
+ cls.figs.move_to_end(manager.num)
+
+ @classmethod
+ def draw_all(cls, force=False):
+ """
+ Redraw all stale managed figures, or, if *force* is True, all managed
+ figures.
+ """
+ for manager in cls.get_all_fig_managers():
+ if force or manager.canvas.figure.stale:
+ manager.canvas.draw_idle()
+
+
+atexit.register(Gcf.destroy_all)
diff --git a/lib/python3.12/site-packages/matplotlib/_pylab_helpers.pyi b/lib/python3.12/site-packages/matplotlib/_pylab_helpers.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..bdd8cfba3173030b37b24af412970cbb62fee3ef
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_pylab_helpers.pyi
@@ -0,0 +1,29 @@
+from collections import OrderedDict
+
+from matplotlib.backend_bases import FigureManagerBase
+from matplotlib.figure import Figure
+
+class Gcf:
+ figs: OrderedDict[int, FigureManagerBase]
+ @classmethod
+ def get_fig_manager(cls, num: int) -> FigureManagerBase | None: ...
+ @classmethod
+ def destroy(cls, num: int | FigureManagerBase) -> None: ...
+ @classmethod
+ def destroy_fig(cls, fig: Figure) -> None: ...
+ @classmethod
+ def destroy_all(cls) -> None: ...
+ @classmethod
+ def has_fignum(cls, num: int) -> bool: ...
+ @classmethod
+ def get_all_fig_managers(cls) -> list[FigureManagerBase]: ...
+ @classmethod
+ def get_num_fig_managers(cls) -> int: ...
+ @classmethod
+ def get_active(cls) -> FigureManagerBase | None: ...
+ @classmethod
+ def _set_new_active_manager(cls, manager: FigureManagerBase) -> None: ...
+ @classmethod
+ def set_active(cls, manager: FigureManagerBase) -> None: ...
+ @classmethod
+ def draw_all(cls, force: bool = ...) -> None: ...
diff --git a/lib/python3.12/site-packages/matplotlib/_text_helpers.py b/lib/python3.12/site-packages/matplotlib/_text_helpers.py
new file mode 100644
index 0000000000000000000000000000000000000000..b9603b114bc245ecf32da926573ddb4157210c7a
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_text_helpers.py
@@ -0,0 +1,82 @@
+"""
+Low-level text helper utilities.
+"""
+
+from __future__ import annotations
+
+import dataclasses
+
+from . import _api
+from .ft2font import FT2Font, Kerning, LoadFlags
+
+
+@dataclasses.dataclass(frozen=True)
+class LayoutItem:
+ ft_object: FT2Font
+ char: str
+ glyph_idx: int
+ x: float
+ prev_kern: float
+
+
+def warn_on_missing_glyph(codepoint, fontnames):
+ _api.warn_external(
+ f"Glyph {codepoint} "
+ f"({chr(codepoint).encode('ascii', 'namereplace').decode('ascii')}) "
+ f"missing from font(s) {fontnames}.")
+
+ block = ("Hebrew" if 0x0590 <= codepoint <= 0x05ff else
+ "Arabic" if 0x0600 <= codepoint <= 0x06ff else
+ "Devanagari" if 0x0900 <= codepoint <= 0x097f else
+ "Bengali" if 0x0980 <= codepoint <= 0x09ff else
+ "Gurmukhi" if 0x0a00 <= codepoint <= 0x0a7f else
+ "Gujarati" if 0x0a80 <= codepoint <= 0x0aff else
+ "Oriya" if 0x0b00 <= codepoint <= 0x0b7f else
+ "Tamil" if 0x0b80 <= codepoint <= 0x0bff else
+ "Telugu" if 0x0c00 <= codepoint <= 0x0c7f else
+ "Kannada" if 0x0c80 <= codepoint <= 0x0cff else
+ "Malayalam" if 0x0d00 <= codepoint <= 0x0d7f else
+ "Sinhala" if 0x0d80 <= codepoint <= 0x0dff else
+ None)
+ if block:
+ _api.warn_external(
+ f"Matplotlib currently does not support {block} natively.")
+
+
+def layout(string, font, *, kern_mode=Kerning.DEFAULT):
+ """
+ Render *string* with *font*.
+
+ For each character in *string*, yield a LayoutItem instance. When such an instance
+ is yielded, the font's glyph is set to the corresponding character.
+
+ Parameters
+ ----------
+ string : str
+ The string to be rendered.
+ font : FT2Font
+ The font.
+ kern_mode : Kerning
+ A FreeType kerning mode.
+
+ Yields
+ ------
+ LayoutItem
+ """
+ x = 0
+ prev_glyph_idx = None
+ char_to_font = font._get_fontmap(string)
+ base_font = font
+ for char in string:
+ # This has done the fallback logic
+ font = char_to_font.get(char, base_font)
+ glyph_idx = font.get_char_index(ord(char))
+ kern = (
+ base_font.get_kerning(prev_glyph_idx, glyph_idx, kern_mode) / 64
+ if prev_glyph_idx is not None else 0.
+ )
+ x += kern
+ glyph = font.load_glyph(glyph_idx, flags=LoadFlags.NO_HINTING)
+ yield LayoutItem(font, char, glyph_idx, x, kern)
+ x += glyph.linearHoriAdvance / 65536
+ prev_glyph_idx = glyph_idx
diff --git a/lib/python3.12/site-packages/matplotlib/_tight_bbox.py b/lib/python3.12/site-packages/matplotlib/_tight_bbox.py
new file mode 100644
index 0000000000000000000000000000000000000000..db72bbdff020680dfd833229cac41e9b33e428ee
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_tight_bbox.py
@@ -0,0 +1,84 @@
+"""
+Helper module for the *bbox_inches* parameter in `.Figure.savefig`.
+"""
+
+from matplotlib.transforms import Bbox, TransformedBbox, Affine2D
+
+
+def adjust_bbox(fig, bbox_inches, fixed_dpi=None):
+ """
+ Temporarily adjust the figure so that only the specified area
+ (bbox_inches) is saved.
+
+ It modifies fig.bbox, fig.bbox_inches,
+ fig.transFigure._boxout, and fig.patch. While the figure size
+ changes, the scale of the original figure is conserved. A
+ function which restores the original values are returned.
+ """
+ origBbox = fig.bbox
+ origBboxInches = fig.bbox_inches
+ _boxout = fig.transFigure._boxout
+
+ old_aspect = []
+ locator_list = []
+ sentinel = object()
+ for ax in fig.axes:
+ locator = ax.get_axes_locator()
+ if locator is not None:
+ ax.apply_aspect(locator(ax, None))
+ locator_list.append(locator)
+ current_pos = ax.get_position(original=False).frozen()
+ ax.set_axes_locator(lambda a, r, _pos=current_pos: _pos)
+ # override the method that enforces the aspect ratio on the Axes
+ if 'apply_aspect' in ax.__dict__:
+ old_aspect.append(ax.apply_aspect)
+ else:
+ old_aspect.append(sentinel)
+ ax.apply_aspect = lambda pos=None: None
+
+ def restore_bbox():
+ for ax, loc, aspect in zip(fig.axes, locator_list, old_aspect):
+ ax.set_axes_locator(loc)
+ if aspect is sentinel:
+ # delete our no-op function which un-hides the original method
+ del ax.apply_aspect
+ else:
+ ax.apply_aspect = aspect
+
+ fig.bbox = origBbox
+ fig.bbox_inches = origBboxInches
+ fig.transFigure._boxout = _boxout
+ fig.transFigure.invalidate()
+ fig.patch.set_bounds(0, 0, 1, 1)
+
+ if fixed_dpi is None:
+ fixed_dpi = fig.dpi
+ tr = Affine2D().scale(fixed_dpi)
+ dpi_scale = fixed_dpi / fig.dpi
+
+ fig.bbox_inches = Bbox.from_bounds(0, 0, *bbox_inches.size)
+ x0, y0 = tr.transform(bbox_inches.p0)
+ w1, h1 = fig.bbox.size * dpi_scale
+ fig.transFigure._boxout = Bbox.from_bounds(-x0, -y0, w1, h1)
+ fig.transFigure.invalidate()
+
+ fig.bbox = TransformedBbox(fig.bbox_inches, tr)
+
+ fig.patch.set_bounds(x0 / w1, y0 / h1,
+ fig.bbox.width / w1, fig.bbox.height / h1)
+
+ return restore_bbox
+
+
+def process_figure_for_rasterizing(fig, bbox_inches_restore, fixed_dpi=None):
+ """
+ A function that needs to be called when figure dpi changes during the
+ drawing (e.g., rasterizing). It recovers the bbox and re-adjust it with
+ the new dpi.
+ """
+
+ bbox_inches, restore_bbox = bbox_inches_restore
+ restore_bbox()
+ r = adjust_bbox(fig, bbox_inches, fixed_dpi)
+
+ return bbox_inches, r
diff --git a/lib/python3.12/site-packages/matplotlib/_tri.pyi b/lib/python3.12/site-packages/matplotlib/_tri.pyi
new file mode 100644
index 0000000000000000000000000000000000000000..a0c710fc2309fbfac3f37297eda919d86de32c76
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_tri.pyi
@@ -0,0 +1,36 @@
+# This is a private module implemented in C++
+from typing import final
+
+import numpy as np
+import numpy.typing as npt
+
+@final
+class TrapezoidMapTriFinder:
+ def __init__(self, triangulation: Triangulation): ...
+ def find_many(self, x: npt.NDArray[np.float64], y: npt.NDArray[np.float64]) -> npt.NDArray[np.int_]: ...
+ def get_tree_stats(self) -> list[int | float]: ...
+ def initialize(self) -> None: ...
+ def print_tree(self) -> None: ...
+
+@final
+class TriContourGenerator:
+ def __init__(self, triangulation: Triangulation, z: npt.NDArray[np.float64]): ...
+ def create_contour(self, level: float) -> tuple[list[float], list[int]]: ...
+ def create_filled_contour(self, lower_level: float, upper_level: float) -> tuple[list[float], list[int]]: ...
+
+@final
+class Triangulation:
+ def __init__(
+ self,
+ x: npt.NDArray[np.float64],
+ y: npt.NDArray[np.float64],
+ triangles: npt.NDArray[np.int_],
+ mask: npt.NDArray[np.bool_] | tuple[()],
+ edges: npt.NDArray[np.int_] | tuple[()],
+ neighbors: npt.NDArray[np.int_] | tuple[()],
+ correct_triangle_orientation: bool,
+ ): ...
+ def calculate_plane_coefficients(self, z: npt.ArrayLike) -> npt.NDArray[np.float64]: ...
+ def get_edges(self) -> npt.NDArray[np.int_]: ...
+ def get_neighbors(self) -> npt.NDArray[np.int_]: ...
+ def set_mask(self, mask: npt.NDArray[np.bool_] | tuple[()]) -> None: ...
diff --git a/lib/python3.12/site-packages/matplotlib/_version.py b/lib/python3.12/site-packages/matplotlib/_version.py
new file mode 100644
index 0000000000000000000000000000000000000000..90807445c956c6ca454fbac2a45b1112f59030be
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/_version.py
@@ -0,0 +1 @@
+version = "3.10.3"
diff --git a/lib/python3.12/site-packages/matplotlib/animation.py b/lib/python3.12/site-packages/matplotlib/animation.py
new file mode 100644
index 0000000000000000000000000000000000000000..a87f002011249f353bd740363e55a0d32c62bc38
--- /dev/null
+++ b/lib/python3.12/site-packages/matplotlib/animation.py
@@ -0,0 +1,1823 @@
+import abc
+import base64
+import contextlib
+from io import BytesIO, TextIOWrapper
+import itertools
+import logging
+from pathlib import Path
+import shutil
+import subprocess
+import sys
+from tempfile import TemporaryDirectory
+import uuid
+import warnings
+
+import numpy as np
+from PIL import Image
+
+import matplotlib as mpl
+from matplotlib._animation_data import (
+ DISPLAY_TEMPLATE, INCLUDED_FRAMES, JS_INCLUDE, STYLE_INCLUDE)
+from matplotlib import _api, cbook
+import matplotlib.colors as mcolors
+
+_log = logging.getLogger(__name__)
+
+# Process creation flag for subprocess to prevent it raising a terminal
+# window. See for example https://stackoverflow.com/q/24130623/
+subprocess_creation_flags = (
+ subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0)
+
+
+def adjusted_figsize(w, h, dpi, n):
+ """
+ Compute figure size so that pixels are a multiple of n.
+
+ Parameters
+ ----------
+ w, h : float
+ Size in inches.
+
+ dpi : float
+ The dpi.
+
+ n : int
+ The target multiple.
+
+ Returns
+ -------
+ wnew, hnew : float
+ The new figure size in inches.
+ """
+
+ # this maybe simplified if / when we adopt consistent rounding for
+ # pixel size across the whole library
+ def correct_roundoff(x, dpi, n):
+ if int(x*dpi) % n != 0:
+ if int(np.nextafter(x, np.inf)*dpi) % n == 0:
+ x = np.nextafter(x, np.inf)
+ elif int(np.nextafter(x, -np.inf)*dpi) % n == 0:
+ x = np.nextafter(x, -np.inf)
+ return x
+
+ wnew = int(w * dpi / n) * n / dpi
+ hnew = int(h * dpi / n) * n / dpi
+ return correct_roundoff(wnew, dpi, n), correct_roundoff(hnew, dpi, n)
+
+
+class MovieWriterRegistry:
+ """Registry of available writer classes by human readable name."""
+
+ def __init__(self):
+ self._registered = dict()
+
+ def register(self, name):
+ """
+ Decorator for registering a class under a name.
+
+ Example use::
+
+ @registry.register(name)
+ class Foo:
+ pass
+ """
+ def wrapper(writer_cls):
+ self._registered[name] = writer_cls
+ return writer_cls
+ return wrapper
+
+ def is_available(self, name):
+ """
+ Check if given writer is available by name.
+
+ Parameters
+ ----------
+ name : str
+
+ Returns
+ -------
+ bool
+ """
+ try:
+ cls = self._registered[name]
+ except KeyError:
+ return False
+ return cls.isAvailable()
+
+ def __iter__(self):
+ """Iterate over names of available writer class."""
+ for name in self._registered:
+ if self.is_available(name):
+ yield name
+
+ def list(self):
+ """Get a list of available MovieWriters."""
+ return [*self]
+
+ def __getitem__(self, name):
+ """Get an available writer class from its name."""
+ if self.is_available(name):
+ return self._registered[name]
+ raise RuntimeError(f"Requested MovieWriter ({name}) not available")
+
+
+writers = MovieWriterRegistry()
+
+
+class AbstractMovieWriter(abc.ABC):
+ """
+ Abstract base class for writing movies, providing a way to grab frames by
+ calling `~AbstractMovieWriter.grab_frame`.
+
+ `setup` is called to start the process and `finish` is called afterwards.
+ `saving` is provided as a context manager to facilitate this process as ::
+
+ with moviewriter.saving(fig, outfile='myfile.mp4', dpi=100):
+ # Iterate over frames
+ moviewriter.grab_frame(**savefig_kwargs)
+
+ The use of the context manager ensures that `setup` and `finish` are
+ performed as necessary.
+
+ An instance of a concrete subclass of this class can be given as the
+ ``writer`` argument of `Animation.save()`.
+ """
+
+ def __init__(self, fps=5, metadata=None, codec=None, bitrate=None):
+ self.fps = fps
+ self.metadata = metadata if metadata is not None else {}
+ self.codec = mpl._val_or_rc(codec, 'animation.codec')
+ self.bitrate = mpl._val_or_rc(bitrate, 'animation.bitrate')
+
+ @abc.abstractmethod
+ def setup(self, fig, outfile, dpi=None):
+ """
+ Setup for writing the movie file.
+
+ Parameters
+ ----------
+ fig : `~matplotlib.figure.Figure`
+ The figure object that contains the information for frames.
+ outfile : str
+ The filename of the resulting movie file.
+ dpi : float, default: ``fig.dpi``
+ The DPI (or resolution) for the file. This controls the size
+ in pixels of the resulting movie file.
+ """
+ # Check that path is valid
+ Path(outfile).parent.resolve(strict=True)
+ self.outfile = outfile
+ self.fig = fig
+ if dpi is None:
+ dpi = self.fig.dpi
+ self.dpi = dpi
+
+ @property
+ def frame_size(self):
+ """A tuple ``(width, height)`` in pixels of a movie frame."""
+ w, h = self.fig.get_size_inches()
+ return int(w * self.dpi), int(h * self.dpi)
+
+ def _supports_transparency(self):
+ """
+ Whether this writer supports transparency.
+
+ Writers may consult output file type and codec to determine this at runtime.
+ """
+ return False
+
+ @abc.abstractmethod
+ def grab_frame(self, **savefig_kwargs):
+ """
+ Grab the image information from the figure and save as a movie frame.
+
+ All keyword arguments in *savefig_kwargs* are passed on to the
+ `~.Figure.savefig` call that saves the figure. However, several
+ keyword arguments that are supported by `~.Figure.savefig` may not be
+ passed as they are controlled by the MovieWriter:
+
+ - *dpi*, *bbox_inches*: These may not be passed because each frame of the
+ animation much be exactly the same size in pixels.
+ - *format*: This is controlled by the MovieWriter.
+ """
+
+ @abc.abstractmethod
+ def finish(self):
+ """Finish any processing for writing the movie."""
+
+ @contextlib.contextmanager
+ def saving(self, fig, outfile, dpi, *args, **kwargs):
+ """
+ Context manager to facilitate writing the movie file.
+
+ ``*args, **kw`` are any parameters that should be passed to `setup`.
+ """
+ if mpl.rcParams['savefig.bbox'] == 'tight':
+ _log.info("Disabling savefig.bbox = 'tight', as it may cause "
+ "frame size to vary, which is inappropriate for "
+ "animation.")
+
+ # This particular sequence is what contextlib.contextmanager wants
+ self.setup(fig, outfile, dpi, *args, **kwargs)
+ with mpl.rc_context({'savefig.bbox': None}):
+ try:
+ yield self
+ finally:
+ self.finish()
+
+
+class MovieWriter(AbstractMovieWriter):
+ """
+ Base class for writing movies.
+
+ This is a base class for MovieWriter subclasses that write a movie frame
+ data to a pipe. You cannot instantiate this class directly.
+ See examples for how to use its subclasses.
+
+ Attributes
+ ----------
+ frame_format : str
+ The format used in writing frame data, defaults to 'rgba'.
+ fig : `~matplotlib.figure.Figure`
+ The figure to capture data from.
+ This must be provided by the subclasses.
+ """
+
+ # Builtin writer subclasses additionally define the _exec_key and _args_key
+ # attributes, which indicate the rcParams entries where the path to the
+ # executable and additional command-line arguments to the executable are
+ # stored. Third-party writers cannot meaningfully set these as they cannot
+ # extend rcParams with new keys.
+
+ # Pipe-based writers only support RGBA, but file-based ones support more
+ # formats.
+ supported_formats = ["rgba"]
+
+ def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None,
+ metadata=None):
+ """
+ Parameters
+ ----------
+ fps : int, default: 5
+ Movie frame rate (per second).
+ codec : str or None, default: :rc:`animation.codec`
+ The codec to use.
+ bitrate : int, default: :rc:`animation.bitrate`
+ The bitrate of the movie, in kilobits per second. Higher values
+ means higher quality movies, but increase the file size. A value
+ of -1 lets the underlying movie encoder select the bitrate.
+ extra_args : list of str or None, optional
+ Extra command-line arguments passed to the underlying movie encoder. These
+ arguments are passed last to the encoder, just before the filename. The
+ default, None, means to use :rc:`animation.[name-of-encoder]_args` for the
+ builtin writers.
+ metadata : dict[str, str], default: {}
+ A dictionary of keys and values for metadata to include in the
+ output file. Some keys that may be of use include:
+ title, artist, genre, subject, copyright, srcform, comment.
+ """
+ if type(self) is MovieWriter:
+ # TODO MovieWriter is still an abstract class and needs to be
+ # extended with a mixin. This should be clearer in naming
+ # and description. For now, just give a reasonable error
+ # message to users.
+ raise TypeError(
+ 'MovieWriter cannot be instantiated directly. Please use one '
+ 'of its subclasses.')
+
+ super().__init__(fps=fps, metadata=metadata, codec=codec,
+ bitrate=bitrate)
+ self.frame_format = self.supported_formats[0]
+ self.extra_args = extra_args
+
+ def _adjust_frame_size(self):
+ if self.codec == 'h264':
+ wo, ho = self.fig.get_size_inches()
+ w, h = adjusted_figsize(wo, ho, self.dpi, 2)
+ if (wo, ho) != (w, h):
+ self.fig.set_size_inches(w, h, forward=True)
+ _log.info('figure size in inches has been adjusted '
+ 'from %s x %s to %s x %s', wo, ho, w, h)
+ else:
+ w, h = self.fig.get_size_inches()
+ _log.debug('frame size in pixels is %s x %s', *self.frame_size)
+ return w, h
+
+ def setup(self, fig, outfile, dpi=None):
+ # docstring inherited
+ super().setup(fig, outfile, dpi=dpi)
+ self._w, self._h = self._adjust_frame_size()
+ # Run here so that grab_frame() can write the data to a pipe. This
+ # eliminates the need for temp files.
+ self._run()
+
+ def _run(self):
+ # Uses subprocess to call the program for assembling frames into a
+ # movie file. *args* returns the sequence of command line arguments
+ # from a few configuration options.
+ command = self._args()
+ _log.info('MovieWriter._run: running command: %s',
+ cbook._pformat_subprocess(command))
+ PIPE = subprocess.PIPE
+ self._proc = subprocess.Popen(
+ command, stdin=PIPE, stdout=PIPE, stderr=PIPE,
+ creationflags=subprocess_creation_flags)
+
+ def finish(self):
+ """Finish any processing for writing the movie."""
+ out, err = self._proc.communicate()
+ # Use the encoding/errors that universal_newlines would use.
+ out = TextIOWrapper(BytesIO(out)).read()
+ err = TextIOWrapper(BytesIO(err)).read()
+ if out:
+ _log.log(
+ logging.WARNING if self._proc.returncode else logging.DEBUG,
+ "MovieWriter stdout:\n%s", out)
+ if err:
+ _log.log(
+ logging.WARNING if self._proc.returncode else logging.DEBUG,
+ "MovieWriter stderr:\n%s", err)
+ if self._proc.returncode:
+ raise subprocess.CalledProcessError(
+ self._proc.returncode, self._proc.args, out, err)
+
+ def grab_frame(self, **savefig_kwargs):
+ # docstring inherited
+ _validate_grabframe_kwargs(savefig_kwargs)
+ _log.debug('MovieWriter.grab_frame: Grabbing frame.')
+ # Readjust the figure size in case it has been changed by the user.
+ # All frames must have the same size to save the movie correctly.
+ self.fig.set_size_inches(self._w, self._h)
+ # Save the figure data to the sink, using the frame format and dpi.
+ self.fig.savefig(self._proc.stdin, format=self.frame_format,
+ dpi=self.dpi, **savefig_kwargs)
+
+ def _args(self):
+ """Assemble list of encoder-specific command-line arguments."""
+ return NotImplementedError("args needs to be implemented by subclass.")
+
+ @classmethod
+ def bin_path(cls):
+ """
+ Return the binary path to the commandline tool used by a specific
+ subclass. This is a class method so that the tool can be looked for
+ before making a particular MovieWriter subclass available.
+ """
+ return str(mpl.rcParams[cls._exec_key])
+
+ @classmethod
+ def isAvailable(cls):
+ """Return whether a MovieWriter subclass is actually available."""
+ return shutil.which(cls.bin_path()) is not None
+
+
+class FileMovieWriter(MovieWriter):
+ """
+ `MovieWriter` for writing to individual files and stitching at the end.
+
+ This must be sub-classed to be useful.
+ """
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.frame_format = mpl.rcParams['animation.frame_format']
+
+ def setup(self, fig, outfile, dpi=None, frame_prefix=None):
+ """
+ Setup for writing the movie file.
+
+ Parameters
+ ----------
+ fig : `~matplotlib.figure.Figure`
+ The figure to grab the rendered frames from.
+ outfile : str
+ The filename of the resulting movie file.
+ dpi : float, default: ``fig.dpi``
+ The dpi of the output file. This, with the figure size,
+ controls the size in pixels of the resulting movie file.
+ frame_prefix : str, optional
+ The filename prefix to use for temporary files. If *None* (the
+ default), files are written to a temporary directory which is
+ deleted by `finish`; if not *None*, no temporary files are
+ deleted.
+ """
+ # Check that path is valid
+ Path(outfile).parent.resolve(strict=True)
+ self.fig = fig
+ self.outfile = outfile
+ if dpi is None:
+ dpi = self.fig.dpi
+ self.dpi = dpi
+ self._adjust_frame_size()
+
+ if frame_prefix is None:
+ self._tmpdir = TemporaryDirectory()
+ self.temp_prefix = str(Path(self._tmpdir.name, 'tmp'))
+ else:
+ self._tmpdir = None
+ self.temp_prefix = frame_prefix
+ self._frame_counter = 0 # used for generating sequential file names
+ self._temp_paths = list()
+ self.fname_format_str = '%s%%07d.%s'
+
+ def __del__(self):
+ if hasattr(self, '_tmpdir') and self._tmpdir:
+ self._tmpdir.cleanup()
+
+ @property
+ def frame_format(self):
+ """
+ Format (png, jpeg, etc.) to use for saving the frames, which can be
+ decided by the individual subclasses.
+ """
+ return self._frame_format
+
+ @frame_format.setter
+ def frame_format(self, frame_format):
+ if frame_format in self.supported_formats:
+ self._frame_format = frame_format
+ else:
+ _api.warn_external(
+ f"Ignoring file format {frame_format!r} which is not "
+ f"supported by {type(self).__name__}; using "
+ f"{self.supported_formats[0]} instead.")
+ self._frame_format = self.supported_formats[0]
+
+ def _base_temp_name(self):
+ # Generates a template name (without number) given the frame format
+ # for extension and the prefix.
+ return self.fname_format_str % (self.temp_prefix, self.frame_format)
+
+ def grab_frame(self, **savefig_kwargs):
+ # docstring inherited
+ # Creates a filename for saving using basename and counter.
+ _validate_grabframe_kwargs(savefig_kwargs)
+ path = Path(self._base_temp_name() % self._frame_counter)
+ self._temp_paths.append(path) # Record the filename for later use.
+ self._frame_counter += 1 # Ensures each created name is unique.
+ _log.debug('FileMovieWriter.grab_frame: Grabbing frame %d to path=%s',
+ self._frame_counter, path)
+ with open(path, 'wb') as sink: # Save figure to the sink.
+ self.fig.savefig(sink, format=self.frame_format, dpi=self.dpi,
+ **savefig_kwargs)
+
+ def finish(self):
+ # Call run here now that all frame grabbing is done. All temp files
+ # are available to be assembled.
+ try:
+ self._run()
+ super().finish()
+ finally:
+ if self._tmpdir:
+ _log.debug(
+ 'MovieWriter: clearing temporary path=%s', self._tmpdir
+ )
+ self._tmpdir.cleanup()
+
+
+@writers.register('pillow')
+class PillowWriter(AbstractMovieWriter):
+ def _supports_transparency(self):
+ return True
+
+ @classmethod
+ def isAvailable(cls):
+ return True
+
+ def setup(self, fig, outfile, dpi=None):
+ super().setup(fig, outfile, dpi=dpi)
+ self._frames = []
+
+ def grab_frame(self, **savefig_kwargs):
+ _validate_grabframe_kwargs(savefig_kwargs)
+ buf = BytesIO()
+ self.fig.savefig(
+ buf, **{**savefig_kwargs, "format": "rgba", "dpi": self.dpi})
+ im = Image.frombuffer(
+ "RGBA", self.frame_size, buf.getbuffer(), "raw", "RGBA", 0, 1)
+ if im.getextrema()[3][0] < 255:
+ # This frame has transparency, so we'll just add it as is.
+ self._frames.append(im)
+ else:
+ # Without transparency, we switch to RGB mode, which converts to P mode a
+ # little better if needed (specifically, this helps with GIF output.)
+ self._frames.append(im.convert("RGB"))
+
+ def finish(self):
+ self._frames[0].save(
+ self.outfile, save_all=True, append_images=self._frames[1:],
+ duration=int(1000 / self.fps), loop=0)
+
+
+# Base class of ffmpeg information. Has the config keys and the common set
+# of arguments that controls the *output* side of things.
+class FFMpegBase:
+ """
+ Mixin class for FFMpeg output.
+
+ This is a base class for the concrete `FFMpegWriter` and `FFMpegFileWriter`
+ classes.
+ """
+
+ _exec_key = 'animation.ffmpeg_path'
+ _args_key = 'animation.ffmpeg_args'
+
+ def _supports_transparency(self):
+ suffix = Path(self.outfile).suffix
+ if suffix in {'.apng', '.avif', '.gif', '.webm', '.webp'}:
+ return True
+ # This list was found by going through `ffmpeg -codecs` for video encoders,
+ # running them with _support_transparency() forced to True, and checking that
+ # the "Pixel format" in Kdenlive included alpha. Note this is not a guarantee
+ # that transparency will work; you may also need to pass `-pix_fmt`, but we
+ # trust the user has done so if they are asking for these formats.
+ return self.codec in {
+ 'apng', 'avrp', 'bmp', 'cfhd', 'dpx', 'ffv1', 'ffvhuff', 'gif', 'huffyuv',
+ 'jpeg2000', 'ljpeg', 'png', 'prores', 'prores_aw', 'prores_ks', 'qtrle',
+ 'rawvideo', 'targa', 'tiff', 'utvideo', 'v408', }
+
+ @property
+ def output_args(self):
+ args = []
+ suffix = Path(self.outfile).suffix
+ if suffix in {'.apng', '.avif', '.gif', '.webm', '.webp'}:
+ self.codec = suffix[1:]
+ else:
+ args.extend(['-vcodec', self.codec])
+ extra_args = (self.extra_args if self.extra_args is not None
+ else mpl.rcParams[self._args_key])
+ # For h264, the default format is yuv444p, which is not compatible
+ # with quicktime (and others). Specifying yuv420p fixes playback on
+ # iOS, as well as HTML5 video in firefox and safari (on both Windows and
+ # macOS). Also fixes internet explorer. This is as of 2015/10/29.
+ if self.codec == 'h264' and '-pix_fmt' not in extra_args:
+ args.extend(['-pix_fmt', 'yuv420p'])
+ # For GIF, we're telling FFmpeg to split the video stream, to generate
+ # a palette, and then use it for encoding.
+ elif self.codec == 'gif' and '-filter_complex' not in extra_args:
+ args.extend(['-filter_complex',
+ 'split [a][b];[a] palettegen [p];[b][p] paletteuse'])
+ # For AVIF, we're telling FFmpeg to split the video stream, extract the alpha,
+ # in order to place it in a secondary stream, as needed by AVIF-in-FFmpeg.
+ elif self.codec == 'avif' and '-filter_complex' not in extra_args:
+ args.extend(['-filter_complex',
+ 'split [rgb][rgba]; [rgba] alphaextract [alpha]',
+ '-map', '[rgb]', '-map', '[alpha]'])
+ if self.bitrate > 0:
+ args.extend(['-b', '%dk' % self.bitrate]) # %dk: bitrate in kbps.
+ for k, v in self.metadata.items():
+ args.extend(['-metadata', f'{k}={v}'])
+ args.extend(extra_args)
+
+ return args + ['-y', self.outfile]
+
+
+# Combine FFMpeg options with pipe-based writing
+@writers.register('ffmpeg')
+class FFMpegWriter(FFMpegBase, MovieWriter):
+ """
+ Pipe-based ffmpeg writer.
+
+ Frames are streamed directly to ffmpeg via a pipe and written in a single pass.
+
+ This effectively works as a slideshow input to ffmpeg with the fps passed as
+ ``-framerate``, so see also `their notes on frame rates`_ for further details.
+
+ .. _their notes on frame rates: https://trac.ffmpeg.org/wiki/Slideshow#Framerates
+ """
+ def _args(self):
+ # Returns the command line parameters for subprocess to use
+ # ffmpeg to create a movie using a pipe.
+ args = [self.bin_path(), '-f', 'rawvideo', '-vcodec', 'rawvideo',
+ '-s', '%dx%d' % self.frame_size, '-pix_fmt', self.frame_format,
+ '-framerate', str(self.fps)]
+ # Logging is quieted because subprocess.PIPE has limited buffer size.
+ # If you have a lot of frames in your animation and set logging to
+ # DEBUG, you will have a buffer overrun.
+ if _log.getEffectiveLevel() > logging.DEBUG:
+ args += ['-loglevel', 'error']
+ args += ['-i', 'pipe:'] + self.output_args
+ return args
+
+
+# Combine FFMpeg options with temp file-based writing
+@writers.register('ffmpeg_file')
+class FFMpegFileWriter(FFMpegBase, FileMovieWriter):
+ """
+ File-based ffmpeg writer.
+
+ Frames are written to temporary files on disk and then stitched together at the end.
+
+ This effectively works as a slideshow input to ffmpeg with the fps passed as
+ ``-framerate``, so see also `their notes on frame rates`_ for further details.
+
+ .. _their notes on frame rates: https://trac.ffmpeg.org/wiki/Slideshow#Framerates
+ """
+ supported_formats = ['png', 'jpeg', 'tiff', 'raw', 'rgba']
+
+ def _args(self):
+ # Returns the command line parameters for subprocess to use
+ # ffmpeg to create a movie using a collection of temp images
+ args = []
+ # For raw frames, we need to explicitly tell ffmpeg the metadata.
+ if self.frame_format in {'raw', 'rgba'}:
+ args += [
+ '-f', 'image2', '-vcodec', 'rawvideo',
+ '-video_size', '%dx%d' % self.frame_size,
+ '-pixel_format', 'rgba',
+ ]
+ args += ['-framerate', str(self.fps), '-i', self._base_temp_name()]
+ if not self._tmpdir:
+ args += ['-frames:v', str(self._frame_counter)]
+ # Logging is quieted because subprocess.PIPE has limited buffer size.
+ # If you have a lot of frames in your animation and set logging to
+ # DEBUG, you will have a buffer overrun.
+ if _log.getEffectiveLevel() > logging.DEBUG:
+ args += ['-loglevel', 'error']
+ return [self.bin_path(), *args, *self.output_args]
+
+
+# Base class for animated GIFs with ImageMagick
+class ImageMagickBase:
+ """
+ Mixin class for ImageMagick output.
+
+ This is a base class for the concrete `ImageMagickWriter` and
+ `ImageMagickFileWriter` classes, which define an ``input_names`` attribute
+ (or property) specifying the input names passed to ImageMagick.
+ """
+
+ _exec_key = 'animation.convert_path'
+ _args_key = 'animation.convert_args'
+
+ def _supports_transparency(self):
+ suffix = Path(self.outfile).suffix
+ return suffix in {'.apng', '.avif', '.gif', '.webm', '.webp'}
+
+ def _args(self):
+ # ImageMagick does not recognize "raw".
+ fmt = "rgba" if self.frame_format == "raw" else self.frame_format
+ extra_args = (self.extra_args if self.extra_args is not None
+ else mpl.rcParams[self._args_key])
+ return [
+ self.bin_path(),
+ "-size", "%ix%i" % self.frame_size,
+ "-depth", "8",
+ "-delay", str(100 / self.fps),
+ "-loop", "0",
+ f"{fmt}:{self.input_names}",
+ *extra_args,
+ self.outfile,
+ ]
+
+ @classmethod
+ def bin_path(cls):
+ binpath = super().bin_path()
+ if binpath == 'convert':
+ binpath = mpl._get_executable_info('magick').executable
+ return binpath
+
+ @classmethod
+ def isAvailable(cls):
+ try:
+ return super().isAvailable()
+ except mpl.ExecutableNotFoundError as _enf:
+ # May be raised by get_executable_info.
+ _log.debug('ImageMagick unavailable due to: %s', _enf)
+ return False
+
+
+# Combine ImageMagick options with pipe-based writing
+@writers.register('imagemagick')
+class ImageMagickWriter(ImageMagickBase, MovieWriter):
+ """
+ Pipe-based animated gif writer.
+
+ Frames are streamed directly to ImageMagick via a pipe and written
+ in a single pass.
+ """
+
+ input_names = "-" # stdin
+
+
+# Combine ImageMagick options with temp file-based writing
+@writers.register('imagemagick_file')
+class ImageMagickFileWriter(ImageMagickBase, FileMovieWriter):
+ """
+ File-based animated gif writer.
+
+ Frames are written to temporary files on disk and then stitched
+ together at the end.
+ """
+
+ supported_formats = ['png', 'jpeg', 'tiff', 'raw', 'rgba']
+ input_names = property(
+ lambda self: f'{self.temp_prefix}*.{self.frame_format}')
+
+
+# Taken directly from jakevdp's JSAnimation package at
+# http://github.com/jakevdp/JSAnimation
+def _included_frames(frame_count, frame_format, frame_dir):
+ return INCLUDED_FRAMES.format(Nframes=frame_count,
+ frame_dir=frame_dir,
+ frame_format=frame_format)
+
+
+def _embedded_frames(frame_list, frame_format):
+ """frame_list should be a list of base64-encoded png files"""
+ if frame_format == 'svg':
+ # Fix MIME type for svg
+ frame_format = 'svg+xml'
+ template = ' frames[{0}] = "data:image/{1};base64,{2}"\n'
+ return "\n" + "".join(
+ template.format(i, frame_format, frame_data.replace('\n', '\\\n'))
+ for i, frame_data in enumerate(frame_list))
+
+
+@writers.register('html')
+class HTMLWriter(FileMovieWriter):
+ """Writer for JavaScript-based HTML movies."""
+
+ supported_formats = ['png', 'jpeg', 'tiff', 'svg']
+
+ @classmethod
+ def isAvailable(cls):
+ return True
+
+ def __init__(self, fps=30, codec=None, bitrate=None, extra_args=None,
+ metadata=None, embed_frames=False, default_mode='loop',
+ embed_limit=None):
+
+ if extra_args:
+ _log.warning("HTMLWriter ignores 'extra_args'")
+ extra_args = () # Don't lookup nonexistent rcParam[args_key].
+ self.embed_frames = embed_frames
+ self.default_mode = default_mode.lower()
+ _api.check_in_list(['loop', 'once', 'reflect'],
+ default_mode=self.default_mode)
+
+ # Save embed limit, which is given in MB
+ self._bytes_limit = mpl._val_or_rc(embed_limit, 'animation.embed_limit')
+ # Convert from MB to bytes
+ self._bytes_limit *= 1024 * 1024
+
+ super().__init__(fps, codec, bitrate, extra_args, metadata)
+
+ def setup(self, fig, outfile, dpi=None, frame_dir=None):
+ outfile = Path(outfile)
+ _api.check_in_list(['.html', '.htm'], outfile_extension=outfile.suffix)
+
+ self._saved_frames = []
+ self._total_bytes = 0
+ self._hit_limit = False
+
+ if not self.embed_frames:
+ if frame_dir is None:
+ frame_dir = outfile.with_name(outfile.stem + '_frames')
+ frame_dir.mkdir(parents=True, exist_ok=True)
+ frame_prefix = frame_dir / 'frame'
+ else:
+ frame_prefix = None
+
+ super().setup(fig, outfile, dpi, frame_prefix)
+ self._clear_temp = False
+
+ def grab_frame(self, **savefig_kwargs):
+ _validate_grabframe_kwargs(savefig_kwargs)
+ if self.embed_frames:
+ # Just stop processing if we hit the limit
+ if self._hit_limit:
+ return
+ f = BytesIO()
+ self.fig.savefig(f, format=self.frame_format,
+ dpi=self.dpi, **savefig_kwargs)
+ imgdata64 = base64.encodebytes(f.getvalue()).decode('ascii')
+ self._total_bytes += len(imgdata64)
+ if self._total_bytes >= self._bytes_limit:
+ _log.warning(
+ "Animation size has reached %s bytes, exceeding the limit "
+ "of %s. If you're sure you want a larger animation "
+ "embedded, set the animation.embed_limit rc parameter to "
+ "a larger value (in MB). This and further frames will be "
+ "dropped.", self._total_bytes, self._bytes_limit)
+ self._hit_limit = True
+ else:
+ self._saved_frames.append(imgdata64)
+ else:
+ return super().grab_frame(**savefig_kwargs)
+
+ def finish(self):
+ # save the frames to an html file
+ if self.embed_frames:
+ fill_frames = _embedded_frames(self._saved_frames,
+ self.frame_format)
+ frame_count = len(self._saved_frames)
+ else:
+ # temp names is filled by FileMovieWriter
+ frame_count = len(self._temp_paths)
+ fill_frames = _included_frames(
+ frame_count, self.frame_format,
+ self._temp_paths[0].parent.relative_to(self.outfile.parent))
+ mode_dict = dict(once_checked='',
+ loop_checked='',
+ reflect_checked='')
+ mode_dict[self.default_mode + '_checked'] = 'checked'
+
+ interval = 1000 // self.fps
+
+ with open(self.outfile, 'w') as of:
+ of.write(JS_INCLUDE + STYLE_INCLUDE)
+ of.write(DISPLAY_TEMPLATE.format(id=uuid.uuid4().hex,
+ Nframes=frame_count,
+ fill_frames=fill_frames,
+ interval=interval,
+ **mode_dict))
+
+ # Duplicate the temporary file clean up logic from
+ # FileMovieWriter.finish. We cannot call the inherited version of
+ # finish because it assumes that there is a subprocess that we either
+ # need to call to merge many frames together or that there is a
+ # subprocess call that we need to clean up.
+ if self._tmpdir:
+ _log.debug('MovieWriter: clearing temporary path=%s', self._tmpdir)
+ self._tmpdir.cleanup()
+
+
+class Animation:
+ """
+ A base class for Animations.
+
+ This class is not usable as is, and should be subclassed to provide needed
+ behavior.
+
+ .. note::
+
+ You must store the created Animation in a variable that lives as long
+ as the animation should run. Otherwise, the Animation object will be
+ garbage-collected and the animation stops.
+
+ Parameters
+ ----------
+ fig : `~matplotlib.figure.Figure`
+ The figure object used to get needed events, such as draw or resize.
+
+ event_source : object, optional
+ A class that can run a callback when desired events
+ are generated, as well as be stopped and started.
+
+ Examples include timers (see `TimedAnimation`) and file
+ system notifications.
+
+ blit : bool, default: False
+ Whether blitting is used to optimize drawing. If the backend does not
+ support blitting, then this parameter has no effect.
+
+ See Also
+ --------
+ FuncAnimation, ArtistAnimation
+ """
+
+ def __init__(self, fig, event_source=None, blit=False):
+ self._draw_was_started = False
+
+ self._fig = fig
+ # Disables blitting for backends that don't support it. This
+ # allows users to request it if available, but still have a
+ # fallback that works if it is not.
+ self._blit = blit and fig.canvas.supports_blit
+
+ # These are the basics of the animation. The frame sequence represents
+ # information for each frame of the animation and depends on how the
+ # drawing is handled by the subclasses. The event source fires events
+ # that cause the frame sequence to be iterated.
+ self.frame_seq = self.new_frame_seq()
+ self.event_source = event_source
+
+ # Instead of starting the event source now, we connect to the figure's
+ # draw_event, so that we only start once the figure has been drawn.
+ self._first_draw_id = fig.canvas.mpl_connect('draw_event', self._start)
+
+ # Connect to the figure's close_event so that we don't continue to
+ # fire events and try to draw to a deleted figure.
+ self._close_id = self._fig.canvas.mpl_connect('close_event',
+ self._stop)
+ if self._blit:
+ self._setup_blit()
+
+ def __del__(self):
+ if not getattr(self, '_draw_was_started', True):
+ warnings.warn(
+ 'Animation was deleted without rendering anything. This is '
+ 'most likely not intended. To prevent deletion, assign the '
+ 'Animation to a variable, e.g. `anim`, that exists until you '
+ 'output the Animation using `plt.show()` or '
+ '`anim.save()`.'
+ )
+
+ def _start(self, *args):
+ """
+ Starts interactive animation. Adds the draw frame command to the GUI
+ handler, calls show to start the event loop.
+ """
+ # Do not start the event source if saving() it.
+ if self._fig.canvas.is_saving():
+ return
+ # First disconnect our draw event handler
+ self._fig.canvas.mpl_disconnect(self._first_draw_id)
+
+ # Now do any initial draw
+ self._init_draw()
+
+ # Add our callback for stepping the animation and
+ # actually start the event_source.
+ self.event_source.add_callback(self._step)
+ self.event_source.start()
+
+ def _stop(self, *args):
+ # On stop we disconnect all of our events.
+ if self._blit:
+ self._fig.canvas.mpl_disconnect(self._resize_id)
+ self._fig.canvas.mpl_disconnect(self._close_id)
+ self.event_source.remove_callback(self._step)
+ self.event_source = None
+
+ def save(self, filename, writer=None, fps=None, dpi=None, codec=None,
+ bitrate=None, extra_args=None, metadata=None, extra_anim=None,
+ savefig_kwargs=None, *, progress_callback=None):
+ """
+ Save the animation as a movie file by drawing every frame.
+
+ Parameters
+ ----------
+ filename : str
+ The output filename, e.g., :file:`mymovie.mp4`.
+
+ writer : `MovieWriter` or str, default: :rc:`animation.writer`
+ A `MovieWriter` instance to use or a key that identifies a
+ class to use, such as 'ffmpeg'.
+
+ fps : int, optional
+ Movie frame rate (per second). If not set, the frame rate from the
+ animation's frame interval.
+
+ dpi : float, default: :rc:`savefig.dpi`
+ Controls the dots per inch for the movie frames. Together with
+ the figure's size in inches, this controls the size of the movie.
+
+ codec : str, default: :rc:`animation.codec`.
+ The video codec to use. Not all codecs are supported by a given
+ `MovieWriter`.
+
+ bitrate : int, default: :rc:`animation.bitrate`
+ The bitrate of the movie, in kilobits per second. Higher values
+ means higher quality movies, but increase the file size. A value
+ of -1 lets the underlying movie encoder select the bitrate.
+
+ extra_args : list of str or None, optional
+ Extra command-line arguments passed to the underlying movie encoder. These
+ arguments are passed last to the encoder, just before the output filename.
+ The default, None, means to use :rc:`animation.[name-of-encoder]_args` for
+ the builtin writers.
+
+ metadata : dict[str, str], default: {}
+ Dictionary of keys and values for metadata to include in
+ the output file. Some keys that may be of use include:
+ title, artist, genre, subject, copyright, srcform, comment.
+
+ extra_anim : list, default: []
+ Additional `Animation` objects that should be included
+ in the saved movie file. These need to be from the same
+ `.Figure` instance. Also, animation frames will
+ just be simply combined, so there should be a 1:1 correspondence
+ between the frames from the different animations.
+
+ savefig_kwargs : dict, default: {}
+ Keyword arguments passed to each `~.Figure.savefig` call used to
+ save the individual frames.
+
+ progress_callback : function, optional
+ A callback function that will be called for every frame to notify
+ the saving progress. It must have the signature ::
+
+ def func(current_frame: int, total_frames: int) -> Any
+
+ where *current_frame* is the current frame number and *total_frames* is the
+ total number of frames to be saved. *total_frames* is set to None, if the
+ total number of frames cannot be determined. Return values may exist but are
+ ignored.
+
+ Example code to write the progress to stdout::
+
+ progress_callback = lambda i, n: print(f'Saving frame {i}/{n}')
+
+ Notes
+ -----
+ *fps*, *codec*, *bitrate*, *extra_args* and *metadata* are used to
+ construct a `.MovieWriter` instance and can only be passed if
+ *writer* is a string. If they are passed as non-*None* and *writer*
+ is a `.MovieWriter`, a `RuntimeError` will be raised.
+ """
+
+ all_anim = [self]
+ if extra_anim is not None:
+ all_anim.extend(anim for anim in extra_anim
+ if anim._fig is self._fig)
+
+ # Disable "Animation was deleted without rendering" warning.
+ for anim in all_anim:
+ anim._draw_was_started = True
+
+ if writer is None:
+ writer = mpl.rcParams['animation.writer']
+ elif (not isinstance(writer, str) and
+ any(arg is not None
+ for arg in (fps, codec, bitrate, extra_args, metadata))):
+ raise RuntimeError('Passing in values for arguments '
+ 'fps, codec, bitrate, extra_args, or metadata '
+ 'is not supported when writer is an existing '
+ 'MovieWriter instance. These should instead be '
+ 'passed as arguments when creating the '
+ 'MovieWriter instance.')
+
+ if savefig_kwargs is None:
+ savefig_kwargs = {}
+ else:
+ # we are going to mutate this below
+ savefig_kwargs = dict(savefig_kwargs)
+
+ if fps is None and hasattr(self, '_interval'):
+ # Convert interval in ms to frames per second
+ fps = 1000. / self._interval
+
+ # Reuse the savefig DPI for ours if none is given.
+ dpi = mpl._val_or_rc(dpi, 'savefig.dpi')
+ if dpi == 'figure':
+ dpi = self._fig.dpi
+
+ writer_kwargs = {}
+ if codec is not None:
+ writer_kwargs['codec'] = codec
+ if bitrate is not None:
+ writer_kwargs['bitrate'] = bitrate
+ if extra_args is not None:
+ writer_kwargs['extra_args'] = extra_args
+ if metadata is not None:
+ writer_kwargs['metadata'] = metadata
+
+ # If we have the name of a writer, instantiate an instance of the
+ # registered class.
+ if isinstance(writer, str):
+ try:
+ writer_cls = writers[writer]
+ except RuntimeError: # Raised if not available.
+ writer_cls = PillowWriter # Always available.
+ _log.warning("MovieWriter %s unavailable; using Pillow "
+ "instead.", writer)
+ writer = writer_cls(fps, **writer_kwargs)
+ _log.info('Animation.save using %s', type(writer))
+
+ if 'bbox_inches' in savefig_kwargs:
+ _log.warning("Warning: discarding the 'bbox_inches' argument in "
+ "'savefig_kwargs' as it may cause frame size "
+ "to vary, which is inappropriate for animation.")
+ savefig_kwargs.pop('bbox_inches')
+
+ # Create a new sequence of frames for saved data. This is different
+ # from new_frame_seq() to give the ability to save 'live' generated
+ # frame information to be saved later.
+ # TODO: Right now, after closing the figure, saving a movie won't work
+ # since GUI widgets are gone. Either need to remove extra code to
+ # allow for this non-existent use case or find a way to make it work.
+
+ def _pre_composite_to_white(color):
+ r, g, b, a = mcolors.to_rgba(color)
+ return a * np.array([r, g, b]) + 1 - a
+
+ # canvas._is_saving = True makes the draw_event animation-starting
+ # callback a no-op; canvas.manager = None prevents resizing the GUI
+ # widget (both are likewise done in savefig()).
+ with (writer.saving(self._fig, filename, dpi),
+ cbook._setattr_cm(self._fig.canvas, _is_saving=True, manager=None)):
+ if not writer._supports_transparency():
+ facecolor = savefig_kwargs.get('facecolor',
+ mpl.rcParams['savefig.facecolor'])
+ if facecolor == 'auto':
+ facecolor = self._fig.get_facecolor()
+ savefig_kwargs['facecolor'] = _pre_composite_to_white(facecolor)
+ savefig_kwargs['transparent'] = False # just to be safe!
+
+ for anim in all_anim:
+ anim._init_draw() # Clear the initial frame
+ frame_number = 0
+ # TODO: Currently only FuncAnimation has a save_count
+ # attribute. Can we generalize this to all Animations?
+ save_count_list = [getattr(a, '_save_count', None)
+ for a in all_anim]
+ if None in save_count_list:
+ total_frames = None
+ else:
+ total_frames = sum(save_count_list)
+ for data in zip(*[a.new_saved_frame_seq() for a in all_anim]):
+ for anim, d in zip(all_anim, data):
+ # TODO: See if turning off blit is really necessary
+ anim._draw_next_frame(d, blit=False)
+ if progress_callback is not None:
+ progress_callback(frame_number, total_frames)
+ frame_number += 1
+ writer.grab_frame(**savefig_kwargs)
+
+ def _step(self, *args):
+ """
+ Handler for getting events. By default, gets the next frame in the
+ sequence and hands the data off to be drawn.
+ """
+ # Returns True to indicate that the event source should continue to
+ # call _step, until the frame sequence reaches the end of iteration,
+ # at which point False will be returned.
+ try:
+ framedata = next(self.frame_seq)
+ self._draw_next_frame(framedata, self._blit)
+ return True
+ except StopIteration:
+ return False
+
+ def new_frame_seq(self):
+ """Return a new sequence of frame information."""
+ # Default implementation is just an iterator over self._framedata
+ return iter(self._framedata)
+
+ def new_saved_frame_seq(self):
+ """Return a new sequence of saved/cached frame information."""
+ # Default is the same as the regular frame sequence
+ return self.new_frame_seq()
+
+ def _draw_next_frame(self, framedata, blit):
+ # Breaks down the drawing of the next frame into steps of pre- and
+ # post- draw, as well as the drawing of the frame itself.
+ self._pre_draw(framedata, blit)
+ self._draw_frame(framedata)
+ self._post_draw(framedata, blit)
+
+ def _init_draw(self):
+ # Initial draw to clear the frame. Also used by the blitting code
+ # when a clean base is required.
+ self._draw_was_started = True
+
+ def _pre_draw(self, framedata, blit):
+ # Perform any cleaning or whatnot before the drawing of the frame.
+ # This default implementation allows blit to clear the frame.
+ if blit:
+ self._blit_clear(self._drawn_artists)
+
+ def _draw_frame(self, framedata):
+ # Performs actual drawing of the frame.
+ raise NotImplementedError('Needs to be implemented by subclasses to'
+ ' actually make an animation.')
+
+ def _post_draw(self, framedata, blit):
+ # After the frame is rendered, this handles the actual flushing of
+ # the draw, which can be a direct draw_idle() or make use of the
+ # blitting.
+ if blit and self._drawn_artists:
+ self._blit_draw(self._drawn_artists)
+ else:
+ self._fig.canvas.draw_idle()
+
+ # The rest of the code in this class is to facilitate easy blitting
+ def _blit_draw(self, artists):
+ # Handles blitted drawing, which renders only the artists given instead
+ # of the entire figure.
+ updated_ax = {a.axes for a in artists}
+ # Enumerate artists to cache Axes backgrounds. We do not draw
+ # artists yet to not cache foreground from plots with shared Axes
+ for ax in updated_ax:
+ # If we haven't cached the background for the current view of this
+ # Axes object, do so now. This might not always be reliable, but
+ # it's an attempt to automate the process.
+ cur_view = ax._get_view()
+ view, bg = self._blit_cache.get(ax, (object(), None))
+ if cur_view != view:
+ self._blit_cache[ax] = (
+ cur_view, ax.figure.canvas.copy_from_bbox(ax.bbox))
+ # Make a separate pass to draw foreground.
+ for a in artists:
+ a.axes.draw_artist(a)
+ # After rendering all the needed artists, blit each Axes individually.
+ for ax in updated_ax:
+ ax.figure.canvas.blit(ax.bbox)
+
+ def _blit_clear(self, artists):
+ # Get a list of the Axes that need clearing from the artists that
+ # have been drawn. Grab the appropriate saved background from the
+ # cache and restore.
+ axes = {a.axes for a in artists}
+ for ax in axes:
+ try:
+ view, bg = self._blit_cache[ax]
+ except KeyError:
+ continue
+ if ax._get_view() == view:
+ ax.figure.canvas.restore_region(bg)
+ else:
+ self._blit_cache.pop(ax)
+
+ def _setup_blit(self):
+ # Setting up the blit requires: a cache of the background for the Axes
+ self._blit_cache = dict()
+ self._drawn_artists = []
+ # _post_draw needs to be called first to initialize the renderer
+ self._post_draw(None, self._blit)
+ # Then we need to clear the Frame for the initial draw
+ # This is typically handled in _on_resize because QT and Tk
+ # emit a resize event on launch, but the macosx backend does not,
+ # thus we force it here for everyone for consistency
+ self._init_draw()
+ # Connect to future resize events
+ self._resize_id = self._fig.canvas.mpl_connect('resize_event',
+ self._on_resize)
+
+ def _on_resize(self, event):
+ # On resize, we need to disable the resize event handling so we don't
+ # get too many events. Also stop the animation events, so that
+ # we're paused. Reset the cache and re-init. Set up an event handler
+ # to catch once the draw has actually taken place.
+ self._fig.canvas.mpl_disconnect(self._resize_id)
+ self.event_source.stop()
+ self._blit_cache.clear()
+ self._init_draw()
+ self._resize_id = self._fig.canvas.mpl_connect('draw_event',
+ self._end_redraw)
+
+ def _end_redraw(self, event):
+ # Now that the redraw has happened, do the post draw flushing and
+ # blit handling. Then re-enable all of the original events.
+ self._post_draw(None, False)
+ self.event_source.start()
+ self._fig.canvas.mpl_disconnect(self._resize_id)
+ self._resize_id = self._fig.canvas.mpl_connect('resize_event',
+ self._on_resize)
+
+ def to_html5_video(self, embed_limit=None):
+ """
+ Convert the animation to an HTML5 ``