Skip to content

Commit 317a6af

Browse files
committed
DOC: re-write most of the new text
1 parent c8fa541 commit 317a6af

File tree

1 file changed

+113
-85
lines changed

1 file changed

+113
-85
lines changed

doc/api/colors_api.rst

Lines changed: 113 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -37,103 +37,101 @@ Color Conversion tools
3737

3838
.. _norms_and_colormaps:
3939

40-
Normalization and Colormapping
41-
------------------------------
40+
Normalization and Colormapping of Continuous Data
41+
-------------------------------------------------
4242

4343
Some `~.artist.Artist` classes can map an array of input data to RGBA
4444
values, (ex `~.axes.Axes.scatter` or `~.axes.Axes.imshow`). The
4545
machinery for this is implemented via the `~.cm.ScalarMappable` base
4646
class in `~.cm` and the `~.Normalize` and `~.Colormap` classes in
4747
`~.colors` (this module).
4848

49-
At the core, colormapping is going from a scalar value to a RGB tuple
50-
(formally :math:`f(x) : ℝ^1 \rightarrow ℝ^3`). To effectively
51-
communicate through the color we want pick a :ref:`colormap suited to
52-
the data <sphx_glr_tutorials_colors_colormaps.py>` but in general
53-
"good" colormaps smoothly and continuously change their RGB values as
54-
a function of the input data. By looking at the RGB values as we go
55-
through the full range of the user data we can trace out the
56-
1-dimensional path the colormap takes through 3-dimensional RGB space.
57-
This allows us to separate the mapping process into two orthogonal
58-
parts :
59-
60-
1. the parameterized path through color space
61-
2. the mapping between the user's data to distance along the curve.
62-
63-
The first step is expressed in Matplotlib via the `.Colormap` family
64-
of classes and the second step is expressed through the `.Normalize` family
65-
of classes. This allows us to fully independently pick what colors to use (by
66-
selecting the colormap), what data range to show (via the ``vmin`` and ``vmax``
67-
attributes on `.Normalize`, or via the `.cm.ScalarMappable.set_clim` method), and
68-
the functional transform (e.g., linear vs log) from data space to distance along the
69-
curve space.
70-
71-
In addition to the colors in the map, `.Colormap` objects carry three
72-
additional colors:
73-
74-
- over (`.Colormap.set_over` / `.Colormap.get_over`)
75-
- under (`.Colormap.set_under` / `.Colormap.get_under`)
76-
- bad (`.Colormap.set_bad` / `.Colormap.get_bad`)
77-
78-
The first two (over / under) control what should be done for values
79-
that are greater or less than the data range set by the user. By
80-
default these are equal to the top and bottom colors of the color map.
81-
The "bad" value is used for masked or non-finite values (e.g. nan and
82-
inf) and defaults to transparent.
83-
84-
85-
.. note::
49+
At the core, colormapping is going from a scalar value to a RGB tuple (formally
50+
:math:`f(x) : ℝ^1 \rightarrow ℝ^3`). To effectively communicate through the
51+
color we want pick a :ref:`colormap suited to the data
52+
<sphx_glr_tutorials_colors_colormaps.py>`. For continuous data types [#f1]_ a
53+
"good" colormap smoothly and continuously change their RGB values as a function
54+
of the input that trace out a 1-dimensional path through the 3-dimensional RGB
55+
space [#f2]_. We can restrict the domain of :math:`f` to $[0, 1]$ which we
56+
interpret as the normalized distance along the curve. This allows us to
57+
cleanly separate the mapping process from the continuous input data to RGB into
58+
two steps:
59+
60+
1. the mapping between the user's data to distance along the curve
61+
2. the parameterized path through color space.
62+
63+
The first step is expressed through the `.Normalize` family of classes and the
64+
second is expressed in Matplotlib via the `.Colormap` family of classes. This
65+
allows us to fully independently pick the functional transform (e.g., linear vs
66+
log) from data space to distance along the curve space, what (user) data range
67+
to show (via the ``vmin`` and ``vmax`` attributes on `.Normalize`, or via the
68+
`.cm.ScalarMappable.set_clim` method), and what colors to use (by selecting the
69+
`.Colormap`). Both `.Colormap` and `.Normalize` are implemented as `callable
70+
classes <https://docs.python.org/3/reference/datamodel.html#object.__call__>`__
71+
which allows use to bind some (mutable) state to a function call. The complete
72+
functionality is exposed in the `.ScalarMappable` family of artists which have
73+
a `.Colormap` and `.Normalize` instances and are responsible for invoking them
74+
at draw time.
75+
76+
The `.Normalize` family has 3 common attributes: *vmin*, *vmax*, and *clip*
77+
which control the data limits. The `.Normalize.__call__` signature is ::
78+
79+
def __call__(value: RawData, clip:Optional[Bool] =None) -> NormedData:
80+
...
8681

87-
Using `.cm.get_cmap` may return to you a reference to a globally
88-
visible instance of the colormap (rather than a new instance). If
89-
you plan to set the over/under/bad values we recommend you first
90-
make a copy ::
82+
It takes in data in the user's data space and converts it to *NormedData* with
83+
the range:
9184

92-
from copy import copy
93-
import matplotlib.cm as mcm
85+
.. math::
9486
95-
my_cmap = copy(mcm.get_cmap('viridis'))
87+
\begin{cases}
88+
\mathrm{under} & d < vmin \\
89+
[0, 1] & vmin \leq d \leq vmax \\
90+
\mathrm{over} & vmax < d \\
91+
\mathrm{bad} & !\mathrm{np.finite(d)}
92+
\end{cases}
9693
9794
98-
Both `.Colormap` and `.Normalize` are implemented as `callable classes
99-
<https://docs.python.org/3/reference/datamodel.html#object.__call__>`__ which
100-
allows use to bind some (mutable) state to a function call.
10195
102-
The `.Normalize.__call__` signature is ::
96+
The `.Colormap.__call__` signature when passed *NormedData* (floats) [#f3]_ is
97+
::
10398

104-
def normalize(value: RawData, clip:Optional[Bool] =None):
99+
def __call__(self, X: NormedData,
100+
alpha:Optional[float] =None, bytes:Bool=False) -> RGBA:
105101
...
106102

107-
It takes in data in the user's data space and converts it to *NormedData*. The
108-
*clip* parameter allows you to override the value set at class instantiation time
109-
and controls if the input data is clipped to the range :math:`[vmin, vmax]` before
110-
being transformed or not.
111-
112-
The `.Colormap.__call__` signature when passed floats ::
113-
114-
def map(X: NormedData, alpha:Optional[float] =None, bytes:Bool=False) -> RGBA:
115-
...
103+
In addition to parameterized path through RGB (which handles values in $[0,
104+
1]$, `.Colormap` objects carry three additional colors:
116105

117-
It takes data in a "normalized" space and:
106+
- *over* (`.Colormap.set_over` / `.Colormap.get_over`)
107+
- *under* (`.Colormap.set_under` / `.Colormap.get_under`)
108+
- *bad* (`.Colormap.set_bad` / `.Colormap.get_bad`)
118109

119-
- maps values in the closed set ``[0, 1]`` to that fraction along the curve
120-
- maps any value greater than 1 to the "over" color
121-
- maps any value less than 0 to the "under" color
122-
- maps any non-finite or masked value to the "bad" color
110+
which control the color for the corresponding values in *NormedData*.
111+
By default the over and under colors are the top and bottom colors of
112+
the colormap respectively and bad is transparent.
123113

124-
broadcasting to match the input shape (scalar to tuple, n-D array to
125-
(n+1)-D array).
114+
.. warning::
126115

127-
.. note ::
128-
129-
This can be useful to draw a set of colors from a colormap ::
116+
Using `.cm.get_cmap` may return to you a reference to a globally
117+
visible instance of the colormap (rather than a new instance). If
118+
you plan to set the over/under/bad values we recommend you first
119+
make a copy ::
130120

121+
from copy import copy
131122
import matplotlib.cm as mcm
132-
import numpy as np
133123

134-
cmap = mcm.get_cmap('viridis')
135-
array_of_colors = cmap(np.arange(0, 1, 5))
124+
my_cmap = copy(mcm.get_cmap('viridis'))
136125

126+
.. rubric:: Footnotes
127+
128+
.. [#f1] Discrete data types, such as Categorical and Ordinal, have different
129+
considerations.
130+
.. [#f2] Notable, the cubehelix colormap is named because it traces a helix
131+
through the RGB color cube from black to white.
132+
.. [#f3] Discrete data, as handled by `.NoNorm` and `.BoundaryNorm` are passed
133+
as integers and act as direct Look Up Table (LUT) indexes into the
134+
colormap.
137135
138136
In practice
139137
~~~~~~~~~~~
@@ -237,10 +235,30 @@ see them pulled out:
237235
[1., 0., 0., 1.]])
238236
239237
238+
239+
Directly using a `.Colormap` outside of a `.ScalarMappable` can be useful
240+
to generate a family of coherent colors for plotting
241+
242+
.. plot::
243+
:include-source:
244+
245+
import matplotlib.cm as mcm
246+
import numpy as np
247+
248+
cmap = mcm.get_cmap('viridis')
249+
array_of_colors = cmap(np.linspace(0, 1, 5))
250+
251+
x = np.linspace(0, 1, 25)
252+
fig, ax = plt.subplots(constrained_layout=True)
253+
for j, color in enumerate(array_of_colors):
254+
ax.plot(x, x**j, color=color, label=f'$x^{j}$')
255+
ax.legend()
256+
240257
API
241258
~~~
242259

243-
260+
Colormap Classes
261+
++++++++++++++++
244262

245263
.. autosummary::
246264
:toctree: _as_gen/
@@ -251,18 +269,37 @@ API
251269
ListedColormap
252270

253271

272+
.. inheritance-diagram:: matplotlib.colors.Colormap matplotlib.colors.LinearSegmentedColormap matplotlib.colors.ListedColormap
273+
:parts: 1
274+
:private-bases:
275+
276+
277+
Norm Classes
278+
++++++++++++
279+
254280
.. autosummary::
255281
:toctree: _as_gen/
256282
:template: autosummary.rst
257283

258284
Normalize
259285
LogNorm
260286
CenteredNorm
261-
BoundaryNorm
262287
TwoSlopeNorm
263288
PowerNorm
264-
NoNorm
265289
SymLogNorm
290+
FuncNorm
291+
BoundaryNorm
292+
NoNorm
293+
294+
295+
.. inheritance-diagram:: matplotlib.colors.Normalize matplotlib.colors.LogNorm matplotlib.colors.PowerNorm matplotlib.colors.NoNorm matplotlib.colors.TwoSlopeNorm matplotlib.colors.SymLogNorm matplotlib.colors.BoundaryNorm matplotlib.colors.FuncNorm matplotlib.colors.CenteredNorm
296+
:parts: 1
297+
:private-bases:
298+
299+
300+
Factory Functions & Decorators
301+
++++++++++++++++++++++++++++++
302+
266303

267304
.. autosummary::
268305
:toctree: _as_gen/
@@ -272,15 +309,6 @@ API
272309
make_norm_from_scale
273310

274311

275-
.. inheritance-diagram:: matplotlib.colors.Colormap matplotlib.colors.LinearSegmentedColormap matplotlib.colors.ListedColormap
276-
:parts: 1
277-
:private-bases:
278-
279-
280-
.. inheritance-diagram:: matplotlib.colors.Normalize matplotlib.colors.LogNorm matplotlib.colors.PowerNorm matplotlib.colors.NoNorm matplotlib.colors.TwoSlopeNorm matplotlib.colors.SymLogNorm matplotlib.colors.BoundaryNorm
281-
:parts: 1
282-
:private-bases:
283-
284312

285313
Hill Shading
286314
------------

0 commit comments

Comments
 (0)