Coverage for /var/devmt/py/utils4_1.5.0rc1/utils4/cmaps.py: 100%
34 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-12 15:38 +0100
« prev ^ index » next coverage.py v7.6.1, created at 2024-08-12 15:38 +0100
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""
4:Purpose: This module provides an easy-access, light-weight wrapper,
5 around ``matplotlib``'s colour maps, and can be used for
6 retrieving and previewing named colour maps.
8:Platform: Linux/Windows | Python 3.6+
9:Developer: J Berendt
10:Email: support@s3dev.uk
12:Comments: n/a
14:Examples:
16 Retrieve 5 colours from the 'viridis' colour map in hex format
17 and preview the colours::
19 >>> from utils4.cmaps import cmaps
21 >>> clrs = cmaps.get_cmap('viridis', 15, as_hex=True, preview=True)
22 >>> clrs
24 ['#2d718e', '#297b8e', '#25858e', '#218f8d', '#1f998a',
25 '#20a386', '#26ad81', '#34b679', '#46c06f', '#5cc863',
26 '#73d056', '#8ed645', '#aadc32', '#c5e021', '#fde725']
28 .. figure:: _static/img/cmaps_viridis15.png
29 :scale: 75%
30 :align: center
32 Preview of the requested 'viridis' colour map of 15 colours
35 List named colours from the matplotlib colour palette::
37 >>> from utils4.cmaps import cmaps
39 >>> cmaps.get_named_colours()
41 {'aliceblue': '#F0F8FF',
42 'antiquewhite': '#FAEBD7',
43 'aqua': '#00FFFF',
44 ...,
45 'whitesmoke': '#F5F5F5',
46 'yellow': '#FFFF00',
47 'yellowgreen': '#9ACD32'}
50 List or retrieve colour map names::
52 >>> from utils4.cmaps import cmaps
54 >>> cmaps.view_cmaps(view_only=True)
56 ['magma',
57 'inferno',
58 'plasma',
59 ...,
60 'tab20_r',
61 'tab20b_r',
62 'tab20c_r']
64"""
65# pylint: disable=import-error
66# pylint: disable=invalid-name
67# pylint: disable=wrong-import-order
69import matplotlib
70import matplotlib.pyplot as plt
71import numpy as np
72from typing import Union
75class _Preview: # pragma: nocover
76 """Provide a preview for a given colourmap."""
78 def __init__(self, colours):
79 """_Preview class initialiser.
81 Args:
82 colours (Union[list, np.array]): Iterable of colours for
83 preview.
85 """
86 self._c = colours
87 self._n = len(colours)
88 self._x = None
89 self._y = None
90 self._build_dataset()
92 def plot(self):
93 """Plot to show colours."""
94 w = 6 if self._n < 50 else 10
95 h = w/1.618033
96 _, ax = plt.subplots(figsize=[w, h])
97 ax.scatter(self._x,
98 self._y,
99 marker='o',
100 s=100,
101 c=self._c)
102 plt.show()
104 def _build_dataset(self):
105 """Create a dataset to be plotted."""
106 self._x = np.arange(self._n)
107 self._y = np.sin(self._x*(np.pi/180))
110class CMaps():
111 """Provides an easy-access layer to ``matplotlib``'s colour maps."""
113 @staticmethod
114 def get_cmap(map_name: str,
115 n: int=25,
116 as_hex: bool=False,
117 preview: bool=False) -> Union[list, np.array]:
118 """Get a list of (n) RGBA or Hex colours from a specified map.
120 This colour wrapper is specialised to return (n) colours from
121 a normalised colour map. Meaning, rather than returning the
122 5 lightest colours, or the 200 lightest to medium colours, the
123 lightest colours are removed (as often they are difficult to
124 see in a graph) and the darkest colour is added. The intent
125 is to provide (n) 'usable' colours for graphing.
127 Args:
128 map_name (str): Name of the matplotlib colourmap.
129 n (int, optional): Number of colours to return. Must
130 be >= 255. Defaults to 25.
131 as_hex (bool, optional): Return the colours as a hex string.
132 Defaults to False, which returns colours as RGBA.
133 preview (bool, optional): Preview the colour map. Defaults
134 to False.
136 Raises:
137 ValueError: If the value of ``n`` is not between 1 and 255.
139 Returns:
140 Union[list, np.array]: Iterable of (n) colours.
142 """
143 if (n < 1) | (n > 255):
144 raise ValueError('The value of n must be: 1 <= n <= 255.')
145 norm = matplotlib.colors.Normalize(vmin=-150, vmax=256)
146 cmap = matplotlib.colormaps.get_cmap(map_name)
147 clrs = cmap(norm(range(256)))
148 N = int(256//n)
149 c = clrs[::N]
150 # Trim colours until desired length is met.
151 while len(c) > n:
152 if len(c) - n == 1:
153 c = c[:-1]
154 else:
155 # Shave colours off boths ends until desired length is met.
156 c = c[:-1] if len(c) % 2 == 0 else c[1:]
157 c[-1] = clrs[-1]
158 if as_hex:
159 c_ = [matplotlib.colors.rgb2hex(i) for i in c]
160 c = c_[:]
161 if preview: # pragma: nocover
162 _Preview(colours=c).plot()
163 return c
165 @staticmethod
166 def get_named_colours() -> dict:
167 """Return a dictionary of CSS name and hex value.
169 Returns:
170 dict: A dict of named colours as ``{name: hex_code}`` pairs.
172 """
173 return matplotlib.colors.cnames
175 @staticmethod
176 def view_cmaps(view_only: bool=True) -> Union[list, None]:
177 """Show the available colour map names.
179 Args:
180 view_only (bool, optional): If ``True`` the list will be
181 printed and ``None`` is returned. If ``False``, the list
182 is returned and nothing is printed. Defaults to True.
184 Returns:
185 Union[list, None]: A list of colour maps names if
186 ``view-only`` is False, otherwise None.
188 """
189 c = plt.colormaps()
190 if view_only:
191 print(c)
192 c = None
193 return c
196cmaps = CMaps()