rcsetup.py 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. """
  2. The rcsetup module contains the validation code for customization using
  3. Matplotlib's rc settings.
  4. Each rc setting is assigned a function used to validate any attempted changes
  5. to that setting. The validation functions are defined in the rcsetup module,
  6. and are used to construct the rcParams global object which stores the settings
  7. and is referenced throughout Matplotlib.
  8. The default values of the rc settings are set in the default matplotlibrc file.
  9. Any additions or deletions to the parameter set listed here should also be
  10. propagated to the :file:`lib/matplotlib/mpl-data/matplotlibrc` in Matplotlib's
  11. root source directory.
  12. """
  13. import ast
  14. from functools import lru_cache, reduce
  15. from numbers import Real
  16. import operator
  17. import os
  18. import re
  19. import numpy as np
  20. from matplotlib import _api, cbook
  21. from matplotlib.cbook import ls_mapper
  22. from matplotlib.colors import Colormap, is_color_like
  23. from matplotlib._fontconfig_pattern import parse_fontconfig_pattern
  24. from matplotlib._enums import JoinStyle, CapStyle
  25. # Don't let the original cycler collide with our validating cycler
  26. from cycler import Cycler, cycler as ccycler
  27. # The capitalized forms are needed for ipython at present; this may
  28. # change for later versions.
  29. interactive_bk = [
  30. 'GTK3Agg', 'GTK3Cairo', 'GTK4Agg', 'GTK4Cairo',
  31. 'MacOSX',
  32. 'nbAgg',
  33. 'QtAgg', 'QtCairo', 'Qt5Agg', 'Qt5Cairo',
  34. 'TkAgg', 'TkCairo',
  35. 'WebAgg',
  36. 'WX', 'WXAgg', 'WXCairo',
  37. ]
  38. non_interactive_bk = ['agg', 'cairo',
  39. 'pdf', 'pgf', 'ps', 'svg', 'template']
  40. all_backends = interactive_bk + non_interactive_bk
  41. class ValidateInStrings:
  42. def __init__(self, key, valid, ignorecase=False, *,
  43. _deprecated_since=None):
  44. """*valid* is a list of legal strings."""
  45. self.key = key
  46. self.ignorecase = ignorecase
  47. self._deprecated_since = _deprecated_since
  48. def func(s):
  49. if ignorecase:
  50. return s.lower()
  51. else:
  52. return s
  53. self.valid = {func(k): k for k in valid}
  54. def __call__(self, s):
  55. if self._deprecated_since:
  56. name, = (k for k, v in globals().items() if v is self)
  57. _api.warn_deprecated(
  58. self._deprecated_since, name=name, obj_type="function")
  59. if self.ignorecase and isinstance(s, str):
  60. s = s.lower()
  61. if s in self.valid:
  62. return self.valid[s]
  63. msg = (f"{s!r} is not a valid value for {self.key}; supported values "
  64. f"are {[*self.valid.values()]}")
  65. if (isinstance(s, str)
  66. and (s.startswith('"') and s.endswith('"')
  67. or s.startswith("'") and s.endswith("'"))
  68. and s[1:-1] in self.valid):
  69. msg += "; remove quotes surrounding your string"
  70. raise ValueError(msg)
  71. @lru_cache
  72. def _listify_validator(scalar_validator, allow_stringlist=False, *,
  73. n=None, doc=None):
  74. def f(s):
  75. if isinstance(s, str):
  76. try:
  77. val = [scalar_validator(v.strip()) for v in s.split(',')
  78. if v.strip()]
  79. except Exception:
  80. if allow_stringlist:
  81. # Sometimes, a list of colors might be a single string
  82. # of single-letter colornames. So give that a shot.
  83. val = [scalar_validator(v.strip()) for v in s if v.strip()]
  84. else:
  85. raise
  86. # Allow any ordered sequence type -- generators, np.ndarray, pd.Series
  87. # -- but not sets, whose iteration order is non-deterministic.
  88. elif np.iterable(s) and not isinstance(s, (set, frozenset)):
  89. # The condition on this list comprehension will preserve the
  90. # behavior of filtering out any empty strings (behavior was
  91. # from the original validate_stringlist()), while allowing
  92. # any non-string/text scalar values such as numbers and arrays.
  93. val = [scalar_validator(v) for v in s
  94. if not isinstance(v, str) or v]
  95. else:
  96. raise ValueError(
  97. f"Expected str or other non-set iterable, but got {s}")
  98. if n is not None and len(val) != n:
  99. raise ValueError(
  100. f"Expected {n} values, but there are {len(val)} values in {s}")
  101. return val
  102. try:
  103. f.__name__ = f"{scalar_validator.__name__}list"
  104. except AttributeError: # class instance.
  105. f.__name__ = f"{type(scalar_validator).__name__}List"
  106. f.__qualname__ = f.__qualname__.rsplit(".", 1)[0] + "." + f.__name__
  107. f.__doc__ = doc if doc is not None else scalar_validator.__doc__
  108. return f
  109. def validate_any(s):
  110. return s
  111. validate_anylist = _listify_validator(validate_any)
  112. def _validate_date(s):
  113. try:
  114. np.datetime64(s)
  115. return s
  116. except ValueError:
  117. raise ValueError(
  118. f'{s!r} should be a string that can be parsed by numpy.datetime64')
  119. def validate_bool(b):
  120. """Convert b to ``bool`` or raise."""
  121. if isinstance(b, str):
  122. b = b.lower()
  123. if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True):
  124. return True
  125. elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False):
  126. return False
  127. else:
  128. raise ValueError(f'Cannot convert {b!r} to bool')
  129. def validate_axisbelow(s):
  130. try:
  131. return validate_bool(s)
  132. except ValueError:
  133. if isinstance(s, str):
  134. if s == 'line':
  135. return 'line'
  136. raise ValueError(f'{s!r} cannot be interpreted as'
  137. ' True, False, or "line"')
  138. def validate_dpi(s):
  139. """Confirm s is string 'figure' or convert s to float or raise."""
  140. if s == 'figure':
  141. return s
  142. try:
  143. return float(s)
  144. except ValueError as e:
  145. raise ValueError(f'{s!r} is not string "figure" and '
  146. f'could not convert {s!r} to float') from e
  147. def _make_type_validator(cls, *, allow_none=False):
  148. """
  149. Return a validator that converts inputs to *cls* or raises (and possibly
  150. allows ``None`` as well).
  151. """
  152. def validator(s):
  153. if (allow_none and
  154. (s is None or isinstance(s, str) and s.lower() == "none")):
  155. return None
  156. if cls is str and not isinstance(s, str):
  157. raise ValueError(f'Could not convert {s!r} to str')
  158. try:
  159. return cls(s)
  160. except (TypeError, ValueError) as e:
  161. raise ValueError(
  162. f'Could not convert {s!r} to {cls.__name__}') from e
  163. validator.__name__ = f"validate_{cls.__name__}"
  164. if allow_none:
  165. validator.__name__ += "_or_None"
  166. validator.__qualname__ = (
  167. validator.__qualname__.rsplit(".", 1)[0] + "." + validator.__name__)
  168. return validator
  169. validate_string = _make_type_validator(str)
  170. validate_string_or_None = _make_type_validator(str, allow_none=True)
  171. validate_stringlist = _listify_validator(
  172. validate_string, doc='return a list of strings')
  173. validate_int = _make_type_validator(int)
  174. validate_int_or_None = _make_type_validator(int, allow_none=True)
  175. validate_float = _make_type_validator(float)
  176. validate_float_or_None = _make_type_validator(float, allow_none=True)
  177. validate_floatlist = _listify_validator(
  178. validate_float, doc='return a list of floats')
  179. def _validate_pathlike(s):
  180. if isinstance(s, (str, os.PathLike)):
  181. # Store value as str because savefig.directory needs to distinguish
  182. # between "" (cwd) and "." (cwd, but gets updated by user selections).
  183. return os.fsdecode(s)
  184. else:
  185. return validate_string(s)
  186. def validate_fonttype(s):
  187. """
  188. Confirm that this is a Postscript or PDF font type that we know how to
  189. convert to.
  190. """
  191. fonttypes = {'type3': 3,
  192. 'truetype': 42}
  193. try:
  194. fonttype = validate_int(s)
  195. except ValueError:
  196. try:
  197. return fonttypes[s.lower()]
  198. except KeyError as e:
  199. raise ValueError('Supported Postscript/PDF font types are %s'
  200. % list(fonttypes)) from e
  201. else:
  202. if fonttype not in fonttypes.values():
  203. raise ValueError(
  204. 'Supported Postscript/PDF font types are %s' %
  205. list(fonttypes.values()))
  206. return fonttype
  207. _validate_standard_backends = ValidateInStrings(
  208. 'backend', all_backends, ignorecase=True)
  209. _auto_backend_sentinel = object()
  210. def validate_backend(s):
  211. backend = (
  212. s if s is _auto_backend_sentinel or s.startswith("module://")
  213. else _validate_standard_backends(s))
  214. return backend
  215. def _validate_toolbar(s):
  216. s = ValidateInStrings(
  217. 'toolbar', ['None', 'toolbar2', 'toolmanager'], ignorecase=True)(s)
  218. if s == 'toolmanager':
  219. _api.warn_external(
  220. "Treat the new Tool classes introduced in v1.5 as experimental "
  221. "for now; the API and rcParam may change in future versions.")
  222. return s
  223. def validate_color_or_inherit(s):
  224. """Return a valid color arg."""
  225. if cbook._str_equal(s, 'inherit'):
  226. return s
  227. return validate_color(s)
  228. def validate_color_or_auto(s):
  229. if cbook._str_equal(s, 'auto'):
  230. return s
  231. return validate_color(s)
  232. def validate_color_for_prop_cycle(s):
  233. # N-th color cycle syntax can't go into the color cycle.
  234. if isinstance(s, str) and re.match("^C[0-9]$", s):
  235. raise ValueError(f"Cannot put cycle reference ({s!r}) in prop_cycler")
  236. return validate_color(s)
  237. def _validate_color_or_linecolor(s):
  238. if cbook._str_equal(s, 'linecolor'):
  239. return s
  240. elif cbook._str_equal(s, 'mfc') or cbook._str_equal(s, 'markerfacecolor'):
  241. return 'markerfacecolor'
  242. elif cbook._str_equal(s, 'mec') or cbook._str_equal(s, 'markeredgecolor'):
  243. return 'markeredgecolor'
  244. elif s is None:
  245. return None
  246. elif isinstance(s, str) and len(s) == 6 or len(s) == 8:
  247. stmp = '#' + s
  248. if is_color_like(stmp):
  249. return stmp
  250. if s.lower() == 'none':
  251. return None
  252. elif is_color_like(s):
  253. return s
  254. raise ValueError(f'{s!r} does not look like a color arg')
  255. def validate_color(s):
  256. """Return a valid color arg."""
  257. if isinstance(s, str):
  258. if s.lower() == 'none':
  259. return 'none'
  260. if len(s) == 6 or len(s) == 8:
  261. stmp = '#' + s
  262. if is_color_like(stmp):
  263. return stmp
  264. if is_color_like(s):
  265. return s
  266. # If it is still valid, it must be a tuple (as a string from matplotlibrc).
  267. try:
  268. color = ast.literal_eval(s)
  269. except (SyntaxError, ValueError):
  270. pass
  271. else:
  272. if is_color_like(color):
  273. return color
  274. raise ValueError(f'{s!r} does not look like a color arg')
  275. validate_colorlist = _listify_validator(
  276. validate_color, allow_stringlist=True, doc='return a list of colorspecs')
  277. def _validate_cmap(s):
  278. _api.check_isinstance((str, Colormap), cmap=s)
  279. return s
  280. def validate_aspect(s):
  281. if s in ('auto', 'equal'):
  282. return s
  283. try:
  284. return float(s)
  285. except ValueError as e:
  286. raise ValueError('not a valid aspect specification') from e
  287. def validate_fontsize_None(s):
  288. if s is None or s == 'None':
  289. return None
  290. else:
  291. return validate_fontsize(s)
  292. def validate_fontsize(s):
  293. fontsizes = ['xx-small', 'x-small', 'small', 'medium', 'large',
  294. 'x-large', 'xx-large', 'smaller', 'larger']
  295. if isinstance(s, str):
  296. s = s.lower()
  297. if s in fontsizes:
  298. return s
  299. try:
  300. return float(s)
  301. except ValueError as e:
  302. raise ValueError("%s is not a valid font size. Valid font sizes "
  303. "are %s." % (s, ", ".join(fontsizes))) from e
  304. validate_fontsizelist = _listify_validator(validate_fontsize)
  305. def validate_fontweight(s):
  306. weights = [
  307. 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman',
  308. 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black']
  309. # Note: Historically, weights have been case-sensitive in Matplotlib
  310. if s in weights:
  311. return s
  312. try:
  313. return int(s)
  314. except (ValueError, TypeError) as e:
  315. raise ValueError(f'{s} is not a valid font weight.') from e
  316. def validate_fontstretch(s):
  317. stretchvalues = [
  318. 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed',
  319. 'normal', 'semi-expanded', 'expanded', 'extra-expanded',
  320. 'ultra-expanded']
  321. # Note: Historically, stretchvalues have been case-sensitive in Matplotlib
  322. if s in stretchvalues:
  323. return s
  324. try:
  325. return int(s)
  326. except (ValueError, TypeError) as e:
  327. raise ValueError(f'{s} is not a valid font stretch.') from e
  328. def validate_font_properties(s):
  329. parse_fontconfig_pattern(s)
  330. return s
  331. def _validate_mathtext_fallback(s):
  332. _fallback_fonts = ['cm', 'stix', 'stixsans']
  333. if isinstance(s, str):
  334. s = s.lower()
  335. if s is None or s == 'none':
  336. return None
  337. elif s.lower() in _fallback_fonts:
  338. return s
  339. else:
  340. raise ValueError(
  341. f"{s} is not a valid fallback font name. Valid fallback font "
  342. f"names are {','.join(_fallback_fonts)}. Passing 'None' will turn "
  343. "fallback off.")
  344. def validate_whiskers(s):
  345. try:
  346. return _listify_validator(validate_float, n=2)(s)
  347. except (TypeError, ValueError):
  348. try:
  349. return float(s)
  350. except ValueError as e:
  351. raise ValueError("Not a valid whisker value [float, "
  352. "(float, float)]") from e
  353. def validate_ps_distiller(s):
  354. if isinstance(s, str):
  355. s = s.lower()
  356. if s in ('none', None, 'false', False):
  357. return None
  358. else:
  359. return ValidateInStrings('ps.usedistiller', ['ghostscript', 'xpdf'])(s)
  360. def _validate_papersize(s):
  361. # Re-inline this validator when the 'auto' deprecation expires.
  362. s = ValidateInStrings("ps.papersize",
  363. ["figure", "auto", "letter", "legal", "ledger",
  364. *[f"{ab}{i}" for ab in "ab" for i in range(11)]],
  365. ignorecase=True)(s)
  366. if s == "auto":
  367. _api.warn_deprecated("3.8", name="ps.papersize='auto'",
  368. addendum="Pass an explicit paper type, figure, or omit "
  369. "the *ps.papersize* rcParam entirely.")
  370. return s
  371. # A validator dedicated to the named line styles, based on the items in
  372. # ls_mapper, and a list of possible strings read from Line2D.set_linestyle
  373. _validate_named_linestyle = ValidateInStrings(
  374. 'linestyle',
  375. [*ls_mapper.keys(), *ls_mapper.values(), 'None', 'none', ' ', ''],
  376. ignorecase=True)
  377. def _validate_linestyle(ls):
  378. """
  379. A validator for all possible line styles, the named ones *and*
  380. the on-off ink sequences.
  381. """
  382. if isinstance(ls, str):
  383. try: # Look first for a valid named line style, like '--' or 'solid'.
  384. return _validate_named_linestyle(ls)
  385. except ValueError:
  386. pass
  387. try:
  388. ls = ast.literal_eval(ls) # Parsing matplotlibrc.
  389. except (SyntaxError, ValueError):
  390. pass # Will error with the ValueError at the end.
  391. def _is_iterable_not_string_like(x):
  392. # Explicitly exclude bytes/bytearrays so that they are not
  393. # nonsensically interpreted as sequences of numbers (codepoints).
  394. return np.iterable(x) and not isinstance(x, (str, bytes, bytearray))
  395. if _is_iterable_not_string_like(ls):
  396. if len(ls) == 2 and _is_iterable_not_string_like(ls[1]):
  397. # (offset, (on, off, on, off, ...))
  398. offset, onoff = ls
  399. else:
  400. # For backcompat: (on, off, on, off, ...); the offset is implicit.
  401. offset = 0
  402. onoff = ls
  403. if (isinstance(offset, Real)
  404. and len(onoff) % 2 == 0
  405. and all(isinstance(elem, Real) for elem in onoff)):
  406. return (offset, onoff)
  407. raise ValueError(f"linestyle {ls!r} is not a valid on-off ink sequence.")
  408. validate_fillstyle = ValidateInStrings(
  409. 'markers.fillstyle', ['full', 'left', 'right', 'bottom', 'top', 'none'])
  410. validate_fillstylelist = _listify_validator(validate_fillstyle)
  411. def validate_markevery(s):
  412. """
  413. Validate the markevery property of a Line2D object.
  414. Parameters
  415. ----------
  416. s : None, int, (int, int), slice, float, (float, float), or list[int]
  417. Returns
  418. -------
  419. None, int, (int, int), slice, float, (float, float), or list[int]
  420. """
  421. # Validate s against type slice float int and None
  422. if isinstance(s, (slice, float, int, type(None))):
  423. return s
  424. # Validate s against type tuple
  425. if isinstance(s, tuple):
  426. if (len(s) == 2
  427. and (all(isinstance(e, int) for e in s)
  428. or all(isinstance(e, float) for e in s))):
  429. return s
  430. else:
  431. raise TypeError(
  432. "'markevery' tuple must be pair of ints or of floats")
  433. # Validate s against type list
  434. if isinstance(s, list):
  435. if all(isinstance(e, int) for e in s):
  436. return s
  437. else:
  438. raise TypeError(
  439. "'markevery' list must have all elements of type int")
  440. raise TypeError("'markevery' is of an invalid type")
  441. validate_markeverylist = _listify_validator(validate_markevery)
  442. def validate_bbox(s):
  443. if isinstance(s, str):
  444. s = s.lower()
  445. if s == 'tight':
  446. return s
  447. if s == 'standard':
  448. return None
  449. raise ValueError("bbox should be 'tight' or 'standard'")
  450. elif s is not None:
  451. # Backwards compatibility. None is equivalent to 'standard'.
  452. raise ValueError("bbox should be 'tight' or 'standard'")
  453. return s
  454. def validate_sketch(s):
  455. if isinstance(s, str):
  456. s = s.lower()
  457. if s == 'none' or s is None:
  458. return None
  459. try:
  460. return tuple(_listify_validator(validate_float, n=3)(s))
  461. except ValueError:
  462. raise ValueError("Expected a (scale, length, randomness) triplet")
  463. def _validate_greaterthan_minushalf(s):
  464. s = validate_float(s)
  465. if s > -0.5:
  466. return s
  467. else:
  468. raise RuntimeError(f'Value must be >-0.5; got {s}')
  469. def _validate_greaterequal0_lessequal1(s):
  470. s = validate_float(s)
  471. if 0 <= s <= 1:
  472. return s
  473. else:
  474. raise RuntimeError(f'Value must be >=0 and <=1; got {s}')
  475. def _validate_int_greaterequal0(s):
  476. s = validate_int(s)
  477. if s >= 0:
  478. return s
  479. else:
  480. raise RuntimeError(f'Value must be >=0; got {s}')
  481. def validate_hatch(s):
  482. r"""
  483. Validate a hatch pattern.
  484. A hatch pattern string can have any sequence of the following
  485. characters: ``\ / | - + * . x o O``.
  486. """
  487. if not isinstance(s, str):
  488. raise ValueError("Hatch pattern must be a string")
  489. _api.check_isinstance(str, hatch_pattern=s)
  490. unknown = set(s) - {'\\', '/', '|', '-', '+', '*', '.', 'x', 'o', 'O'}
  491. if unknown:
  492. raise ValueError("Unknown hatch symbol(s): %s" % list(unknown))
  493. return s
  494. validate_hatchlist = _listify_validator(validate_hatch)
  495. validate_dashlist = _listify_validator(validate_floatlist)
  496. def _validate_minor_tick_ndivs(n):
  497. """
  498. Validate ndiv parameter related to the minor ticks.
  499. It controls the number of minor ticks to be placed between
  500. two major ticks.
  501. """
  502. if isinstance(n, str) and n.lower() == 'auto':
  503. return n
  504. try:
  505. n = _validate_int_greaterequal0(n)
  506. return n
  507. except (RuntimeError, ValueError):
  508. pass
  509. raise ValueError("'tick.minor.ndivs' must be 'auto' or non-negative int")
  510. _prop_validators = {
  511. 'color': _listify_validator(validate_color_for_prop_cycle,
  512. allow_stringlist=True),
  513. 'linewidth': validate_floatlist,
  514. 'linestyle': _listify_validator(_validate_linestyle),
  515. 'facecolor': validate_colorlist,
  516. 'edgecolor': validate_colorlist,
  517. 'joinstyle': _listify_validator(JoinStyle),
  518. 'capstyle': _listify_validator(CapStyle),
  519. 'fillstyle': validate_fillstylelist,
  520. 'markerfacecolor': validate_colorlist,
  521. 'markersize': validate_floatlist,
  522. 'markeredgewidth': validate_floatlist,
  523. 'markeredgecolor': validate_colorlist,
  524. 'markevery': validate_markeverylist,
  525. 'alpha': validate_floatlist,
  526. 'marker': validate_stringlist,
  527. 'hatch': validate_hatchlist,
  528. 'dashes': validate_dashlist,
  529. }
  530. _prop_aliases = {
  531. 'c': 'color',
  532. 'lw': 'linewidth',
  533. 'ls': 'linestyle',
  534. 'fc': 'facecolor',
  535. 'ec': 'edgecolor',
  536. 'mfc': 'markerfacecolor',
  537. 'mec': 'markeredgecolor',
  538. 'mew': 'markeredgewidth',
  539. 'ms': 'markersize',
  540. }
  541. def cycler(*args, **kwargs):
  542. """
  543. Create a `~cycler.Cycler` object much like :func:`cycler.cycler`,
  544. but includes input validation.
  545. Call signatures::
  546. cycler(cycler)
  547. cycler(label=values[, label2=values2[, ...]])
  548. cycler(label, values)
  549. Form 1 copies a given `~cycler.Cycler` object.
  550. Form 2 creates a `~cycler.Cycler` which cycles over one or more
  551. properties simultaneously. If multiple properties are given, their
  552. value lists must have the same length.
  553. Form 3 creates a `~cycler.Cycler` for a single property. This form
  554. exists for compatibility with the original cycler. Its use is
  555. discouraged in favor of the kwarg form, i.e. ``cycler(label=values)``.
  556. Parameters
  557. ----------
  558. cycler : Cycler
  559. Copy constructor for Cycler.
  560. label : str
  561. The property key. Must be a valid `.Artist` property.
  562. For example, 'color' or 'linestyle'. Aliases are allowed,
  563. such as 'c' for 'color' and 'lw' for 'linewidth'.
  564. values : iterable
  565. Finite-length iterable of the property values. These values
  566. are validated and will raise a ValueError if invalid.
  567. Returns
  568. -------
  569. Cycler
  570. A new :class:`~cycler.Cycler` for the given properties.
  571. Examples
  572. --------
  573. Creating a cycler for a single property:
  574. >>> c = cycler(color=['red', 'green', 'blue'])
  575. Creating a cycler for simultaneously cycling over multiple properties
  576. (e.g. red circle, green plus, blue cross):
  577. >>> c = cycler(color=['red', 'green', 'blue'],
  578. ... marker=['o', '+', 'x'])
  579. """
  580. if args and kwargs:
  581. raise TypeError("cycler() can only accept positional OR keyword "
  582. "arguments -- not both.")
  583. elif not args and not kwargs:
  584. raise TypeError("cycler() must have positional OR keyword arguments")
  585. if len(args) == 1:
  586. if not isinstance(args[0], Cycler):
  587. raise TypeError("If only one positional argument given, it must "
  588. "be a Cycler instance.")
  589. return validate_cycler(args[0])
  590. elif len(args) == 2:
  591. pairs = [(args[0], args[1])]
  592. elif len(args) > 2:
  593. raise _api.nargs_error('cycler', '0-2', len(args))
  594. else:
  595. pairs = kwargs.items()
  596. validated = []
  597. for prop, vals in pairs:
  598. norm_prop = _prop_aliases.get(prop, prop)
  599. validator = _prop_validators.get(norm_prop, None)
  600. if validator is None:
  601. raise TypeError("Unknown artist property: %s" % prop)
  602. vals = validator(vals)
  603. # We will normalize the property names as well to reduce
  604. # the amount of alias handling code elsewhere.
  605. validated.append((norm_prop, vals))
  606. return reduce(operator.add, (ccycler(k, v) for k, v in validated))
  607. class _DunderChecker(ast.NodeVisitor):
  608. def visit_Attribute(self, node):
  609. if node.attr.startswith("__") and node.attr.endswith("__"):
  610. raise ValueError("cycler strings with dunders are forbidden")
  611. self.generic_visit(node)
  612. # A validator dedicated to the named legend loc
  613. _validate_named_legend_loc = ValidateInStrings(
  614. 'legend.loc',
  615. [
  616. "best",
  617. "upper right", "upper left", "lower left", "lower right", "right",
  618. "center left", "center right", "lower center", "upper center",
  619. "center"],
  620. ignorecase=True)
  621. def _validate_legend_loc(loc):
  622. """
  623. Confirm that loc is a type which rc.Params["legend.loc"] supports.
  624. .. versionadded:: 3.8
  625. Parameters
  626. ----------
  627. loc : str | int | (float, float) | str((float, float))
  628. The location of the legend.
  629. Returns
  630. -------
  631. loc : str | int | (float, float) or raise ValueError exception
  632. The location of the legend.
  633. """
  634. if isinstance(loc, str):
  635. try:
  636. return _validate_named_legend_loc(loc)
  637. except ValueError:
  638. pass
  639. try:
  640. loc = ast.literal_eval(loc)
  641. except (SyntaxError, ValueError):
  642. pass
  643. if isinstance(loc, int):
  644. if 0 <= loc <= 10:
  645. return loc
  646. if isinstance(loc, tuple):
  647. if len(loc) == 2 and all(isinstance(e, Real) for e in loc):
  648. return loc
  649. raise ValueError(f"{loc} is not a valid legend location.")
  650. def validate_cycler(s):
  651. """Return a Cycler object from a string repr or the object itself."""
  652. if isinstance(s, str):
  653. # TODO: We might want to rethink this...
  654. # While I think I have it quite locked down, it is execution of
  655. # arbitrary code without sanitation.
  656. # Combine this with the possibility that rcparams might come from the
  657. # internet (future plans), this could be downright dangerous.
  658. # I locked it down by only having the 'cycler()' function available.
  659. # UPDATE: Partly plugging a security hole.
  660. # I really should have read this:
  661. # https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
  662. # We should replace this eval with a combo of PyParsing and
  663. # ast.literal_eval()
  664. try:
  665. _DunderChecker().visit(ast.parse(s))
  666. s = eval(s, {'cycler': cycler, '__builtins__': {}})
  667. except BaseException as e:
  668. raise ValueError(f"{s!r} is not a valid cycler construction: {e}"
  669. ) from e
  670. # Should make sure what comes from the above eval()
  671. # is a Cycler object.
  672. if isinstance(s, Cycler):
  673. cycler_inst = s
  674. else:
  675. raise ValueError(f"Object is not a string or Cycler instance: {s!r}")
  676. unknowns = cycler_inst.keys - (set(_prop_validators) | set(_prop_aliases))
  677. if unknowns:
  678. raise ValueError("Unknown artist properties: %s" % unknowns)
  679. # Not a full validation, but it'll at least normalize property names
  680. # A fuller validation would require v0.10 of cycler.
  681. checker = set()
  682. for prop in cycler_inst.keys:
  683. norm_prop = _prop_aliases.get(prop, prop)
  684. if norm_prop != prop and norm_prop in cycler_inst.keys:
  685. raise ValueError(f"Cannot specify both {norm_prop!r} and alias "
  686. f"{prop!r} in the same prop_cycle")
  687. if norm_prop in checker:
  688. raise ValueError(f"Another property was already aliased to "
  689. f"{norm_prop!r}. Collision normalizing {prop!r}.")
  690. checker.update([norm_prop])
  691. # This is just an extra-careful check, just in case there is some
  692. # edge-case I haven't thought of.
  693. assert len(checker) == len(cycler_inst.keys)
  694. # Now, it should be safe to mutate this cycler
  695. for prop in cycler_inst.keys:
  696. norm_prop = _prop_aliases.get(prop, prop)
  697. cycler_inst.change_key(prop, norm_prop)
  698. for key, vals in cycler_inst.by_key().items():
  699. _prop_validators[key](vals)
  700. return cycler_inst
  701. def validate_hist_bins(s):
  702. valid_strs = ["auto", "sturges", "fd", "doane", "scott", "rice", "sqrt"]
  703. if isinstance(s, str) and s in valid_strs:
  704. return s
  705. try:
  706. return int(s)
  707. except (TypeError, ValueError):
  708. pass
  709. try:
  710. return validate_floatlist(s)
  711. except ValueError:
  712. pass
  713. raise ValueError(f"'hist.bins' must be one of {valid_strs}, an int or"
  714. " a sequence of floats")
  715. class _ignorecase(list):
  716. """A marker class indicating that a list-of-str is case-insensitive."""
  717. def _convert_validator_spec(key, conv):
  718. if isinstance(conv, list):
  719. ignorecase = isinstance(conv, _ignorecase)
  720. return ValidateInStrings(key, conv, ignorecase=ignorecase)
  721. else:
  722. return conv
  723. # Mapping of rcParams to validators.
  724. # Converters given as lists or _ignorecase are converted to ValidateInStrings
  725. # immediately below.
  726. # The rcParams defaults are defined in lib/matplotlib/mpl-data/matplotlibrc, which
  727. # gets copied to matplotlib/mpl-data/matplotlibrc by the setup script.
  728. _validators = {
  729. "backend": validate_backend,
  730. "backend_fallback": validate_bool,
  731. "figure.hooks": validate_stringlist,
  732. "toolbar": _validate_toolbar,
  733. "interactive": validate_bool,
  734. "timezone": validate_string,
  735. "webagg.port": validate_int,
  736. "webagg.address": validate_string,
  737. "webagg.open_in_browser": validate_bool,
  738. "webagg.port_retries": validate_int,
  739. # line props
  740. "lines.linewidth": validate_float, # line width in points
  741. "lines.linestyle": _validate_linestyle, # solid line
  742. "lines.color": validate_color, # first color in color cycle
  743. "lines.marker": validate_string, # marker name
  744. "lines.markerfacecolor": validate_color_or_auto, # default color
  745. "lines.markeredgecolor": validate_color_or_auto, # default color
  746. "lines.markeredgewidth": validate_float,
  747. "lines.markersize": validate_float, # markersize, in points
  748. "lines.antialiased": validate_bool, # antialiased (no jaggies)
  749. "lines.dash_joinstyle": JoinStyle,
  750. "lines.solid_joinstyle": JoinStyle,
  751. "lines.dash_capstyle": CapStyle,
  752. "lines.solid_capstyle": CapStyle,
  753. "lines.dashed_pattern": validate_floatlist,
  754. "lines.dashdot_pattern": validate_floatlist,
  755. "lines.dotted_pattern": validate_floatlist,
  756. "lines.scale_dashes": validate_bool,
  757. # marker props
  758. "markers.fillstyle": validate_fillstyle,
  759. ## pcolor(mesh) props:
  760. "pcolor.shading": ["auto", "flat", "nearest", "gouraud"],
  761. "pcolormesh.snap": validate_bool,
  762. ## patch props
  763. "patch.linewidth": validate_float, # line width in points
  764. "patch.edgecolor": validate_color,
  765. "patch.force_edgecolor": validate_bool,
  766. "patch.facecolor": validate_color, # first color in cycle
  767. "patch.antialiased": validate_bool, # antialiased (no jaggies)
  768. ## hatch props
  769. "hatch.color": validate_color,
  770. "hatch.linewidth": validate_float,
  771. ## Histogram properties
  772. "hist.bins": validate_hist_bins,
  773. ## Boxplot properties
  774. "boxplot.notch": validate_bool,
  775. "boxplot.vertical": validate_bool,
  776. "boxplot.whiskers": validate_whiskers,
  777. "boxplot.bootstrap": validate_int_or_None,
  778. "boxplot.patchartist": validate_bool,
  779. "boxplot.showmeans": validate_bool,
  780. "boxplot.showcaps": validate_bool,
  781. "boxplot.showbox": validate_bool,
  782. "boxplot.showfliers": validate_bool,
  783. "boxplot.meanline": validate_bool,
  784. "boxplot.flierprops.color": validate_color,
  785. "boxplot.flierprops.marker": validate_string,
  786. "boxplot.flierprops.markerfacecolor": validate_color_or_auto,
  787. "boxplot.flierprops.markeredgecolor": validate_color,
  788. "boxplot.flierprops.markeredgewidth": validate_float,
  789. "boxplot.flierprops.markersize": validate_float,
  790. "boxplot.flierprops.linestyle": _validate_linestyle,
  791. "boxplot.flierprops.linewidth": validate_float,
  792. "boxplot.boxprops.color": validate_color,
  793. "boxplot.boxprops.linewidth": validate_float,
  794. "boxplot.boxprops.linestyle": _validate_linestyle,
  795. "boxplot.whiskerprops.color": validate_color,
  796. "boxplot.whiskerprops.linewidth": validate_float,
  797. "boxplot.whiskerprops.linestyle": _validate_linestyle,
  798. "boxplot.capprops.color": validate_color,
  799. "boxplot.capprops.linewidth": validate_float,
  800. "boxplot.capprops.linestyle": _validate_linestyle,
  801. "boxplot.medianprops.color": validate_color,
  802. "boxplot.medianprops.linewidth": validate_float,
  803. "boxplot.medianprops.linestyle": _validate_linestyle,
  804. "boxplot.meanprops.color": validate_color,
  805. "boxplot.meanprops.marker": validate_string,
  806. "boxplot.meanprops.markerfacecolor": validate_color,
  807. "boxplot.meanprops.markeredgecolor": validate_color,
  808. "boxplot.meanprops.markersize": validate_float,
  809. "boxplot.meanprops.linestyle": _validate_linestyle,
  810. "boxplot.meanprops.linewidth": validate_float,
  811. ## font props
  812. "font.family": validate_stringlist, # used by text object
  813. "font.style": validate_string,
  814. "font.variant": validate_string,
  815. "font.stretch": validate_fontstretch,
  816. "font.weight": validate_fontweight,
  817. "font.size": validate_float, # Base font size in points
  818. "font.serif": validate_stringlist,
  819. "font.sans-serif": validate_stringlist,
  820. "font.cursive": validate_stringlist,
  821. "font.fantasy": validate_stringlist,
  822. "font.monospace": validate_stringlist,
  823. # text props
  824. "text.color": validate_color,
  825. "text.usetex": validate_bool,
  826. "text.latex.preamble": validate_string,
  827. "text.hinting": ["default", "no_autohint", "force_autohint",
  828. "no_hinting", "auto", "native", "either", "none"],
  829. "text.hinting_factor": validate_int,
  830. "text.kerning_factor": validate_int,
  831. "text.antialiased": validate_bool,
  832. "text.parse_math": validate_bool,
  833. "mathtext.cal": validate_font_properties,
  834. "mathtext.rm": validate_font_properties,
  835. "mathtext.tt": validate_font_properties,
  836. "mathtext.it": validate_font_properties,
  837. "mathtext.bf": validate_font_properties,
  838. "mathtext.bfit": validate_font_properties,
  839. "mathtext.sf": validate_font_properties,
  840. "mathtext.fontset": ["dejavusans", "dejavuserif", "cm", "stix",
  841. "stixsans", "custom"],
  842. "mathtext.default": ["rm", "cal", "bfit", "it", "tt", "sf", "bf", "default",
  843. "bb", "frak", "scr", "regular"],
  844. "mathtext.fallback": _validate_mathtext_fallback,
  845. "image.aspect": validate_aspect, # equal, auto, a number
  846. "image.interpolation": validate_string,
  847. "image.cmap": _validate_cmap, # gray, jet, etc.
  848. "image.lut": validate_int, # lookup table
  849. "image.origin": ["upper", "lower"],
  850. "image.resample": validate_bool,
  851. # Specify whether vector graphics backends will combine all images on a
  852. # set of axes into a single composite image
  853. "image.composite_image": validate_bool,
  854. # contour props
  855. "contour.negative_linestyle": _validate_linestyle,
  856. "contour.corner_mask": validate_bool,
  857. "contour.linewidth": validate_float_or_None,
  858. "contour.algorithm": ["mpl2005", "mpl2014", "serial", "threaded"],
  859. # errorbar props
  860. "errorbar.capsize": validate_float,
  861. # axis props
  862. # alignment of x/y axis title
  863. "xaxis.labellocation": ["left", "center", "right"],
  864. "yaxis.labellocation": ["bottom", "center", "top"],
  865. # axes props
  866. "axes.axisbelow": validate_axisbelow,
  867. "axes.facecolor": validate_color, # background color
  868. "axes.edgecolor": validate_color, # edge color
  869. "axes.linewidth": validate_float, # edge linewidth
  870. "axes.spines.left": validate_bool, # Set visibility of axes spines,
  871. "axes.spines.right": validate_bool, # i.e., the lines around the chart
  872. "axes.spines.bottom": validate_bool, # denoting data boundary.
  873. "axes.spines.top": validate_bool,
  874. "axes.titlesize": validate_fontsize, # axes title fontsize
  875. "axes.titlelocation": ["left", "center", "right"], # axes title alignment
  876. "axes.titleweight": validate_fontweight, # axes title font weight
  877. "axes.titlecolor": validate_color_or_auto, # axes title font color
  878. # title location, axes units, None means auto
  879. "axes.titley": validate_float_or_None,
  880. # pad from axes top decoration to title in points
  881. "axes.titlepad": validate_float,
  882. "axes.grid": validate_bool, # display grid or not
  883. "axes.grid.which": ["minor", "both", "major"], # which grids are drawn
  884. "axes.grid.axis": ["x", "y", "both"], # grid type
  885. "axes.labelsize": validate_fontsize, # fontsize of x & y labels
  886. "axes.labelpad": validate_float, # space between label and axis
  887. "axes.labelweight": validate_fontweight, # fontsize of x & y labels
  888. "axes.labelcolor": validate_color, # color of axis label
  889. # use scientific notation if log10 of the axis range is smaller than the
  890. # first or larger than the second
  891. "axes.formatter.limits": _listify_validator(validate_int, n=2),
  892. # use current locale to format ticks
  893. "axes.formatter.use_locale": validate_bool,
  894. "axes.formatter.use_mathtext": validate_bool,
  895. # minimum exponent to format in scientific notation
  896. "axes.formatter.min_exponent": validate_int,
  897. "axes.formatter.useoffset": validate_bool,
  898. "axes.formatter.offset_threshold": validate_int,
  899. "axes.unicode_minus": validate_bool,
  900. # This entry can be either a cycler object or a string repr of a
  901. # cycler-object, which gets eval()'ed to create the object.
  902. "axes.prop_cycle": validate_cycler,
  903. # If "data", axes limits are set close to the data.
  904. # If "round_numbers" axes limits are set to the nearest round numbers.
  905. "axes.autolimit_mode": ["data", "round_numbers"],
  906. "axes.xmargin": _validate_greaterthan_minushalf, # margin added to xaxis
  907. "axes.ymargin": _validate_greaterthan_minushalf, # margin added to yaxis
  908. "axes.zmargin": _validate_greaterthan_minushalf, # margin added to zaxis
  909. "polaraxes.grid": validate_bool, # display polar grid or not
  910. "axes3d.grid": validate_bool, # display 3d grid
  911. "axes3d.xaxis.panecolor": validate_color, # 3d background pane
  912. "axes3d.yaxis.panecolor": validate_color, # 3d background pane
  913. "axes3d.zaxis.panecolor": validate_color, # 3d background pane
  914. # scatter props
  915. "scatter.marker": validate_string,
  916. "scatter.edgecolors": validate_string,
  917. "date.epoch": _validate_date,
  918. "date.autoformatter.year": validate_string,
  919. "date.autoformatter.month": validate_string,
  920. "date.autoformatter.day": validate_string,
  921. "date.autoformatter.hour": validate_string,
  922. "date.autoformatter.minute": validate_string,
  923. "date.autoformatter.second": validate_string,
  924. "date.autoformatter.microsecond": validate_string,
  925. 'date.converter': ['auto', 'concise'],
  926. # for auto date locator, choose interval_multiples
  927. 'date.interval_multiples': validate_bool,
  928. # legend properties
  929. "legend.fancybox": validate_bool,
  930. "legend.loc": _validate_legend_loc,
  931. # the number of points in the legend line
  932. "legend.numpoints": validate_int,
  933. # the number of points in the legend line for scatter
  934. "legend.scatterpoints": validate_int,
  935. "legend.fontsize": validate_fontsize,
  936. "legend.title_fontsize": validate_fontsize_None,
  937. # color of the legend
  938. "legend.labelcolor": _validate_color_or_linecolor,
  939. # the relative size of legend markers vs. original
  940. "legend.markerscale": validate_float,
  941. # using dict in rcParams not yet supported, so make sure it is bool
  942. "legend.shadow": validate_bool,
  943. # whether or not to draw a frame around legend
  944. "legend.frameon": validate_bool,
  945. # alpha value of the legend frame
  946. "legend.framealpha": validate_float_or_None,
  947. ## the following dimensions are in fraction of the font size
  948. "legend.borderpad": validate_float, # units are fontsize
  949. # the vertical space between the legend entries
  950. "legend.labelspacing": validate_float,
  951. # the length of the legend lines
  952. "legend.handlelength": validate_float,
  953. # the length of the legend lines
  954. "legend.handleheight": validate_float,
  955. # the space between the legend line and legend text
  956. "legend.handletextpad": validate_float,
  957. # the border between the axes and legend edge
  958. "legend.borderaxespad": validate_float,
  959. # the border between the axes and legend edge
  960. "legend.columnspacing": validate_float,
  961. "legend.facecolor": validate_color_or_inherit,
  962. "legend.edgecolor": validate_color_or_inherit,
  963. # tick properties
  964. "xtick.top": validate_bool, # draw ticks on top side
  965. "xtick.bottom": validate_bool, # draw ticks on bottom side
  966. "xtick.labeltop": validate_bool, # draw label on top
  967. "xtick.labelbottom": validate_bool, # draw label on bottom
  968. "xtick.major.size": validate_float, # major xtick size in points
  969. "xtick.minor.size": validate_float, # minor xtick size in points
  970. "xtick.major.width": validate_float, # major xtick width in points
  971. "xtick.minor.width": validate_float, # minor xtick width in points
  972. "xtick.major.pad": validate_float, # distance to label in points
  973. "xtick.minor.pad": validate_float, # distance to label in points
  974. "xtick.color": validate_color, # color of xticks
  975. "xtick.labelcolor": validate_color_or_inherit, # color of xtick labels
  976. "xtick.minor.visible": validate_bool, # visibility of minor xticks
  977. "xtick.minor.top": validate_bool, # draw top minor xticks
  978. "xtick.minor.bottom": validate_bool, # draw bottom minor xticks
  979. "xtick.major.top": validate_bool, # draw top major xticks
  980. "xtick.major.bottom": validate_bool, # draw bottom major xticks
  981. # number of minor xticks
  982. "xtick.minor.ndivs": _validate_minor_tick_ndivs,
  983. "xtick.labelsize": validate_fontsize, # fontsize of xtick labels
  984. "xtick.direction": ["out", "in", "inout"], # direction of xticks
  985. "xtick.alignment": ["center", "right", "left"],
  986. "ytick.left": validate_bool, # draw ticks on left side
  987. "ytick.right": validate_bool, # draw ticks on right side
  988. "ytick.labelleft": validate_bool, # draw tick labels on left side
  989. "ytick.labelright": validate_bool, # draw tick labels on right side
  990. "ytick.major.size": validate_float, # major ytick size in points
  991. "ytick.minor.size": validate_float, # minor ytick size in points
  992. "ytick.major.width": validate_float, # major ytick width in points
  993. "ytick.minor.width": validate_float, # minor ytick width in points
  994. "ytick.major.pad": validate_float, # distance to label in points
  995. "ytick.minor.pad": validate_float, # distance to label in points
  996. "ytick.color": validate_color, # color of yticks
  997. "ytick.labelcolor": validate_color_or_inherit, # color of ytick labels
  998. "ytick.minor.visible": validate_bool, # visibility of minor yticks
  999. "ytick.minor.left": validate_bool, # draw left minor yticks
  1000. "ytick.minor.right": validate_bool, # draw right minor yticks
  1001. "ytick.major.left": validate_bool, # draw left major yticks
  1002. "ytick.major.right": validate_bool, # draw right major yticks
  1003. # number of minor yticks
  1004. "ytick.minor.ndivs": _validate_minor_tick_ndivs,
  1005. "ytick.labelsize": validate_fontsize, # fontsize of ytick labels
  1006. "ytick.direction": ["out", "in", "inout"], # direction of yticks
  1007. "ytick.alignment": [
  1008. "center", "top", "bottom", "baseline", "center_baseline"],
  1009. "grid.color": validate_color, # grid color
  1010. "grid.linestyle": _validate_linestyle, # solid
  1011. "grid.linewidth": validate_float, # in points
  1012. "grid.alpha": validate_float,
  1013. ## figure props
  1014. # figure title
  1015. "figure.titlesize": validate_fontsize,
  1016. "figure.titleweight": validate_fontweight,
  1017. # figure labels
  1018. "figure.labelsize": validate_fontsize,
  1019. "figure.labelweight": validate_fontweight,
  1020. # figure size in inches: width by height
  1021. "figure.figsize": _listify_validator(validate_float, n=2),
  1022. "figure.dpi": validate_float,
  1023. "figure.facecolor": validate_color,
  1024. "figure.edgecolor": validate_color,
  1025. "figure.frameon": validate_bool,
  1026. "figure.autolayout": validate_bool,
  1027. "figure.max_open_warning": validate_int,
  1028. "figure.raise_window": validate_bool,
  1029. "macosx.window_mode": ["system", "tab", "window"],
  1030. "figure.subplot.left": validate_float,
  1031. "figure.subplot.right": validate_float,
  1032. "figure.subplot.bottom": validate_float,
  1033. "figure.subplot.top": validate_float,
  1034. "figure.subplot.wspace": validate_float,
  1035. "figure.subplot.hspace": validate_float,
  1036. "figure.constrained_layout.use": validate_bool, # run constrained_layout?
  1037. # wspace and hspace are fraction of adjacent subplots to use for space.
  1038. # Much smaller than above because we don't need room for the text.
  1039. "figure.constrained_layout.hspace": validate_float,
  1040. "figure.constrained_layout.wspace": validate_float,
  1041. # buffer around the axes, in inches.
  1042. "figure.constrained_layout.h_pad": validate_float,
  1043. "figure.constrained_layout.w_pad": validate_float,
  1044. ## Saving figure's properties
  1045. 'savefig.dpi': validate_dpi,
  1046. 'savefig.facecolor': validate_color_or_auto,
  1047. 'savefig.edgecolor': validate_color_or_auto,
  1048. 'savefig.orientation': ['landscape', 'portrait'],
  1049. "savefig.format": validate_string,
  1050. "savefig.bbox": validate_bbox, # "tight", or "standard" (= None)
  1051. "savefig.pad_inches": validate_float,
  1052. # default directory in savefig dialog box
  1053. "savefig.directory": _validate_pathlike,
  1054. "savefig.transparent": validate_bool,
  1055. "tk.window_focus": validate_bool, # Maintain shell focus for TkAgg
  1056. # Set the papersize/type
  1057. "ps.papersize": _validate_papersize,
  1058. "ps.useafm": validate_bool,
  1059. # use ghostscript or xpdf to distill ps output
  1060. "ps.usedistiller": validate_ps_distiller,
  1061. "ps.distiller.res": validate_int, # dpi
  1062. "ps.fonttype": validate_fonttype, # 3 (Type3) or 42 (Truetype)
  1063. "pdf.compression": validate_int, # 0-9 compression level; 0 to disable
  1064. "pdf.inheritcolor": validate_bool, # skip color setting commands
  1065. # use only the 14 PDF core fonts embedded in every PDF viewing application
  1066. "pdf.use14corefonts": validate_bool,
  1067. "pdf.fonttype": validate_fonttype, # 3 (Type3) or 42 (Truetype)
  1068. "pgf.texsystem": ["xelatex", "lualatex", "pdflatex"], # latex variant used
  1069. "pgf.rcfonts": validate_bool, # use mpl's rc settings for font config
  1070. "pgf.preamble": validate_string, # custom LaTeX preamble
  1071. # write raster image data into the svg file
  1072. "svg.image_inline": validate_bool,
  1073. "svg.fonttype": ["none", "path"], # save text as text ("none") or "paths"
  1074. "svg.hashsalt": validate_string_or_None,
  1075. # set this when you want to generate hardcopy docstring
  1076. "docstring.hardcopy": validate_bool,
  1077. "path.simplify": validate_bool,
  1078. "path.simplify_threshold": _validate_greaterequal0_lessequal1,
  1079. "path.snap": validate_bool,
  1080. "path.sketch": validate_sketch,
  1081. "path.effects": validate_anylist,
  1082. "agg.path.chunksize": validate_int, # 0 to disable chunking
  1083. # key-mappings (multi-character mappings should be a list/tuple)
  1084. "keymap.fullscreen": validate_stringlist,
  1085. "keymap.home": validate_stringlist,
  1086. "keymap.back": validate_stringlist,
  1087. "keymap.forward": validate_stringlist,
  1088. "keymap.pan": validate_stringlist,
  1089. "keymap.zoom": validate_stringlist,
  1090. "keymap.save": validate_stringlist,
  1091. "keymap.quit": validate_stringlist,
  1092. "keymap.quit_all": validate_stringlist, # e.g.: "W", "cmd+W", "Q"
  1093. "keymap.grid": validate_stringlist,
  1094. "keymap.grid_minor": validate_stringlist,
  1095. "keymap.yscale": validate_stringlist,
  1096. "keymap.xscale": validate_stringlist,
  1097. "keymap.help": validate_stringlist,
  1098. "keymap.copy": validate_stringlist,
  1099. # Animation settings
  1100. "animation.html": ["html5", "jshtml", "none"],
  1101. # Limit, in MB, of size of base64 encoded animation in HTML
  1102. # (i.e. IPython notebook)
  1103. "animation.embed_limit": validate_float,
  1104. "animation.writer": validate_string,
  1105. "animation.codec": validate_string,
  1106. "animation.bitrate": validate_int,
  1107. # Controls image format when frames are written to disk
  1108. "animation.frame_format": ["png", "jpeg", "tiff", "raw", "rgba", "ppm",
  1109. "sgi", "bmp", "pbm", "svg"],
  1110. # Path to ffmpeg binary. If just binary name, subprocess uses $PATH.
  1111. "animation.ffmpeg_path": _validate_pathlike,
  1112. # Additional arguments for ffmpeg movie writer (using pipes)
  1113. "animation.ffmpeg_args": validate_stringlist,
  1114. # Path to convert binary. If just binary name, subprocess uses $PATH.
  1115. "animation.convert_path": _validate_pathlike,
  1116. # Additional arguments for convert movie writer (using pipes)
  1117. "animation.convert_args": validate_stringlist,
  1118. # Classic (pre 2.0) compatibility mode
  1119. # This is used for things that are hard to make backward compatible
  1120. # with a sane rcParam alone. This does *not* turn on classic mode
  1121. # altogether. For that use `matplotlib.style.use("classic")`.
  1122. "_internal.classic_mode": validate_bool
  1123. }
  1124. _hardcoded_defaults = { # Defaults not inferred from
  1125. # lib/matplotlib/mpl-data/matplotlibrc...
  1126. # ... because they are private:
  1127. "_internal.classic_mode": False,
  1128. # ... because they are deprecated:
  1129. # No current deprecations.
  1130. # backend is handled separately when constructing rcParamsDefault.
  1131. }
  1132. _validators = {k: _convert_validator_spec(k, conv)
  1133. for k, conv in _validators.items()}