Source code for cmaps

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
:Purpose:   This module provides an easy-access, light-weight wrapper,
            around ``matplotlib``'s colour maps, and can be used for
            retrieving and previewing named colour maps.

:Platform:  Linux/Windows | Python 3.7+
:Developer: J Berendt
:Email:     support@s3dev.uk

:Comments:  n/a

:Examples:

    Retrieve 5 colours from the 'viridis' colour map in hex format
    and preview the colours::

        >>> from utils4.cmaps import cmaps

        >>> clrs = cmaps.get_cmap('viridis', 15, as_hex=True, preview=True)
        >>> clrs

        ['#2d718e', '#297b8e', '#25858e', '#218f8d', '#1f998a',
         '#20a386', '#26ad81', '#34b679', '#46c06f', '#5cc863',
         '#73d056', '#8ed645', '#aadc32', '#c5e021', '#fde725']

    .. figure:: _static/img/cmaps_viridis15.png
        :scale: 75%
        :align: center

        Preview of the requested 'viridis' colour map of 15 colours


    List named colours from the matplotlib colour palette::

        >>> from utils4.cmaps import cmaps

        >>> cmaps.get_named_colours()

        {'aliceblue': '#F0F8FF',
         'antiquewhite': '#FAEBD7',
         'aqua': '#00FFFF',
         ...,
         'whitesmoke': '#F5F5F5',
         'yellow': '#FFFF00',
         'yellowgreen': '#9ACD32'}


    List or retrieve colour map names::

        >>> from utils4.cmaps import cmaps

        >>> cmaps.view_cmaps(view_only=True)

        ['magma',
         'inferno',
         'plasma',
         ...,
         'tab20_r',
         'tab20b_r',
         'tab20c_r']

"""
# pylint: disable=import-error
# pylint: disable=invalid-name
# pylint: disable=wrong-import-order

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from typing import Union


[docs] class _Preview: # pragma: nocover """Provide a preview for a given colourmap."""
[docs] def __init__(self, colours): """_Preview class initialiser. Args: colours (Union[list, np.array]): Iterable of colours for preview. """ self._c = colours self._n = len(colours) self._x = None self._y = None self._build_dataset()
[docs] def plot(self): """Plot to show colours.""" w = 6 if self._n < 50 else 10 h = w/1.618033 _, ax = plt.subplots(figsize=[w, h]) ax.scatter(self._x, self._y, marker='o', s=100, c=self._c) plt.show()
[docs] def _build_dataset(self): """Create a dataset to be plotted.""" self._x = np.arange(self._n) self._y = np.sin(self._x*(np.pi/180))
[docs] class CMaps(): """Provides an easy-access layer to ``matplotlib``'s colour maps."""
[docs] @staticmethod def get_cmap(map_name: str, n: int=25, as_hex: bool=False, preview: bool=False) -> Union[list, np.array]: """Get a list of (n) RGBA or Hex colours from a specified map. This colour wrapper is specialised to return (n) colours from a normalised colour map. Meaning, rather than returning the 5 lightest colours, or the 200 lightest to medium colours, the lightest colours are removed (as often they are difficult to see in a graph) and the darkest colour is added. The intent is to provide (n) 'usable' colours for graphing. Args: map_name (str): Name of the matplotlib colourmap. n (int, optional): Number of colours to return. Must be >= 255. Defaults to 25. as_hex (bool, optional): Return the colours as a hex string. Defaults to False, which returns colours as RGBA. preview (bool, optional): Preview the colour map. Defaults to False. Raises: ValueError: If the value of ``n`` is not between 1 and 255. Returns: Union[list, np.array]: Iterable of (n) colours. """ if (n < 1) | (n > 255): raise ValueError('The value of n must be: 1 <= n <= 255.') norm = matplotlib.colors.Normalize(vmin=-150, vmax=256) cmap = matplotlib.colormaps.get_cmap(map_name) clrs = cmap(norm(range(256))) N = int(256//n) c = clrs[::N] # Trim colours until desired length is met. while len(c) > n: if len(c) - n == 1: c = c[:-1] else: # Shave colours off boths ends until desired length is met. c = c[:-1] if len(c) % 2 == 0 else c[1:] c[-1] = clrs[-1] if as_hex: c_ = [matplotlib.colors.rgb2hex(i) for i in c] c = c_[:] if preview: # pragma: nocover _Preview(colours=c).plot() return c
[docs] @staticmethod def get_named_colours() -> dict: """Return a dictionary of CSS name and hex value. Returns: dict: A dict of named colours as ``{name: hex_code}`` pairs. """ return matplotlib.colors.cnames
[docs] @staticmethod def view_cmaps(view_only: bool=True) -> Union[list, None]: """Show the available colour map names. Args: view_only (bool, optional): If ``True`` the list will be printed and ``None`` is returned. If ``False``, the list is returned and nothing is printed. Defaults to True. Returns: Union[list, None]: A list of colour maps names if ``view-only`` is False, otherwise None. """ c = plt.colormaps() if view_only: print(c) c = None return c
cmaps = CMaps()