Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/matplotlib/rcsetup.py: 66%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

474 statements  

1""" 

2The rcsetup module contains the validation code for customization using 

3Matplotlib's rc settings. 

4 

5Each rc setting is assigned a function used to validate any attempted changes 

6to that setting. The validation functions are defined in the rcsetup module, 

7and are used to construct the rcParams global object which stores the settings 

8and is referenced throughout Matplotlib. 

9 

10The default values of the rc settings are set in the default matplotlibrc file. 

11Any additions or deletions to the parameter set listed here should also be 

12propagated to the :file:`lib/matplotlib/mpl-data/matplotlibrc` in Matplotlib's 

13root source directory. 

14""" 

15 

16import ast 

17from functools import lru_cache, reduce 

18from numbers import Real 

19import operator 

20import os 

21import re 

22 

23import numpy as np 

24 

25from matplotlib import _api, cbook 

26from matplotlib.backends import BackendFilter, backend_registry 

27from matplotlib.cbook import ls_mapper 

28from matplotlib.colors import Colormap, is_color_like 

29from matplotlib._fontconfig_pattern import parse_fontconfig_pattern 

30from matplotlib._enums import JoinStyle, CapStyle 

31 

32# Don't let the original cycler collide with our validating cycler 

33from cycler import Cycler, cycler as ccycler 

34 

35 

36@_api.caching_module_getattr 

37class __getattr__: 

38 @_api.deprecated( 

39 "3.9", 

40 alternative="``matplotlib.backends.backend_registry.list_builtin" 

41 "(matplotlib.backends.BackendFilter.INTERACTIVE)``") 

42 @property 

43 def interactive_bk(self): 

44 return backend_registry.list_builtin(BackendFilter.INTERACTIVE) 

45 

46 @_api.deprecated( 

47 "3.9", 

48 alternative="``matplotlib.backends.backend_registry.list_builtin" 

49 "(matplotlib.backends.BackendFilter.NON_INTERACTIVE)``") 

50 @property 

51 def non_interactive_bk(self): 

52 return backend_registry.list_builtin(BackendFilter.NON_INTERACTIVE) 

53 

54 @_api.deprecated( 

55 "3.9", 

56 alternative="``matplotlib.backends.backend_registry.list_builtin()``") 

57 @property 

58 def all_backends(self): 

59 return backend_registry.list_builtin() 

60 

61 

62class ValidateInStrings: 

63 def __init__(self, key, valid, ignorecase=False, *, 

64 _deprecated_since=None): 

65 """*valid* is a list of legal strings.""" 

66 self.key = key 

67 self.ignorecase = ignorecase 

68 self._deprecated_since = _deprecated_since 

69 

70 def func(s): 

71 if ignorecase: 

72 return s.lower() 

73 else: 

74 return s 

75 self.valid = {func(k): k for k in valid} 

76 

77 def __call__(self, s): 

78 if self._deprecated_since: 

79 name, = (k for k, v in globals().items() if v is self) 

80 _api.warn_deprecated( 

81 self._deprecated_since, name=name, obj_type="function") 

82 if self.ignorecase and isinstance(s, str): 

83 s = s.lower() 

84 if s in self.valid: 

85 return self.valid[s] 

86 msg = (f"{s!r} is not a valid value for {self.key}; supported values " 

87 f"are {[*self.valid.values()]}") 

88 if (isinstance(s, str) 

89 and (s.startswith('"') and s.endswith('"') 

90 or s.startswith("'") and s.endswith("'")) 

91 and s[1:-1] in self.valid): 

92 msg += "; remove quotes surrounding your string" 

93 raise ValueError(msg) 

94 

95 

96@lru_cache 

97def _listify_validator(scalar_validator, allow_stringlist=False, *, 

98 n=None, doc=None): 

99 def f(s): 

100 if isinstance(s, str): 

101 try: 

102 val = [scalar_validator(v.strip()) for v in s.split(',') 

103 if v.strip()] 

104 except Exception: 

105 if allow_stringlist: 

106 # Sometimes, a list of colors might be a single string 

107 # of single-letter colornames. So give that a shot. 

108 val = [scalar_validator(v.strip()) for v in s if v.strip()] 

109 else: 

110 raise 

111 # Allow any ordered sequence type -- generators, np.ndarray, pd.Series 

112 # -- but not sets, whose iteration order is non-deterministic. 

113 elif np.iterable(s) and not isinstance(s, (set, frozenset)): 

114 # The condition on this list comprehension will preserve the 

115 # behavior of filtering out any empty strings (behavior was 

116 # from the original validate_stringlist()), while allowing 

117 # any non-string/text scalar values such as numbers and arrays. 

118 val = [scalar_validator(v) for v in s 

119 if not isinstance(v, str) or v] 

120 else: 

121 raise ValueError( 

122 f"Expected str or other non-set iterable, but got {s}") 

123 if n is not None and len(val) != n: 

124 raise ValueError( 

125 f"Expected {n} values, but there are {len(val)} values in {s}") 

126 return val 

127 

128 try: 

129 f.__name__ = f"{scalar_validator.__name__}list" 

130 except AttributeError: # class instance. 

131 f.__name__ = f"{type(scalar_validator).__name__}List" 

132 f.__qualname__ = f.__qualname__.rsplit(".", 1)[0] + "." + f.__name__ 

133 f.__doc__ = doc if doc is not None else scalar_validator.__doc__ 

134 return f 

135 

136 

137def validate_any(s): 

138 return s 

139validate_anylist = _listify_validator(validate_any) 

140 

141 

142def _validate_date(s): 

143 try: 

144 np.datetime64(s) 

145 return s 

146 except ValueError: 

147 raise ValueError( 

148 f'{s!r} should be a string that can be parsed by numpy.datetime64') 

149 

150 

151def validate_bool(b): 

152 """Convert b to ``bool`` or raise.""" 

153 if isinstance(b, str): 

154 b = b.lower() 

155 if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True): 

156 return True 

157 elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False): 

158 return False 

159 else: 

160 raise ValueError(f'Cannot convert {b!r} to bool') 

161 

162 

163def validate_axisbelow(s): 

164 try: 

165 return validate_bool(s) 

166 except ValueError: 

167 if isinstance(s, str): 

168 if s == 'line': 

169 return 'line' 

170 raise ValueError(f'{s!r} cannot be interpreted as' 

171 ' True, False, or "line"') 

172 

173 

174def validate_dpi(s): 

175 """Confirm s is string 'figure' or convert s to float or raise.""" 

176 if s == 'figure': 

177 return s 

178 try: 

179 return float(s) 

180 except ValueError as e: 

181 raise ValueError(f'{s!r} is not string "figure" and ' 

182 f'could not convert {s!r} to float') from e 

183 

184 

185def _make_type_validator(cls, *, allow_none=False): 

186 """ 

187 Return a validator that converts inputs to *cls* or raises (and possibly 

188 allows ``None`` as well). 

189 """ 

190 

191 def validator(s): 

192 if (allow_none and 

193 (s is None or cbook._str_lower_equal(s, "none"))): 

194 return None 

195 if cls is str and not isinstance(s, str): 

196 raise ValueError(f'Could not convert {s!r} to str') 

197 try: 

198 return cls(s) 

199 except (TypeError, ValueError) as e: 

200 raise ValueError( 

201 f'Could not convert {s!r} to {cls.__name__}') from e 

202 

203 validator.__name__ = f"validate_{cls.__name__}" 

204 if allow_none: 

205 validator.__name__ += "_or_None" 

206 validator.__qualname__ = ( 

207 validator.__qualname__.rsplit(".", 1)[0] + "." + validator.__name__) 

208 return validator 

209 

210 

211validate_string = _make_type_validator(str) 

212validate_string_or_None = _make_type_validator(str, allow_none=True) 

213validate_stringlist = _listify_validator( 

214 validate_string, doc='return a list of strings') 

215validate_int = _make_type_validator(int) 

216validate_int_or_None = _make_type_validator(int, allow_none=True) 

217validate_float = _make_type_validator(float) 

218validate_float_or_None = _make_type_validator(float, allow_none=True) 

219validate_floatlist = _listify_validator( 

220 validate_float, doc='return a list of floats') 

221 

222 

223def _validate_marker(s): 

224 try: 

225 return validate_int(s) 

226 except ValueError as e: 

227 try: 

228 return validate_string(s) 

229 except ValueError as e: 

230 raise ValueError('Supported markers are [string, int]') from e 

231 

232 

233_validate_markerlist = _listify_validator( 

234 _validate_marker, doc='return a list of markers') 

235 

236 

237def _validate_pathlike(s): 

238 if isinstance(s, (str, os.PathLike)): 

239 # Store value as str because savefig.directory needs to distinguish 

240 # between "" (cwd) and "." (cwd, but gets updated by user selections). 

241 return os.fsdecode(s) 

242 else: 

243 return validate_string(s) 

244 

245 

246def validate_fonttype(s): 

247 """ 

248 Confirm that this is a Postscript or PDF font type that we know how to 

249 convert to. 

250 """ 

251 fonttypes = {'type3': 3, 

252 'truetype': 42} 

253 try: 

254 fonttype = validate_int(s) 

255 except ValueError: 

256 try: 

257 return fonttypes[s.lower()] 

258 except KeyError as e: 

259 raise ValueError('Supported Postscript/PDF font types are %s' 

260 % list(fonttypes)) from e 

261 else: 

262 if fonttype not in fonttypes.values(): 

263 raise ValueError( 

264 'Supported Postscript/PDF font types are %s' % 

265 list(fonttypes.values())) 

266 return fonttype 

267 

268 

269_auto_backend_sentinel = object() 

270 

271 

272def validate_backend(s): 

273 if s is _auto_backend_sentinel or backend_registry.is_valid_backend(s): 

274 return s 

275 else: 

276 msg = (f"'{s}' is not a valid value for backend; supported values are " 

277 f"{backend_registry.list_all()}") 

278 raise ValueError(msg) 

279 

280 

281def _validate_toolbar(s): 

282 s = ValidateInStrings( 

283 'toolbar', ['None', 'toolbar2', 'toolmanager'], ignorecase=True)(s) 

284 if s == 'toolmanager': 

285 _api.warn_external( 

286 "Treat the new Tool classes introduced in v1.5 as experimental " 

287 "for now; the API and rcParam may change in future versions.") 

288 return s 

289 

290 

291def validate_color_or_inherit(s): 

292 """Return a valid color arg.""" 

293 if cbook._str_equal(s, 'inherit'): 

294 return s 

295 return validate_color(s) 

296 

297 

298def validate_color_or_auto(s): 

299 if cbook._str_equal(s, 'auto'): 

300 return s 

301 return validate_color(s) 

302 

303 

304def validate_color_for_prop_cycle(s): 

305 # N-th color cycle syntax can't go into the color cycle. 

306 if isinstance(s, str) and re.match("^C[0-9]$", s): 

307 raise ValueError(f"Cannot put cycle reference ({s!r}) in prop_cycler") 

308 return validate_color(s) 

309 

310 

311def _validate_color_or_linecolor(s): 

312 if cbook._str_equal(s, 'linecolor'): 

313 return s 

314 elif cbook._str_equal(s, 'mfc') or cbook._str_equal(s, 'markerfacecolor'): 

315 return 'markerfacecolor' 

316 elif cbook._str_equal(s, 'mec') or cbook._str_equal(s, 'markeredgecolor'): 

317 return 'markeredgecolor' 

318 elif s is None: 

319 return None 

320 elif isinstance(s, str) and len(s) == 6 or len(s) == 8: 

321 stmp = '#' + s 

322 if is_color_like(stmp): 

323 return stmp 

324 if s.lower() == 'none': 

325 return None 

326 elif is_color_like(s): 

327 return s 

328 

329 raise ValueError(f'{s!r} does not look like a color arg') 

330 

331 

332def validate_color(s): 

333 """Return a valid color arg.""" 

334 if isinstance(s, str): 

335 if s.lower() == 'none': 

336 return 'none' 

337 if len(s) == 6 or len(s) == 8: 

338 stmp = '#' + s 

339 if is_color_like(stmp): 

340 return stmp 

341 

342 if is_color_like(s): 

343 return s 

344 

345 # If it is still valid, it must be a tuple (as a string from matplotlibrc). 

346 try: 

347 color = ast.literal_eval(s) 

348 except (SyntaxError, ValueError): 

349 pass 

350 else: 

351 if is_color_like(color): 

352 return color 

353 

354 raise ValueError(f'{s!r} does not look like a color arg') 

355 

356 

357validate_colorlist = _listify_validator( 

358 validate_color, allow_stringlist=True, doc='return a list of colorspecs') 

359 

360 

361def _validate_cmap(s): 

362 _api.check_isinstance((str, Colormap), cmap=s) 

363 return s 

364 

365 

366def validate_aspect(s): 

367 if s in ('auto', 'equal'): 

368 return s 

369 try: 

370 return float(s) 

371 except ValueError as e: 

372 raise ValueError('not a valid aspect specification') from e 

373 

374 

375def validate_fontsize_None(s): 

376 if s is None or s == 'None': 

377 return None 

378 else: 

379 return validate_fontsize(s) 

380 

381 

382def validate_fontsize(s): 

383 fontsizes = ['xx-small', 'x-small', 'small', 'medium', 'large', 

384 'x-large', 'xx-large', 'smaller', 'larger'] 

385 if isinstance(s, str): 

386 s = s.lower() 

387 if s in fontsizes: 

388 return s 

389 try: 

390 return float(s) 

391 except ValueError as e: 

392 raise ValueError("%s is not a valid font size. Valid font sizes " 

393 "are %s." % (s, ", ".join(fontsizes))) from e 

394 

395 

396validate_fontsizelist = _listify_validator(validate_fontsize) 

397 

398 

399def validate_fontweight(s): 

400 weights = [ 

401 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', 

402 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'] 

403 # Note: Historically, weights have been case-sensitive in Matplotlib 

404 if s in weights: 

405 return s 

406 try: 

407 return int(s) 

408 except (ValueError, TypeError) as e: 

409 raise ValueError(f'{s} is not a valid font weight.') from e 

410 

411 

412def validate_fontstretch(s): 

413 stretchvalues = [ 

414 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', 

415 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 

416 'ultra-expanded'] 

417 # Note: Historically, stretchvalues have been case-sensitive in Matplotlib 

418 if s in stretchvalues: 

419 return s 

420 try: 

421 return int(s) 

422 except (ValueError, TypeError) as e: 

423 raise ValueError(f'{s} is not a valid font stretch.') from e 

424 

425 

426def validate_font_properties(s): 

427 parse_fontconfig_pattern(s) 

428 return s 

429 

430 

431def _validate_mathtext_fallback(s): 

432 _fallback_fonts = ['cm', 'stix', 'stixsans'] 

433 if isinstance(s, str): 

434 s = s.lower() 

435 if s is None or s == 'none': 

436 return None 

437 elif s.lower() in _fallback_fonts: 

438 return s 

439 else: 

440 raise ValueError( 

441 f"{s} is not a valid fallback font name. Valid fallback font " 

442 f"names are {','.join(_fallback_fonts)}. Passing 'None' will turn " 

443 "fallback off.") 

444 

445 

446def validate_whiskers(s): 

447 try: 

448 return _listify_validator(validate_float, n=2)(s) 

449 except (TypeError, ValueError): 

450 try: 

451 return float(s) 

452 except ValueError as e: 

453 raise ValueError("Not a valid whisker value [float, " 

454 "(float, float)]") from e 

455 

456 

457def validate_ps_distiller(s): 

458 if isinstance(s, str): 

459 s = s.lower() 

460 if s in ('none', None, 'false', False): 

461 return None 

462 else: 

463 return ValidateInStrings('ps.usedistiller', ['ghostscript', 'xpdf'])(s) 

464 

465 

466def _validate_papersize(s): 

467 # Re-inline this validator when the 'auto' deprecation expires. 

468 s = ValidateInStrings("ps.papersize", 

469 ["figure", "auto", "letter", "legal", "ledger", 

470 *[f"{ab}{i}" for ab in "ab" for i in range(11)]], 

471 ignorecase=True)(s) 

472 if s == "auto": 

473 _api.warn_deprecated("3.8", name="ps.papersize='auto'", 

474 addendum="Pass an explicit paper type, figure, or omit " 

475 "the *ps.papersize* rcParam entirely.") 

476 return s 

477 

478 

479# A validator dedicated to the named line styles, based on the items in 

480# ls_mapper, and a list of possible strings read from Line2D.set_linestyle 

481_validate_named_linestyle = ValidateInStrings( 

482 'linestyle', 

483 [*ls_mapper.keys(), *ls_mapper.values(), 'None', 'none', ' ', ''], 

484 ignorecase=True) 

485 

486 

487def _validate_linestyle(ls): 

488 """ 

489 A validator for all possible line styles, the named ones *and* 

490 the on-off ink sequences. 

491 """ 

492 if isinstance(ls, str): 

493 try: # Look first for a valid named line style, like '--' or 'solid'. 

494 return _validate_named_linestyle(ls) 

495 except ValueError: 

496 pass 

497 try: 

498 ls = ast.literal_eval(ls) # Parsing matplotlibrc. 

499 except (SyntaxError, ValueError): 

500 pass # Will error with the ValueError at the end. 

501 

502 def _is_iterable_not_string_like(x): 

503 # Explicitly exclude bytes/bytearrays so that they are not 

504 # nonsensically interpreted as sequences of numbers (codepoints). 

505 return np.iterable(x) and not isinstance(x, (str, bytes, bytearray)) 

506 

507 if _is_iterable_not_string_like(ls): 

508 if len(ls) == 2 and _is_iterable_not_string_like(ls[1]): 

509 # (offset, (on, off, on, off, ...)) 

510 offset, onoff = ls 

511 else: 

512 # For backcompat: (on, off, on, off, ...); the offset is implicit. 

513 offset = 0 

514 onoff = ls 

515 

516 if (isinstance(offset, Real) 

517 and len(onoff) % 2 == 0 

518 and all(isinstance(elem, Real) for elem in onoff)): 

519 return (offset, onoff) 

520 

521 raise ValueError(f"linestyle {ls!r} is not a valid on-off ink sequence.") 

522 

523 

524validate_fillstyle = ValidateInStrings( 

525 'markers.fillstyle', ['full', 'left', 'right', 'bottom', 'top', 'none']) 

526 

527 

528validate_fillstylelist = _listify_validator(validate_fillstyle) 

529 

530 

531def validate_markevery(s): 

532 """ 

533 Validate the markevery property of a Line2D object. 

534 

535 Parameters 

536 ---------- 

537 s : None, int, (int, int), slice, float, (float, float), or list[int] 

538 

539 Returns 

540 ------- 

541 None, int, (int, int), slice, float, (float, float), or list[int] 

542 """ 

543 # Validate s against type slice float int and None 

544 if isinstance(s, (slice, float, int, type(None))): 

545 return s 

546 # Validate s against type tuple 

547 if isinstance(s, tuple): 

548 if (len(s) == 2 

549 and (all(isinstance(e, int) for e in s) 

550 or all(isinstance(e, float) for e in s))): 

551 return s 

552 else: 

553 raise TypeError( 

554 "'markevery' tuple must be pair of ints or of floats") 

555 # Validate s against type list 

556 if isinstance(s, list): 

557 if all(isinstance(e, int) for e in s): 

558 return s 

559 else: 

560 raise TypeError( 

561 "'markevery' list must have all elements of type int") 

562 raise TypeError("'markevery' is of an invalid type") 

563 

564 

565validate_markeverylist = _listify_validator(validate_markevery) 

566 

567 

568def validate_bbox(s): 

569 if isinstance(s, str): 

570 s = s.lower() 

571 if s == 'tight': 

572 return s 

573 if s == 'standard': 

574 return None 

575 raise ValueError("bbox should be 'tight' or 'standard'") 

576 elif s is not None: 

577 # Backwards compatibility. None is equivalent to 'standard'. 

578 raise ValueError("bbox should be 'tight' or 'standard'") 

579 return s 

580 

581 

582def validate_sketch(s): 

583 

584 if isinstance(s, str): 

585 s = s.lower().strip() 

586 if s.startswith("(") and s.endswith(")"): 

587 s = s[1:-1] 

588 if s == 'none' or s is None: 

589 return None 

590 try: 

591 return tuple(_listify_validator(validate_float, n=3)(s)) 

592 except ValueError as exc: 

593 raise ValueError("Expected a (scale, length, randomness) tuple") from exc 

594 

595 

596def _validate_greaterthan_minushalf(s): 

597 s = validate_float(s) 

598 if s > -0.5: 

599 return s 

600 else: 

601 raise RuntimeError(f'Value must be >-0.5; got {s}') 

602 

603 

604def _validate_greaterequal0_lessequal1(s): 

605 s = validate_float(s) 

606 if 0 <= s <= 1: 

607 return s 

608 else: 

609 raise RuntimeError(f'Value must be >=0 and <=1; got {s}') 

610 

611 

612def _validate_int_greaterequal0(s): 

613 s = validate_int(s) 

614 if s >= 0: 

615 return s 

616 else: 

617 raise RuntimeError(f'Value must be >=0; got {s}') 

618 

619 

620def validate_hatch(s): 

621 r""" 

622 Validate a hatch pattern. 

623 A hatch pattern string can have any sequence of the following 

624 characters: ``\ / | - + * . x o O``. 

625 """ 

626 if not isinstance(s, str): 

627 raise ValueError("Hatch pattern must be a string") 

628 _api.check_isinstance(str, hatch_pattern=s) 

629 unknown = set(s) - {'\\', '/', '|', '-', '+', '*', '.', 'x', 'o', 'O'} 

630 if unknown: 

631 raise ValueError("Unknown hatch symbol(s): %s" % list(unknown)) 

632 return s 

633 

634 

635validate_hatchlist = _listify_validator(validate_hatch) 

636validate_dashlist = _listify_validator(validate_floatlist) 

637 

638 

639def _validate_minor_tick_ndivs(n): 

640 """ 

641 Validate ndiv parameter related to the minor ticks. 

642 It controls the number of minor ticks to be placed between 

643 two major ticks. 

644 """ 

645 

646 if cbook._str_lower_equal(n, 'auto'): 

647 return n 

648 try: 

649 n = _validate_int_greaterequal0(n) 

650 return n 

651 except (RuntimeError, ValueError): 

652 pass 

653 

654 raise ValueError("'tick.minor.ndivs' must be 'auto' or non-negative int") 

655 

656 

657_prop_validators = { 

658 'color': _listify_validator(validate_color_for_prop_cycle, 

659 allow_stringlist=True), 

660 'linewidth': validate_floatlist, 

661 'linestyle': _listify_validator(_validate_linestyle), 

662 'facecolor': validate_colorlist, 

663 'edgecolor': validate_colorlist, 

664 'joinstyle': _listify_validator(JoinStyle), 

665 'capstyle': _listify_validator(CapStyle), 

666 'fillstyle': validate_fillstylelist, 

667 'markerfacecolor': validate_colorlist, 

668 'markersize': validate_floatlist, 

669 'markeredgewidth': validate_floatlist, 

670 'markeredgecolor': validate_colorlist, 

671 'markevery': validate_markeverylist, 

672 'alpha': validate_floatlist, 

673 'marker': _validate_markerlist, 

674 'hatch': validate_hatchlist, 

675 'dashes': validate_dashlist, 

676 } 

677_prop_aliases = { 

678 'c': 'color', 

679 'lw': 'linewidth', 

680 'ls': 'linestyle', 

681 'fc': 'facecolor', 

682 'ec': 'edgecolor', 

683 'mfc': 'markerfacecolor', 

684 'mec': 'markeredgecolor', 

685 'mew': 'markeredgewidth', 

686 'ms': 'markersize', 

687 } 

688 

689 

690def cycler(*args, **kwargs): 

691 """ 

692 Create a `~cycler.Cycler` object much like :func:`cycler.cycler`, 

693 but includes input validation. 

694 

695 Call signatures:: 

696 

697 cycler(cycler) 

698 cycler(label=values[, label2=values2[, ...]]) 

699 cycler(label, values) 

700 

701 Form 1 copies a given `~cycler.Cycler` object. 

702 

703 Form 2 creates a `~cycler.Cycler` which cycles over one or more 

704 properties simultaneously. If multiple properties are given, their 

705 value lists must have the same length. 

706 

707 Form 3 creates a `~cycler.Cycler` for a single property. This form 

708 exists for compatibility with the original cycler. Its use is 

709 discouraged in favor of the kwarg form, i.e. ``cycler(label=values)``. 

710 

711 Parameters 

712 ---------- 

713 cycler : Cycler 

714 Copy constructor for Cycler. 

715 

716 label : str 

717 The property key. Must be a valid `.Artist` property. 

718 For example, 'color' or 'linestyle'. Aliases are allowed, 

719 such as 'c' for 'color' and 'lw' for 'linewidth'. 

720 

721 values : iterable 

722 Finite-length iterable of the property values. These values 

723 are validated and will raise a ValueError if invalid. 

724 

725 Returns 

726 ------- 

727 Cycler 

728 A new :class:`~cycler.Cycler` for the given properties. 

729 

730 Examples 

731 -------- 

732 Creating a cycler for a single property: 

733 

734 >>> c = cycler(color=['red', 'green', 'blue']) 

735 

736 Creating a cycler for simultaneously cycling over multiple properties 

737 (e.g. red circle, green plus, blue cross): 

738 

739 >>> c = cycler(color=['red', 'green', 'blue'], 

740 ... marker=['o', '+', 'x']) 

741 

742 """ 

743 if args and kwargs: 

744 raise TypeError("cycler() can only accept positional OR keyword " 

745 "arguments -- not both.") 

746 elif not args and not kwargs: 

747 raise TypeError("cycler() must have positional OR keyword arguments") 

748 

749 if len(args) == 1: 

750 if not isinstance(args[0], Cycler): 

751 raise TypeError("If only one positional argument given, it must " 

752 "be a Cycler instance.") 

753 return validate_cycler(args[0]) 

754 elif len(args) == 2: 

755 pairs = [(args[0], args[1])] 

756 elif len(args) > 2: 

757 raise _api.nargs_error('cycler', '0-2', len(args)) 

758 else: 

759 pairs = kwargs.items() 

760 

761 validated = [] 

762 for prop, vals in pairs: 

763 norm_prop = _prop_aliases.get(prop, prop) 

764 validator = _prop_validators.get(norm_prop, None) 

765 if validator is None: 

766 raise TypeError("Unknown artist property: %s" % prop) 

767 vals = validator(vals) 

768 # We will normalize the property names as well to reduce 

769 # the amount of alias handling code elsewhere. 

770 validated.append((norm_prop, vals)) 

771 

772 return reduce(operator.add, (ccycler(k, v) for k, v in validated)) 

773 

774 

775class _DunderChecker(ast.NodeVisitor): 

776 def visit_Attribute(self, node): 

777 if node.attr.startswith("__") and node.attr.endswith("__"): 

778 raise ValueError("cycler strings with dunders are forbidden") 

779 self.generic_visit(node) 

780 

781 

782# A validator dedicated to the named legend loc 

783_validate_named_legend_loc = ValidateInStrings( 

784 'legend.loc', 

785 [ 

786 "best", 

787 "upper right", "upper left", "lower left", "lower right", "right", 

788 "center left", "center right", "lower center", "upper center", 

789 "center"], 

790 ignorecase=True) 

791 

792 

793def _validate_legend_loc(loc): 

794 """ 

795 Confirm that loc is a type which rc.Params["legend.loc"] supports. 

796 

797 .. versionadded:: 3.8 

798 

799 Parameters 

800 ---------- 

801 loc : str | int | (float, float) | str((float, float)) 

802 The location of the legend. 

803 

804 Returns 

805 ------- 

806 loc : str | int | (float, float) or raise ValueError exception 

807 The location of the legend. 

808 """ 

809 if isinstance(loc, str): 

810 try: 

811 return _validate_named_legend_loc(loc) 

812 except ValueError: 

813 pass 

814 try: 

815 loc = ast.literal_eval(loc) 

816 except (SyntaxError, ValueError): 

817 pass 

818 if isinstance(loc, int): 

819 if 0 <= loc <= 10: 

820 return loc 

821 if isinstance(loc, tuple): 

822 if len(loc) == 2 and all(isinstance(e, Real) for e in loc): 

823 return loc 

824 raise ValueError(f"{loc} is not a valid legend location.") 

825 

826 

827def validate_cycler(s): 

828 """Return a Cycler object from a string repr or the object itself.""" 

829 if isinstance(s, str): 

830 # TODO: We might want to rethink this... 

831 # While I think I have it quite locked down, it is execution of 

832 # arbitrary code without sanitation. 

833 # Combine this with the possibility that rcparams might come from the 

834 # internet (future plans), this could be downright dangerous. 

835 # I locked it down by only having the 'cycler()' function available. 

836 # UPDATE: Partly plugging a security hole. 

837 # I really should have read this: 

838 # https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html 

839 # We should replace this eval with a combo of PyParsing and 

840 # ast.literal_eval() 

841 try: 

842 _DunderChecker().visit(ast.parse(s)) 

843 s = eval(s, {'cycler': cycler, '__builtins__': {}}) 

844 except BaseException as e: 

845 raise ValueError(f"{s!r} is not a valid cycler construction: {e}" 

846 ) from e 

847 # Should make sure what comes from the above eval() 

848 # is a Cycler object. 

849 if isinstance(s, Cycler): 

850 cycler_inst = s 

851 else: 

852 raise ValueError(f"Object is not a string or Cycler instance: {s!r}") 

853 

854 unknowns = cycler_inst.keys - (set(_prop_validators) | set(_prop_aliases)) 

855 if unknowns: 

856 raise ValueError("Unknown artist properties: %s" % unknowns) 

857 

858 # Not a full validation, but it'll at least normalize property names 

859 # A fuller validation would require v0.10 of cycler. 

860 checker = set() 

861 for prop in cycler_inst.keys: 

862 norm_prop = _prop_aliases.get(prop, prop) 

863 if norm_prop != prop and norm_prop in cycler_inst.keys: 

864 raise ValueError(f"Cannot specify both {norm_prop!r} and alias " 

865 f"{prop!r} in the same prop_cycle") 

866 if norm_prop in checker: 

867 raise ValueError(f"Another property was already aliased to " 

868 f"{norm_prop!r}. Collision normalizing {prop!r}.") 

869 checker.update([norm_prop]) 

870 

871 # This is just an extra-careful check, just in case there is some 

872 # edge-case I haven't thought of. 

873 assert len(checker) == len(cycler_inst.keys) 

874 

875 # Now, it should be safe to mutate this cycler 

876 for prop in cycler_inst.keys: 

877 norm_prop = _prop_aliases.get(prop, prop) 

878 cycler_inst.change_key(prop, norm_prop) 

879 

880 for key, vals in cycler_inst.by_key().items(): 

881 _prop_validators[key](vals) 

882 

883 return cycler_inst 

884 

885 

886def validate_hist_bins(s): 

887 valid_strs = ["auto", "sturges", "fd", "doane", "scott", "rice", "sqrt"] 

888 if isinstance(s, str) and s in valid_strs: 

889 return s 

890 try: 

891 return int(s) 

892 except (TypeError, ValueError): 

893 pass 

894 try: 

895 return validate_floatlist(s) 

896 except ValueError: 

897 pass 

898 raise ValueError(f"'hist.bins' must be one of {valid_strs}, an int or" 

899 " a sequence of floats") 

900 

901 

902class _ignorecase(list): 

903 """A marker class indicating that a list-of-str is case-insensitive.""" 

904 

905 

906def _convert_validator_spec(key, conv): 

907 if isinstance(conv, list): 

908 ignorecase = isinstance(conv, _ignorecase) 

909 return ValidateInStrings(key, conv, ignorecase=ignorecase) 

910 else: 

911 return conv 

912 

913 

914# Mapping of rcParams to validators. 

915# Converters given as lists or _ignorecase are converted to ValidateInStrings 

916# immediately below. 

917# The rcParams defaults are defined in lib/matplotlib/mpl-data/matplotlibrc, which 

918# gets copied to matplotlib/mpl-data/matplotlibrc by the setup script. 

919_validators = { 

920 "backend": validate_backend, 

921 "backend_fallback": validate_bool, 

922 "figure.hooks": validate_stringlist, 

923 "toolbar": _validate_toolbar, 

924 "interactive": validate_bool, 

925 "timezone": validate_string, 

926 

927 "webagg.port": validate_int, 

928 "webagg.address": validate_string, 

929 "webagg.open_in_browser": validate_bool, 

930 "webagg.port_retries": validate_int, 

931 

932 # line props 

933 "lines.linewidth": validate_float, # line width in points 

934 "lines.linestyle": _validate_linestyle, # solid line 

935 "lines.color": validate_color, # first color in color cycle 

936 "lines.marker": _validate_marker, # marker name 

937 "lines.markerfacecolor": validate_color_or_auto, # default color 

938 "lines.markeredgecolor": validate_color_or_auto, # default color 

939 "lines.markeredgewidth": validate_float, 

940 "lines.markersize": validate_float, # markersize, in points 

941 "lines.antialiased": validate_bool, # antialiased (no jaggies) 

942 "lines.dash_joinstyle": JoinStyle, 

943 "lines.solid_joinstyle": JoinStyle, 

944 "lines.dash_capstyle": CapStyle, 

945 "lines.solid_capstyle": CapStyle, 

946 "lines.dashed_pattern": validate_floatlist, 

947 "lines.dashdot_pattern": validate_floatlist, 

948 "lines.dotted_pattern": validate_floatlist, 

949 "lines.scale_dashes": validate_bool, 

950 

951 # marker props 

952 "markers.fillstyle": validate_fillstyle, 

953 

954 ## pcolor(mesh) props: 

955 "pcolor.shading": ["auto", "flat", "nearest", "gouraud"], 

956 "pcolormesh.snap": validate_bool, 

957 

958 ## patch props 

959 "patch.linewidth": validate_float, # line width in points 

960 "patch.edgecolor": validate_color, 

961 "patch.force_edgecolor": validate_bool, 

962 "patch.facecolor": validate_color, # first color in cycle 

963 "patch.antialiased": validate_bool, # antialiased (no jaggies) 

964 

965 ## hatch props 

966 "hatch.color": validate_color, 

967 "hatch.linewidth": validate_float, 

968 

969 ## Histogram properties 

970 "hist.bins": validate_hist_bins, 

971 

972 ## Boxplot properties 

973 "boxplot.notch": validate_bool, 

974 "boxplot.vertical": validate_bool, 

975 "boxplot.whiskers": validate_whiskers, 

976 "boxplot.bootstrap": validate_int_or_None, 

977 "boxplot.patchartist": validate_bool, 

978 "boxplot.showmeans": validate_bool, 

979 "boxplot.showcaps": validate_bool, 

980 "boxplot.showbox": validate_bool, 

981 "boxplot.showfliers": validate_bool, 

982 "boxplot.meanline": validate_bool, 

983 

984 "boxplot.flierprops.color": validate_color, 

985 "boxplot.flierprops.marker": _validate_marker, 

986 "boxplot.flierprops.markerfacecolor": validate_color_or_auto, 

987 "boxplot.flierprops.markeredgecolor": validate_color, 

988 "boxplot.flierprops.markeredgewidth": validate_float, 

989 "boxplot.flierprops.markersize": validate_float, 

990 "boxplot.flierprops.linestyle": _validate_linestyle, 

991 "boxplot.flierprops.linewidth": validate_float, 

992 

993 "boxplot.boxprops.color": validate_color, 

994 "boxplot.boxprops.linewidth": validate_float, 

995 "boxplot.boxprops.linestyle": _validate_linestyle, 

996 

997 "boxplot.whiskerprops.color": validate_color, 

998 "boxplot.whiskerprops.linewidth": validate_float, 

999 "boxplot.whiskerprops.linestyle": _validate_linestyle, 

1000 

1001 "boxplot.capprops.color": validate_color, 

1002 "boxplot.capprops.linewidth": validate_float, 

1003 "boxplot.capprops.linestyle": _validate_linestyle, 

1004 

1005 "boxplot.medianprops.color": validate_color, 

1006 "boxplot.medianprops.linewidth": validate_float, 

1007 "boxplot.medianprops.linestyle": _validate_linestyle, 

1008 

1009 "boxplot.meanprops.color": validate_color, 

1010 "boxplot.meanprops.marker": _validate_marker, 

1011 "boxplot.meanprops.markerfacecolor": validate_color, 

1012 "boxplot.meanprops.markeredgecolor": validate_color, 

1013 "boxplot.meanprops.markersize": validate_float, 

1014 "boxplot.meanprops.linestyle": _validate_linestyle, 

1015 "boxplot.meanprops.linewidth": validate_float, 

1016 

1017 ## font props 

1018 "font.family": validate_stringlist, # used by text object 

1019 "font.style": validate_string, 

1020 "font.variant": validate_string, 

1021 "font.stretch": validate_fontstretch, 

1022 "font.weight": validate_fontweight, 

1023 "font.size": validate_float, # Base font size in points 

1024 "font.serif": validate_stringlist, 

1025 "font.sans-serif": validate_stringlist, 

1026 "font.cursive": validate_stringlist, 

1027 "font.fantasy": validate_stringlist, 

1028 "font.monospace": validate_stringlist, 

1029 

1030 # text props 

1031 "text.color": validate_color, 

1032 "text.usetex": validate_bool, 

1033 "text.latex.preamble": validate_string, 

1034 "text.hinting": ["default", "no_autohint", "force_autohint", 

1035 "no_hinting", "auto", "native", "either", "none"], 

1036 "text.hinting_factor": validate_int, 

1037 "text.kerning_factor": validate_int, 

1038 "text.antialiased": validate_bool, 

1039 "text.parse_math": validate_bool, 

1040 

1041 "mathtext.cal": validate_font_properties, 

1042 "mathtext.rm": validate_font_properties, 

1043 "mathtext.tt": validate_font_properties, 

1044 "mathtext.it": validate_font_properties, 

1045 "mathtext.bf": validate_font_properties, 

1046 "mathtext.bfit": validate_font_properties, 

1047 "mathtext.sf": validate_font_properties, 

1048 "mathtext.fontset": ["dejavusans", "dejavuserif", "cm", "stix", 

1049 "stixsans", "custom"], 

1050 "mathtext.default": ["rm", "cal", "bfit", "it", "tt", "sf", "bf", "default", 

1051 "bb", "frak", "scr", "regular"], 

1052 "mathtext.fallback": _validate_mathtext_fallback, 

1053 

1054 "image.aspect": validate_aspect, # equal, auto, a number 

1055 "image.interpolation": validate_string, 

1056 "image.interpolation_stage": ["data", "rgba"], 

1057 "image.cmap": _validate_cmap, # gray, jet, etc. 

1058 "image.lut": validate_int, # lookup table 

1059 "image.origin": ["upper", "lower"], 

1060 "image.resample": validate_bool, 

1061 # Specify whether vector graphics backends will combine all images on a 

1062 # set of Axes into a single composite image 

1063 "image.composite_image": validate_bool, 

1064 

1065 # contour props 

1066 "contour.negative_linestyle": _validate_linestyle, 

1067 "contour.corner_mask": validate_bool, 

1068 "contour.linewidth": validate_float_or_None, 

1069 "contour.algorithm": ["mpl2005", "mpl2014", "serial", "threaded"], 

1070 

1071 # errorbar props 

1072 "errorbar.capsize": validate_float, 

1073 

1074 # axis props 

1075 # alignment of x/y axis title 

1076 "xaxis.labellocation": ["left", "center", "right"], 

1077 "yaxis.labellocation": ["bottom", "center", "top"], 

1078 

1079 # Axes props 

1080 "axes.axisbelow": validate_axisbelow, 

1081 "axes.facecolor": validate_color, # background color 

1082 "axes.edgecolor": validate_color, # edge color 

1083 "axes.linewidth": validate_float, # edge linewidth 

1084 

1085 "axes.spines.left": validate_bool, # Set visibility of axes spines, 

1086 "axes.spines.right": validate_bool, # i.e., the lines around the chart 

1087 "axes.spines.bottom": validate_bool, # denoting data boundary. 

1088 "axes.spines.top": validate_bool, 

1089 

1090 "axes.titlesize": validate_fontsize, # Axes title fontsize 

1091 "axes.titlelocation": ["left", "center", "right"], # Axes title alignment 

1092 "axes.titleweight": validate_fontweight, # Axes title font weight 

1093 "axes.titlecolor": validate_color_or_auto, # Axes title font color 

1094 # title location, axes units, None means auto 

1095 "axes.titley": validate_float_or_None, 

1096 # pad from Axes top decoration to title in points 

1097 "axes.titlepad": validate_float, 

1098 "axes.grid": validate_bool, # display grid or not 

1099 "axes.grid.which": ["minor", "both", "major"], # which grids are drawn 

1100 "axes.grid.axis": ["x", "y", "both"], # grid type 

1101 "axes.labelsize": validate_fontsize, # fontsize of x & y labels 

1102 "axes.labelpad": validate_float, # space between label and axis 

1103 "axes.labelweight": validate_fontweight, # fontsize of x & y labels 

1104 "axes.labelcolor": validate_color, # color of axis label 

1105 # use scientific notation if log10 of the axis range is smaller than the 

1106 # first or larger than the second 

1107 "axes.formatter.limits": _listify_validator(validate_int, n=2), 

1108 # use current locale to format ticks 

1109 "axes.formatter.use_locale": validate_bool, 

1110 "axes.formatter.use_mathtext": validate_bool, 

1111 # minimum exponent to format in scientific notation 

1112 "axes.formatter.min_exponent": validate_int, 

1113 "axes.formatter.useoffset": validate_bool, 

1114 "axes.formatter.offset_threshold": validate_int, 

1115 "axes.unicode_minus": validate_bool, 

1116 # This entry can be either a cycler object or a string repr of a 

1117 # cycler-object, which gets eval()'ed to create the object. 

1118 "axes.prop_cycle": validate_cycler, 

1119 # If "data", axes limits are set close to the data. 

1120 # If "round_numbers" axes limits are set to the nearest round numbers. 

1121 "axes.autolimit_mode": ["data", "round_numbers"], 

1122 "axes.xmargin": _validate_greaterthan_minushalf, # margin added to xaxis 

1123 "axes.ymargin": _validate_greaterthan_minushalf, # margin added to yaxis 

1124 "axes.zmargin": _validate_greaterthan_minushalf, # margin added to zaxis 

1125 

1126 "polaraxes.grid": validate_bool, # display polar grid or not 

1127 "axes3d.grid": validate_bool, # display 3d grid 

1128 "axes3d.automargin": validate_bool, # automatically add margin when 

1129 # manually setting 3D axis limits 

1130 

1131 "axes3d.xaxis.panecolor": validate_color, # 3d background pane 

1132 "axes3d.yaxis.panecolor": validate_color, # 3d background pane 

1133 "axes3d.zaxis.panecolor": validate_color, # 3d background pane 

1134 

1135 # scatter props 

1136 "scatter.marker": _validate_marker, 

1137 "scatter.edgecolors": validate_string, 

1138 

1139 "date.epoch": _validate_date, 

1140 "date.autoformatter.year": validate_string, 

1141 "date.autoformatter.month": validate_string, 

1142 "date.autoformatter.day": validate_string, 

1143 "date.autoformatter.hour": validate_string, 

1144 "date.autoformatter.minute": validate_string, 

1145 "date.autoformatter.second": validate_string, 

1146 "date.autoformatter.microsecond": validate_string, 

1147 

1148 'date.converter': ['auto', 'concise'], 

1149 # for auto date locator, choose interval_multiples 

1150 'date.interval_multiples': validate_bool, 

1151 

1152 # legend properties 

1153 "legend.fancybox": validate_bool, 

1154 "legend.loc": _validate_legend_loc, 

1155 

1156 # the number of points in the legend line 

1157 "legend.numpoints": validate_int, 

1158 # the number of points in the legend line for scatter 

1159 "legend.scatterpoints": validate_int, 

1160 "legend.fontsize": validate_fontsize, 

1161 "legend.title_fontsize": validate_fontsize_None, 

1162 # color of the legend 

1163 "legend.labelcolor": _validate_color_or_linecolor, 

1164 # the relative size of legend markers vs. original 

1165 "legend.markerscale": validate_float, 

1166 # using dict in rcParams not yet supported, so make sure it is bool 

1167 "legend.shadow": validate_bool, 

1168 # whether or not to draw a frame around legend 

1169 "legend.frameon": validate_bool, 

1170 # alpha value of the legend frame 

1171 "legend.framealpha": validate_float_or_None, 

1172 

1173 ## the following dimensions are in fraction of the font size 

1174 "legend.borderpad": validate_float, # units are fontsize 

1175 # the vertical space between the legend entries 

1176 "legend.labelspacing": validate_float, 

1177 # the length of the legend lines 

1178 "legend.handlelength": validate_float, 

1179 # the length of the legend lines 

1180 "legend.handleheight": validate_float, 

1181 # the space between the legend line and legend text 

1182 "legend.handletextpad": validate_float, 

1183 # the border between the Axes and legend edge 

1184 "legend.borderaxespad": validate_float, 

1185 # the border between the Axes and legend edge 

1186 "legend.columnspacing": validate_float, 

1187 "legend.facecolor": validate_color_or_inherit, 

1188 "legend.edgecolor": validate_color_or_inherit, 

1189 

1190 # tick properties 

1191 "xtick.top": validate_bool, # draw ticks on top side 

1192 "xtick.bottom": validate_bool, # draw ticks on bottom side 

1193 "xtick.labeltop": validate_bool, # draw label on top 

1194 "xtick.labelbottom": validate_bool, # draw label on bottom 

1195 "xtick.major.size": validate_float, # major xtick size in points 

1196 "xtick.minor.size": validate_float, # minor xtick size in points 

1197 "xtick.major.width": validate_float, # major xtick width in points 

1198 "xtick.minor.width": validate_float, # minor xtick width in points 

1199 "xtick.major.pad": validate_float, # distance to label in points 

1200 "xtick.minor.pad": validate_float, # distance to label in points 

1201 "xtick.color": validate_color, # color of xticks 

1202 "xtick.labelcolor": validate_color_or_inherit, # color of xtick labels 

1203 "xtick.minor.visible": validate_bool, # visibility of minor xticks 

1204 "xtick.minor.top": validate_bool, # draw top minor xticks 

1205 "xtick.minor.bottom": validate_bool, # draw bottom minor xticks 

1206 "xtick.major.top": validate_bool, # draw top major xticks 

1207 "xtick.major.bottom": validate_bool, # draw bottom major xticks 

1208 # number of minor xticks 

1209 "xtick.minor.ndivs": _validate_minor_tick_ndivs, 

1210 "xtick.labelsize": validate_fontsize, # fontsize of xtick labels 

1211 "xtick.direction": ["out", "in", "inout"], # direction of xticks 

1212 "xtick.alignment": ["center", "right", "left"], 

1213 

1214 "ytick.left": validate_bool, # draw ticks on left side 

1215 "ytick.right": validate_bool, # draw ticks on right side 

1216 "ytick.labelleft": validate_bool, # draw tick labels on left side 

1217 "ytick.labelright": validate_bool, # draw tick labels on right side 

1218 "ytick.major.size": validate_float, # major ytick size in points 

1219 "ytick.minor.size": validate_float, # minor ytick size in points 

1220 "ytick.major.width": validate_float, # major ytick width in points 

1221 "ytick.minor.width": validate_float, # minor ytick width in points 

1222 "ytick.major.pad": validate_float, # distance to label in points 

1223 "ytick.minor.pad": validate_float, # distance to label in points 

1224 "ytick.color": validate_color, # color of yticks 

1225 "ytick.labelcolor": validate_color_or_inherit, # color of ytick labels 

1226 "ytick.minor.visible": validate_bool, # visibility of minor yticks 

1227 "ytick.minor.left": validate_bool, # draw left minor yticks 

1228 "ytick.minor.right": validate_bool, # draw right minor yticks 

1229 "ytick.major.left": validate_bool, # draw left major yticks 

1230 "ytick.major.right": validate_bool, # draw right major yticks 

1231 # number of minor yticks 

1232 "ytick.minor.ndivs": _validate_minor_tick_ndivs, 

1233 "ytick.labelsize": validate_fontsize, # fontsize of ytick labels 

1234 "ytick.direction": ["out", "in", "inout"], # direction of yticks 

1235 "ytick.alignment": [ 

1236 "center", "top", "bottom", "baseline", "center_baseline"], 

1237 

1238 "grid.color": validate_color, # grid color 

1239 "grid.linestyle": _validate_linestyle, # solid 

1240 "grid.linewidth": validate_float, # in points 

1241 "grid.alpha": validate_float, 

1242 

1243 ## figure props 

1244 # figure title 

1245 "figure.titlesize": validate_fontsize, 

1246 "figure.titleweight": validate_fontweight, 

1247 

1248 # figure labels 

1249 "figure.labelsize": validate_fontsize, 

1250 "figure.labelweight": validate_fontweight, 

1251 

1252 # figure size in inches: width by height 

1253 "figure.figsize": _listify_validator(validate_float, n=2), 

1254 "figure.dpi": validate_float, 

1255 "figure.facecolor": validate_color, 

1256 "figure.edgecolor": validate_color, 

1257 "figure.frameon": validate_bool, 

1258 "figure.autolayout": validate_bool, 

1259 "figure.max_open_warning": validate_int, 

1260 "figure.raise_window": validate_bool, 

1261 "macosx.window_mode": ["system", "tab", "window"], 

1262 

1263 "figure.subplot.left": validate_float, 

1264 "figure.subplot.right": validate_float, 

1265 "figure.subplot.bottom": validate_float, 

1266 "figure.subplot.top": validate_float, 

1267 "figure.subplot.wspace": validate_float, 

1268 "figure.subplot.hspace": validate_float, 

1269 

1270 "figure.constrained_layout.use": validate_bool, # run constrained_layout? 

1271 # wspace and hspace are fraction of adjacent subplots to use for space. 

1272 # Much smaller than above because we don't need room for the text. 

1273 "figure.constrained_layout.hspace": validate_float, 

1274 "figure.constrained_layout.wspace": validate_float, 

1275 # buffer around the Axes, in inches. 

1276 "figure.constrained_layout.h_pad": validate_float, 

1277 "figure.constrained_layout.w_pad": validate_float, 

1278 

1279 ## Saving figure's properties 

1280 'savefig.dpi': validate_dpi, 

1281 'savefig.facecolor': validate_color_or_auto, 

1282 'savefig.edgecolor': validate_color_or_auto, 

1283 'savefig.orientation': ['landscape', 'portrait'], 

1284 "savefig.format": validate_string, 

1285 "savefig.bbox": validate_bbox, # "tight", or "standard" (= None) 

1286 "savefig.pad_inches": validate_float, 

1287 # default directory in savefig dialog box 

1288 "savefig.directory": _validate_pathlike, 

1289 "savefig.transparent": validate_bool, 

1290 

1291 "tk.window_focus": validate_bool, # Maintain shell focus for TkAgg 

1292 

1293 # Set the papersize/type 

1294 "ps.papersize": _validate_papersize, 

1295 "ps.useafm": validate_bool, 

1296 # use ghostscript or xpdf to distill ps output 

1297 "ps.usedistiller": validate_ps_distiller, 

1298 "ps.distiller.res": validate_int, # dpi 

1299 "ps.fonttype": validate_fonttype, # 3 (Type3) or 42 (Truetype) 

1300 "pdf.compression": validate_int, # 0-9 compression level; 0 to disable 

1301 "pdf.inheritcolor": validate_bool, # skip color setting commands 

1302 # use only the 14 PDF core fonts embedded in every PDF viewing application 

1303 "pdf.use14corefonts": validate_bool, 

1304 "pdf.fonttype": validate_fonttype, # 3 (Type3) or 42 (Truetype) 

1305 

1306 "pgf.texsystem": ["xelatex", "lualatex", "pdflatex"], # latex variant used 

1307 "pgf.rcfonts": validate_bool, # use mpl's rc settings for font config 

1308 "pgf.preamble": validate_string, # custom LaTeX preamble 

1309 

1310 # write raster image data into the svg file 

1311 "svg.image_inline": validate_bool, 

1312 "svg.fonttype": ["none", "path"], # save text as text ("none") or "paths" 

1313 "svg.hashsalt": validate_string_or_None, 

1314 

1315 # set this when you want to generate hardcopy docstring 

1316 "docstring.hardcopy": validate_bool, 

1317 

1318 "path.simplify": validate_bool, 

1319 "path.simplify_threshold": _validate_greaterequal0_lessequal1, 

1320 "path.snap": validate_bool, 

1321 "path.sketch": validate_sketch, 

1322 "path.effects": validate_anylist, 

1323 "agg.path.chunksize": validate_int, # 0 to disable chunking 

1324 

1325 # key-mappings (multi-character mappings should be a list/tuple) 

1326 "keymap.fullscreen": validate_stringlist, 

1327 "keymap.home": validate_stringlist, 

1328 "keymap.back": validate_stringlist, 

1329 "keymap.forward": validate_stringlist, 

1330 "keymap.pan": validate_stringlist, 

1331 "keymap.zoom": validate_stringlist, 

1332 "keymap.save": validate_stringlist, 

1333 "keymap.quit": validate_stringlist, 

1334 "keymap.quit_all": validate_stringlist, # e.g.: "W", "cmd+W", "Q" 

1335 "keymap.grid": validate_stringlist, 

1336 "keymap.grid_minor": validate_stringlist, 

1337 "keymap.yscale": validate_stringlist, 

1338 "keymap.xscale": validate_stringlist, 

1339 "keymap.help": validate_stringlist, 

1340 "keymap.copy": validate_stringlist, 

1341 

1342 # Animation settings 

1343 "animation.html": ["html5", "jshtml", "none"], 

1344 # Limit, in MB, of size of base64 encoded animation in HTML 

1345 # (i.e. IPython notebook) 

1346 "animation.embed_limit": validate_float, 

1347 "animation.writer": validate_string, 

1348 "animation.codec": validate_string, 

1349 "animation.bitrate": validate_int, 

1350 # Controls image format when frames are written to disk 

1351 "animation.frame_format": ["png", "jpeg", "tiff", "raw", "rgba", "ppm", 

1352 "sgi", "bmp", "pbm", "svg"], 

1353 # Path to ffmpeg binary. If just binary name, subprocess uses $PATH. 

1354 "animation.ffmpeg_path": _validate_pathlike, 

1355 # Additional arguments for ffmpeg movie writer (using pipes) 

1356 "animation.ffmpeg_args": validate_stringlist, 

1357 # Path to convert binary. If just binary name, subprocess uses $PATH. 

1358 "animation.convert_path": _validate_pathlike, 

1359 # Additional arguments for convert movie writer (using pipes) 

1360 "animation.convert_args": validate_stringlist, 

1361 

1362 # Classic (pre 2.0) compatibility mode 

1363 # This is used for things that are hard to make backward compatible 

1364 # with a sane rcParam alone. This does *not* turn on classic mode 

1365 # altogether. For that use `matplotlib.style.use("classic")`. 

1366 "_internal.classic_mode": validate_bool 

1367} 

1368_hardcoded_defaults = { # Defaults not inferred from 

1369 # lib/matplotlib/mpl-data/matplotlibrc... 

1370 # ... because they are private: 

1371 "_internal.classic_mode": False, 

1372 # ... because they are deprecated: 

1373 # No current deprecations. 

1374 # backend is handled separately when constructing rcParamsDefault. 

1375} 

1376_validators = {k: _convert_validator_spec(k, conv) 

1377 for k, conv in _validators.items()}