Skip to content

Commit 906f6ea

Browse files
authored
Merge pull request #12789 from tacaswell/backports_colormap
DOC: Backport colormap documentation Includes #11905, #11799, #11881, and #12084
2 parents a7562be + 448413a commit 906f6ea

File tree

7 files changed

+298
-43
lines changed

7 files changed

+298
-43
lines changed

.flake8

+2-1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ per-file-ignores =
9494
tutorials/advanced/transforms_tutorial.py: E402, E501
9595
tutorials/colors/colormaps.py: E501
9696
tutorials/colors/colors.py: E402
97+
tutorials/colors/colormap-manipulation.py: E402
9798
tutorials/intermediate/artists.py: E402, E501
9899
tutorials/intermediate/constrainedlayout_guide.py: E402
99100
tutorials/intermediate/gridspec.py: E402, E501
@@ -121,6 +122,7 @@ per-file-ignores =
121122
examples/color/color_demo.py: E402
122123
examples/color/colorbar_basics.py: E402
123124
examples/color/colormap_reference.py: E402
125+
examples/color/custom_cmap.py: E402
124126
examples/color/named_colors.py: E402
125127
examples/event_handling/data_browser.py: E501
126128
examples/event_handling/path_editor.py: E501
@@ -136,7 +138,6 @@ per-file-ignores =
136138
examples/images_contours_and_fields/contourf_demo.py: E402, E501
137139
examples/images_contours_and_fields/contourf_hatching.py: E402
138140
examples/images_contours_and_fields/contourf_log.py: E402
139-
examples/images_contours_and_fields/custom_cmap.py: E402
140141
examples/images_contours_and_fields/demo_bboximage.py: E402
141142
examples/images_contours_and_fields/image_clip_path.py: E402
142143
examples/images_contours_and_fields/image_demo.py: E402

examples/images_contours_and_fields/custom_cmap.py renamed to examples/color/custom_cmap.py

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
Creating a colormap from a list of colors
44
=========================================
55
6+
For more detail on creating and manipulating colormaps see
7+
:doc:`/tutorials/colors/colormap-manipulation`.
8+
69
Creating a :doc:`colormap </tutorials/colors/colormaps>`
710
from a list of colors can be done with the
811
:meth:`~.colors.LinearSegmentedColormap.from_list` method of

lib/matplotlib/cm.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
"""
22
Builtin colormaps, colormap handling utilities, and the `ScalarMappable` mixin.
33
4-
See :doc:`/gallery/color/colormap_reference` for a list of builtin colormaps.
5-
See :doc:`/tutorials/colors/colormaps` for an in-depth discussion of colormaps.
4+
.. seealso::
5+
6+
:doc:`/gallery/color/colormap_reference` for a list of builtin
7+
colormaps.
8+
9+
:doc:`/tutorials/colors/colormap-manipulation` for examples of how to
10+
make colormaps and
11+
12+
:doc:`/tutorials/colors/colormaps` an in-depth discussion of
13+
choosing colormaps.
14+
15+
:doc:`/tutorials/colors/colormapnorms` for more details about data
16+
normalization
17+
18+
619
"""
720

821
import functools

lib/matplotlib/colors.py

+24-8
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,27 @@
66
77
This module includes functions and classes for color specification
88
conversions, and for mapping numbers to colors in a 1-D array of colors called
9-
a colormap. Colormapping typically involves two steps: a data array is first
10-
mapped onto the range 0-1 using an instance of :class:`Normalize` or of a
11-
subclass; then this number in the 0-1 range is mapped to a color using an
12-
instance of a subclass of :class:`Colormap`. Two are provided here:
13-
:class:`LinearSegmentedColormap`, which is used to generate all the built-in
14-
colormap instances, but is also useful for making custom colormaps, and
15-
:class:`ListedColormap`, which is used for generating a custom colormap from a
16-
list of color specifications.
9+
a colormap.
10+
11+
Mapping data onto colors using a colormap typically involves two steps:
12+
a data array is first mapped onto the range 0-1 using a subclass of
13+
:class:`Normalize`, then this number is mapped to a color using
14+
a subclass of :class:`Colormap`. Two are provided here:
15+
:class:`LinearSegmentedColormap`, which uses piecewise-linear interpolation
16+
to define colormaps, and :class:`ListedColormap`, which makes a colormap
17+
from a list of colors.
18+
19+
.. seealso::
20+
21+
:doc:`/tutorials/colors/colormap-manipulation` for examples of how to
22+
make colormaps and
23+
24+
:doc:`/tutorials/colors/colormaps` for a list of built-in colormaps.
25+
26+
:doc:`/tutorials/colors/colormapnorms` for more details about data
27+
normalization
28+
29+
More colormaps are available at palettable_
1730
1831
The module also provides functions for checking whether an object can be
1932
interpreted as a color (:func:`is_color_like`), for converting such an object
@@ -42,6 +55,9 @@
4255
cycle does not include color.
4356
4457
All string specifications of color, other than "CN", are case-insensitive.
58+
59+
.. _palettable: https://jiffyclub.github.io/palettable/
60+
4561
"""
4662

4763
from collections.abc import Sized

requirements/testing/travis35.txt

+1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ pyparsing==2.0.1
88
pytest==3.4
99
pytest-cov==2.3.1
1010
pytest-timeout==1.2.1 # Newer pytest-timeouts don't support pytest 3.4.
11+
pytest-rerunfailures<5 # newer versions require pytest3.6
1112
sphinx==1.3
+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
"""
2+
********************************
3+
Creating Colormaps in Matplotlib
4+
********************************
5+
6+
Matplotlib has a number of built-in colormaps accessible via
7+
`.matplotlib.cm.get_cmap`. There are also external libraries like
8+
palettable_ that have many extra colormaps.
9+
10+
.. _palettable: https://jiffyclub.github.io/palettable/
11+
12+
However, we often want to create or manipulate colormaps in Matplotlib.
13+
This can be done using the class `.ListedColormap` and a Nx4 numpy array of
14+
values between 0 and 1 to represent the RGBA values of the colormap. There
15+
is also a `.LinearSegmentedColormap` class that allows colormaps to be
16+
specified with a few anchor points defining segments, and linearly
17+
interpolating between the anchor points.
18+
19+
Getting colormaps and accessing their values
20+
============================================
21+
22+
First, getting a named colormap, most of which are listed in
23+
:doc:`/tutorials/colors/colormaps` requires the use of
24+
`.matplotlib.cm.get_cmap`, which returns a
25+
:class:`.matplotlib.colors.ListedColormap` object. The second argument gives
26+
the size of the list of colors used to define the colormap, and below we
27+
use a modest value of 12 so there are not a lot of values to look at.
28+
"""
29+
30+
import numpy as np
31+
import matplotlib as mpl
32+
import matplotlib.pyplot as plt
33+
from matplotlib import cm
34+
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
35+
from collections import OrderedDict
36+
37+
viridis = cm.get_cmap('viridis', 12)
38+
print(viridis)
39+
40+
##############################################################################
41+
# The object ``viridis`` is a callable, that when passed a float between
42+
# 0 and 1 returns an RGBA value from the colormap:
43+
44+
print(viridis(0.56))
45+
46+
##############################################################################
47+
# The list of colors that comprise the colormap can be directly accessed using
48+
# the ``colors`` property,
49+
# or it can be acccessed indirectly by calling ``viridis`` with an array
50+
# of values matching the length of the colormap. Note that the returned list
51+
# is in the form of an RGBA Nx4 array, where N is the length of the colormap.
52+
53+
print('viridis.colors', viridis.colors)
54+
print('viridis(range(12))', viridis(range(12)))
55+
print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))
56+
57+
##############################################################################
58+
# The colormap is a lookup table, so "oversampling" the colormap returns
59+
# nearest-neighbor interpolation (note the repeated colors in the list below)
60+
61+
print('viridis(np.linspace(0, 1, 15))', viridis(np.linspace(0, 1, 15)))
62+
63+
##############################################################################
64+
# Creating listed colormaps
65+
# =========================
66+
#
67+
# This is essential the inverse operation of the above where we supply a
68+
# Nx4 numpy array with all values between 0 and 1,
69+
# to `.ListedColormap` to make a new colormap. This means that
70+
# any numpy operations that we can do on a Nx4 array make carpentry of
71+
# new colormaps from existing colormaps quite straight forward.
72+
#
73+
# Suppose we want to make the first 25 entries of a 256-length "viridis"
74+
# colormap pink for some reason:
75+
76+
viridis = cm.get_cmap('viridis', 256)
77+
newcolors = viridis(np.linspace(0, 1, 256))
78+
pink = np.array([248/256, 24/256, 148/256, 1])
79+
newcolors[:25, :] = pink
80+
newcmp = ListedColormap(newcolors)
81+
82+
83+
def plot_examples(cms):
84+
"""
85+
helper function to plot two colormaps
86+
"""
87+
np.random.seed(19680801)
88+
data = np.random.randn(30, 30)
89+
90+
fig, axs = plt.subplots(1, 2, figsize=(6, 3), constrained_layout=True)
91+
for [ax, cmap] in zip(axs, cms):
92+
psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
93+
fig.colorbar(psm, ax=ax)
94+
plt.show()
95+
96+
plot_examples([viridis, newcmp])
97+
98+
##############################################################################
99+
# We can easily reduce the dynamic range of a colormap; here we choose the
100+
# middle 0.5 of the colormap. However, we need to interpolate from a larger
101+
# colormap, otherwise the new colormap will have repeated values.
102+
103+
viridisBig = cm.get_cmap('viridis', 512)
104+
newcmp = ListedColormap(viridisBig(np.linspace(0.25, 0.75, 256)))
105+
plot_examples([viridis, newcmp])
106+
107+
##############################################################################
108+
# and we can easily concatenate two colormaps:
109+
110+
top = cm.get_cmap('Oranges_r', 128)
111+
bottom = cm.get_cmap('Blues', 128)
112+
113+
newcolors = np.vstack((top(np.linspace(0, 1, 128)),
114+
bottom(np.linspace(0, 1, 128))))
115+
newcmp = ListedColormap(newcolors, name='OrangeBlue')
116+
plot_examples([viridis, newcmp])
117+
118+
##############################################################################
119+
# Of course we need not start from a named colormap, we just need to create
120+
# the Nx4 array to pass to `.ListedColormap`. Here we create a
121+
# brown colormap that goes to white....
122+
123+
N = 256
124+
vals = np.ones((N, 4))
125+
vals[:, 0] = np.linspace(90/256, 1, N)
126+
vals[:, 1] = np.linspace(39/256, 1, N)
127+
vals[:, 2] = np.linspace(41/256, 1, N)
128+
newcmp = ListedColormap(vals)
129+
plot_examples([viridis, newcmp])
130+
131+
##############################################################################
132+
# Creating linear segmented colormaps
133+
# ===================================
134+
#
135+
# `.LinearSegmentedColormap` class specifies colormaps using anchor points
136+
# between which RGB(A) values are interpolated.
137+
#
138+
# The format to specify these colormaps allows discontinuities at the anchor
139+
# points. Each anchor point is specified as a row in a matrix of the
140+
# form ``[x[i] yleft[i] yright[i]]``, where ``x[i]`` is the anchor, and
141+
# ``yleft[i]`` and ``yright[i]`` are the values of the color on either
142+
# side of the anchor point.
143+
#
144+
# If there are no discontinuities, then ``yleft[i]=yright[i]``:
145+
146+
cdict = {'red': [[0.0, 0.0, 0.0],
147+
[0.5, 1.0, 1.0],
148+
[1.0, 1.0, 1.0]],
149+
'green': [[0.0, 0.0, 0.0],
150+
[0.25, 0.0, 0.0],
151+
[0.75, 1.0, 1.0],
152+
[1.0, 1.0, 1.0]],
153+
'blue': [[0.0, 0.0, 0.0],
154+
[0.5, 0.0, 0.0],
155+
[1.0, 1.0, 1.0]]}
156+
157+
158+
def plot_linearmap(cdict):
159+
newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256)
160+
rgba = newcmp(np.linspace(0, 1, 256))
161+
fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)
162+
col = ['r', 'g', 'b']
163+
for xx in [0.25, 0.5, 0.75]:
164+
ax.axvline(xx, color='0.7', linestyle='--')
165+
for i in range(3):
166+
ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])
167+
ax.set_xlabel('index')
168+
ax.set_ylabel('RGB')
169+
plt.show()
170+
171+
plot_linearmap(cdict)
172+
173+
#############################################################################
174+
# In order to make a discontinuity at an anchor point, the third column is
175+
# different than the second. The matrix for each of "red", "green", "blue",
176+
# and optionally "alpha" is set up as::
177+
#
178+
# cdict['red'] = [...
179+
# [x[i] yleft[i] yright[i]],
180+
# [x[i+1] yleft[i+1] yright[i+1]],
181+
# ...]
182+
#
183+
# and for values passed to the colormap between ``x[i]`` and ``x[i+1]``,
184+
# the interpolation is between ``yright[i]`` and ``yleft[i+1]``.
185+
#
186+
# In the example below there is a discontiuity in red at 0.5. The
187+
# interpolation between 0 and 0.5 goes from 0.3 to 1, and between 0.5 and 1
188+
# it goes from 0.9 to 1. Note that red[0, 1], and red[2, 2] are both
189+
# superfluous to the interpolation because red[0, 1] is the value to the
190+
# left of 0, and red[2, 2] is the value to the right of 1.0.
191+
192+
cdict['red'] = [[0.0, 0.0, 0.3],
193+
[0.5, 1.0, 0.9],
194+
[1.0, 1.0, 1.0]]
195+
plot_linearmap(cdict)
196+
197+
198+
#############################################################################
199+
#
200+
# ------------
201+
#
202+
# References
203+
# """"""""""
204+
#
205+
# The use of the following functions, methods, classes and modules is shown
206+
# in this example:
207+
208+
import matplotlib
209+
matplotlib.axes.Axes.pcolormesh
210+
matplotlib.figure.Figure.colorbar
211+
matplotlib.colors
212+
matplotlib.colors.LinearSegmentedColormap
213+
matplotlib.colors.ListedColormap
214+
matplotlib.cm
215+
matplotlib.cm.get_cmap

0 commit comments

Comments
 (0)