From 9b408b1074140e5a7bbed71c1367c25c8a6ab73d Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Tue, 7 Jan 2020 14:43:18 -0700 Subject: [PATCH 1/6] Add comment headers to cycle files --- proplot/cycles/538.hex | 1 + proplot/cycles/Qual1.rgb | 1 + proplot/cycles/Qual2.rgb | 1 + proplot/cycles/colorblind.hex | 1 + proplot/cycles/colorblind10.hex | 1 + proplot/cycles/default.hex | 1 + 6 files changed, 6 insertions(+) diff --git a/proplot/cycles/538.hex b/proplot/cycles/538.hex index 52f7cec0b..a799a8f73 100644 --- a/proplot/cycles/538.hex +++ b/proplot/cycles/538.hex @@ -1 +1,2 @@ +# From the 538 matplotlib stylesheet '#008fd5', '#fc4f30', '#e5ae38', '#6d904f', '#8b8b8b', '#810f7c', diff --git a/proplot/cycles/Qual1.rgb b/proplot/cycles/Qual1.rgb index fea52946f..5fb0b09c4 100644 --- a/proplot/cycles/Qual1.rgb +++ b/proplot/cycles/Qual1.rgb @@ -1,3 +1,4 @@ +# Unknown source 91,190,148 145,190,100 229,207,108 diff --git a/proplot/cycles/Qual2.rgb b/proplot/cycles/Qual2.rgb index 592d6c8e4..689b8592a 100644 --- a/proplot/cycles/Qual2.rgb +++ b/proplot/cycles/Qual2.rgb @@ -1,3 +1,4 @@ +# Unknown source 91,190,148 182,227,209 145,190,100 diff --git a/proplot/cycles/colorblind.hex b/proplot/cycles/colorblind.hex index 7d7218dd4..23c0ad4fa 100644 --- a/proplot/cycles/colorblind.hex +++ b/proplot/cycles/colorblind.hex @@ -1 +1,2 @@ +# Seaborn and proplot default style '#0072B2', '#D55E00', '#009E73', '#CC79A7', '#F0E442', '#56B4E9', diff --git a/proplot/cycles/colorblind10.hex b/proplot/cycles/colorblind10.hex index 7d356f95b..d20d0a59a 100644 --- a/proplot/cycles/colorblind10.hex +++ b/proplot/cycles/colorblind10.hex @@ -1 +1,2 @@ +# Expanded seaborn default style "#0173B2", "#DE8F05", "#029E73", "#D55E00", "#CC78BC", "#CA9161", "#FBAFE4", "#949494", "#ECE133", "#56B4E9" diff --git a/proplot/cycles/default.hex b/proplot/cycles/default.hex index 9d8b2e450..cc5f3ddf0 100644 --- a/proplot/cycles/default.hex +++ b/proplot/cycles/default.hex @@ -1 +1,2 @@ +# Matplotlib latest default style '#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf', From 92d3a3918244552c88523009245a8332886cf7bd Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Tue, 7 Jan 2020 14:44:03 -0700 Subject: [PATCH 2/6] Add new color cycles --- proplot/cycles/bmh.hex | 2 ++ proplot/cycles/classic.hex | 2 ++ proplot/cycles/solarized.hex | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 proplot/cycles/bmh.hex create mode 100644 proplot/cycles/classic.hex create mode 100644 proplot/cycles/solarized.hex diff --git a/proplot/cycles/bmh.hex b/proplot/cycles/bmh.hex new file mode 100644 index 000000000..52ec87ab4 --- /dev/null +++ b/proplot/cycles/bmh.hex @@ -0,0 +1,2 @@ +# From bmh stylesheet +'#348ABD', '#A60628', '#7A68A6', '#467821', '#D55E00', '#CC79A7', '#56B4E9', '#009E73', '#F0E442', '#0072B2' diff --git a/proplot/cycles/classic.hex b/proplot/cycles/classic.hex new file mode 100644 index 000000000..79fa00326 --- /dev/null +++ b/proplot/cycles/classic.hex @@ -0,0 +1,2 @@ +# Matplotlib classic 'bgrcmyk' style +'#0000ff', '#008000', '#ff0000', '#00bfbf', '#bf00bf', '#bfbf00', '#000000' diff --git a/proplot/cycles/solarized.hex b/proplot/cycles/solarized.hex new file mode 100644 index 000000000..6417b59fb --- /dev/null +++ b/proplot/cycles/solarized.hex @@ -0,0 +1,2 @@ +# From solarized stylesheet +'#268BD2', '#2AA198', '#859900', '#B58900', '#CB4B16', '#DC322F', '#D33682', '#6C71C4' From 60a28b9bc373a2b751f6b2e5de4fe9870bcc88ab Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Tue, 7 Jan 2020 14:44:39 -0700 Subject: [PATCH 3/6] Graceful failure when CmapDict cannot find global vars --- proplot/styletools.py | 44 +++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/proplot/styletools.py b/proplot/styletools.py index 4e83e8c7e..89f25a282 100644 --- a/proplot/styletools.py +++ b/proplot/styletools.py @@ -1835,17 +1835,23 @@ def __init__(self, kwargs): if not isinstance(key, str): raise KeyError(f'Invalid key {key}. Must be string.') self.__setitem__(key, value, sort=False) - for record in (cmaps, cycles): - record[:] = sorted(record) + try: + for record in (cmaps, cycles): + record[:] = sorted(record) + except NameError: + pass def __delitem__(self, key): """Delete the item from the list records.""" super().__delitem__(self, key) - for record in (cmaps, cycles): - try: - record.remove(key) - except ValueError: - pass + try: + for record in (cmaps, cycles): + try: + record.remove(key) + except ValueError: + pass + except NameError: + pass def __getitem__(self, key): """Retrieve the colormap associated with the sanitized key name. The @@ -1904,10 +1910,13 @@ def __setitem__(self, key, item, sort=True): 'matplotlib.colors.LinearSegmentedColormap.' ) key = self._sanitize_key(key, mirror=False) - record = cycles if isinstance(item, ListedColormap) else cmaps - record.append(key) - if sort: - record[:] = sorted(record) + try: + record = cycles if isinstance(item, ListedColormap) else cmaps + record.append(key) + if sort: + record[:] = sorted(record) + except NameError: + pass return super().__setitem__(key, item) def __contains__(self, item): @@ -1950,11 +1959,14 @@ def get(self, key, *args): def pop(self, key, *args): """Pop the sanitized colormap name.""" key = self._sanitize_key(key, mirror=True) - for record in (cmaps, cycles): - try: - record.remove(key) - except ValueError: - pass + try: + for record in (cmaps, cycles): + try: + record.remove(key) + except ValueError: + pass + except NameError: + pass return super().pop(key, *args) def update(self, *args, **kwargs): From 35c2c8b9e09d74c80302a5e6cd0bcb38ce53b672 Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Tue, 7 Jan 2020 14:44:57 -0700 Subject: [PATCH 4/6] Permit comment headers in RGB cmap/cycle files --- proplot/styletools.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/proplot/styletools.py b/proplot/styletools.py index 89f25a282..fd8287236 100644 --- a/proplot/styletools.py +++ b/proplot/styletools.py @@ -2848,8 +2848,11 @@ def _warn_or_raise(msg): # NOTE: This appears to be biggest import time bottleneck! Increases # time from 0.05s to 0.2s, with numpy loadtxt or with this regex thing. delim = re.compile(r'[,\s]+') - data = [delim.split(line.strip()) - for line in open(filename).readlines() if line.strip()] + data = [ + delim.split(line.strip()) + for line in open(filename).readlines() + if line.strip() and line.strip()[0] != '#' + ] try: data = [[float(num) for num in line] for line in data] except ValueError: From 58d84619e6cde28b631343d8e86fbe6ac1553109 Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Tue, 7 Jan 2020 14:45:51 -0700 Subject: [PATCH 5/6] Categorize color cycles, just like cmaps --- proplot/styletools.py | 60 +++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/proplot/styletools.py b/proplot/styletools.py index fd8287236..0a3eea2c6 100644 --- a/proplot/styletools.py +++ b/proplot/styletools.py @@ -39,6 +39,26 @@ ] # Colormap stuff +CYCLES_TABLE = { + 'Matplotlib originals': ( + 'default', 'classic', + ), + 'Matplotlib stylesheets': ( + 'colorblind', 'colorblind10', 'ggplot', 'bmh', 'solarized', '538', + ), + 'ColorBrewer2.0 qualitative': ( + 'Accent', 'Dark2', + 'Paired', 'Pastel1', 'Pastel2', + 'Set1', 'Set2', 'Set3', + ), + 'Other qualitative': ( + 'FlatUI', 'Qual1', 'Qual2', 'Viz', + ), + 'ProPlot originals': ( + 'Cool', 'Warm', 'Hot', + 'Floral', 'Contrast', 'Sharp', + ), +} CMAPS_TABLE = { # Assorted origin, but these belong together 'Grayscale': ( @@ -3164,12 +3184,20 @@ def register_fonts(): fonts[:] = [*fonts_proplot, *fonts_system] -def _draw_bars(cmapdict, length=4.0, width=0.2): +def _draw_bars(names, *, source, unknown='User', length=4.0, width=0.2): """ Draw colorbars for "colormaps" and "color cycles". This is called by `show_cycles` and `show_cmaps`. """ - # Figure + # Categorize the input names + cmapdict = {} + names_all = list(map(str.lower, names)) + names_known = list(map(str.lower, sum(map(list, source.values()), []))) + cmapdict[unknown] = [name for name in names if name not in names_known] + for cat, names in source.items(): + cmapdict[cat] = [name for name in names if name.lower() in names_all] + + # Draw figure from . import subplots naxs = len(cmapdict) + sum(map(len, cmapdict.values())) fig, axs = subplots( @@ -3526,10 +3554,10 @@ def _color_filter(i, hcl): # noqa: E306 return figs -def show_cmaps(*args, N=None, unknown='User', **kwargs): +def show_cmaps(*args, N=None, **kwargs): """ - Generate a table of the registered colormaps or the input colormaps. - Adapted from `this example \ + Generate a table of the registered colormaps or the input colormaps + categorized by source. Adapted from `this example \ `__. Parameters @@ -3564,26 +3592,24 @@ def show_cmaps(*args, N=None, unknown='User', **kwargs): isinstance(mcm.cmap_d[name], LinearSegmentedColormap) ] - # Get dictionary of registered colormaps and their categories - cmapdict = {} - names_all = list(map(str.lower, names)) - names_known = sum(map(list, CMAPS_TABLE.values()), []) - cmapdict[unknown] = [name for name in names if name not in names_known] - for cat, names in CMAPS_TABLE.items(): - cmapdict[cat] = [name for name in names if name.lower() in names_all] - # Return figure of colorbars - return _draw_bars(cmapdict, **kwargs) + kwargs.setdefault('source', CMAPS_TABLE) + return _draw_bars(names, **kwargs) def show_cycles(*args, **kwargs): """ - Generate a table of registered color cycles or the input color cycles. + Generate a table of registered color cycles or the input color cycles + categorized by source. Adapted from `this example \ +`__. Parameters ---------- *args : colormap-spec, optional Cycle names or objects. + unknown : str, optional + Category name for cycles that are unknown to ProPlot. The + default is ``'User'``. length : float or str, optional The length of the colorbars. Units are interpreted by `~proplot.utils.units`. @@ -3606,8 +3632,8 @@ def show_cycles(*args, **kwargs): ] # Return figure of colorbars - cmapdict = {'Color cycles': names} - return _draw_bars(cmapdict, **kwargs) + kwargs.setdefault('source', CYCLES_TABLE) + return _draw_bars(names, **kwargs) def show_fonts(*args, size=12, text=None): From b7afd018526869cc6ce49a468202417b1cb1106b Mon Sep 17 00:00:00 2001 From: Luke Davis Date: Tue, 7 Jan 2020 14:59:59 -0700 Subject: [PATCH 6/6] Fix bugs in show_cycles/cmaps displays --- proplot/styletools.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/proplot/styletools.py b/proplot/styletools.py index 0a3eea2c6..20a581118 100644 --- a/proplot/styletools.py +++ b/proplot/styletools.py @@ -146,7 +146,7 @@ ), 'Other': ( 'binary', 'bwr', 'brg', # appear to be custom matplotlib - 'cubehelix', 'wistia', 'CMRmap', # individually released + 'cubehelix', 'Wistia', 'CMRmap', # individually released 'seismic', 'terrain', 'nipy_spectral', # origin ambiguous 'tab10', 'tab20', 'tab20b', 'tab20c', # merged colormap cycles ) @@ -3193,9 +3193,13 @@ def _draw_bars(names, *, source, unknown='User', length=4.0, width=0.2): cmapdict = {} names_all = list(map(str.lower, names)) names_known = list(map(str.lower, sum(map(list, source.values()), []))) - cmapdict[unknown] = [name for name in names if name not in names_known] + names_unknown = [name for name in names if name not in names_known] + if names_unknown: + cmapdict[unknown] = names_unknown for cat, names in source.items(): - cmapdict[cat] = [name for name in names if name.lower() in names_all] + names_cat = [name for name in names if name.lower() in names_all] + if names_cat: + cmapdict[cat] = names_cat # Draw figure from . import subplots @@ -3209,8 +3213,6 @@ def _draw_bars(names, *, source, unknown='User', length=4.0, width=0.2): a = np.linspace(0, 1, 257).reshape(1, -1) a = np.vstack((a, a)) for cat, names in cmapdict.items(): - if not names: - continue nheads += 1 for imap, name in enumerate(names): iax += 1 @@ -3695,9 +3697,10 @@ def show_fonts(*args, size=12, text=None): # Apply custom changes -mcm.cmap_d['Grays'] = mcm.cmap_d.pop('Greys', None) # 'Murica (and consistency with registered colors) # noqa -mcm.cmap_d['Spectral'] = mcm.cmap_d['Spectral'].reversed( - name='Spectral') # make spectral go from 'cold' to 'hot' +if 'Greys' in mcm.cmap_d: # 'Murica (and consistency with registered colors) + mcm.cmap_d['Grays'] = mcm.cmap_d.pop('Greys') +if 'Spectral' in mcm.cmap_d: # make spectral go from 'cold' to 'hot' + mcm.cmap_d['Spectral'] = mcm.cmap_d['Spectral'].reversed(name='Spectral') for _name in CMAPS_TABLE['Matplotlib originals']: # initialize as empty lists if _name == 'twilight_shifted': mcm.cmap_d.pop(_name, None)