Coverage for /usr/lib/python3/dist-packages/matplotlib/__init__.py: 47%

554 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1""" 

2An object-oriented plotting library. 

3 

4A procedural interface is provided by the companion pyplot module, 

5which may be imported directly, e.g.:: 

6 

7 import matplotlib.pyplot as plt 

8 

9or using ipython:: 

10 

11 ipython 

12 

13at your terminal, followed by:: 

14 

15 In [1]: %matplotlib 

16 In [2]: import matplotlib.pyplot as plt 

17 

18at the ipython shell prompt. 

19 

20For the most part, direct use of the explicit object-oriented library is 

21encouraged when programming; the implicit pyplot interface is primarily for 

22working interactively. The exceptions to this suggestion are the pyplot 

23functions `.pyplot.figure`, `.pyplot.subplot`, `.pyplot.subplots`, and 

24`.pyplot.savefig`, which can greatly simplify scripting. See 

25:ref:`api_interfaces` for an explanation of the tradeoffs between the implicit 

26and explicit interfaces. 

27 

28Modules include: 

29 

30 :mod:`matplotlib.axes` 

31 The `~.axes.Axes` class. Most pyplot functions are wrappers for 

32 `~.axes.Axes` methods. The axes module is the highest level of OO 

33 access to the library. 

34 

35 :mod:`matplotlib.figure` 

36 The `.Figure` class. 

37 

38 :mod:`matplotlib.artist` 

39 The `.Artist` base class for all classes that draw things. 

40 

41 :mod:`matplotlib.lines` 

42 The `.Line2D` class for drawing lines and markers. 

43 

44 :mod:`matplotlib.patches` 

45 Classes for drawing polygons. 

46 

47 :mod:`matplotlib.text` 

48 The `.Text` and `.Annotation` classes. 

49 

50 :mod:`matplotlib.image` 

51 The `.AxesImage` and `.FigureImage` classes. 

52 

53 :mod:`matplotlib.collections` 

54 Classes for efficient drawing of groups of lines or polygons. 

55 

56 :mod:`matplotlib.colors` 

57 Color specifications and making colormaps. 

58 

59 :mod:`matplotlib.cm` 

60 Colormaps, and the `.ScalarMappable` mixin class for providing color 

61 mapping functionality to other classes. 

62 

63 :mod:`matplotlib.ticker` 

64 Calculation of tick mark locations and formatting of tick labels. 

65 

66 :mod:`matplotlib.backends` 

67 A subpackage with modules for various GUI libraries and output formats. 

68 

69The base matplotlib namespace includes: 

70 

71 `~matplotlib.rcParams` 

72 Default configuration settings; their defaults may be overridden using 

73 a :file:`matplotlibrc` file. 

74 

75 `~matplotlib.use` 

76 Setting the Matplotlib backend. This should be called before any 

77 figure is created, because it is not possible to switch between 

78 different GUI backends after that. 

79 

80Matplotlib was initially written by John D. Hunter (1968-2012) and is now 

81developed and maintained by a host of others. 

82 

83Occasionally the internal documentation (python docstrings) will refer 

84to MATLAB®, a registered trademark of The MathWorks, Inc. 

85 

86""" 

87 

88import atexit 

89from collections import namedtuple 

90from collections.abc import MutableMapping 

91import contextlib 

92import functools 

93import importlib 

94import inspect 

95from inspect import Parameter 

96import locale 

97import logging 

98import os 

99from pathlib import Path 

100import pprint 

101import re 

102import shutil 

103import subprocess 

104import sys 

105import tempfile 

106import warnings 

107 

108import numpy 

109from packaging.version import parse as parse_version 

110 

111# cbook must import matplotlib only within function 

112# definitions, so it is safe to import from it here. 

113from . import _api, _version, cbook, _docstring, rcsetup 

114from matplotlib.cbook import sanitize_sequence 

115from matplotlib._api import MatplotlibDeprecationWarning 

116from matplotlib.rcsetup import validate_backend, cycler 

117 

118 

119_log = logging.getLogger(__name__) 

120 

121__bibtex__ = r"""@Article{Hunter:2007, 

122 Author = {Hunter, J. D.}, 

123 Title = {Matplotlib: A 2D graphics environment}, 

124 Journal = {Computing in Science \& Engineering}, 

125 Volume = {9}, 

126 Number = {3}, 

127 Pages = {90--95}, 

128 abstract = {Matplotlib is a 2D graphics package used for Python 

129 for application development, interactive scripting, and 

130 publication-quality image generation across user 

131 interfaces and operating systems.}, 

132 publisher = {IEEE COMPUTER SOC}, 

133 year = 2007 

134}""" 

135 

136# modelled after sys.version_info 

137_VersionInfo = namedtuple('_VersionInfo', 

138 'major, minor, micro, releaselevel, serial') 

139 

140 

141def _parse_to_version_info(version_str): 

142 """ 

143 Parse a version string to a namedtuple analogous to sys.version_info. 

144 

145 See: 

146 https://packaging.pypa.io/en/latest/version.html#packaging.version.parse 

147 https://docs.python.org/3/library/sys.html#sys.version_info 

148 """ 

149 v = parse_version(version_str) 

150 if v.pre is None and v.post is None and v.dev is None: 

151 return _VersionInfo(v.major, v.minor, v.micro, 'final', 0) 

152 elif v.dev is not None: 

153 return _VersionInfo(v.major, v.minor, v.micro, 'alpha', v.dev) 

154 elif v.pre is not None: 

155 releaselevel = { 

156 'a': 'alpha', 

157 'b': 'beta', 

158 'rc': 'candidate'}.get(v.pre[0], 'alpha') 

159 return _VersionInfo(v.major, v.minor, v.micro, releaselevel, v.pre[1]) 

160 else: 

161 # fallback for v.post: guess-next-dev scheme from setuptools_scm 

162 return _VersionInfo(v.major, v.minor, v.micro + 1, 'alpha', v.post) 

163 

164 

165def _get_version(): 

166 """Return the version string used for __version__.""" 

167 # Only shell out to a git subprocess if really needed, i.e. when we are in 

168 # a matplotlib git repo but not in a shallow clone, such as those used by 

169 # CI, as the latter would trigger a warning from setuptools_scm. 

170 root = Path(__file__).resolve().parents[2] 

171 if ((root / ".matplotlib-repo").exists() 

172 and (root / ".git").exists() 

173 and not (root / ".git/shallow").exists()): 

174 import setuptools_scm 

175 return setuptools_scm.get_version( 

176 root=root, 

177 version_scheme="release-branch-semver", 

178 local_scheme="node-and-date", 

179 fallback_version=_version.version, 

180 ) 

181 else: # Get the version from the _version.py setuptools_scm file. 

182 return _version.version 

183 

184 

185@_api.caching_module_getattr 

186class __getattr__: 

187 __version__ = property(lambda self: _get_version()) 

188 __version_info__ = property( 

189 lambda self: _parse_to_version_info(self.__version__)) 

190 # module-level deprecations 

191 URL_REGEX = _api.deprecated("3.5", obj_type="")(property( 

192 lambda self: re.compile(r'^http://|^https://|^ftp://|^file:'))) 

193 

194 

195def _check_versions(): 

196 

197 # Quickfix to ensure Microsoft Visual C++ redistributable 

198 # DLLs are loaded before importing kiwisolver 

199 from . import ft2font 

200 

201 for modname, minver in [ 

202 ("cycler", "0.10"), 

203 ("dateutil", "2.7"), 

204 ("kiwisolver", "1.0.1"), 

205 ("numpy", "1.19"), 

206 ("pyparsing", "2.2.1"), 

207 ]: 

208 module = importlib.import_module(modname) 

209 if parse_version(module.__version__) < parse_version(minver): 

210 raise ImportError(f"Matplotlib requires {modname}>={minver}; " 

211 f"you have {module.__version__}") 

212 

213 

214_check_versions() 

215 

216 

217# The decorator ensures this always returns the same handler (and it is only 

218# attached once). 

219@functools.lru_cache() 

220def _ensure_handler(): 

221 """ 

222 The first time this function is called, attach a `StreamHandler` using the 

223 same format as `logging.basicConfig` to the Matplotlib root logger. 

224 

225 Return this handler every time this function is called. 

226 """ 

227 handler = logging.StreamHandler() 

228 handler.setFormatter(logging.Formatter(logging.BASIC_FORMAT)) 

229 _log.addHandler(handler) 

230 return handler 

231 

232 

233def set_loglevel(level): 

234 """ 

235 Set Matplotlib's root logger and root logger handler level, creating 

236 the handler if it does not exist yet. 

237 

238 Typically, one should call ``set_loglevel("info")`` or 

239 ``set_loglevel("debug")`` to get additional debugging information. 

240 

241 Parameters 

242 ---------- 

243 level : {"notset", "debug", "info", "warning", "error", "critical"} 

244 The log level of the handler. 

245 

246 Notes 

247 ----- 

248 The first time this function is called, an additional handler is attached 

249 to Matplotlib's root handler; this handler is reused every time and this 

250 function simply manipulates the logger and handler's level. 

251 """ 

252 _log.setLevel(level.upper()) 

253 _ensure_handler().setLevel(level.upper()) 

254 

255 

256def _logged_cached(fmt, func=None): 

257 """ 

258 Decorator that logs a function's return value, and memoizes that value. 

259 

260 After :: 

261 

262 @_logged_cached(fmt) 

263 def func(): ... 

264 

265 the first call to *func* will log its return value at the DEBUG level using 

266 %-format string *fmt*, and memoize it; later calls to *func* will directly 

267 return that value. 

268 """ 

269 if func is None: # Return the actual decorator. 

270 return functools.partial(_logged_cached, fmt) 

271 

272 called = False 

273 ret = None 

274 

275 @functools.wraps(func) 

276 def wrapper(**kwargs): 

277 nonlocal called, ret 

278 if not called: 

279 ret = func(**kwargs) 

280 called = True 

281 _log.debug(fmt, ret) 

282 return ret 

283 

284 return wrapper 

285 

286 

287_ExecInfo = namedtuple("_ExecInfo", "executable raw_version version") 

288 

289 

290class ExecutableNotFoundError(FileNotFoundError): 

291 """ 

292 Error raised when an executable that Matplotlib optionally 

293 depends on can't be found. 

294 """ 

295 pass 

296 

297 

298@functools.lru_cache() 

299def _get_executable_info(name): 

300 """ 

301 Get the version of some executable that Matplotlib optionally depends on. 

302 

303 .. warning:: 

304 The list of executables that this function supports is set according to 

305 Matplotlib's internal needs, and may change without notice. 

306 

307 Parameters 

308 ---------- 

309 name : str 

310 The executable to query. The following values are currently supported: 

311 "dvipng", "gs", "inkscape", "magick", "pdftocairo", "pdftops". This 

312 list is subject to change without notice. 

313 

314 Returns 

315 ------- 

316 tuple 

317 A namedtuple with fields ``executable`` (`str`) and ``version`` 

318 (`packaging.Version`, or ``None`` if the version cannot be determined). 

319 

320 Raises 

321 ------ 

322 ExecutableNotFoundError 

323 If the executable is not found or older than the oldest version 

324 supported by Matplotlib. For debugging purposes, it is also 

325 possible to "hide" an executable from Matplotlib by adding it to the 

326 :envvar:`_MPLHIDEEXECUTABLES` environment variable (a comma-separated 

327 list), which must be set prior to any calls to this function. 

328 ValueError 

329 If the executable is not one that we know how to query. 

330 """ 

331 

332 def impl(args, regex, min_ver=None, ignore_exit_code=False): 

333 # Execute the subprocess specified by args; capture stdout and stderr. 

334 # Search for a regex match in the output; if the match succeeds, the 

335 # first group of the match is the version. 

336 # Return an _ExecInfo if the executable exists, and has a version of 

337 # at least min_ver (if set); else, raise ExecutableNotFoundError. 

338 try: 

339 output = subprocess.check_output( 

340 args, stderr=subprocess.STDOUT, 

341 universal_newlines=True, errors="replace") 

342 except subprocess.CalledProcessError as _cpe: 

343 if ignore_exit_code: 

344 output = _cpe.output 

345 else: 

346 raise ExecutableNotFoundError(str(_cpe)) from _cpe 

347 except OSError as _ose: 

348 raise ExecutableNotFoundError(str(_ose)) from _ose 

349 match = re.search(regex, output) 

350 if match: 

351 raw_version = match.group(1) 

352 version = parse_version(raw_version) 

353 if min_ver is not None and version < parse_version(min_ver): 

354 raise ExecutableNotFoundError( 

355 f"You have {args[0]} version {version} but the minimum " 

356 f"version supported by Matplotlib is {min_ver}") 

357 return _ExecInfo(args[0], raw_version, version) 

358 else: 

359 raise ExecutableNotFoundError( 

360 f"Failed to determine the version of {args[0]} from " 

361 f"{' '.join(args)}, which output {output}") 

362 

363 if name in os.environ.get("_MPLHIDEEXECUTABLES", "").split(","): 

364 raise ExecutableNotFoundError(f"{name} was hidden") 

365 

366 if name == "dvipng": 

367 return impl(["dvipng", "-version"], "(?m)^dvipng(?: .*)? (.+)", "1.6") 

368 elif name == "gs": 

369 execs = (["gswin32c", "gswin64c", "mgs", "gs"] # "mgs" for miktex. 

370 if sys.platform == "win32" else 

371 ["gs"]) 

372 for e in execs: 

373 try: 

374 return impl([e, "--version"], "(.*)", "9") 

375 except ExecutableNotFoundError: 

376 pass 

377 message = "Failed to find a Ghostscript installation" 

378 raise ExecutableNotFoundError(message) 

379 elif name == "inkscape": 

380 try: 

381 # Try headless option first (needed for Inkscape version < 1.0): 

382 return impl(["inkscape", "--without-gui", "-V"], 

383 "Inkscape ([^ ]*)") 

384 except ExecutableNotFoundError: 

385 pass # Suppress exception chaining. 

386 # If --without-gui is not accepted, we may be using Inkscape >= 1.0 so 

387 # try without it: 

388 return impl(["inkscape", "-V"], "Inkscape ([^ ]*)") 

389 elif name == "magick": 

390 if sys.platform == "win32": 

391 # Check the registry to avoid confusing ImageMagick's convert with 

392 # Windows's builtin convert.exe. 

393 import winreg 

394 binpath = "" 

395 for flag in [0, winreg.KEY_WOW64_32KEY, winreg.KEY_WOW64_64KEY]: 

396 try: 

397 with winreg.OpenKeyEx( 

398 winreg.HKEY_LOCAL_MACHINE, 

399 r"Software\Imagemagick\Current", 

400 0, winreg.KEY_QUERY_VALUE | flag) as hkey: 

401 binpath = winreg.QueryValueEx(hkey, "BinPath")[0] 

402 except OSError: 

403 pass 

404 path = None 

405 if binpath: 

406 for name in ["convert.exe", "magick.exe"]: 

407 candidate = Path(binpath, name) 

408 if candidate.exists(): 

409 path = str(candidate) 

410 break 

411 if path is None: 

412 raise ExecutableNotFoundError( 

413 "Failed to find an ImageMagick installation") 

414 else: 

415 path = "convert" 

416 info = impl([path, "--version"], r"^Version: ImageMagick (\S*)") 

417 if info.raw_version == "7.0.10-34": 

418 # https://github.com/ImageMagick/ImageMagick/issues/2720 

419 raise ExecutableNotFoundError( 

420 f"You have ImageMagick {info.version}, which is unsupported") 

421 return info 

422 elif name == "pdftocairo": 

423 return impl(["pdftocairo", "-v"], "pdftocairo version (.*)") 

424 elif name == "pdftops": 

425 info = impl(["pdftops", "-v"], "^pdftops version (.*)", 

426 ignore_exit_code=True) 

427 if info and not ( 

428 3 <= info.version.major or 

429 # poppler version numbers. 

430 parse_version("0.9") <= info.version < parse_version("1.0")): 

431 raise ExecutableNotFoundError( 

432 f"You have pdftops version {info.version} but the minimum " 

433 f"version supported by Matplotlib is 3.0") 

434 return info 

435 else: 

436 raise ValueError("Unknown executable: {!r}".format(name)) 

437 

438 

439@_api.deprecated("3.6", alternative="a vendored copy of this function") 

440def checkdep_usetex(s): 

441 if not s: 

442 return False 

443 if not shutil.which("tex"): 

444 _log.warning("usetex mode requires TeX.") 

445 return False 

446 try: 

447 _get_executable_info("dvipng") 

448 except ExecutableNotFoundError: 

449 _log.warning("usetex mode requires dvipng.") 

450 return False 

451 try: 

452 _get_executable_info("gs") 

453 except ExecutableNotFoundError: 

454 _log.warning("usetex mode requires ghostscript.") 

455 return False 

456 return True 

457 

458 

459def _get_xdg_config_dir(): 

460 """ 

461 Return the XDG configuration directory, according to the XDG base 

462 directory spec: 

463 

464 https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 

465 """ 

466 return os.environ.get('XDG_CONFIG_HOME') or str(Path.home() / ".config") 

467 

468 

469def _get_xdg_cache_dir(): 

470 """ 

471 Return the XDG cache directory, according to the XDG base directory spec: 

472 

473 https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html 

474 """ 

475 return os.environ.get('XDG_CACHE_HOME') or str(Path.home() / ".cache") 

476 

477 

478def _get_config_or_cache_dir(xdg_base_getter): 

479 configdir = os.environ.get('MPLCONFIGDIR') 

480 if configdir: 

481 configdir = Path(configdir).resolve() 

482 elif sys.platform.startswith(('linux', 'freebsd')): 

483 # Only call _xdg_base_getter here so that MPLCONFIGDIR is tried first, 

484 # as _xdg_base_getter can throw. 

485 configdir = Path(xdg_base_getter(), "matplotlib") 

486 else: 

487 configdir = Path.home() / ".matplotlib" 

488 try: 

489 configdir.mkdir(parents=True, exist_ok=True) 

490 except OSError: 

491 pass 

492 else: 

493 if os.access(str(configdir), os.W_OK) and configdir.is_dir(): 

494 return str(configdir) 

495 # If the config or cache directory cannot be created or is not a writable 

496 # directory, create a temporary one. 

497 tmpdir = os.environ["MPLCONFIGDIR"] = \ 

498 tempfile.mkdtemp(prefix="matplotlib-") 

499 atexit.register(shutil.rmtree, tmpdir) 

500 _log.warning( 

501 "Matplotlib created a temporary config/cache directory at %s because " 

502 "the default path (%s) is not a writable directory; it is highly " 

503 "recommended to set the MPLCONFIGDIR environment variable to a " 

504 "writable directory, in particular to speed up the import of " 

505 "Matplotlib and to better support multiprocessing.", 

506 tmpdir, configdir) 

507 return tmpdir 

508 

509 

510@_logged_cached('CONFIGDIR=%s') 

511def get_configdir(): 

512 """ 

513 Return the string path of the configuration directory. 

514 

515 The directory is chosen as follows: 

516 

517 1. If the MPLCONFIGDIR environment variable is supplied, choose that. 

518 2. On Linux, follow the XDG specification and look first in 

519 ``$XDG_CONFIG_HOME``, if defined, or ``$HOME/.config``. On other 

520 platforms, choose ``$HOME/.matplotlib``. 

521 3. If the chosen directory exists and is writable, use that as the 

522 configuration directory. 

523 4. Else, create a temporary directory, and use it as the configuration 

524 directory. 

525 """ 

526 return _get_config_or_cache_dir(_get_xdg_config_dir) 

527 

528 

529@_logged_cached('CACHEDIR=%s') 

530def get_cachedir(): 

531 """ 

532 Return the string path of the cache directory. 

533 

534 The procedure used to find the directory is the same as for 

535 _get_config_dir, except using ``$XDG_CACHE_HOME``/``$HOME/.cache`` instead. 

536 """ 

537 return _get_config_or_cache_dir(_get_xdg_cache_dir) 

538 

539 

540@_logged_cached('matplotlib data path: %s') 

541def get_data_path(): 

542 """Return the path to Matplotlib data.""" 

543 _data_path = Path(__file__).with_name("mpl-data") 

544 if _data_path.exists(): 

545 return str(_data_path) 

546 else: 

547 return '/usr/share/matplotlib/mpl-data' 

548 

549 

550def matplotlib_fname(): 

551 """ 

552 Get the location of the config file. 

553 

554 The file location is determined in the following order 

555 

556 - ``$PWD/matplotlibrc`` 

557 - ``$MATPLOTLIBRC`` if it is not a directory 

558 - ``$MATPLOTLIBRC/matplotlibrc`` 

559 - ``$MPLCONFIGDIR/matplotlibrc`` 

560 - On Linux, 

561 - ``$XDG_CONFIG_HOME/matplotlib/matplotlibrc`` (if ``$XDG_CONFIG_HOME`` 

562 is defined) 

563 - or ``$HOME/.config/matplotlib/matplotlibrc`` (if ``$XDG_CONFIG_HOME`` 

564 is not defined) 

565 - On other platforms, 

566 - ``$HOME/.matplotlib/matplotlibrc`` if ``$HOME`` is defined 

567 - Lastly, it looks in ``$MATPLOTLIBDATA/matplotlibrc``, which should always 

568 exist. 

569 """ 

570 

571 def gen_candidates(): 

572 # rely on down-stream code to make absolute. This protects us 

573 # from having to directly get the current working directory 

574 # which can fail if the user has ended up with a cwd that is 

575 # non-existent. 

576 yield 'matplotlibrc' 

577 try: 

578 matplotlibrc = os.environ['MATPLOTLIBRC'] 

579 except KeyError: 

580 pass 

581 else: 

582 yield matplotlibrc 

583 yield os.path.join(matplotlibrc, 'matplotlibrc') 

584 yield os.path.join(get_configdir(), 'matplotlibrc') 

585 yield '/etc/matplotlibrc' 

586 

587 for fname in gen_candidates(): 

588 if os.path.exists(fname) and not os.path.isdir(fname): 

589 return fname 

590 

591 raise RuntimeError("Could not find matplotlibrc file; your Matplotlib " 

592 "install is broken") 

593 

594 

595# rcParams deprecated and automatically mapped to another key. 

596# Values are tuples of (version, new_name, f_old2new, f_new2old). 

597_deprecated_map = {} 

598# rcParams deprecated; some can manually be mapped to another key. 

599# Values are tuples of (version, new_name_or_None). 

600_deprecated_ignore_map = {} 

601# rcParams deprecated; can use None to suppress warnings; remain actually 

602# listed in the rcParams. 

603# Values are tuples of (version,) 

604_deprecated_remain_as_none = {} 

605 

606 

607@_docstring.Substitution( 

608 "\n".join(map("- {}".format, sorted(rcsetup._validators, key=str.lower))) 

609) 

610class RcParams(MutableMapping, dict): 

611 """ 

612 A dictionary object including validation. 

613 

614 Validating functions are defined and associated with rc parameters in 

615 :mod:`matplotlib.rcsetup`. 

616 

617 The list of rcParams is: 

618 

619 %s 

620 

621 See Also 

622 -------- 

623 :ref:`customizing-with-matplotlibrc-files` 

624 """ 

625 

626 validate = rcsetup._validators 

627 

628 # validate values on the way in 

629 def __init__(self, *args, **kwargs): 

630 self.update(*args, **kwargs) 

631 

632 def __setitem__(self, key, val): 

633 try: 

634 if key in _deprecated_map: 

635 version, alt_key, alt_val, inverse_alt = _deprecated_map[key] 

636 _api.warn_deprecated( 

637 version, name=key, obj_type="rcparam", alternative=alt_key) 

638 key = alt_key 

639 val = alt_val(val) 

640 elif key in _deprecated_remain_as_none and val is not None: 

641 version, = _deprecated_remain_as_none[key] 

642 _api.warn_deprecated(version, name=key, obj_type="rcparam") 

643 elif key in _deprecated_ignore_map: 

644 version, alt_key = _deprecated_ignore_map[key] 

645 _api.warn_deprecated( 

646 version, name=key, obj_type="rcparam", alternative=alt_key) 

647 return 

648 elif key == 'backend': 

649 if val is rcsetup._auto_backend_sentinel: 

650 if 'backend' in self: 

651 return 

652 try: 

653 cval = self.validate[key](val) 

654 except ValueError as ve: 

655 raise ValueError(f"Key {key}: {ve}") from None 

656 dict.__setitem__(self, key, cval) 

657 except KeyError as err: 

658 raise KeyError( 

659 f"{key} is not a valid rc parameter (see rcParams.keys() for " 

660 f"a list of valid parameters)") from err 

661 

662 def __getitem__(self, key): 

663 if key in _deprecated_map: 

664 version, alt_key, alt_val, inverse_alt = _deprecated_map[key] 

665 _api.warn_deprecated( 

666 version, name=key, obj_type="rcparam", alternative=alt_key) 

667 return inverse_alt(dict.__getitem__(self, alt_key)) 

668 

669 elif key in _deprecated_ignore_map: 

670 version, alt_key = _deprecated_ignore_map[key] 

671 _api.warn_deprecated( 

672 version, name=key, obj_type="rcparam", alternative=alt_key) 

673 return dict.__getitem__(self, alt_key) if alt_key else None 

674 

675 # In theory, this should only ever be used after the global rcParams 

676 # has been set up, but better be safe e.g. in presence of breakpoints. 

677 elif key == "backend" and self is globals().get("rcParams"): 

678 val = dict.__getitem__(self, key) 

679 if val is rcsetup._auto_backend_sentinel: 

680 from matplotlib import pyplot as plt 

681 plt.switch_backend(rcsetup._auto_backend_sentinel) 

682 

683 return dict.__getitem__(self, key) 

684 

685 def _get_backend_or_none(self): 

686 """Get the requested backend, if any, without triggering resolution.""" 

687 backend = dict.__getitem__(self, "backend") 

688 return None if backend is rcsetup._auto_backend_sentinel else backend 

689 

690 def __repr__(self): 

691 class_name = self.__class__.__name__ 

692 indent = len(class_name) + 1 

693 with _api.suppress_matplotlib_deprecation_warning(): 

694 repr_split = pprint.pformat(dict(self), indent=1, 

695 width=80 - indent).split('\n') 

696 repr_indented = ('\n' + ' ' * indent).join(repr_split) 

697 return '{}({})'.format(class_name, repr_indented) 

698 

699 def __str__(self): 

700 return '\n'.join(map('{0[0]}: {0[1]}'.format, sorted(self.items()))) 

701 

702 def __iter__(self): 

703 """Yield sorted list of keys.""" 

704 with _api.suppress_matplotlib_deprecation_warning(): 

705 yield from sorted(dict.__iter__(self)) 

706 

707 def __len__(self): 

708 return dict.__len__(self) 

709 

710 def find_all(self, pattern): 

711 """ 

712 Return the subset of this RcParams dictionary whose keys match, 

713 using :func:`re.search`, the given ``pattern``. 

714 

715 .. note:: 

716 

717 Changes to the returned dictionary are *not* propagated to 

718 the parent RcParams dictionary. 

719 

720 """ 

721 pattern_re = re.compile(pattern) 

722 return RcParams((key, value) 

723 for key, value in self.items() 

724 if pattern_re.search(key)) 

725 

726 def copy(self): 

727 """Copy this RcParams instance.""" 

728 rccopy = RcParams() 

729 for k in self: # Skip deprecations and revalidation. 

730 dict.__setitem__(rccopy, k, dict.__getitem__(self, k)) 

731 return rccopy 

732 

733 

734def rc_params(fail_on_error=False): 

735 """Construct a `RcParams` instance from the default Matplotlib rc file.""" 

736 return rc_params_from_file(matplotlib_fname(), fail_on_error) 

737 

738 

739@_api.deprecated("3.5") 

740def is_url(filename): 

741 """Return whether *filename* is an http, https, ftp, or file URL path.""" 

742 return __getattr__("URL_REGEX").match(filename) is not None 

743 

744 

745@functools.lru_cache() 

746def _get_ssl_context(): 

747 try: 

748 import certifi 

749 except ImportError: 

750 _log.debug("Could not import certifi.") 

751 return None 

752 import ssl 

753 return ssl.create_default_context(cafile=certifi.where()) 

754 

755 

756@contextlib.contextmanager 

757def _open_file_or_url(fname): 

758 if (isinstance(fname, str) 

759 and fname.startswith(('http://', 'https://', 'ftp://', 'file:'))): 

760 import urllib.request 

761 ssl_ctx = _get_ssl_context() 

762 if ssl_ctx is None: 

763 _log.debug( 

764 "Could not get certifi ssl context, https may not work." 

765 ) 

766 with urllib.request.urlopen(fname, context=ssl_ctx) as f: 

767 yield (line.decode('utf-8') for line in f) 

768 else: 

769 fname = os.path.expanduser(fname) 

770 with open(fname, encoding='utf-8') as f: 

771 yield f 

772 

773 

774def _rc_params_in_file(fname, transform=lambda x: x, fail_on_error=False): 

775 """ 

776 Construct a `RcParams` instance from file *fname*. 

777 

778 Unlike `rc_params_from_file`, the configuration class only contains the 

779 parameters specified in the file (i.e. default values are not filled in). 

780 

781 Parameters 

782 ---------- 

783 fname : path-like 

784 The loaded file. 

785 transform : callable, default: the identity function 

786 A function called on each individual line of the file to transform it, 

787 before further parsing. 

788 fail_on_error : bool, default: False 

789 Whether invalid entries should result in an exception or a warning. 

790 """ 

791 import matplotlib as mpl 

792 rc_temp = {} 

793 with _open_file_or_url(fname) as fd: 

794 try: 

795 for line_no, line in enumerate(fd, 1): 

796 line = transform(line) 

797 strippedline = cbook._strip_comment(line) 

798 if not strippedline: 

799 continue 

800 tup = strippedline.split(':', 1) 

801 if len(tup) != 2: 

802 _log.warning('Missing colon in file %r, line %d (%r)', 

803 fname, line_no, line.rstrip('\n')) 

804 continue 

805 key, val = tup 

806 key = key.strip() 

807 val = val.strip() 

808 if val.startswith('"') and val.endswith('"'): 

809 val = val[1:-1] # strip double quotes 

810 if key in rc_temp: 

811 _log.warning('Duplicate key in file %r, line %d (%r)', 

812 fname, line_no, line.rstrip('\n')) 

813 rc_temp[key] = (val, line, line_no) 

814 except UnicodeDecodeError: 

815 _log.warning('Cannot decode configuration file %r as utf-8.', 

816 fname) 

817 raise 

818 

819 config = RcParams() 

820 

821 for key, (val, line, line_no) in rc_temp.items(): 

822 if key in rcsetup._validators: 

823 if fail_on_error: 

824 config[key] = val # try to convert to proper type or raise 

825 else: 

826 try: 

827 config[key] = val # try to convert to proper type or skip 

828 except Exception as msg: 

829 _log.warning('Bad value in file %r, line %d (%r): %s', 

830 fname, line_no, line.rstrip('\n'), msg) 

831 elif key in _deprecated_ignore_map: 

832 version, alt_key = _deprecated_ignore_map[key] 

833 _api.warn_deprecated( 

834 version, name=key, alternative=alt_key, obj_type='rcparam', 

835 addendum="Please update your matplotlibrc.") 

836 else: 

837 # __version__ must be looked up as an attribute to trigger the 

838 # module-level __getattr__. 

839 version = ('main' if '.post' in mpl.__version__ 

840 else f'v{mpl.__version__}') 

841 _log.warning(""" 

842Bad key %(key)s in file %(fname)s, line %(line_no)s (%(line)r) 

843You probably need to get an updated matplotlibrc file from 

844https://github.com/matplotlib/matplotlib/blob/%(version)s/matplotlibrc.template 

845or from the matplotlib source distribution""", 

846 dict(key=key, fname=fname, line_no=line_no, 

847 line=line.rstrip('\n'), version=version)) 

848 return config 

849 

850 

851def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): 

852 """ 

853 Construct a `RcParams` from file *fname*. 

854 

855 Parameters 

856 ---------- 

857 fname : str or path-like 

858 A file with Matplotlib rc settings. 

859 fail_on_error : bool 

860 If True, raise an error when the parser fails to convert a parameter. 

861 use_default_template : bool 

862 If True, initialize with default parameters before updating with those 

863 in the given file. If False, the configuration class only contains the 

864 parameters specified in the file. (Useful for updating dicts.) 

865 """ 

866 config_from_file = _rc_params_in_file(fname, fail_on_error=fail_on_error) 

867 

868 if not use_default_template: 

869 return config_from_file 

870 

871 with _api.suppress_matplotlib_deprecation_warning(): 

872 config = RcParams({**rcParamsDefault, **config_from_file}) 

873 

874 if "".join(config['text.latex.preamble']): 

875 _log.info(""" 

876***************************************************************** 

877You have the following UNSUPPORTED LaTeX preamble customizations: 

878%s 

879Please do not ask for support with these customizations active. 

880***************************************************************** 

881""", '\n'.join(config['text.latex.preamble'])) 

882 _log.debug('loaded rc file %s', fname) 

883 

884 return config 

885 

886 

887# When constructing the global instances, we need to perform certain updates 

888# by explicitly calling the superclass (dict.update, dict.items) to avoid 

889# triggering resolution of _auto_backend_sentinel. 

890rcParamsDefault = _rc_params_in_file( 

891 cbook._get_data_path("matplotlibrc"), 

892 # Strip leading comment. 

893 transform=lambda line: line[1:] if line.startswith("#") else line, 

894 fail_on_error=True) 

895dict.update(rcParamsDefault, rcsetup._hardcoded_defaults) 

896# Normally, the default matplotlibrc file contains *no* entry for backend (the 

897# corresponding line starts with ##, not #; we fill on _auto_backend_sentinel 

898# in that case. However, packagers can set a different default backend 

899# (resulting in a normal `#backend: foo` line) in which case we should *not* 

900# fill in _auto_backend_sentinel. 

901dict.setdefault(rcParamsDefault, "backend", rcsetup._auto_backend_sentinel) 

902rcParams = RcParams() # The global instance. 

903dict.update(rcParams, dict.items(rcParamsDefault)) 

904dict.update(rcParams, _rc_params_in_file(matplotlib_fname())) 

905rcParamsOrig = rcParams.copy() 

906with _api.suppress_matplotlib_deprecation_warning(): 

907 # This also checks that all rcParams are indeed listed in the template. 

908 # Assigning to rcsetup.defaultParams is left only for backcompat. 

909 defaultParams = rcsetup.defaultParams = { 

910 # We want to resolve deprecated rcParams, but not backend... 

911 key: [(rcsetup._auto_backend_sentinel if key == "backend" else 

912 rcParamsDefault[key]), 

913 validator] 

914 for key, validator in rcsetup._validators.items()} 

915if rcParams['axes.formatter.use_locale']: 

916 locale.setlocale(locale.LC_ALL, '') 

917 

918 

919def rc(group, **kwargs): 

920 """ 

921 Set the current `.rcParams`. *group* is the grouping for the rc, e.g., 

922 for ``lines.linewidth`` the group is ``lines``, for 

923 ``axes.facecolor``, the group is ``axes``, and so on. Group may 

924 also be a list or tuple of group names, e.g., (*xtick*, *ytick*). 

925 *kwargs* is a dictionary attribute name/value pairs, e.g.,:: 

926 

927 rc('lines', linewidth=2, color='r') 

928 

929 sets the current `.rcParams` and is equivalent to:: 

930 

931 rcParams['lines.linewidth'] = 2 

932 rcParams['lines.color'] = 'r' 

933 

934 The following aliases are available to save typing for interactive users: 

935 

936 ===== ================= 

937 Alias Property 

938 ===== ================= 

939 'lw' 'linewidth' 

940 'ls' 'linestyle' 

941 'c' 'color' 

942 'fc' 'facecolor' 

943 'ec' 'edgecolor' 

944 'mew' 'markeredgewidth' 

945 'aa' 'antialiased' 

946 ===== ================= 

947 

948 Thus you could abbreviate the above call as:: 

949 

950 rc('lines', lw=2, c='r') 

951 

952 Note you can use python's kwargs dictionary facility to store 

953 dictionaries of default parameters. e.g., you can customize the 

954 font rc as follows:: 

955 

956 font = {'family' : 'monospace', 

957 'weight' : 'bold', 

958 'size' : 'larger'} 

959 rc('font', **font) # pass in the font dict as kwargs 

960 

961 This enables you to easily switch between several configurations. Use 

962 ``matplotlib.style.use('default')`` or :func:`~matplotlib.rcdefaults` to 

963 restore the default `.rcParams` after changes. 

964 

965 Notes 

966 ----- 

967 Similar functionality is available by using the normal dict interface, i.e. 

968 ``rcParams.update({"lines.linewidth": 2, ...})`` (but ``rcParams.update`` 

969 does not support abbreviations or grouping). 

970 """ 

971 

972 aliases = { 

973 'lw': 'linewidth', 

974 'ls': 'linestyle', 

975 'c': 'color', 

976 'fc': 'facecolor', 

977 'ec': 'edgecolor', 

978 'mew': 'markeredgewidth', 

979 'aa': 'antialiased', 

980 } 

981 

982 if isinstance(group, str): 

983 group = (group,) 

984 for g in group: 

985 for k, v in kwargs.items(): 

986 name = aliases.get(k) or k 

987 key = '%s.%s' % (g, name) 

988 try: 

989 rcParams[key] = v 

990 except KeyError as err: 

991 raise KeyError(('Unrecognized key "%s" for group "%s" and ' 

992 'name "%s"') % (key, g, name)) from err 

993 

994 

995def rcdefaults(): 

996 """ 

997 Restore the `.rcParams` from Matplotlib's internal default style. 

998 

999 Style-blacklisted `.rcParams` (defined in 

1000 ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated. 

1001 

1002 See Also 

1003 -------- 

1004 matplotlib.rc_file_defaults 

1005 Restore the `.rcParams` from the rc file originally loaded by 

1006 Matplotlib. 

1007 matplotlib.style.use 

1008 Use a specific style file. Call ``style.use('default')`` to restore 

1009 the default style. 

1010 """ 

1011 # Deprecation warnings were already handled when creating rcParamsDefault, 

1012 # no need to reemit them here. 

1013 with _api.suppress_matplotlib_deprecation_warning(): 

1014 from .style.core import STYLE_BLACKLIST 

1015 rcParams.clear() 

1016 rcParams.update({k: v for k, v in rcParamsDefault.items() 

1017 if k not in STYLE_BLACKLIST}) 

1018 

1019 

1020def rc_file_defaults(): 

1021 """ 

1022 Restore the `.rcParams` from the original rc file loaded by Matplotlib. 

1023 

1024 Style-blacklisted `.rcParams` (defined in 

1025 ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated. 

1026 """ 

1027 # Deprecation warnings were already handled when creating rcParamsOrig, no 

1028 # need to reemit them here. 

1029 with _api.suppress_matplotlib_deprecation_warning(): 

1030 from .style.core import STYLE_BLACKLIST 

1031 rcParams.update({k: rcParamsOrig[k] for k in rcParamsOrig 

1032 if k not in STYLE_BLACKLIST}) 

1033 

1034 

1035def rc_file(fname, *, use_default_template=True): 

1036 """ 

1037 Update `.rcParams` from file. 

1038 

1039 Style-blacklisted `.rcParams` (defined in 

1040 ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated. 

1041 

1042 Parameters 

1043 ---------- 

1044 fname : str or path-like 

1045 A file with Matplotlib rc settings. 

1046 

1047 use_default_template : bool 

1048 If True, initialize with default parameters before updating with those 

1049 in the given file. If False, the current configuration persists 

1050 and only the parameters specified in the file are updated. 

1051 """ 

1052 # Deprecation warnings were already handled in rc_params_from_file, no need 

1053 # to reemit them here. 

1054 with _api.suppress_matplotlib_deprecation_warning(): 

1055 from .style.core import STYLE_BLACKLIST 

1056 rc_from_file = rc_params_from_file( 

1057 fname, use_default_template=use_default_template) 

1058 rcParams.update({k: rc_from_file[k] for k in rc_from_file 

1059 if k not in STYLE_BLACKLIST}) 

1060 

1061 

1062@contextlib.contextmanager 

1063def rc_context(rc=None, fname=None): 

1064 """ 

1065 Return a context manager for temporarily changing rcParams. 

1066 

1067 The :rc:`backend` will not be reset by the context manager. 

1068 

1069 rcParams changed both through the context manager invocation and 

1070 in the body of the context will be reset on context exit. 

1071 

1072 Parameters 

1073 ---------- 

1074 rc : dict 

1075 The rcParams to temporarily set. 

1076 fname : str or path-like 

1077 A file with Matplotlib rc settings. If both *fname* and *rc* are given, 

1078 settings from *rc* take precedence. 

1079 

1080 See Also 

1081 -------- 

1082 :ref:`customizing-with-matplotlibrc-files` 

1083 

1084 Examples 

1085 -------- 

1086 Passing explicit values via a dict:: 

1087 

1088 with mpl.rc_context({'interactive': False}): 

1089 fig, ax = plt.subplots() 

1090 ax.plot(range(3), range(3)) 

1091 fig.savefig('example.png') 

1092 plt.close(fig) 

1093 

1094 Loading settings from a file:: 

1095 

1096 with mpl.rc_context(fname='print.rc'): 

1097 plt.plot(x, y) # uses 'print.rc' 

1098 

1099 Setting in the context body:: 

1100 

1101 with mpl.rc_context(): 

1102 # will be reset 

1103 mpl.rcParams['lines.linewidth'] = 5 

1104 plt.plot(x, y) 

1105 

1106 """ 

1107 orig = dict(rcParams.copy()) 

1108 del orig['backend'] 

1109 try: 

1110 if fname: 

1111 rc_file(fname) 

1112 if rc: 

1113 rcParams.update(rc) 

1114 yield 

1115 finally: 

1116 dict.update(rcParams, orig) # Revert to the original rcs. 

1117 

1118 

1119def use(backend, *, force=True): 

1120 """ 

1121 Select the backend used for rendering and GUI integration. 

1122 

1123 Parameters 

1124 ---------- 

1125 backend : str 

1126 The backend to switch to. This can either be one of the standard 

1127 backend names, which are case-insensitive: 

1128 

1129 - interactive backends: 

1130 GTK3Agg, GTK3Cairo, GTK4Agg, GTK4Cairo, MacOSX, nbAgg, QtAgg, 

1131 QtCairo, TkAgg, TkCairo, WebAgg, WX, WXAgg, WXCairo, Qt5Agg, Qt5Cairo 

1132 

1133 - non-interactive backends: 

1134 agg, cairo, pdf, pgf, ps, svg, template 

1135 

1136 or a string of the form: ``module://my.module.name``. 

1137 

1138 Switching to an interactive backend is not possible if an unrelated 

1139 event loop has already been started (e.g., switching to GTK3Agg if a 

1140 TkAgg window has already been opened). Switching to a non-interactive 

1141 backend is always possible. 

1142 

1143 force : bool, default: True 

1144 If True (the default), raise an `ImportError` if the backend cannot be 

1145 set up (either because it fails to import, or because an incompatible 

1146 GUI interactive framework is already running); if False, silently 

1147 ignore the failure. 

1148 

1149 See Also 

1150 -------- 

1151 :ref:`backends` 

1152 matplotlib.get_backend 

1153 """ 

1154 name = validate_backend(backend) 

1155 # don't (prematurely) resolve the "auto" backend setting 

1156 if rcParams._get_backend_or_none() == name: 

1157 # Nothing to do if the requested backend is already set 

1158 pass 

1159 else: 

1160 # if pyplot is not already imported, do not import it. Doing 

1161 # so may trigger a `plt.switch_backend` to the _default_ backend 

1162 # before we get a chance to change to the one the user just requested 

1163 plt = sys.modules.get('matplotlib.pyplot') 

1164 # if pyplot is imported, then try to change backends 

1165 if plt is not None: 

1166 try: 

1167 # we need this import check here to re-raise if the 

1168 # user does not have the libraries to support their 

1169 # chosen backend installed. 

1170 plt.switch_backend(name) 

1171 except ImportError: 

1172 if force: 

1173 raise 

1174 # if we have not imported pyplot, then we can set the rcParam 

1175 # value which will be respected when the user finally imports 

1176 # pyplot 

1177 else: 

1178 rcParams['backend'] = backend 

1179 # if the user has asked for a given backend, do not helpfully 

1180 # fallback 

1181 rcParams['backend_fallback'] = False 

1182 

1183 

1184if os.environ.get('MPLBACKEND'): 

1185 rcParams['backend'] = os.environ.get('MPLBACKEND') 

1186 

1187 

1188def get_backend(): 

1189 """ 

1190 Return the name of the current backend. 

1191 

1192 See Also 

1193 -------- 

1194 matplotlib.use 

1195 """ 

1196 return rcParams['backend'] 

1197 

1198 

1199def interactive(b): 

1200 """ 

1201 Set whether to redraw after every plotting command (e.g. `.pyplot.xlabel`). 

1202 """ 

1203 rcParams['interactive'] = b 

1204 

1205 

1206def is_interactive(): 

1207 """ 

1208 Return whether to redraw after every plotting command. 

1209 

1210 .. note:: 

1211 

1212 This function is only intended for use in backends. End users should 

1213 use `.pyplot.isinteractive` instead. 

1214 """ 

1215 return rcParams['interactive'] 

1216 

1217 

1218default_test_modules = [ 

1219 'matplotlib.tests', 

1220 'mpl_toolkits.tests', 

1221] 

1222 

1223 

1224def _init_tests(): 

1225 # The version of FreeType to install locally for running the 

1226 # tests. This must match the value in `setupext.py` 

1227 LOCAL_FREETYPE_VERSION = '2.6.1' 

1228 

1229 from matplotlib import ft2font 

1230 if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or 

1231 ft2font.__freetype_build_type__ != 'local'): 

1232 _log.warning( 

1233 f"Matplotlib is not built with the correct FreeType version to " 

1234 f"run tests. Rebuild without setting system_freetype=1 in " 

1235 f"mplsetup.cfg. Expect many image comparison failures below. " 

1236 f"Expected freetype version {LOCAL_FREETYPE_VERSION}. " 

1237 f"Found freetype version {ft2font.__freetype_version__}. " 

1238 "Freetype build type is {}local".format( 

1239 "" if ft2font.__freetype_build_type__ == 'local' else "not ")) 

1240 

1241 

1242@_api.deprecated("3.5", alternative='pytest') 

1243def test(verbosity=None, coverage=False, **kwargs): 

1244 """Run the matplotlib test suite.""" 

1245 

1246 try: 

1247 import pytest 

1248 except ImportError: 

1249 print("matplotlib.test requires pytest to run.") 

1250 return -1 

1251 

1252 if not os.path.isdir(os.path.join(os.path.dirname(__file__), 'tests')): 

1253 print("Matplotlib test data is not installed") 

1254 return -1 

1255 

1256 old_backend = get_backend() 

1257 try: 

1258 use('agg') 

1259 

1260 args = kwargs.pop('argv', []) 

1261 provide_default_modules = True 

1262 use_pyargs = True 

1263 for arg in args: 

1264 if any(arg.startswith(module_path) 

1265 for module_path in default_test_modules): 

1266 provide_default_modules = False 

1267 break 

1268 if os.path.exists(arg): 

1269 provide_default_modules = False 

1270 use_pyargs = False 

1271 break 

1272 if use_pyargs: 

1273 args += ['--pyargs'] 

1274 if provide_default_modules: 

1275 args += default_test_modules 

1276 

1277 if coverage: 

1278 args += ['--cov'] 

1279 

1280 if verbosity: 

1281 args += ['-' + 'v' * verbosity] 

1282 

1283 retcode = pytest.main(args, **kwargs) 

1284 finally: 

1285 if old_backend.lower() != 'agg': 

1286 use(old_backend) 

1287 

1288 return retcode 

1289 

1290 

1291test.__test__ = False # pytest: this function is not a test 

1292 

1293 

1294def _replacer(data, value): 

1295 """ 

1296 Either returns ``data[value]`` or passes ``data`` back, converts either to 

1297 a sequence. 

1298 """ 

1299 try: 

1300 # if key isn't a string don't bother 

1301 if isinstance(value, str): 

1302 # try to use __getitem__ 

1303 value = data[value] 

1304 except Exception: 

1305 # key does not exist, silently fall back to key 

1306 pass 

1307 return sanitize_sequence(value) 

1308 

1309 

1310def _label_from_arg(y, default_name): 

1311 try: 

1312 return y.name 

1313 except AttributeError: 

1314 if isinstance(default_name, str): 

1315 return default_name 

1316 return None 

1317 

1318 

1319def _add_data_doc(docstring, replace_names): 

1320 """ 

1321 Add documentation for a *data* field to the given docstring. 

1322 

1323 Parameters 

1324 ---------- 

1325 docstring : str 

1326 The input docstring. 

1327 replace_names : list of str or None 

1328 The list of parameter names which arguments should be replaced by 

1329 ``data[name]`` (if ``data[name]`` does not throw an exception). If 

1330 None, replacement is attempted for all arguments. 

1331 

1332 Returns 

1333 ------- 

1334 str 

1335 The augmented docstring. 

1336 """ 

1337 if (docstring is None 

1338 or replace_names is not None and len(replace_names) == 0): 

1339 return docstring 

1340 docstring = inspect.cleandoc(docstring) 

1341 

1342 data_doc = ("""\ 

1343 If given, all parameters also accept a string ``s``, which is 

1344 interpreted as ``data[s]`` (unless this raises an exception).""" 

1345 if replace_names is None else f"""\ 

1346 If given, the following parameters also accept a string ``s``, which is 

1347 interpreted as ``data[s]`` (unless this raises an exception): 

1348 

1349 {', '.join(map('*{}*'.format, replace_names))}""") 

1350 # using string replacement instead of formatting has the advantages 

1351 # 1) simpler indent handling 

1352 # 2) prevent problems with formatting characters '{', '%' in the docstring 

1353 if _log.level <= logging.DEBUG: 

1354 # test_data_parameter_replacement() tests against these log messages 

1355 # make sure to keep message and test in sync 

1356 if "data : indexable object, optional" not in docstring: 

1357 _log.debug("data parameter docstring error: no data parameter") 

1358 if 'DATA_PARAMETER_PLACEHOLDER' not in docstring: 

1359 _log.debug("data parameter docstring error: missing placeholder") 

1360 return docstring.replace(' DATA_PARAMETER_PLACEHOLDER', data_doc) 

1361 

1362 

1363def _preprocess_data(func=None, *, replace_names=None, label_namer=None): 

1364 """ 

1365 A decorator to add a 'data' kwarg to a function. 

1366 

1367 When applied:: 

1368 

1369 @_preprocess_data() 

1370 def func(ax, *args, **kwargs): ... 

1371 

1372 the signature is modified to ``decorated(ax, *args, data=None, **kwargs)`` 

1373 with the following behavior: 

1374 

1375 - if called with ``data=None``, forward the other arguments to ``func``; 

1376 - otherwise, *data* must be a mapping; for any argument passed in as a 

1377 string ``name``, replace the argument by ``data[name]`` (if this does not 

1378 throw an exception), then forward the arguments to ``func``. 

1379 

1380 In either case, any argument that is a `MappingView` is also converted to a 

1381 list. 

1382 

1383 Parameters 

1384 ---------- 

1385 replace_names : list of str or None, default: None 

1386 The list of parameter names for which lookup into *data* should be 

1387 attempted. If None, replacement is attempted for all arguments. 

1388 label_namer : str, default: None 

1389 If set e.g. to "namer" (which must be a kwarg in the function's 

1390 signature -- not as ``**kwargs``), if the *namer* argument passed in is 

1391 a (string) key of *data* and no *label* kwarg is passed, then use the 

1392 (string) value of the *namer* as *label*. :: 

1393 

1394 @_preprocess_data(label_namer="foo") 

1395 def func(foo, label=None): ... 

1396 

1397 func("key", data={"key": value}) 

1398 # is equivalent to 

1399 func.__wrapped__(value, label="key") 

1400 """ 

1401 

1402 if func is None: # Return the actual decorator. 

1403 return functools.partial( 

1404 _preprocess_data, 

1405 replace_names=replace_names, label_namer=label_namer) 

1406 

1407 sig = inspect.signature(func) 

1408 varargs_name = None 

1409 varkwargs_name = None 

1410 arg_names = [] 

1411 params = list(sig.parameters.values()) 

1412 for p in params: 

1413 if p.kind is Parameter.VAR_POSITIONAL: 

1414 varargs_name = p.name 

1415 elif p.kind is Parameter.VAR_KEYWORD: 

1416 varkwargs_name = p.name 

1417 else: 

1418 arg_names.append(p.name) 

1419 data_param = Parameter("data", Parameter.KEYWORD_ONLY, default=None) 

1420 if varkwargs_name: 

1421 params.insert(-1, data_param) 

1422 else: 

1423 params.append(data_param) 

1424 new_sig = sig.replace(parameters=params) 

1425 arg_names = arg_names[1:] # remove the first "ax" / self arg 

1426 

1427 assert {*arg_names}.issuperset(replace_names or []) or varkwargs_name, ( 

1428 "Matplotlib internal error: invalid replace_names ({!r}) for {!r}" 

1429 .format(replace_names, func.__name__)) 

1430 assert label_namer is None or label_namer in arg_names, ( 

1431 "Matplotlib internal error: invalid label_namer ({!r}) for {!r}" 

1432 .format(label_namer, func.__name__)) 

1433 

1434 @functools.wraps(func) 

1435 def inner(ax, *args, data=None, **kwargs): 

1436 if data is None: 

1437 return func(ax, *map(sanitize_sequence, args), **kwargs) 

1438 

1439 bound = new_sig.bind(ax, *args, **kwargs) 

1440 auto_label = (bound.arguments.get(label_namer) 

1441 or bound.kwargs.get(label_namer)) 

1442 

1443 for k, v in bound.arguments.items(): 

1444 if k == varkwargs_name: 

1445 for k1, v1 in v.items(): 

1446 if replace_names is None or k1 in replace_names: 

1447 v[k1] = _replacer(data, v1) 

1448 elif k == varargs_name: 

1449 if replace_names is None: 

1450 bound.arguments[k] = tuple(_replacer(data, v1) for v1 in v) 

1451 else: 

1452 if replace_names is None or k in replace_names: 

1453 bound.arguments[k] = _replacer(data, v) 

1454 

1455 new_args = bound.args 

1456 new_kwargs = bound.kwargs 

1457 

1458 args_and_kwargs = {**bound.arguments, **bound.kwargs} 

1459 if label_namer and "label" not in args_and_kwargs: 

1460 new_kwargs["label"] = _label_from_arg( 

1461 args_and_kwargs.get(label_namer), auto_label) 

1462 

1463 return func(*new_args, **new_kwargs) 

1464 

1465 inner.__doc__ = _add_data_doc(inner.__doc__, replace_names) 

1466 inner.__signature__ = new_sig 

1467 return inner 

1468 

1469 

1470_log.debug('interactive is %s', is_interactive()) 

1471_log.debug('platform is %s', sys.platform) 

1472 

1473 

1474# workaround: we must defer colormaps import to after loading rcParams, because 

1475# colormap creation depends on rcParams 

1476from matplotlib.cm import _colormaps as colormaps 

1477from matplotlib.colors import _color_sequences as color_sequences