Skip to content

Commit 8c05a31

Browse files
committed
Clean up internals, module constants
1 parent 25d5e2b commit 8c05a31

File tree

4 files changed

+53
-50
lines changed

4 files changed

+53
-50
lines changed

proplot/axes/plot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2474,7 +2474,7 @@ def _parse_cmap(
24742474
# Create the user-input colormap
24752475
# Also force options in special cases
24762476
if plot_lines:
2477-
cmap_kw['default_luminance'] = pcolors.CYCLE_LUMINANCE
2477+
cmap_kw['default_luminance'] = constructor.DEFAULT_CYCLE_LUMINANCE
24782478
if cmap is not None:
24792479
cmap = constructor.Colormap(cmap, **cmap_kw) # for testing only
24802480
cyclic = _not_none(cyclic, getattr(cmap, '_cyclic', None))

proplot/colors.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,13 @@
5151
# Default colormap properties
5252
DEFAULT_NAME = '_no_name'
5353
DEFAULT_SPACE = 'hsl'
54-
DEFAULT_SAMPLES = 10 # used in Colormap() and relied upon in Cycle()
55-
CYCLE_LUMINANCE = 90 # used in Cycle()
5654

5755
# Color regexes
5856
# NOTE: We do not compile hex regex because config.py needs this surrounded by \A\Z
5957
_regex_hex = r'#(?:[0-9a-fA-F]{3,4}){2}' # 6-8 digit hex
60-
REGEX_HEX = re.compile(rf'\A{_regex_hex}\Z')
6158
REGEX_HEX_MULTI = re.compile(_regex_hex)
62-
REGEX_GRAY = re.compile(r'\A(light|dark|medium|pale|charcoal)?\s*(gr[ea]y[0-9]?)?\Z')
59+
REGEX_HEX_SINGLE = re.compile(rf'\A{_regex_hex}\Z')
60+
REGEX_ADJUST = re.compile(r'\A(light|dark|medium|pale|charcoal)?\s*(gr[ea]y[0-9]?)?\Z')
6361

6462
# Colormap constants
6563
CMAPS_CYCLIC = tuple( # cyclic colormaps loaded from rgb files
@@ -160,9 +158,6 @@
160158
# Color constants
161159
COLORS_OPEN = {} # populated during register_colors
162160
COLORS_XKCD = {} # populated during register_colors
163-
COLORS_ORIG = ( # always use these colors as XKCD colors
164-
'red', 'green', 'blue', 'cyan', 'yellow', 'magenta', 'white', 'black'
165-
)
166161
COLORS_KEEP = (
167162
*( # always load these XKCD colors regardless of settings
168163
'charcoal', 'tomato', 'burgundy', 'maroon', 'burgundy', 'lavendar',
@@ -207,7 +202,7 @@
207202
'icky',
208203
'sickly',
209204
)
210-
COLORS_SUBS = (
205+
COLORS_REPLACE = (
211206
# prevent registering similar-sounding names
212207
# these can all be combined
213208
('/', ' '), # convert [color1]/[color2] to compound (e.g. grey/blue to grey blue)
@@ -580,7 +575,7 @@ def _load_colors(path, warn_on_failure=True):
580575
if not stripped or stripped[0] == '#':
581576
continue
582577
pair = tuple(item.strip().lower() for item in line.split(':'))
583-
if len(pair) != 2 or not REGEX_HEX.match(pair[1]):
578+
if len(pair) != 2 or not REGEX_HEX_SINGLE.match(pair[1]):
584579
warnings._warn_proplot(
585580
f'Illegal line #{count + 1} in color file {path!r}:\n'
586581
f'{line!r}\n'
@@ -625,7 +620,7 @@ def _standardize_colors(input, space, margin):
625620
# Translate remaining colors and remove bad names
626621
# WARNING: Unique axis argument requires numpy version >=1.13
627622
for name, color in input.items():
628-
for sub, rep in COLORS_SUBS:
623+
for sub, rep in COLORS_REPLACE:
629624
if sub in name:
630625
name = name.replace(sub, rep)
631626
if any(sub in name for sub in COLORS_REMOVE):
@@ -2225,7 +2220,7 @@ def from_list(cls, *args, adjust_grays=True, **kwargs):
22252220
hues = cdict['hue'] # segment data
22262221
for i, color in enumerate(colors):
22272222
rgb = to_rgb(color)
2228-
if isinstance(color, str) and REGEX_GRAY.match(color):
2223+
if isinstance(color, str) and REGEX_ADJUST.match(color):
22292224
pass
22302225
elif not np.allclose(np.array(rgb), rgb[0]):
22312226
continue

proplot/config.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,16 @@ def get_ipython():
5656
]
5757

5858
# Constants
59-
REGEX_STRING = re.compile('\\A(\'.*\'|".*")\\Z')
59+
COLORS_KEEP = (
60+
'red',
61+
'green',
62+
'blue',
63+
'cyan',
64+
'yellow',
65+
'magenta',
66+
'white',
67+
'black'
68+
)
6069
FONT_KEYS = ( # re-apply these whenever 'font.size' is changed
6170
'abc.size',
6271
'axes.labelsize',
@@ -655,8 +664,8 @@ def register_colors(*args, user=None, default=False, space=None, margin=None, **
655664
The margin by which the normalized hue, saturation, and luminance of each
656665
XKCD color must differ from the channel values of the other XKCD colors to
657666
be deemed "perceptually distinct" and registered. Must fall between ``0``
658-
and ``1`` (``0`` will register all colors). Default is ``0.1``. If
659-
passed then `default` is set to ``True``.
667+
and ``1`` (``0`` will register all colors). Default is ``0.1``. If passed
668+
then `default` is set to ``True``.
660669
**kwargs
661670
Additional color name specifications passed as keyword arguments rather
662671
than positional dictionaries.
@@ -674,12 +683,13 @@ def register_colors(*args, user=None, default=False, space=None, margin=None, **
674683
space = _not_none(space, 'hcl')
675684

676685
# Remove previously registered colors
677-
# NOTE: Add
686+
# NOTE: Try not to touch matplotlib colors for compatibility
678687
srcs = {'xkcd': pcolors.COLORS_XKCD, 'opencolor': pcolors.COLORS_OPEN}
679688
if default: # possibly slow but not these dicts are empty on startup
680689
for src in srcs.values():
681690
for key in src:
682-
pcolors._color_database.pop(key, None) # MutableMapping clears cache
691+
if key not in COLORS_KEEP:
692+
pcolors._color_database.pop(key, None) # this also clears cache
683693
src.clear()
684694

685695
# Register input colors
@@ -706,7 +716,7 @@ def register_colors(*args, user=None, default=False, space=None, margin=None, **
706716
raise RuntimeError(f'Unknown proplot color database {path!r}.')
707717
src = srcs[cat]
708718
if cat == 'xkcd':
709-
for key in pcolors.COLORS_ORIG: # noqa: E501
719+
for key in COLORS_KEEP:
710720
loaded[key] = pcolors._color_database[key] # keep the same
711721
loaded = pcolors._standardize_colors(loaded, space, margin)
712722
src.clear()

proplot/constructor.py

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,13 @@
5454
'Colors', # deprecated
5555
]
5656

57-
# Dictionary of possible normalizers. See `Norm` for a table.
57+
# Color cycle constants
58+
# TODO: Also automatically truncate the 'bright' end of colormaps
59+
# when building color cycles from colormaps? Or add simple option.
60+
DEFAULT_CYCLE_SAMPLES = 10
61+
DEFAULT_CYCLE_LUMINANCE = 90
62+
63+
# Normalizer registry
5864
NORMS = {
5965
'none': mcolors.NoNorm,
6066
'null': mcolors.NoNorm,
@@ -70,8 +76,7 @@
7076
if hasattr(mcolors, 'TwoSlopeNorm'):
7177
NORMS['twoslope'] = mcolors.TwoSlopeNorm
7278

73-
# Mapping of strings to `~matplotlib.ticker.Locator` classes. See
74-
# `Locator` for a table."""
79+
# Locator registry
7580
LOCATORS = {
7681
'none': mticker.NullLocator,
7782
'null': mticker.NullLocator,
@@ -101,18 +106,13 @@
101106
}
102107
if dependencies._version_cartopy >= 0.18:
103108
# NOTE: This only makes sense when paired with degree-minute-second formatter
104-
# NOTE: We copied cartopy locators because they are short and necessary
105-
# for determining both cartopy and basemap tick locations. We did *not* copy
106-
# formatter because they are long and we have nice, simpler alternatives of
107-
# deglon and deglat.
108109
LOCATORS['dms'] = partial(pticker.DegreeLocator, dms=True)
109110
LOCATORS['dmslon'] = partial(pticker.LongitudeLocator, dms=True)
110111
LOCATORS['dmslat'] = partial(pticker.LatitudeLocator, dms=True)
111112
if hasattr(mproj.polar, 'ThetaLocator'):
112113
LOCATORS['theta'] = mproj.polar.ThetaLocator
113114

114-
# Mapping of strings to `~matplotlib.ticker.Formatter` classes. See
115-
# `Formatter` for a table.
115+
# Formatter registry
116116
# NOTE: Critical to use SimpleFormatter for cardinal formatters rather than
117117
# AutoFormatter because latter fails with Basemap formatting.
118118
# NOTE: Define cartopy longitude/latitude formatters with dms=True because that
@@ -156,8 +156,7 @@
156156
if hasattr(mdates, 'ConciseDateFormatter'):
157157
FORMATTERS['concise'] = mdates.ConciseDateFormatter
158158

159-
# The registered scale names and their associated
160-
# `~matplotlib.scale.ScaleBase` classes. See `Scale` for a table.
159+
# Scale registry and presets
161160
SCALES = mscale._scale_mapping
162161
SCALE_PRESETS = {
163162
'quadratic': ('power', 2,),
@@ -182,8 +181,7 @@
182181
mscale.register_scale(pscale.SineLatitudeScale)
183182
mscale.register_scale(pscale.SymmetricalLogScale)
184183

185-
# Mapping of "projection names" to cartopy `~cartopy.crs.Projection` classes
186-
# and default keyword args for `~mpl_toolkits.basemap.Basemap` projections.
184+
# Cartopy projection registry and default basemap keyword args
187185
# NOTE: Normally basemap raises error if you omit keyword args
188186
PROJ_ALIASES = { # aliases to basemap naming conventions
189187
'eqc': 'cyl',
@@ -296,23 +294,6 @@
296294
+ ' . Please consider updating cartopy.'
297295
)
298296

299-
# Resolution aliases
300-
# NOTE: Maximum basemap resolutions are much finer than cartopy
301-
RESOS_CARTOPY = {
302-
'lo': '110m',
303-
'med': '50m',
304-
'hi': '10m',
305-
'x-hi': '10m', # extra high
306-
'xx-hi': '10m', # extra extra high
307-
}
308-
RESOS_BASEMAP = {
309-
'lo': 'c', # coarse
310-
'med': 'l',
311-
'hi': 'i', # intermediate
312-
'x-hi': 'h',
313-
'xx-hi': 'f', # fine
314-
}
315-
316297
# Geographic feature properties
317298
FEATURES_CARTOPY = { # positional arguments passed to NaturalEarthFeature
318299
'land': ('physical', 'land'),
@@ -331,6 +312,23 @@
331312
'innerborders': 'drawstates',
332313
}
333314

315+
# Resolution names
316+
# NOTE: Maximum basemap resolutions are much finer than cartopy
317+
RESOS_CARTOPY = {
318+
'lo': '110m',
319+
'med': '50m',
320+
'hi': '10m',
321+
'x-hi': '10m', # extra high
322+
'xx-hi': '10m', # extra extra high
323+
}
324+
RESOS_BASEMAP = {
325+
'lo': 'c', # coarse
326+
'med': 'l',
327+
'hi': 'i', # intermediate
328+
'x-hi': 'h',
329+
'xx-hi': 'f', # fine
330+
}
331+
334332

335333
def _modify_colormap(cmap, *, cut, left, right, reverse, shift, alpha, samples):
336334
"""
@@ -675,7 +673,7 @@ def _pop_modification(key):
675673

676674
# Modify the colormap
677675
if discrete and isinstance(cmap, pcolors.ContinuousColormap): # noqa: E501
678-
samples = _not_none(samples, pcolors.DEFAULT_SAMPLES)
676+
samples = _not_none(samples, DEFAULT_CYCLE_SAMPLES)
679677
cmap = _modify_colormap(
680678
cmap, cut=cut, left=left, right=right,
681679
reverse=reverse, shift=shift, alpha=alpha, samples=samples
@@ -818,7 +816,7 @@ def Cycle(*args, N=None, samples=None, name=None, **kwargs):
818816
kwargs.setdefault('listmode', 'discrete')
819817
kwargs.setdefault('filemode', 'discrete')
820818
kwargs['discrete'] = True # triggers application of default 'samples'
821-
kwargs['default_luminance'] = pcolors.CYCLE_LUMINANCE
819+
kwargs['default_luminance'] = DEFAULT_CYCLE_LUMINANCE
822820
cmap = Colormap(*args, name=name, samples=samples, **kwargs)
823821
name = _not_none(name, cmap.name)
824822
dict_ = {'color': [c if isinstance(c, str) else to_hex(c) for c in cmap.colors]}

0 commit comments

Comments
 (0)