8000 doc colormap manipulation tutorial update · matplotlib/matplotlib@9e8378f · GitHub
[go: up one dir, main page]

Skip to content

Commit 9e8378f

Browse files
doc colormap manipulation tutorial update
1 parent 667a100 commit 9e8378f

File tree

1 file changed

+99
-37
lines changed

1 file changed

+99
-37
lines changed

tutorials/colors/colormap-manipulation.py

Lines changed: 99 additions & 37 deletions
8000
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,33 @@
1010
.. _palettable: https://jiffyclub.github.io/palettable/
1111
1212
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.
13+
This can be done using the class `.ListedColormap` or
14+
`.LinearSegmentedColormap`.
15+
Seen from the outside, both colormap classes map values between 0 and 1 to
16+
a bunch of colors. There are, however, slight differences, some of which are
17+
shown in the following.
18+
19+
Before manually creating or manipulating colormaps, let us first see how we
20+
can obtain colormaps and their colors from existing colormap classes.
21+
1822
1923
Getting colormaps and accessing their values
2024
============================================
2125
2226
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.
27+
:doc:`/tutorials/colors/colormaps`, may be done using
28+
`.matplotlib.cm.get_cmap`, which returns a colormap object.
29+
The second argument gives the size of the list of colors used to define the
30+
colormap, and below we use a modest value of 8 so there are not a lot of
31+
values to look at.
2832
"""
2933

3034
import numpy as np
3135
import matplotlib.pyplot as plt
3236
from matplotlib import cm
3337
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
3438

35-
viridis = cm.get_cmap('viridis', 12)
39+
viridis = cm.get_cmap('viridis', 8)
3640
print(viridis)
3741

3842
##############################################################################
@@ -42,53 +46,90 @@
4246
print(viridis(0.56))
4347

4448
##############################################################################
49+
# ListedColormap
50+
# --------------
51+
#
52+
# `ListedColormap` s store their color values in a ``.colors`` attribute.
4553
# The list of colors that comprise the colormap can be directly accessed using
4654
# the ``colors`` property,
4755
# or it can be accessed indirectly by calling ``viridis`` with an array
4856
# of values matching the length of the colormap. Note that the returned list
4957
# is in the form of an RGBA Nx4 array, where N is the length of the colormap.
5058

5159
print('viridis.colors', viridis.colors)
52-
print('viridis(range(12))', viridis(range(12)))
53-
print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))
60+
print('viridis(range(8))', viridis(range(8)))
61+
print('viridis(np.linspace(0, 1, 8))', viridis(np.linspace(0, 1, 8)))
5462

5563
##############################################################################
5664
# The colormap is a lookup table, so "oversampling" the colormap returns
5765
# nearest-neighbor interpolation (note the repeated colors in the list below)
5866

59-
print('viridis(np.linspace(0, 1, 15))', viridis(np.linspace(0, 1, 15)))
67+
print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))
68+
69+
##################### 8000 #########################################################
70+
# LinearSegmentedColormap
71+
# -----------------------
72+
# `LinearSegmentedColormap` s do not have a ``.colors`` attribute.
73+
# However, one may still call the colormap with an integer array, or with a
74+
# float array between 0 and 1.
75+
76+
copper = cm.get_cmap('copper', 8)
77+
print(copper)
78+
79+
print('copper(range(8))', copper(range(8)))
80+
print('copper(np.linspace(0, 1, 8))', copper(np.linspace(0, 1, 8)))
6081

6182
##############################################################################
6283
# Creating listed colormaps
6384
# =========================
6485
#
65-
# This is essential the inverse operation of the above where we supply a
66-
# Nx4 numpy array with all values between 0 and 1,
67-
# to `.ListedColormap` to make a new colormap. This means that
68-
# any numpy operations that we can do on a Nx4 array make carpentry of
69-
# new colormaps from existing colormaps quite straight forward.
86+
# Creating a colormap is essentially the inverse operation of the above where
87+
# we supply a list or array of color specifications to `.ListedColormap` to
88+
# make a new colormap.
89+
#
90+
# Before continuing with the tutorial, let us define a helper function that
91+
# takes one of more colormaps as input, creates some random data and applies
92+
# the colormap(s) to an image plot of that dataset.
93+
94+
def plot_examples(colormaps):
95+
"""
96+
Helper function to plot data with associated colormap.
97+
"""
98+
np.random.seed(19680801)
99+
data = np.random.randn(30, 30)
100+
n = len(colormaps)
101+
fig, axs = plt.subplots(1, n, figsize=(n * 2 + 2, 3),
102+
constrained_layout=True, squeeze=False)
103+
for [ax, cmap] in zip(axs.flat, colormaps):
104+
psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
105+
fig.colorbar(psm, ax=ax)
106+
plt.show()
107+
108+
109+
##############################################################################
110+
# In the simplest case we might type in a list of color names to create a
111+
# colormap from those.
112+
113+
cmap = ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"])
114+
plot_examples([cmap])
115+
116+
##############################################################################
117+
# In fact, that list may contain any valid
118+
# :doc:`matplotlib color specification </tutorials/colors/colors>`.
119+
# Particularly useful for creating custom colormaps are Nx4 numpy arrays.
120+
# Because with the variety of numpy operations that we can do on a such an
121+
# array, carpentry of new colormaps from existing colormaps become quite
122+
# straight forward.
70123
#
71-
# Suppose we want to make the first 25 entries of a 256-length "viridis"
72-
# colormap pink for some reason:
124+
# For example, suppose we want to make the first 25 entries of a 256-length
125+
# "viridis" colormap pink for some reason:
73126

74127
viridis = cm.get_cmap('viridis', 256)
75128
newcolors = viridis(np.linspace(0, 1, 256))
76129
pink = np.array([248/256, 24/256, 148/256, 1])
77130
newcolors[:25, :] = pink
78131
newcmp = ListedColormap(newcolors)
79132

80-
81-
def plot_examples(cms):
82-
"""Helper function to plot two colormaps."""
83-
np.random.seed(19680801)
84-
data = np.random.randn(30, 30)
85-
86-
fig, axs = plt.subplots(1, 2, figsize=(6, 3), constrained_layout=True)
87-
for [ax, cmap] in zip(axs, cms):
88-
psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)
89-
fig.colorbar(psm, ax=ax)
90-
plt.show()
91-
92133
plot_examples([viridis, newcmp])
93134

94135
##############################################################################
@@ -113,14 +154,14 @@ def plot_examples(cms):
113154

114155
##############################################################################
115156
# Of course we need not start from a named colormap, we just need to create
116-
# the Nx4 array to pass to `.ListedColormap`. Here we create a
117-
# brown colormap that goes to white....
157+
# the Nx4 array to pass to `.ListedColormap`. Here we create a
158+
# colormap that goes from brown (RGB: 90,40,40) to white (RGB: 255,255,255).
118159

119160
N = 256
120161
vals = np.ones((N, 4))
121162
vals[:, 0] = np.linspace(90/256, 1, N)
122-
vals[:, 1] = np.linspace(39/256, 1, N)
123-
vals[:, 2] = np.linspace(41/256, 1, N)
163+
vals[:, 1] = np.linspace(40/256, 1, N)
164+
vals[:, 2] = np.linspace(40/256, 1, N)
124165
newcmp = ListedColormap(vals)
125166
plot_examples([viridis, newcmp])
126167

@@ -190,6 +231,27 @@ def plot_linearmap(cdict):
190231
[1.0, 1.0, 1.0]]
191232
plot_linearmap(cdict)
192233

234+
#############################################################################
235+
# Directly creating a segmented colormap from a list
236+
# --------------------------------------------------
237+
#
238+
# The above described is a very versatile approach, but admitedly a bit
239+
# cumbersome to implement. For some basic cases, the use of
240+
# `LinearSegmentedColormap.from_list` may be easier. This creates a segmented
241+
# colormap with equal spacings from a supplied list of colors.
242+
243+
colors = ["darkorange", "gold", "lawngreen", "lightseagreen"]
244+
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)
245+
246+
#############################################################################
247+
# If desired, the nodes of the colormap can be given as numbers
248+
# between 0 and 1. E.g. one could have the reddish part take more space in the
249+
# colormap.
250+
251+
nodes = [0.0, 0.4, 0.8, 1.0]
252+
cmap2 = LinearSegmentedColormap.from_list("mycmap", list(zip(nodes, colors)))
253+
254+
plot_examples([cmap1, cmap2])
193255

194256
#############################################################################
195257
#

0 commit comments

Comments
 (0)
0