1919 from IPython import get_ipython
2020except ModuleNotFoundError :
2121 def get_ipython ():
22- return None
22+ return
2323from .utils import _warn_proplot , _counter , _benchmark , units
2424
2525# Disable mathtext "missing glyph" warnings
@@ -33,7 +33,11 @@ def get_ipython():
3333 'ipython_autoreload' , 'ipython_matplotlib' ,
3434]
3535
36- # Initialize
36+ # Dictionaries used to track custom proplot settings
37+ rcParamsShort = {}
38+ rcParamsLong = {}
39+
40+ # Dictionaries containing default settings
3741defaultParamsShort = {
3842 'abc' : False ,
3943 'align' : False ,
@@ -242,38 +246,7 @@ def get_ipython():
242246 'text.usetex' : False ,
243247 'xtick.minor.visible' : True ,
244248 'ytick.minor.visible' : True ,
245-
246249}
247- rcParamsShort = {}
248- rcParamsLong = {}
249-
250- # Initialize user file
251- _rc_file = os .path .join (os .path .expanduser ('~' ), '.proplotrc' )
252- if not os .path .isfile (_rc_file ):
253- def _tabulate (rcdict ):
254- string = ''
255- maxlen = max (map (len , rcdict ))
256- for key , value in rcdict .items ():
257- value = '' if value is None else repr (value )
258- space = ' ' * (maxlen - len (key ) + 1 ) * int (bool (value ))
259- string += f'# { key } :{ space } { value } \n '
260- return string .strip ()
261- with open (_rc_file , 'x' ) as f :
262- f .write (f"""
263- #------------------------------------------------------
264- # Use this file to customize settings
265- # For descriptions of each key name see:
266- # https://proplot.readthedocs.io/en/latest/rctools.html
267- #------------------------------------------------------
268- # ProPlot short name settings
269- { _tabulate (defaultParamsShort )}
270- #
271- # ProPlot long name settings
272- { _tabulate (defaultParamsLong )}
273- #
274- # Matplotlib settings
275- { _tabulate (defaultParams )}
276- """ .strip ())
277250
278251# "Global" settings and the lower-level settings they change
279252_rc_children = {
@@ -338,159 +311,42 @@ def _tabulate(rcdict):
338311 'xtick.major.pad' , 'xtick.minor.pad' ,
339312 'ytick.major.pad' , 'ytick.minor.pad'
340313 ),
314+ 'grid.color' : (
315+ 'gridminor.color' ,
316+ ),
317+ 'grid.linewidth' : (
318+ 'gridminor.linewidth' ,
319+ ),
320+ 'grid.linestyle' : (
321+ 'gridminor.linestyle' ,
322+ ),
323+ 'grid.alpha' : (
324+ 'gridminor.alpha' ,
325+ ),
341326}
342327
343- # Names of the new settings
344- RC_PARAMNAMES = {* rcParams .keys ()}
345- RC_SHORTNAMES = {
346- 'abc' ,
347- 'align' ,
348- 'alpha' ,
349- 'autoreload' ,
350- 'autosave' ,
351- 'borders' ,
352- 'cmap' ,
353- 'coast' ,
354- 'color' ,
355- 'cycle' ,
356- 'facecolor' ,
357- 'fontname' ,
358- 'geogrid' ,
359- 'grid' ,
360- 'gridminor' ,
361- 'gridratio' ,
362- 'inlinefmt' ,
363- 'innerborders' ,
364- 'lakes' ,
365- 'land' ,
366- 'large' ,
367- 'linewidth' ,
368- 'lut' ,
369- 'margin' ,
370- 'matplotlib' ,
371- 'ocean' ,
372- 'reso' ,
373- 'rgbcycle' ,
374- 'rivers' ,
375- 'share' ,
376- 'small' ,
377- 'span' ,
378- 'tickdir' ,
379- 'ticklen' ,
380- 'ticklenratio' ,
381- 'tickpad' ,
382- 'tickratio' ,
383- 'tight' ,
384- }
385- RC_LONGNAMES = {
386- 'abc.border' ,
387- 'abc.color' ,
388- 'abc.linewidth' ,
389- 'abc.loc' ,
390- 'abc.size' ,
391- 'abc.style' ,
392- 'abc.weight' ,
393- 'axes.alpha' ,
394- 'axes.formatter.timerotation' ,
395- 'axes.formatter.zerotrim' ,
396- 'axes.geogrid' ,
397- 'axes.gridminor' ,
398- 'borders.color' ,
399- 'borders.linewidth' ,
400- 'bottomlabel.color' ,
401- 'bottomlabel.size' ,
402- 'bottomlabel.weight' ,
403- 'coast.color' ,
404- 'coast.linewidth' ,
405- 'colorbar.axespad' ,
406- 'colorbar.extend' ,
407- 'colorbar.framealpha' ,
408- 'colorbar.frameon' ,
409- 'colorbar.grid' ,
410- 'colorbar.insetextend' ,
411- 'colorbar.insetlength' ,
412- 'colorbar.insetwidth' ,
413- 'colorbar.length' ,
414- 'colorbar.loc' ,
415- 'colorbar.width' ,
416- 'geoaxes.edgecolor' ,
417- 'geoaxes.facecolor' ,
418- 'geoaxes.linewidth' ,
419- 'geogrid.alpha' ,
420- 'geogrid.color' ,
421- 'geogrid.labels' ,
422- 'geogrid.labelsize' ,
423- 'geogrid.latmax' ,
424- 'geogrid.latstep' ,
425- 'geogrid.linestyle' ,
426- 'geogrid.linewidth' ,
427- 'geogrid.lonstep' ,
428- 'gridminor.alpha' ,
429- 'gridminor.color' ,
430- 'gridminor.linestyle' ,
431- 'gridminor.linewidth' ,
432- 'image.edgefix' ,
433- 'image.levels' ,
434- 'innerborders.color' ,
435- 'innerborders.linewidth' ,
436- 'lakes.color' ,
437- 'land.color' ,
438- 'leftlabel.color' ,
439- 'leftlabel.size' ,
440- 'leftlabel.weight' ,
441- 'ocean.color' ,
442- 'rightlabel.color' ,
443- 'rightlabel.size' ,
444- 'rightlabel.weight' ,
445- 'rivers.color' ,
446- 'rivers.linewidth' ,
447- 'subplots.axpad' ,
448- 'subplots.axwidth' ,
449- 'subplots.pad' ,
450- 'subplots.panelpad' ,
451- 'subplots.panelwidth' ,
452- 'suptitle.color' ,
453- 'suptitle.size' ,
454- 'suptitle.weight' ,
455- 'tick.labelcolor' ,
456- 'tick.labelsize' ,
457- 'tick.labelweight' ,
458- 'title.border' ,
459- 'title.color' ,
460- 'title.linewidth' ,
461- 'title.loc' ,
462- 'title.pad' ,
463- 'title.size' ,
464- 'title.weight' ,
465- 'toplabel.color' ,
466- 'toplabel.size' ,
467- 'toplabel.weight' ,
468- }
469- # Used by Axes.format, allows user to pass rc settings as keyword args,
470- # way less verbose. For example, landcolor='b' vs. rc_kw={'land.color':'b'}.
471- RC_NODOTSNAMES = { # useful for passing these as kwargs
472- name .replace ('.' , '' ): name for names in
473- (RC_LONGNAMES , RC_PARAMNAMES , RC_SHORTNAMES )
474- for name in names
328+ # Mapping of settings without "dots" to their full names. This lets us pass
329+ # all settings as kwargs, e.g. ax.format(landcolor='b') instead of the much
330+ # more verbose ax.format(rc_kw={'land.color':'b'}).
331+ _rc_nodots = {
332+ name .replace ('.' , '' ): name
333+ for names in (defaultParamsLong , rcParams )
334+ for name in names .keys ()
475335}
476- # Categories for returning dict of subcategory properties
477- RC_CATEGORIES = {
478- * (re .sub (r'\.[^.]*$' , '' , name ) for names in
479- (RC_LONGNAMES , RC_PARAMNAMES ) for name in names ),
480- * (re .sub (r'\..*$' , '' , name ) for names in
481- (RC_LONGNAMES , RC_PARAMNAMES ) for name in names )
482- }
483-
484336
485- def _to_points (key , value ):
486- """Convert certain rc keys to the units "points"."""
487- # See: https://matplotlib.org/users/customizing.html, all props matching
488- # the below strings use the units 'points', except custom categories!
489- if (isinstance (value , str )
490- and key .split ('.' )[0 ] not in ('colorbar' , 'subplots' )
491- and re .match ('^.*(width|space|size|pad|len|small|large)$' , key )):
492- value = units (value , 'pt' )
493- return value
337+ # Category names, used for returning dicts of subcategory properties
338+ _rc_categories = {
339+ * (
340+ re .sub (r'\.[^.]*$' , '' , name )
341+ for names in (defaultParamsLong , rcParams )
342+ for name in names .keys ()
343+ ),
344+ * (
345+ re .sub (r'\..*$' , '' , name )
346+ for names in (defaultParamsLong , rcParams )
347+ for name in names .keys ()
348+ )
349+ }
494350
495351
496352def _get_config_paths ():
@@ -521,10 +377,9 @@ def _get_synced_params(key, value):
521377 kw = {} # builtin properties that global setting applies to
522378 kw_long = {} # custom properties that global setting applies to
523379 kw_short = {} # short name properties
524- if '.' not in key and key not in rcParamsShort :
525- key = RC_NODOTSNAMES .get (key , key )
526380
527381 # Skip full name keys
382+ key = _sanitize_key (key )
528383 if '.' in key :
529384 pass
530385
@@ -538,10 +393,9 @@ def _get_synced_params(key, value):
538393 colors = mcm .cmap_d [cycle ].colors
539394 except (KeyError , AttributeError ):
540395 cycles = sorted (
541- name for name ,
542- cmap in mcm .cmap_d .items () if isinstance (
543- cmap ,
544- mcolors .ListedColormap ))
396+ name for name , cmap in mcm .cmap_d .items ()
397+ if isinstance (cmap , mcolors .ListedColormap )
398+ )
545399 raise ValueError (
546400 f'Invalid cycle name { cycle !r} . Options are: '
547401 ', ' .join (map (repr , cycles )) + '.'
@@ -550,9 +404,14 @@ def _get_synced_params(key, value):
550404 regcolors = colors + [(0.1 , 0.1 , 0.1 )]
551405 elif mcolors .to_rgb ('r' ) != (1.0 , 0.0 , 0.0 ): # reset
552406 regcolors = [
553- (0.0 , 0.0 , 1.0 ), (1.0 , 0.0 , 0.0 ), (0.0 , 1.0 , 0.0 ),
554- (0.75 , 0.75 , 0.0 ), (0.75 , 0.75 , 0.0 ), (0.0 , 0.75 , 0.75 ),
555- (0.0 , 0.0 , 0.0 )]
407+ (0.0 , 0.0 , 1.0 ),
408+ (1.0 , 0.0 , 0.0 ),
409+ (0.0 , 1.0 , 0.0 ),
410+ (0.75 , 0.75 , 0.0 ),
411+ (0.75 , 0.75 , 0.0 ),
412+ (0.0 , 0.75 , 0.75 ),
413+ (0.0 , 0.0 , 0.0 )
414+ ]
556415 else :
557416 regcolors = [] # no reset necessary
558417 for code , color in zip ('brgmyck' , regcolors ):
@@ -648,7 +507,7 @@ def _get_synced_params(key, value):
648507 kw [key ] = value
649508 else :
650509 raise KeyError (f'Invalid key { key !r} .' )
651- for name in RC_CHILDREN .get (key , ()):
510+ for name in _rc_children .get (key , ()):
652511 if name in rcParamsLong :
653512 kw_long [name ] = value
654513 else :
@@ -657,14 +516,28 @@ def _get_synced_params(key, value):
657516
658517
659518def _sanitize_key (key ):
660- """Convert the key to a palatable value ."""
519+ """Ensure string and convert keys with omitted dots ."""
661520 if not isinstance (key , str ):
662521 raise KeyError (f'Invalid key { key !r} . Must be string.' )
663- if '.' not in key and key not in rcParamsShort :
664- key = RC_NODOTSNAMES .get (key , key )
522+ if '.' not in key and key not in rcParamsShort : # speedup
523+ key = _rc_nodots .get (key , key )
665524 return key .lower ()
666525
667526
527+ def _to_points (key , value ):
528+ """Convert certain rc keys to the units "points"."""
529+ # TODO: Incorporate into more sophisticated validation system
530+ # See: https://matplotlib.org/users/customizing.html, all props matching
531+ # the below strings use the units 'points', except custom categories!
532+ if (
533+ isinstance (value , str )
534+ and key .split ('.' )[0 ] not in ('colorbar' , 'subplots' )
535+ and re .match ('^.*(width|space|size|pad|len|small|large)$' , key )
536+ ):
537+ value = units (value , 'pt' )
538+ return value
539+
540+
668541def _update_from_file (file ):
669542 """
670543 Apply updates from a file. This is largely copied from matplotlib.
@@ -927,7 +800,7 @@ def __getitem__(self, key):
927800 return kw [key ]
928801 except KeyError :
929802 continue
930- raise KeyError (f'Invalid property name { key !r} .' )
803+ raise KeyError (f'Invalid setting name { key !r} .' )
931804
932805 def __setattr__ (self , attr , value ):
933806 """Pass the attribute and value to `~rc_configurator.__setitem__`."""
@@ -971,9 +844,9 @@ def _get_item(self, key, mode=None):
971844 except KeyError :
972845 continue
973846 if mode == 0 :
974- raise KeyError (f'Invalid property name { key !r} .' )
847+ raise KeyError (f'Invalid setting name { key !r} .' )
975848 else :
976- return None
849+ return
977850
978851 def category (self , cat , * , trimcat = True , context = False ):
979852 """
@@ -992,10 +865,10 @@ def category(self, cat, *, trimcat=True, context=False):
992865 context mode dictionaries is omitted from the output dictionary.
993866 See `~rc_configurator.context`.
994867 """
995- if cat not in RC_CATEGORIES :
868+ if cat not in _rc_categories :
996869 raise ValueError (
997870 f'Invalid rc category { cat !r} . Valid categories are '
998- ', ' .join (map (repr , RC_CATEGORIES )) + '.'
871+ ', ' .join (map (repr , _rc_categories )) + '.'
999872 )
1000873 kw = {}
1001874 mode = 0 if not context else None
0 commit comments