You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1460 lines
57 KiB

4 years ago
  1. """
  2. The rcsetup module contains the default values and the validation code for
  3. customization using matplotlib's rc settings.
  4. Each rc setting is assigned a default value and a function used to validate
  5. any attempted changes to that setting. The default values and validation
  6. functions are defined in the rcsetup module, and are used to construct the
  7. rcParams global object which stores the settings and is referenced throughout
  8. matplotlib.
  9. These default values should be consistent with the default matplotlibrc file
  10. that actually reflects the values given here. Any additions or deletions to the
  11. parameter set listed here should also be visited to the
  12. :file:`matplotlibrc.template` in matplotlib's root source directory.
  13. """
  14. from collections.abc import Iterable, Mapping
  15. from functools import reduce
  16. import operator
  17. import os
  18. import re
  19. import sys
  20. from matplotlib import cbook
  21. from matplotlib.cbook import ls_mapper
  22. from matplotlib.fontconfig_pattern import parse_fontconfig_pattern
  23. from matplotlib.colors import is_color_like
  24. # Don't let the original cycler collide with our validating cycler
  25. from cycler import Cycler, cycler as ccycler
  26. # The capitalized forms are needed for ipython at present; this may
  27. # change for later versions.
  28. interactive_bk = ['GTK3Agg', 'GTK3Cairo',
  29. 'MacOSX',
  30. 'nbAgg',
  31. 'Qt4Agg', 'Qt4Cairo', 'Qt5Agg', 'Qt5Cairo',
  32. 'TkAgg', 'TkCairo',
  33. 'WebAgg',
  34. 'WX', 'WXAgg', 'WXCairo']
  35. non_interactive_bk = ['agg', 'cairo',
  36. 'pdf', 'pgf', 'ps', 'svg', 'template']
  37. all_backends = interactive_bk + non_interactive_bk
  38. class ValidateInStrings(object):
  39. def __init__(self, key, valid, ignorecase=False):
  40. 'valid is a list of legal strings'
  41. self.key = key
  42. self.ignorecase = ignorecase
  43. def func(s):
  44. if ignorecase:
  45. return s.lower()
  46. else:
  47. return s
  48. self.valid = {func(k): k for k in valid}
  49. def __call__(self, s):
  50. if self.ignorecase:
  51. s = s.lower()
  52. if s in self.valid:
  53. return self.valid[s]
  54. raise ValueError('Unrecognized %s string %r: valid strings are %s'
  55. % (self.key, s, list(self.valid.values())))
  56. def _listify_validator(scalar_validator, allow_stringlist=False):
  57. def f(s):
  58. if isinstance(s, str):
  59. try:
  60. return [scalar_validator(v.strip()) for v in s.split(',')
  61. if v.strip()]
  62. except Exception:
  63. if allow_stringlist:
  64. # Sometimes, a list of colors might be a single string
  65. # of single-letter colornames. So give that a shot.
  66. return [scalar_validator(v.strip()) for v in s if v.strip()]
  67. else:
  68. raise
  69. # We should allow any generic sequence type, including generators,
  70. # Numpy ndarrays, and pandas data structures. However, unordered
  71. # sequences, such as sets, should be allowed but discouraged unless the
  72. # user desires pseudorandom behavior.
  73. elif isinstance(s, Iterable) and not isinstance(s, Mapping):
  74. # The condition on this list comprehension will preserve the
  75. # behavior of filtering out any empty strings (behavior was
  76. # from the original validate_stringlist()), while allowing
  77. # any non-string/text scalar values such as numbers and arrays.
  78. return [scalar_validator(v) for v in s
  79. if not isinstance(v, str) or v]
  80. else:
  81. raise ValueError("{!r} must be of type: string or non-dictionary "
  82. "iterable".format(s))
  83. try:
  84. f.__name__ = "{}list".format(scalar_validator.__name__)
  85. except AttributeError: # class instance.
  86. f.__name__ = "{}List".format(type(scalar_validator).__name__)
  87. f.__doc__ = scalar_validator.__doc__
  88. return f
  89. def validate_any(s):
  90. return s
  91. validate_anylist = _listify_validator(validate_any)
  92. def validate_path_exists(s):
  93. """If s is a path, return s, else False"""
  94. if s is None:
  95. return None
  96. if os.path.exists(s):
  97. return s
  98. else:
  99. raise RuntimeError('"%s" should be a path but it does not exist' % s)
  100. def validate_bool(b):
  101. """Convert b to a boolean or raise"""
  102. if isinstance(b, str):
  103. b = b.lower()
  104. if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True):
  105. return True
  106. elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False):
  107. return False
  108. else:
  109. raise ValueError('Could not convert "%s" to boolean' % b)
  110. def validate_bool_maybe_none(b):
  111. 'Convert b to a boolean or raise'
  112. if isinstance(b, str):
  113. b = b.lower()
  114. if b is None or b == 'none':
  115. return None
  116. if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True):
  117. return True
  118. elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False):
  119. return False
  120. else:
  121. raise ValueError('Could not convert "%s" to boolean' % b)
  122. def validate_float(s):
  123. """convert s to float or raise"""
  124. try:
  125. return float(s)
  126. except ValueError:
  127. raise ValueError('Could not convert "%s" to float' % s)
  128. validate_floatlist = _listify_validator(validate_float)
  129. def validate_float_or_None(s):
  130. """convert s to float, None or raise"""
  131. # values directly from the rc file can only be strings,
  132. # so we need to recognize the string "None" and convert
  133. # it into the object. We will be case-sensitive here to
  134. # avoid confusion between string values of 'none', which
  135. # can be a valid string value for some other parameters.
  136. if s is None or s == 'None':
  137. return None
  138. try:
  139. return float(s)
  140. except ValueError:
  141. raise ValueError('Could not convert "%s" to float or None' % s)
  142. def validate_string_or_None(s):
  143. """convert s to string or raise"""
  144. if s is None:
  145. return None
  146. try:
  147. return validate_string(s)
  148. except ValueError:
  149. raise ValueError('Could not convert "%s" to string' % s)
  150. def validate_axisbelow(s):
  151. try:
  152. return validate_bool(s)
  153. except ValueError:
  154. if isinstance(s, str):
  155. s = s.lower()
  156. if s.startswith('line'):
  157. return 'line'
  158. raise ValueError('%s cannot be interpreted as'
  159. ' True, False, or "line"' % s)
  160. def validate_dpi(s):
  161. """confirm s is string 'figure' or convert s to float or raise"""
  162. if s == 'figure':
  163. return s
  164. try:
  165. return float(s)
  166. except ValueError:
  167. raise ValueError('"%s" is not string "figure" or'
  168. ' could not convert "%s" to float' % (s, s))
  169. def validate_int(s):
  170. """convert s to int or raise"""
  171. try:
  172. return int(s)
  173. except ValueError:
  174. raise ValueError('Could not convert "%s" to int' % s)
  175. def validate_int_or_None(s):
  176. """if not None, tries to validate as an int"""
  177. if s=='None':
  178. s = None
  179. if s is None:
  180. return None
  181. try:
  182. return int(s)
  183. except ValueError:
  184. raise ValueError('Could not convert "%s" to int' % s)
  185. def validate_fonttype(s):
  186. """
  187. confirm that this is a Postscript of PDF font type that we know how to
  188. convert to
  189. """
  190. fonttypes = {'type3': 3,
  191. 'truetype': 42}
  192. try:
  193. fonttype = validate_int(s)
  194. except ValueError:
  195. try:
  196. return fonttypes[s.lower()]
  197. except KeyError:
  198. raise ValueError(
  199. 'Supported Postscript/PDF font types are %s' % list(fonttypes))
  200. else:
  201. if fonttype not in fonttypes.values():
  202. raise ValueError(
  203. 'Supported Postscript/PDF font types are %s' %
  204. list(fonttypes.values()))
  205. return fonttype
  206. _validate_standard_backends = ValidateInStrings(
  207. 'backend', all_backends, ignorecase=True)
  208. _auto_backend_sentinel = object()
  209. def validate_backend(s):
  210. backend = (
  211. s if s is _auto_backend_sentinel or s.startswith("module://")
  212. else _validate_standard_backends(s))
  213. return backend
  214. def validate_qt4(s):
  215. if s is None:
  216. return None
  217. return ValidateInStrings("backend.qt4", ['PyQt4', 'PySide', 'PyQt4v2'])(s)
  218. def validate_qt5(s):
  219. if s is None:
  220. return None
  221. return ValidateInStrings("backend.qt5", ['PyQt5', 'PySide2'])(s)
  222. def validate_toolbar(s):
  223. validator = ValidateInStrings(
  224. 'toolbar',
  225. ['None', 'toolbar2', 'toolmanager'],
  226. ignorecase=True)
  227. return validator(s)
  228. _seq_err_msg = ('You must supply exactly {n} values, you provided {num} '
  229. 'values: {s}')
  230. _str_err_msg = ('You must supply exactly {n} comma-separated values, you '
  231. 'provided {num} comma-separated values: {s}')
  232. class validate_nseq_float(object):
  233. def __init__(self, n=None, allow_none=False):
  234. self.n = n
  235. self.allow_none = allow_none
  236. def __call__(self, s):
  237. """return a seq of n floats or raise"""
  238. if isinstance(s, str):
  239. s = [x.strip() for x in s.split(',')]
  240. err_msg = _str_err_msg
  241. else:
  242. err_msg = _seq_err_msg
  243. if self.n is not None and len(s) != self.n:
  244. raise ValueError(err_msg.format(n=self.n, num=len(s), s=s))
  245. try:
  246. return [float(val)
  247. if not self.allow_none or val is not None
  248. else val
  249. for val in s]
  250. except ValueError:
  251. raise ValueError('Could not convert all entries to floats')
  252. class validate_nseq_int(object):
  253. def __init__(self, n=None):
  254. self.n = n
  255. def __call__(self, s):
  256. """return a seq of n ints or raise"""
  257. if isinstance(s, str):
  258. s = [x.strip() for x in s.split(',')]
  259. err_msg = _str_err_msg
  260. else:
  261. err_msg = _seq_err_msg
  262. if self.n is not None and len(s) != self.n:
  263. raise ValueError(err_msg.format(n=self.n, num=len(s), s=s))
  264. try:
  265. return [int(val) for val in s]
  266. except ValueError:
  267. raise ValueError('Could not convert all entries to ints')
  268. def validate_color_or_inherit(s):
  269. 'return a valid color arg'
  270. if s == 'inherit':
  271. return s
  272. return validate_color(s)
  273. def validate_color_or_auto(s):
  274. if s == 'auto':
  275. return s
  276. return validate_color(s)
  277. def validate_color_for_prop_cycle(s):
  278. # Special-case the N-th color cycle syntax, this obviously can not
  279. # go in the color cycle.
  280. if isinstance(s, bytes):
  281. match = re.match(b'^C[0-9]$', s)
  282. if match is not None:
  283. raise ValueError('Can not put cycle reference ({cn!r}) in '
  284. 'prop_cycler'.format(cn=s))
  285. elif isinstance(s, str):
  286. match = re.match('^C[0-9]$', s)
  287. if match is not None:
  288. raise ValueError('Can not put cycle reference ({cn!r}) in '
  289. 'prop_cycler'.format(cn=s))
  290. return validate_color(s)
  291. def validate_color(s):
  292. 'return a valid color arg'
  293. try:
  294. if s.lower() == 'none':
  295. return 'none'
  296. except AttributeError:
  297. pass
  298. if isinstance(s, str):
  299. if len(s) == 6 or len(s) == 8:
  300. stmp = '#' + s
  301. if is_color_like(stmp):
  302. return stmp
  303. if is_color_like(s):
  304. return s
  305. # If it is still valid, it must be a tuple.
  306. colorarg = s
  307. msg = ''
  308. if s.find(',') >= 0:
  309. # get rid of grouping symbols
  310. stmp = ''.join([c for c in s if c.isdigit() or c == '.' or c == ','])
  311. vals = stmp.split(',')
  312. if len(vals) not in [3, 4]:
  313. msg = '\nColor tuples must be of length 3 or 4'
  314. else:
  315. try:
  316. colorarg = [float(val) for val in vals]
  317. except ValueError:
  318. msg = '\nCould not convert all entries to floats'
  319. if not msg and is_color_like(colorarg):
  320. return colorarg
  321. raise ValueError('%s does not look like a color arg%s' % (s, msg))
  322. validate_colorlist = _listify_validator(validate_color, allow_stringlist=True)
  323. validate_colorlist.__doc__ = 'return a list of colorspecs'
  324. def validate_string(s):
  325. if isinstance(s, (str, str)):
  326. # Always leave str as str and unicode as unicode
  327. return s
  328. else:
  329. return str(s)
  330. validate_stringlist = _listify_validator(str)
  331. validate_stringlist.__doc__ = 'return a list'
  332. validate_orientation = ValidateInStrings(
  333. 'orientation', ['landscape', 'portrait'])
  334. def validate_aspect(s):
  335. if s in ('auto', 'equal'):
  336. return s
  337. try:
  338. return float(s)
  339. except ValueError:
  340. raise ValueError('not a valid aspect specification')
  341. def validate_fontsize_None(s):
  342. if s is None or s == 'None':
  343. return None
  344. else:
  345. return validate_fontsize(s)
  346. def validate_fontsize(s):
  347. fontsizes = ['xx-small', 'x-small', 'small', 'medium', 'large',
  348. 'x-large', 'xx-large', 'smaller', 'larger']
  349. if isinstance(s, str):
  350. s = s.lower()
  351. if s in fontsizes:
  352. return s
  353. try:
  354. return float(s)
  355. except ValueError:
  356. raise ValueError("%s is not a valid font size. Valid font sizes "
  357. "are %s." % (s, ", ".join(fontsizes)))
  358. validate_fontsizelist = _listify_validator(validate_fontsize)
  359. def validate_font_properties(s):
  360. parse_fontconfig_pattern(s)
  361. return s
  362. validate_fontset = ValidateInStrings(
  363. 'fontset',
  364. ['dejavusans', 'dejavuserif', 'cm', 'stix', 'stixsans', 'custom'])
  365. validate_mathtext_default = ValidateInStrings(
  366. 'default',
  367. "rm cal it tt sf bf default bb frak circled scr regular".split())
  368. validate_verbose = ValidateInStrings(
  369. 'verbose',
  370. ['silent', 'helpful', 'debug', 'debug-annoying'])
  371. _validate_alignment = ValidateInStrings(
  372. 'alignment',
  373. ['center', 'top', 'bottom', 'baseline',
  374. 'center_baseline'])
  375. def validate_whiskers(s):
  376. if s == 'range':
  377. return 'range'
  378. else:
  379. try:
  380. v = validate_nseq_float(2)(s)
  381. return v
  382. except (TypeError, ValueError):
  383. try:
  384. v = float(s)
  385. return v
  386. except ValueError:
  387. raise ValueError("Not a valid whisker value ['range', float, "
  388. "(float, float)]")
  389. def update_savefig_format(value):
  390. # The old savefig.extension could also have a value of "auto", but
  391. # the new savefig.format does not. We need to fix this here.
  392. value = validate_string(value)
  393. if value == 'auto':
  394. value = 'png'
  395. return value
  396. validate_ps_papersize = ValidateInStrings(
  397. 'ps_papersize',
  398. ['auto', 'letter', 'legal', 'ledger',
  399. 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'a10',
  400. 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'b10',
  401. ], ignorecase=True)
  402. def validate_ps_distiller(s):
  403. if isinstance(s, str):
  404. s = s.lower()
  405. if s in ('none', None):
  406. return None
  407. elif s in ('false', False):
  408. return False
  409. elif s in ('ghostscript', 'xpdf'):
  410. return s
  411. else:
  412. raise ValueError('matplotlibrc ps.usedistiller must either be none, '
  413. 'ghostscript or xpdf')
  414. validate_joinstyle = ValidateInStrings('joinstyle',
  415. ['miter', 'round', 'bevel'],
  416. ignorecase=True)
  417. validate_joinstylelist = _listify_validator(validate_joinstyle)
  418. validate_capstyle = ValidateInStrings('capstyle',
  419. ['butt', 'round', 'projecting'],
  420. ignorecase=True)
  421. validate_capstylelist = _listify_validator(validate_capstyle)
  422. validate_fillstyle = ValidateInStrings('markers.fillstyle',
  423. ['full', 'left', 'right', 'bottom',
  424. 'top', 'none'])
  425. validate_fillstylelist = _listify_validator(validate_fillstyle)
  426. _validate_negative_linestyle = ValidateInStrings('negative_linestyle',
  427. ['solid', 'dashed'],
  428. ignorecase=True)
  429. def validate_markevery(s):
  430. """
  431. Validate the markevery property of a Line2D object.
  432. Parameters
  433. ----------
  434. s : None, int, float, slice, length-2 tuple of ints,
  435. length-2 tuple of floats, list of ints
  436. Returns
  437. -------
  438. s : None, int, float, slice, length-2 tuple of ints,
  439. length-2 tuple of floats, list of ints
  440. """
  441. # Validate s against type slice
  442. if isinstance(s, slice):
  443. return s
  444. # Validate s against type tuple
  445. if isinstance(s, tuple):
  446. tupMaxLength = 2
  447. tupType = type(s[0])
  448. if len(s) != tupMaxLength:
  449. raise TypeError("'markevery' tuple must have a length of "
  450. "%d" % (tupMaxLength))
  451. if tupType is int and not all(isinstance(e, int) for e in s):
  452. raise TypeError("'markevery' tuple with first element of "
  453. "type int must have all elements of type "
  454. "int")
  455. if tupType is float and not all(isinstance(e, float) for e in s):
  456. raise TypeError("'markevery' tuple with first element of "
  457. "type float must have all elements of type "
  458. "float")
  459. if tupType is not float and tupType is not int:
  460. raise TypeError("'markevery' tuple contains an invalid type")
  461. # Validate s against type list
  462. elif isinstance(s, list):
  463. if not all(isinstance(e, int) for e in s):
  464. raise TypeError("'markevery' list must have all elements of "
  465. "type int")
  466. # Validate s against type float int and None
  467. elif not isinstance(s, (float, int)):
  468. if s is not None:
  469. raise TypeError("'markevery' is of an invalid type")
  470. return s
  471. validate_markeverylist = _listify_validator(validate_markevery)
  472. validate_legend_loc = ValidateInStrings(
  473. 'legend_loc',
  474. ['best',
  475. 'upper right',
  476. 'upper left',
  477. 'lower left',
  478. 'lower right',
  479. 'right',
  480. 'center left',
  481. 'center right',
  482. 'lower center',
  483. 'upper center',
  484. 'center'], ignorecase=True)
  485. def validate_svg_fonttype(s):
  486. if s in ["none", "path"]:
  487. return s
  488. if s == "svgfont":
  489. cbook.warn_deprecated(
  490. "2.2", "'svgfont' support for svg.fonttype is deprecated.")
  491. return s
  492. raise ValueError("Unrecognized svg.fonttype string '{}'; "
  493. "valid strings are 'none', 'path'")
  494. def validate_hinting(s):
  495. if s in (True, False):
  496. return s
  497. if s.lower() in ('auto', 'native', 'either', 'none'):
  498. return s.lower()
  499. raise ValueError("hinting should be 'auto', 'native', 'either' or 'none'")
  500. validate_pgf_texsystem = ValidateInStrings('pgf.texsystem',
  501. ['xelatex', 'lualatex', 'pdflatex'])
  502. validate_movie_writer = ValidateInStrings('animation.writer',
  503. ['ffmpeg', 'ffmpeg_file',
  504. 'avconv', 'avconv_file',
  505. 'imagemagick', 'imagemagick_file',
  506. 'html'])
  507. validate_movie_frame_fmt = ValidateInStrings('animation.frame_format',
  508. ['png', 'jpeg', 'tiff', 'raw', 'rgba'])
  509. validate_axis_locator = ValidateInStrings('major', ['minor', 'both', 'major'])
  510. validate_movie_html_fmt = ValidateInStrings('animation.html',
  511. ['html5', 'jshtml', 'none'])
  512. def validate_bbox(s):
  513. if isinstance(s, str):
  514. s = s.lower()
  515. if s == 'tight':
  516. return s
  517. if s == 'standard':
  518. return None
  519. raise ValueError("bbox should be 'tight' or 'standard'")
  520. elif s is not None:
  521. # Backwards compatibility. None is equivalent to 'standard'.
  522. raise ValueError("bbox should be 'tight' or 'standard'")
  523. return s
  524. def validate_sketch(s):
  525. if isinstance(s, str):
  526. s = s.lower()
  527. if s == 'none' or s is None:
  528. return None
  529. if isinstance(s, str):
  530. result = tuple([float(v.strip()) for v in s.split(',')])
  531. elif isinstance(s, (list, tuple)):
  532. result = tuple([float(v) for v in s])
  533. if len(result) != 3:
  534. raise ValueError("path.sketch must be a tuple (scale, length, randomness)")
  535. return result
  536. class ValidateInterval(object):
  537. """
  538. Value must be in interval
  539. """
  540. def __init__(self, vmin, vmax, closedmin=True, closedmax=True):
  541. self.vmin = vmin
  542. self.vmax = vmax
  543. self.cmin = closedmin
  544. self.cmax = closedmax
  545. def __call__(self, s):
  546. try:
  547. s = float(s)
  548. except ValueError:
  549. raise RuntimeError('Value must be a float; found "%s"' % s)
  550. if self.cmin and s < self.vmin:
  551. raise RuntimeError('Value must be >= %f; found "%f"' %
  552. (self.vmin, s))
  553. elif not self.cmin and s <= self.vmin:
  554. raise RuntimeError('Value must be > %f; found "%f"' %
  555. (self.vmin, s))
  556. if self.cmax and s > self.vmax:
  557. raise RuntimeError('Value must be <= %f; found "%f"' %
  558. (self.vmax, s))
  559. elif not self.cmax and s >= self.vmax:
  560. raise RuntimeError('Value must be < %f; found "%f"' %
  561. (self.vmax, s))
  562. return s
  563. validate_grid_axis = ValidateInStrings('axes.grid.axis', ['x', 'y', 'both'])
  564. def validate_hatch(s):
  565. """
  566. Validate a hatch pattern.
  567. A hatch pattern string can have any sequence of the following
  568. characters: ``\\ / | - + * . x o O``.
  569. """
  570. if not isinstance(s, str):
  571. raise ValueError("Hatch pattern must be a string")
  572. unknown = set(s) - {'\\', '/', '|', '-', '+', '*', '.', 'x', 'o', 'O'}
  573. if unknown:
  574. raise ValueError("Unknown hatch symbol(s): %s" % list(unknown))
  575. return s
  576. validate_hatchlist = _listify_validator(validate_hatch)
  577. validate_dashlist = _listify_validator(validate_nseq_float(allow_none=True))
  578. _prop_validators = {
  579. 'color': _listify_validator(validate_color_for_prop_cycle,
  580. allow_stringlist=True),
  581. 'linewidth': validate_floatlist,
  582. 'linestyle': validate_stringlist,
  583. 'facecolor': validate_colorlist,
  584. 'edgecolor': validate_colorlist,
  585. 'joinstyle': validate_joinstylelist,
  586. 'capstyle': validate_capstylelist,
  587. 'fillstyle': validate_fillstylelist,
  588. 'markerfacecolor': validate_colorlist,
  589. 'markersize': validate_floatlist,
  590. 'markeredgewidth': validate_floatlist,
  591. 'markeredgecolor': validate_colorlist,
  592. 'markevery': validate_markeverylist,
  593. 'alpha': validate_floatlist,
  594. 'marker': validate_stringlist,
  595. 'hatch': validate_hatchlist,
  596. 'dashes': validate_dashlist,
  597. }
  598. _prop_aliases = {
  599. 'c': 'color',
  600. 'lw': 'linewidth',
  601. 'ls': 'linestyle',
  602. 'fc': 'facecolor',
  603. 'ec': 'edgecolor',
  604. 'mfc': 'markerfacecolor',
  605. 'mec': 'markeredgecolor',
  606. 'mew': 'markeredgewidth',
  607. 'ms': 'markersize',
  608. }
  609. def cycler(*args, **kwargs):
  610. """
  611. Creates a `~cycler.Cycler` object much like :func:`cycler.cycler`,
  612. but includes input validation.
  613. Call signatures::
  614. cycler(cycler)
  615. cycler(label=values[, label2=values2[, ...]])
  616. cycler(label, values)
  617. Form 1 copies a given `~cycler.Cycler` object.
  618. Form 2 creates a `~cycler.Cycler` which cycles over one or more
  619. properties simultaneously. If multiple properties are given, their
  620. value lists must have the same length.
  621. Form 3 creates a `~cycler.Cycler` for a single property. This form
  622. exists for compatibility with the original cycler. Its use is
  623. discouraged in favor of the kwarg form, i.e. ``cycler(label=values)``.
  624. Parameters
  625. ----------
  626. cycler : Cycler
  627. Copy constructor for Cycler.
  628. label : str
  629. The property key. Must be a valid `.Artist` property.
  630. For example, 'color' or 'linestyle'. Aliases are allowed,
  631. such as 'c' for 'color' and 'lw' for 'linewidth'.
  632. values : iterable
  633. Finite-length iterable of the property values. These values
  634. are validated and will raise a ValueError if invalid.
  635. Returns
  636. -------
  637. cycler : Cycler
  638. A new :class:`~cycler.Cycler` for the given properties.
  639. Examples
  640. --------
  641. Creating a cycler for a single property:
  642. >>> c = cycler(color=['red', 'green', 'blue'])
  643. Creating a cycler for simultaneously cycling over multiple properties
  644. (e.g. red circle, green plus, blue cross):
  645. >>> c = cycler(color=['red', 'green', 'blue'],
  646. ... marker=['o', '+', 'x'])
  647. """
  648. if args and kwargs:
  649. raise TypeError("cycler() can only accept positional OR keyword "
  650. "arguments -- not both.")
  651. elif not args and not kwargs:
  652. raise TypeError("cycler() must have positional OR keyword arguments")
  653. if len(args) == 1:
  654. if not isinstance(args[0], Cycler):
  655. raise TypeError("If only one positional argument given, it must "
  656. " be a Cycler instance.")
  657. return validate_cycler(args[0])
  658. elif len(args) == 2:
  659. pairs = [(args[0], args[1])]
  660. elif len(args) > 2:
  661. raise TypeError("No more than 2 positional arguments allowed")
  662. else:
  663. pairs = kwargs.items()
  664. validated = []
  665. for prop, vals in pairs:
  666. norm_prop = _prop_aliases.get(prop, prop)
  667. validator = _prop_validators.get(norm_prop, None)
  668. if validator is None:
  669. raise TypeError("Unknown artist property: %s" % prop)
  670. vals = validator(vals)
  671. # We will normalize the property names as well to reduce
  672. # the amount of alias handling code elsewhere.
  673. validated.append((norm_prop, vals))
  674. return reduce(operator.add, (ccycler(k, v) for k, v in validated))
  675. def validate_cycler(s):
  676. 'return a Cycler object from a string repr or the object itself'
  677. if isinstance(s, str):
  678. try:
  679. # TODO: We might want to rethink this...
  680. # While I think I have it quite locked down,
  681. # it is execution of arbitrary code without
  682. # sanitation.
  683. # Combine this with the possibility that rcparams
  684. # might come from the internet (future plans), this
  685. # could be downright dangerous.
  686. # I locked it down by only having the 'cycler()' function
  687. # available.
  688. # UPDATE: Partly plugging a security hole.
  689. # I really should have read this:
  690. # http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
  691. # We should replace this eval with a combo of PyParsing and
  692. # ast.literal_eval()
  693. if '.__' in s.replace(' ', ''):
  694. raise ValueError("'%s' seems to have dunder methods. Raising"
  695. " an exception for your safety")
  696. s = eval(s, {'cycler': cycler, '__builtins__': {}})
  697. except BaseException as e:
  698. raise ValueError("'%s' is not a valid cycler construction: %s" %
  699. (s, e))
  700. # Should make sure what comes from the above eval()
  701. # is a Cycler object.
  702. if isinstance(s, Cycler):
  703. cycler_inst = s
  704. else:
  705. raise ValueError("object was not a string or Cycler instance: %s" % s)
  706. unknowns = cycler_inst.keys - (set(_prop_validators) | set(_prop_aliases))
  707. if unknowns:
  708. raise ValueError("Unknown artist properties: %s" % unknowns)
  709. # Not a full validation, but it'll at least normalize property names
  710. # A fuller validation would require v0.10 of cycler.
  711. checker = set()
  712. for prop in cycler_inst.keys:
  713. norm_prop = _prop_aliases.get(prop, prop)
  714. if norm_prop != prop and norm_prop in cycler_inst.keys:
  715. raise ValueError("Cannot specify both '{0}' and alias '{1}'"
  716. " in the same prop_cycle".format(norm_prop, prop))
  717. if norm_prop in checker:
  718. raise ValueError("Another property was already aliased to '{0}'."
  719. " Collision normalizing '{1}'.".format(norm_prop,
  720. prop))
  721. checker.update([norm_prop])
  722. # This is just an extra-careful check, just in case there is some
  723. # edge-case I haven't thought of.
  724. assert len(checker) == len(cycler_inst.keys)
  725. # Now, it should be safe to mutate this cycler
  726. for prop in cycler_inst.keys:
  727. norm_prop = _prop_aliases.get(prop, prop)
  728. cycler_inst.change_key(prop, norm_prop)
  729. for key, vals in cycler_inst.by_key().items():
  730. _prop_validators[key](vals)
  731. return cycler_inst
  732. def validate_hist_bins(s):
  733. if cbook._str_equal(s, "auto"):
  734. return s
  735. try:
  736. return int(s)
  737. except (TypeError, ValueError):
  738. pass
  739. try:
  740. return validate_floatlist(s)
  741. except ValueError:
  742. pass
  743. raise ValueError("'hist.bins' must be 'auto', an int or " +
  744. "a sequence of floats")
  745. def validate_animation_writer_path(p):
  746. # Make sure it's a string and then figure out if the animations
  747. # are already loaded and reset the writers (which will validate
  748. # the path on next call)
  749. if not isinstance(p, str):
  750. raise ValueError("path must be a (unicode) string")
  751. from sys import modules
  752. # set dirty, so that the next call to the registry will re-evaluate
  753. # the state.
  754. # only set dirty if already loaded. If not loaded, the load will
  755. # trigger the checks.
  756. if "matplotlib.animation" in modules:
  757. modules["matplotlib.animation"].writers.set_dirty()
  758. return p
  759. def validate_webagg_address(s):
  760. if s is not None:
  761. import socket
  762. try:
  763. socket.inet_aton(s)
  764. except socket.error as e:
  765. raise ValueError("'webagg.address' is not a valid IP address")
  766. return s
  767. raise ValueError("'webagg.address' is not a valid IP address")
  768. # A validator dedicated to the named line styles, based on the items in
  769. # ls_mapper, and a list of possible strings read from Line2D.set_linestyle
  770. _validate_named_linestyle = ValidateInStrings(
  771. 'linestyle',
  772. [*ls_mapper.keys(), *ls_mapper.values(), 'None', 'none', ' ', ''],
  773. ignorecase=True)
  774. def _validate_linestyle(ls):
  775. """
  776. A validator for all possible line styles, the named ones *and*
  777. the on-off ink sequences.
  778. """
  779. # Look first for a valid named line style, like '--' or 'solid' Also
  780. # includes bytes(-arrays) here (they all fail _validate_named_linestyle);
  781. # otherwise, if *ls* is of even-length, it will be passed to the instance
  782. # of validate_nseq_float, which will return an absurd on-off ink
  783. # sequence...
  784. if isinstance(ls, (str, bytes, bytearray)):
  785. return _validate_named_linestyle(ls)
  786. # Look for an on-off ink sequence (in points) *of even length*.
  787. # Offset is set to None.
  788. try:
  789. if len(ls) % 2 != 0:
  790. raise ValueError("the linestyle sequence {!r} is not of even "
  791. "length.".format(ls))
  792. return (None, validate_nseq_float()(ls))
  793. except (ValueError, TypeError):
  794. # TypeError can be raised inside the instance of validate_nseq_float,
  795. # by wrong types passed to float(), like NoneType.
  796. raise ValueError("linestyle {!r} is not a valid on-off ink "
  797. "sequence.".format(ls))
  798. # a map from key -> value, converter
  799. defaultParams = {
  800. 'backend': [_auto_backend_sentinel, validate_backend],
  801. 'backend_fallback': [True, validate_bool],
  802. 'backend.qt4': [None, validate_qt4],
  803. 'backend.qt5': [None, validate_qt5],
  804. 'webagg.port': [8988, validate_int],
  805. 'webagg.address': ['127.0.0.1', validate_webagg_address],
  806. 'webagg.open_in_browser': [True, validate_bool],
  807. 'webagg.port_retries': [50, validate_int],
  808. 'nbagg.transparent': [True, validate_bool],
  809. 'toolbar': ['toolbar2', validate_toolbar],
  810. 'datapath': [None, validate_path_exists], # handled by
  811. # _get_data_path_cached
  812. 'interactive': [False, validate_bool],
  813. 'timezone': ['UTC', validate_string],
  814. # the verbosity setting
  815. 'verbose.level': ['silent', validate_verbose],
  816. 'verbose.fileo': ['sys.stdout', validate_string],
  817. # line props
  818. 'lines.linewidth': [1.5, validate_float], # line width in points
  819. 'lines.linestyle': ['-', _validate_linestyle], # solid line
  820. 'lines.color': ['C0', validate_color], # first color in color cycle
  821. 'lines.marker': ['None', validate_string], # marker name
  822. 'lines.markerfacecolor': ['auto', validate_color_or_auto], # default color
  823. 'lines.markeredgecolor': ['auto', validate_color_or_auto], # default color
  824. 'lines.markeredgewidth': [1.0, validate_float],
  825. 'lines.markersize': [6, validate_float], # markersize, in points
  826. 'lines.antialiased': [True, validate_bool], # antialiased (no jaggies)
  827. 'lines.dash_joinstyle': ['round', validate_joinstyle],
  828. 'lines.solid_joinstyle': ['round', validate_joinstyle],
  829. 'lines.dash_capstyle': ['butt', validate_capstyle],
  830. 'lines.solid_capstyle': ['projecting', validate_capstyle],
  831. 'lines.dashed_pattern': [[3.7, 1.6], validate_nseq_float(allow_none=True)],
  832. 'lines.dashdot_pattern': [[6.4, 1.6, 1, 1.6],
  833. validate_nseq_float(allow_none=True)],
  834. 'lines.dotted_pattern': [[1, 1.65], validate_nseq_float(allow_none=True)],
  835. 'lines.scale_dashes': [True, validate_bool],
  836. # marker props
  837. 'markers.fillstyle': ['full', validate_fillstyle],
  838. ## patch props
  839. 'patch.linewidth': [1.0, validate_float], # line width in points
  840. 'patch.edgecolor': ['black', validate_color],
  841. 'patch.force_edgecolor' : [False, validate_bool],
  842. 'patch.facecolor': ['C0', validate_color], # first color in cycle
  843. 'patch.antialiased': [True, validate_bool], # antialiased (no jaggies)
  844. ## hatch props
  845. 'hatch.color': ['black', validate_color],
  846. 'hatch.linewidth': [1.0, validate_float],
  847. ## Histogram properties
  848. 'hist.bins': [10, validate_hist_bins],
  849. ## Boxplot properties
  850. 'boxplot.notch': [False, validate_bool],
  851. 'boxplot.vertical': [True, validate_bool],
  852. 'boxplot.whiskers': [1.5, validate_whiskers],
  853. 'boxplot.bootstrap': [None, validate_int_or_None],
  854. 'boxplot.patchartist': [False, validate_bool],
  855. 'boxplot.showmeans': [False, validate_bool],
  856. 'boxplot.showcaps': [True, validate_bool],
  857. 'boxplot.showbox': [True, validate_bool],
  858. 'boxplot.showfliers': [True, validate_bool],
  859. 'boxplot.meanline': [False, validate_bool],
  860. 'boxplot.flierprops.color': ['black', validate_color],
  861. 'boxplot.flierprops.marker': ['o', validate_string],
  862. 'boxplot.flierprops.markerfacecolor': ['none', validate_color_or_auto],
  863. 'boxplot.flierprops.markeredgecolor': ['black', validate_color],
  864. 'boxplot.flierprops.markersize': [6, validate_float],
  865. 'boxplot.flierprops.linestyle': ['none', _validate_linestyle],
  866. 'boxplot.flierprops.linewidth': [1.0, validate_float],
  867. 'boxplot.boxprops.color': ['black', validate_color],
  868. 'boxplot.boxprops.linewidth': [1.0, validate_float],
  869. 'boxplot.boxprops.linestyle': ['-', _validate_linestyle],
  870. 'boxplot.whiskerprops.color': ['black', validate_color],
  871. 'boxplot.whiskerprops.linewidth': [1.0, validate_float],
  872. 'boxplot.whiskerprops.linestyle': ['-', _validate_linestyle],
  873. 'boxplot.capprops.color': ['black', validate_color],
  874. 'boxplot.capprops.linewidth': [1.0, validate_float],
  875. 'boxplot.capprops.linestyle': ['-', _validate_linestyle],
  876. 'boxplot.medianprops.color': ['C1', validate_color],
  877. 'boxplot.medianprops.linewidth': [1.0, validate_float],
  878. 'boxplot.medianprops.linestyle': ['-', _validate_linestyle],
  879. 'boxplot.meanprops.color': ['C2', validate_color],
  880. 'boxplot.meanprops.marker': ['^', validate_string],
  881. 'boxplot.meanprops.markerfacecolor': ['C2', validate_color],
  882. 'boxplot.meanprops.markeredgecolor': ['C2', validate_color],
  883. 'boxplot.meanprops.markersize': [6, validate_float],
  884. 'boxplot.meanprops.linestyle': ['--', _validate_linestyle],
  885. 'boxplot.meanprops.linewidth': [1.0, validate_float],
  886. ## font props
  887. 'font.family': [['sans-serif'], validate_stringlist], # used by text object
  888. 'font.style': ['normal', validate_string],
  889. 'font.variant': ['normal', validate_string],
  890. 'font.stretch': ['normal', validate_string],
  891. 'font.weight': ['normal', validate_string],
  892. 'font.size': [10, validate_float], # Base font size in points
  893. 'font.serif': [['DejaVu Serif', 'Bitstream Vera Serif',
  894. 'Computer Modern Roman',
  895. 'New Century Schoolbook', 'Century Schoolbook L',
  896. 'Utopia', 'ITC Bookman', 'Bookman',
  897. 'Nimbus Roman No9 L', 'Times New Roman',
  898. 'Times', 'Palatino', 'Charter', 'serif'],
  899. validate_stringlist],
  900. 'font.sans-serif': [['DejaVu Sans', 'Bitstream Vera Sans',
  901. 'Computer Modern Sans Serif',
  902. 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid',
  903. 'Arial', 'Helvetica', 'Avant Garde', 'sans-serif'],
  904. validate_stringlist],
  905. 'font.cursive': [['Apple Chancery', 'Textile', 'Zapf Chancery',
  906. 'Sand', 'Script MT', 'Felipa', 'cursive'],
  907. validate_stringlist],
  908. 'font.fantasy': [['Comic Sans MS', 'Chicago', 'Charcoal', 'Impact',
  909. 'Western', 'Humor Sans', 'xkcd', 'fantasy'],
  910. validate_stringlist],
  911. 'font.monospace': [['DejaVu Sans Mono', 'Bitstream Vera Sans Mono',
  912. 'Computer Modern Typewriter',
  913. 'Andale Mono', 'Nimbus Mono L', 'Courier New',
  914. 'Courier', 'Fixed', 'Terminal', 'monospace'],
  915. validate_stringlist],
  916. # text props
  917. 'text.color': ['black', validate_color],
  918. 'text.usetex': [False, validate_bool],
  919. 'text.latex.unicode': [True, validate_bool],
  920. 'text.latex.preamble': [[''], validate_stringlist],
  921. 'text.latex.preview': [False, validate_bool],
  922. 'text.dvipnghack': [None, validate_bool_maybe_none],
  923. 'text.hinting': ['auto', validate_hinting],
  924. 'text.hinting_factor': [8, validate_int],
  925. 'text.antialiased': [True, validate_bool],
  926. 'mathtext.cal': ['cursive', validate_font_properties],
  927. 'mathtext.rm': ['sans', validate_font_properties],
  928. 'mathtext.tt': ['monospace', validate_font_properties],
  929. 'mathtext.it': ['sans:italic', validate_font_properties],
  930. 'mathtext.bf': ['sans:bold', validate_font_properties],
  931. 'mathtext.sf': ['sans', validate_font_properties],
  932. 'mathtext.fontset': ['dejavusans', validate_fontset],
  933. 'mathtext.default': ['it', validate_mathtext_default],
  934. 'mathtext.fallback_to_cm': [True, validate_bool],
  935. 'image.aspect': ['equal', validate_aspect], # equal, auto, a number
  936. 'image.interpolation': ['nearest', validate_string],
  937. 'image.cmap': ['viridis', validate_string], # one of gray, jet, etc
  938. 'image.lut': [256, validate_int], # lookup table
  939. 'image.origin': ['upper', validate_string], # lookup table
  940. 'image.resample': [True, validate_bool],
  941. # Specify whether vector graphics backends will combine all images on a
  942. # set of axes into a single composite image
  943. 'image.composite_image': [True, validate_bool],
  944. # contour props
  945. 'contour.negative_linestyle': ['dashed', _validate_linestyle],
  946. 'contour.corner_mask': [True, validate_bool],
  947. # errorbar props
  948. 'errorbar.capsize': [0, validate_float],
  949. # axes props
  950. 'axes.axisbelow': ['line', validate_axisbelow],
  951. 'axes.facecolor': ['white', validate_color], # background color
  952. 'axes.edgecolor': ['black', validate_color], # edge color
  953. 'axes.linewidth': [0.8, validate_float], # edge linewidth
  954. 'axes.spines.left': [True, validate_bool], # Set visibility of axes
  955. 'axes.spines.right': [True, validate_bool], # 'spines', the lines
  956. 'axes.spines.bottom': [True, validate_bool], # around the chart
  957. 'axes.spines.top': [True, validate_bool], # denoting data boundary
  958. 'axes.titlesize': ['large', validate_fontsize], # fontsize of the
  959. # axes title
  960. 'axes.titleweight': ['normal', validate_string], # font weight of axes title
  961. 'axes.titlepad': [6.0, validate_float], # pad from axes top to title in points
  962. 'axes.grid': [False, validate_bool], # display grid or not
  963. 'axes.grid.which': ['major', validate_axis_locator], # set whether the gid are by
  964. # default draw on 'major'
  965. # 'minor' or 'both' kind of
  966. # axis locator
  967. 'axes.grid.axis': ['both', validate_grid_axis], # grid type.
  968. # Can be 'x', 'y', 'both'
  969. 'axes.labelsize': ['medium', validate_fontsize], # fontsize of the
  970. # x any y labels
  971. 'axes.labelpad': [4.0, validate_float], # space between label and axis
  972. 'axes.labelweight': ['normal', validate_string], # fontsize of the x any y labels
  973. 'axes.labelcolor': ['black', validate_color], # color of axis label
  974. 'axes.formatter.limits': [[-7, 7], validate_nseq_int(2)],
  975. # use scientific notation if log10
  976. # of the axis range is smaller than the
  977. # first or larger than the second
  978. 'axes.formatter.use_locale': [False, validate_bool],
  979. # Use the current locale to format ticks
  980. 'axes.formatter.use_mathtext': [False, validate_bool],
  981. 'axes.formatter.min_exponent': [0, validate_int], # minimum exponent to format in scientific notation
  982. 'axes.formatter.useoffset': [True, validate_bool],
  983. 'axes.formatter.offset_threshold': [4, validate_int],
  984. 'axes.unicode_minus': [True, validate_bool],
  985. # This entry can be either a cycler object or a
  986. # string repr of a cycler-object, which gets eval()'ed
  987. # to create the object.
  988. 'axes.prop_cycle': [
  989. ccycler('color',
  990. ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728',
  991. '#9467bd', '#8c564b', '#e377c2', '#7f7f7f',
  992. '#bcbd22', '#17becf']),
  993. validate_cycler],
  994. # If 'data', axes limits are set close to the data.
  995. # If 'round_numbers' axes limits are set to the nearest round numbers.
  996. 'axes.autolimit_mode': [
  997. 'data',
  998. ValidateInStrings('autolimit_mode', ['data', 'round_numbers'])],
  999. 'axes.xmargin': [0.05, ValidateInterval(0, 1,
  1000. closedmin=True,
  1001. closedmax=True)], # margin added to xaxis
  1002. 'axes.ymargin': [0.05, ValidateInterval(0, 1,
  1003. closedmin=True,
  1004. closedmax=True)],# margin added to yaxis
  1005. 'polaraxes.grid': [True, validate_bool], # display polar grid or
  1006. # not
  1007. 'axes3d.grid': [True, validate_bool], # display 3d grid
  1008. # scatter props
  1009. 'scatter.marker': ['o', validate_string],
  1010. # TODO validate that these are valid datetime format strings
  1011. 'date.autoformatter.year': ['%Y', validate_string],
  1012. 'date.autoformatter.month': ['%Y-%m', validate_string],
  1013. 'date.autoformatter.day': ['%Y-%m-%d', validate_string],
  1014. 'date.autoformatter.hour': ['%m-%d %H', validate_string],
  1015. 'date.autoformatter.minute': ['%d %H:%M', validate_string],
  1016. 'date.autoformatter.second': ['%H:%M:%S', validate_string],
  1017. 'date.autoformatter.microsecond': ['%M:%S.%f', validate_string],
  1018. #legend properties
  1019. 'legend.fancybox': [True, validate_bool],
  1020. 'legend.loc': ['best', validate_legend_loc],
  1021. # the number of points in the legend line
  1022. 'legend.numpoints': [1, validate_int],
  1023. # the number of points in the legend line for scatter
  1024. 'legend.scatterpoints': [1, validate_int],
  1025. 'legend.fontsize': ['medium', validate_fontsize],
  1026. 'legend.title_fontsize': [None, validate_fontsize_None],
  1027. # the relative size of legend markers vs. original
  1028. 'legend.markerscale': [1.0, validate_float],
  1029. 'legend.shadow': [False, validate_bool],
  1030. # whether or not to draw a frame around legend
  1031. 'legend.frameon': [True, validate_bool],
  1032. # alpha value of the legend frame
  1033. 'legend.framealpha': [0.8, validate_float_or_None],
  1034. ## the following dimensions are in fraction of the font size
  1035. 'legend.borderpad': [0.4, validate_float], # units are fontsize
  1036. # the vertical space between the legend entries
  1037. 'legend.labelspacing': [0.5, validate_float],
  1038. # the length of the legend lines
  1039. 'legend.handlelength': [2., validate_float],
  1040. # the length of the legend lines
  1041. 'legend.handleheight': [0.7, validate_float],
  1042. # the space between the legend line and legend text
  1043. 'legend.handletextpad': [.8, validate_float],
  1044. # the border between the axes and legend edge
  1045. 'legend.borderaxespad': [0.5, validate_float],
  1046. # the border between the axes and legend edge
  1047. 'legend.columnspacing': [2., validate_float],
  1048. 'legend.facecolor': ['inherit', validate_color_or_inherit],
  1049. 'legend.edgecolor': ['0.8', validate_color_or_inherit],
  1050. # tick properties
  1051. 'xtick.top': [False, validate_bool], # draw ticks on the top side
  1052. 'xtick.bottom': [True, validate_bool], # draw ticks on the bottom side
  1053. 'xtick.labeltop': [False, validate_bool], # draw label on the top
  1054. 'xtick.labelbottom': [True, validate_bool], # draw label on the bottom
  1055. 'xtick.major.size': [3.5, validate_float], # major xtick size in points
  1056. 'xtick.minor.size': [2, validate_float], # minor xtick size in points
  1057. 'xtick.major.width': [0.8, validate_float], # major xtick width in points
  1058. 'xtick.minor.width': [0.6, validate_float], # minor xtick width in points
  1059. 'xtick.major.pad': [3.5, validate_float], # distance to label in points
  1060. 'xtick.minor.pad': [3.4, validate_float], # distance to label in points
  1061. 'xtick.color': ['black', validate_color], # color of the xtick labels
  1062. 'xtick.minor.visible': [False, validate_bool], # visibility of the x axis minor ticks
  1063. 'xtick.minor.top': [True, validate_bool], # draw x axis top minor ticks
  1064. 'xtick.minor.bottom': [True, validate_bool], # draw x axis bottom minor ticks
  1065. 'xtick.major.top': [True, validate_bool], # draw x axis top major ticks
  1066. 'xtick.major.bottom': [True, validate_bool], # draw x axis bottom major ticks
  1067. # fontsize of the xtick labels
  1068. 'xtick.labelsize': ['medium', validate_fontsize],
  1069. 'xtick.direction': ['out', validate_string], # direction of xticks
  1070. 'xtick.alignment': ["center", _validate_alignment],
  1071. 'ytick.left': [True, validate_bool], # draw ticks on the left side
  1072. 'ytick.right': [False, validate_bool], # draw ticks on the right side
  1073. 'ytick.labelleft': [True, validate_bool], # draw tick labels on the left side
  1074. 'ytick.labelright': [False, validate_bool], # draw tick labels on the right side
  1075. 'ytick.major.size': [3.5, validate_float], # major ytick size in points
  1076. 'ytick.minor.size': [2, validate_float], # minor ytick size in points
  1077. 'ytick.major.width': [0.8, validate_float], # major ytick width in points
  1078. 'ytick.minor.width': [0.6, validate_float], # minor ytick width in points
  1079. 'ytick.major.pad': [3.5, validate_float], # distance to label in points
  1080. 'ytick.minor.pad': [3.4, validate_float], # distance to label in points
  1081. 'ytick.color': ['black', validate_color], # color of the ytick labels
  1082. 'ytick.minor.visible': [False, validate_bool], # visibility of the y axis minor ticks
  1083. 'ytick.minor.left': [True, validate_bool], # draw y axis left minor ticks
  1084. 'ytick.minor.right': [True, validate_bool], # draw y axis right minor ticks
  1085. 'ytick.major.left': [True, validate_bool], # draw y axis left major ticks
  1086. 'ytick.major.right': [True, validate_bool], # draw y axis right major ticks
  1087. # fontsize of the ytick labels
  1088. 'ytick.labelsize': ['medium', validate_fontsize],
  1089. 'ytick.direction': ['out', validate_string], # direction of yticks
  1090. 'ytick.alignment': ["center_baseline", _validate_alignment],
  1091. 'grid.color': ['#b0b0b0', validate_color], # grid color
  1092. 'grid.linestyle': ['-', _validate_linestyle], # solid
  1093. 'grid.linewidth': [0.8, validate_float], # in points
  1094. 'grid.alpha': [1.0, validate_float],
  1095. ## figure props
  1096. # figure title
  1097. 'figure.titlesize': ['large', validate_fontsize],
  1098. 'figure.titleweight': ['normal', validate_string],
  1099. # figure size in inches: width by height
  1100. 'figure.figsize': [[6.4, 4.8], validate_nseq_float(2)],
  1101. 'figure.dpi': [100, validate_float], # DPI
  1102. 'figure.facecolor': ['white', validate_color],
  1103. 'figure.edgecolor': ['white', validate_color],
  1104. 'figure.frameon': [True, validate_bool],
  1105. 'figure.autolayout': [False, validate_bool],
  1106. 'figure.max_open_warning': [20, validate_int],
  1107. 'figure.subplot.left': [0.125, ValidateInterval(0, 1, closedmin=True,
  1108. closedmax=True)],
  1109. 'figure.subplot.right': [0.9, ValidateInterval(0, 1, closedmin=True,
  1110. closedmax=True)],
  1111. 'figure.subplot.bottom': [0.11, ValidateInterval(0, 1, closedmin=True,
  1112. closedmax=True)],
  1113. 'figure.subplot.top': [0.88, ValidateInterval(0, 1, closedmin=True,
  1114. closedmax=True)],
  1115. 'figure.subplot.wspace': [0.2, ValidateInterval(0, 1, closedmin=True,
  1116. closedmax=False)],
  1117. 'figure.subplot.hspace': [0.2, ValidateInterval(0, 1, closedmin=True,
  1118. closedmax=False)],
  1119. # do constrained_layout.
  1120. 'figure.constrained_layout.use': [False, validate_bool],
  1121. # wspace and hspace are fraction of adjacent subplots to use
  1122. # for space. Much smaller than above because we don't need
  1123. # room for the text.
  1124. 'figure.constrained_layout.hspace': [0.02, ValidateInterval(
  1125. 0, 1, closedmin=True, closedmax=False)],
  1126. 'figure.constrained_layout.wspace': [0.02, ValidateInterval(
  1127. 0, 1, closedmin=True, closedmax=False)],
  1128. # This is a buffer around the axes in inches. This is 3pts.
  1129. 'figure.constrained_layout.h_pad': [0.04167, validate_float],
  1130. 'figure.constrained_layout.w_pad': [0.04167, validate_float],
  1131. ## Saving figure's properties
  1132. 'savefig.dpi': ['figure', validate_dpi], # DPI
  1133. 'savefig.facecolor': ['white', validate_color],
  1134. 'savefig.edgecolor': ['white', validate_color],
  1135. 'savefig.frameon': [True, validate_bool],
  1136. 'savefig.orientation': ['portrait', validate_orientation], # edgecolor;
  1137. #white
  1138. 'savefig.jpeg_quality': [95, validate_int],
  1139. # value checked by backend at runtime
  1140. 'savefig.format': ['png', update_savefig_format],
  1141. # options are 'tight', or 'standard'. 'standard' validates to None.
  1142. 'savefig.bbox': ['standard', validate_bbox],
  1143. 'savefig.pad_inches': [0.1, validate_float],
  1144. # default directory in savefig dialog box
  1145. 'savefig.directory': ['~', validate_string],
  1146. 'savefig.transparent': [False, validate_bool],
  1147. # Maintain shell focus for TkAgg
  1148. 'tk.window_focus': [False, validate_bool],
  1149. # Set the papersize/type
  1150. 'ps.papersize': ['letter', validate_ps_papersize],
  1151. 'ps.useafm': [False, validate_bool], # Set PYTHONINSPECT
  1152. # use ghostscript or xpdf to distill ps output
  1153. 'ps.usedistiller': [False, validate_ps_distiller],
  1154. 'ps.distiller.res': [6000, validate_int], # dpi
  1155. 'ps.fonttype': [3, validate_fonttype], # 3 (Type3) or 42 (Truetype)
  1156. # compression level from 0 to 9; 0 to disable
  1157. 'pdf.compression': [6, validate_int],
  1158. # ignore any color-setting commands from the frontend
  1159. 'pdf.inheritcolor': [False, validate_bool],
  1160. # use only the 14 PDF core fonts embedded in every PDF viewing application
  1161. 'pdf.use14corefonts': [False, validate_bool],
  1162. 'pdf.fonttype': [3, validate_fonttype], # 3 (Type3) or 42 (Truetype)
  1163. 'pgf.debug': [False, validate_bool], # output debug information
  1164. # choose latex application for creating pdf files (xelatex/lualatex)
  1165. 'pgf.texsystem': ['xelatex', validate_pgf_texsystem],
  1166. # use matplotlib rc settings for font configuration
  1167. 'pgf.rcfonts': [True, validate_bool],
  1168. # provide a custom preamble for the latex process
  1169. 'pgf.preamble': [[''], validate_stringlist],
  1170. # write raster image data directly into the svg file
  1171. 'svg.image_inline': [True, validate_bool],
  1172. # True to save all characters as paths in the SVG
  1173. 'svg.fonttype': ['path', validate_svg_fonttype],
  1174. 'svg.hashsalt': [None, validate_string_or_None],
  1175. # set this when you want to generate hardcopy docstring
  1176. 'docstring.hardcopy': [False, validate_bool],
  1177. # where plugin directory is locate
  1178. 'plugins.directory': ['.matplotlib_plugins', validate_string],
  1179. 'path.simplify': [True, validate_bool],
  1180. 'path.simplify_threshold': [1.0 / 9.0, ValidateInterval(0.0, 1.0)],
  1181. 'path.snap': [True, validate_bool],
  1182. 'path.sketch': [None, validate_sketch],
  1183. 'path.effects': [[], validate_any],
  1184. 'agg.path.chunksize': [0, validate_int], # 0 to disable chunking;
  1185. # key-mappings (multi-character mappings should be a list/tuple)
  1186. 'keymap.fullscreen': [('f', 'ctrl+f'), validate_stringlist],
  1187. 'keymap.home': [['h', 'r', 'home'], validate_stringlist],
  1188. 'keymap.back': [['left', 'c', 'backspace'], validate_stringlist],
  1189. 'keymap.forward': [['right', 'v'], validate_stringlist],
  1190. 'keymap.pan': [['p'], validate_stringlist],
  1191. 'keymap.zoom': [['o'], validate_stringlist],
  1192. 'keymap.save': [['s', 'ctrl+s'], validate_stringlist],
  1193. 'keymap.quit': [['ctrl+w', 'cmd+w', 'q'], validate_stringlist],
  1194. 'keymap.quit_all': [['W', 'cmd+W', 'Q'], validate_stringlist],
  1195. 'keymap.grid': [['g'], validate_stringlist],
  1196. 'keymap.grid_minor': [['G'], validate_stringlist],
  1197. 'keymap.yscale': [['l'], validate_stringlist],
  1198. 'keymap.xscale': [['k', 'L'], validate_stringlist],
  1199. 'keymap.all_axes': [['a'], validate_stringlist],
  1200. 'keymap.help': [['f1'], validate_stringlist],
  1201. 'keymap.copy': [['ctrl+c', 'cmd+c'], validate_stringlist],
  1202. # sample data
  1203. 'examples.directory': ['', validate_string],
  1204. # Animation settings
  1205. 'animation.html': ['none', validate_movie_html_fmt],
  1206. # Limit, in MB, of size of base64 encoded animation in HTML
  1207. # (i.e. IPython notebook)
  1208. 'animation.embed_limit': [20, validate_float],
  1209. 'animation.writer': ['ffmpeg', validate_movie_writer],
  1210. 'animation.codec': ['h264', validate_string],
  1211. 'animation.bitrate': [-1, validate_int],
  1212. # Controls image format when frames are written to disk
  1213. 'animation.frame_format': ['png', validate_movie_frame_fmt],
  1214. # Additional arguments for HTML writer
  1215. 'animation.html_args': [[], validate_stringlist],
  1216. # Path to ffmpeg binary. If just binary name, subprocess uses $PATH.
  1217. 'animation.ffmpeg_path': ['ffmpeg', validate_animation_writer_path],
  1218. # Additional arguments for ffmpeg movie writer (using pipes)
  1219. 'animation.ffmpeg_args': [[], validate_stringlist],
  1220. # Path to AVConv binary. If just binary name, subprocess uses $PATH.
  1221. 'animation.avconv_path': ['avconv', validate_animation_writer_path],
  1222. # Additional arguments for avconv movie writer (using pipes)
  1223. 'animation.avconv_args': [[], validate_stringlist],
  1224. # Path to convert binary. If just binary name, subprocess uses $PATH.
  1225. 'animation.convert_path': ['convert', validate_animation_writer_path],
  1226. # Additional arguments for convert movie writer (using pipes)
  1227. 'animation.convert_args': [[], validate_stringlist],
  1228. # Classic (pre 2.0) compatibility mode
  1229. # This is used for things that are hard to make backward compatible
  1230. # with a sane rcParam alone. This does *not* turn on classic mode
  1231. # altogether. For that use `matplotlib.style.use('classic')`.
  1232. '_internal.classic_mode': [False, validate_bool]
  1233. }
  1234. if __name__ == '__main__':
  1235. rc = defaultParams
  1236. rc['datapath'][0] = '/'
  1237. for key in rc:
  1238. if not rc[key][1](rc[key][0]) == rc[key][0]:
  1239. print("%s: %s != %s" % (key, rc[key][1](rc[key][0]), rc[key][0]))