Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 55e8727

Browse files
committed
Initial docs for colormapnorms.rst
1 parent 11c172f commit 55e8727

7 files changed

Lines changed: 447 additions & 0 deletions

doc/users/colormapnorms.rst

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
.. _colormapnorm-tutorial:
2+
3+
Colormap Normaliztions
4+
================================
5+
6+
Objects that use colormaps usually linearly map the colors in the
7+
colormap from data values ``vmin`` to ``vmax``. For example::
8+
9+
pcm = ax.pcolormesh(x, y, Z, vmin=-1., vmax=1., cmap='RdBu_r')
10+
11+
will map the data in *Z* linearly from `-1` to `+1`, so *Z=0* will
12+
give a color at the center of the colormap *RdBu_r* (white in this
13+
case).
14+
15+
Normalizations are defined as part of :func:`matplotlib.colors`
16+
module. The default normalization is
17+
:func:`matplotlib.colors.Normalize`. The artists that map data to
18+
color pass the arguments ``vmin`` and ``vmax`` to
19+
:func:`matplotlib.colors.Normalize`. We can
20+
substnatiate the normalization and see what it returns. In this case
21+
it returns 0.5::
22+
23+
norm = mpl.colors.Normalize(vmin=-1., vmax=1.)
24+
norm(0.)
25+
26+
However, there are sometimes cases where it is useful to map data to
27+
colormaps in a non-linear fashion.
28+
29+
Logarithmic
30+
---------------------------------
31+
32+
One of the most common transformations is to plot data by taking its
33+
logarithm (to the base-10). This transofrmation is useful when there
34+
are changes across disparate scales that we still want to be able to
35+
see. Using :func:`colors.LogNorm` normalizes the data by :math:`log_{10}`. In
36+
the example below, there are two bumps, one much smaller than the
37+
other. Using :func:`colors.LogNorm`, the shape and location of each
38+
bump can clearly be seen:
39+
40+
.. plot:: users/plotting/examples/colormap_normalizations_lognorm.py
41+
:include-source:
42+
43+
Symetric logarithmic
44+
---------------------------------
45+
46+
Similarly, it sometimes happens that there is data that is positive
47+
and negative, but we would still like a logarithmic scaling applied to
48+
both. In this case, the negative numbers are also scaled
49+
logarithmically, and mapped to small numbers. i.e. If `vmin=-vmax`, then
50+
they the negative numbers are mapped from 0 to 0.5.
51+
52+
Since the values close to zero tend toward infinity, there is a need
53+
to have a range around zero that is linear. The parameter *linthresh*
54+
allows the user to specify the size of this range (-*linthresh*,
55+
*linthresh*). The size of this range in the colormap is set by
56+
*linscale*. When *linscale* == 1.0 (the default), the space used for
57+
the positive and negative halves of the linear range will be equal to
58+
one decade in the logarithmic range.
59+
60+
.. plot:: users/plotting/examples/colormap_normalizations_symlognorm.py
61+
:include-source:
62+
63+
Power-law
64+
---------------------------------
65+
66+
Sometimes it is useful to remap the colors onto a power-law
67+
relationship (i.e. :math:`y=x^{\gamma}`, where :math:`\gamma` is the
68+
power). For this we use the :func:`colors.PowerNorm`. It takes as an
69+
argument *gamma* (*gamma*==1.0 will just yield the defalut linear
70+
normalization):
71+
72+
.. note::
73+
74+
There should probably be a good reason for plotting the data using
75+
this type of transformation. Technical viewers are used to linear
76+
and logarithmic axes and data transformations. Power laws are less
77+
common, and readers should explictly be made aware that they have
78+
been used.
79+
80+
81+
.. plot:: users/plotting/examples/colormap_normalizations_power.py
82+
:include-source:
83+
84+
85+
Custom normalization: Two linear ranges
86+
--------------------------------------
87+
88+
It is possible to define your own normalization, as shown in the
89+
example below. This example is plotting the same data as the
90+
:func:`colors:SymLogNorm` example, but this time a different linear
91+
map is used for the negative number than the positive. (Note that
92+
this example is simple, and does not account for the edge cases like
93+
masked data or invalid values of *vmin* and *vmax*)
94+
95+
.. note::
96+
97+
As above, non-symetric mapping of data to color is non-standard
98+
practice, and should be used advisedly.
99+
100+
.. plot:: users/plotting/examples/colormap_normalizations_custom.py
101+
:include-source:
102+
103+
Discrete bounds
104+
---------------------------------
105+
106+
Another normaization that comes with matplolib is
107+
:func:`colors.BoundaryNorm`. In addition to *vmin* and *vmax*, this
108+
takes as arguments boundaries between which data is to be mapped. The
109+
colors are then linearly distributed between these "bounds". For
110+
instance, if ::
111+
112+
bounds = np.array([-0.25, -0.125, 0, 0.5, 1])
113+
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=4)
114+
print norm([-0.2,-0.15,-0.02,0.3, 0.8, 0.99])
115+
116+
This returns: [0, 0, 1, 2, 3, 3]. Note unlike the other norms, this
117+
one returns values from 0 to *ncolors*-1.
118+
119+
120+
.. plot:: users/plotting/examples/colormap_normalizations_bounds.py
121+
:include-source:
122+
123+
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
"""
2+
Demonstration of using norm to map colormaps onto data in non-linear ways.
3+
"""
4+
5+
import numpy as np
6+
import matplotlib.pyplot as plt
7+
import matplotlib.colors as colors
8+
from matplotlib.mlab import bivariate_normal
9+
10+
'''
11+
Lognorm: Instead of pcolor log10(Z1) you can have colorbars that have
12+
the exponential labels using a norm.
13+
'''
14+
N = 100
15+
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
16+
17+
# A low hump with a spike coming out of the top right. Needs to have
18+
# z/colour axis on a log scale so we see both hump and spike. linear
19+
# scale only shows the spike.
20+
Z1 = bivariate_normal(X, Y, 0.1, 0.2, 1.0, 1.0) + \
21+
0.1 * bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
22+
23+
fig, ax = plt.subplots(2, 1)
24+
25+
pcm = ax[0].pcolor(X, Y, Z1,
26+
norm=colors.LogNorm(vmin=Z1.min(), vmax=Z1.max()),
27+
cmap='PuBu_r')
28+
fig.colorbar(pcm, ax=ax[0], extend='max')
29+
30+
pcm = ax[1].pcolor(X, Y, Z1, cmap='PuBu_r')
31+
fig.colorbar(pcm, ax=ax[1], extend='max')
32+
fig.show()
33+
34+
35+
'''
36+
PowerNorm: Here a power-law trend in X partially obscures a rectified
37+
sine wave in Y. We can remove the power law using a PowerNorm.
38+
'''
39+
X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)]
40+
Z1 = (1 + np.sin(Y * 10.)) * X**(2.)
41+
42+
fig, ax = plt.subplots(2, 1)
43+
44+
pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=1./2.),
45+
cmap='PuBu_r')
46+
fig.colorbar(pcm, ax=ax[0], extend='max')
47+
48+
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r')
49+
fig.colorbar(pcm, ax=ax[1], extend='max')
50+
fig.show()
51+
52+
'''
53+
SymLogNorm: two humps, one negative and one positive, The positive
54+
with 5-times the amplitude. Linearly, you cannot see detail in the
55+
negative hump. Here we logarithmically scale the positive and
56+
negative data separately.
57+
58+
Note that colorbar labels do not come out looking very good.
59+
'''
60+
61+
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
62+
Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \
63+
- 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2
64+
Z1 = Z1/0.03
65+
66+
fig, ax = plt.subplots(2, 1)
67+
68+
pcm = ax[0].pcolormesh(X, Y, Z1,
69+
norm=colors.SymLogNorm(linthresh=0.03, linscale=0.03,
70+
vmin=-1.0, vmax=1.0),
71+
cmap='RdBu_r')
72+
fig.colorbar(pcm, ax=ax[0], extend='both')
73+
74+
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1))
75+
fig.colorbar(pcm, ax=ax[1], extend='both')
76+
fig.show()
77+
78+
79+
'''
80+
Custom Norm: An example with a customized normalization. This one
81+
uses the example above, and normalizes the negative data differently
82+
from the positive.
83+
'''
84+
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
85+
Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \
86+
- 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2
87+
Z1 = Z1/0.03
88+
89+
# Example of making your own norm. Also see matplotlib.colors.
90+
# From Joe Kington: This one gives two different linear ramps:
91+
92+
93+
class MidpointNormalize(colors.Normalize):
94+
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
95+
self.midpoint = midpoint
96+
colors.Normalize.__init__(self, vmin, vmax, clip)
97+
98+
def __call__(self, value, clip=None):
99+
# I'm ignoring masked values and all kinds of edge cases to make a
100+
# simple example...
101+
x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
102+
return np.ma.masked_array(np.interp(value, x, y))
103+
#####
104+
fig, ax = plt.subplots(2, 1)
105+
106+
pcm = ax[0].pcolormesh(X, Y, Z1,
107+
norm=MidpointNormalize(midpoint=0.),
108+
cmap='RdBu_r')
109+
fig.colorbar(pcm, ax=ax[0], extend='both')
110+
111+
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1))
112+
fig.colorbar(pcm, ax=ax[1], extend='both')
113+
fig.show()
114+
115+
'''
116+
BoundaryNorm: For this one you provide the boundaries for your colors,
117+
and the Norm puts the first color in between the first pair, the
118+
second color between the second pair, etc.
119+
'''
120+
121+
fig, ax = plt.subplots(3, 1, figsize=(8, 8))
122+
ax = ax.flatten()
123+
# even bounds gives a contour-like effect
124+
bounds = np.linspace(-1, 1, 10)
125+
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
126+
pcm = ax[0].pcolormesh(X, Y, Z1,
127+
norm=norm,
128+
cmap='RdBu_r')
129+
fig.colorbar(pcm, ax=ax[0], extend='both', orientation='vertical')
130+
131+
# uneven bounds changes the colormapping:
132+
bounds = np.array([-0.25, -0.125, 0, 0.5, 1])
133+
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
134+
pcm = ax[1].pcolormesh(X, Y, Z1, norm=norm, cmap='RdBu_r')
135+
fig.colorbar(pcm, ax=ax[1], extend='both', orientation='vertical')
136+
137+
pcm = ax[2].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1))
138+
fig.colorbar(pcm, ax=ax[2], extend='both', orientation='vertical')
139+
fig.show()
140+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"""
2+
Demonstration of using norm to map colormaps onto data in non-linear ways.
3+
"""
4+
5+
import numpy as np
6+
import matplotlib.pyplot as plt
7+
import matplotlib.colors as colors
8+
from matplotlib.mlab import bivariate_normal
9+
10+
N = 100
11+
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
12+
Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \
13+
- 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2
14+
Z1 = Z1/0.03
15+
16+
'''
17+
BoundaryNorm: For this one you provide the boundaries for your colors,
18+
and the Norm puts the first color in between the first pair, the
19+
second color between the second pair, etc.
20+
'''
21+
22+
fig, ax = plt.subplots(3, 1, figsize=(8, 8))
23+
ax = ax.flatten()
24+
# even bounds gives a contour-like effect
25+
bounds = np.linspace(-1, 1, 10)
26+
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
27+
pcm = ax[0].pcolormesh(X, Y, Z1,
28+
norm=norm,
29+
cmap='RdBu_r')
30+
fig.colorbar(pcm, ax=ax[0], extend='both', orientation='vertical')
31+
32+
# uneven bounds changes the colormapping:
33+
bounds = np.array([-0.25, -0.125, 0, 0.5, 1])
34+
norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256)
35+
pcm = ax[1].pcolormesh(X, Y, Z1, norm=norm, cmap='RdBu_r')
36+
fig.colorbar(pcm, ax=ax[1], extend='both', orientation='vertical')
37+
38+
pcm = ax[2].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1))
39+
fig.colorbar(pcm, ax=ax[2], extend='both', orientation='vertical')
40+
fig.show()
41+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
Demonstration of using norm to map colormaps onto data in non-linear ways.
3+
"""
4+
5+
import numpy as np
6+
import matplotlib.pyplot as plt
7+
import matplotlib.colors as colors
8+
from matplotlib.mlab import bivariate_normal
9+
10+
N = 100
11+
'''
12+
Custom Norm: An example with a customized normalization. This one
13+
uses the example above, and normalizes the negative data differently
14+
from the positive.
15+
'''
16+
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
17+
Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \
18+
- 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2
19+
Z1 = Z1/0.03
20+
21+
# Example of making your own norm. Also see matplotlib.colors.
22+
# From Joe Kington: This one gives two different linear ramps:
23+
24+
25+
class MidpointNormalize(colors.Normalize):
26+
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
27+
self.midpoint = midpoint
28+
colors.Normalize.__init__(self, vmin, vmax, clip)
29+
30+
def __call__(self, value, clip=None):
31+
# I'm ignoring masked values and all kinds of edge cases to make a
32+
# simple example...
33+
x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
34+
return np.ma.masked_array(np.interp(value, x, y))
35+
#####
36+
fig, ax = plt.subplots(2, 1)
37+
38+
pcm = ax[0].pcolormesh(X, Y, Z1,
39+
norm=MidpointNormalize(midpoint=0.),
40+
cmap='RdBu_r')
41+
fig.colorbar(pcm, ax=ax[0], extend='both')
42+
43+
pcm = ax[1].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1))
44+
fig.colorbar(pcm, ax=ax[1], extend='both')
45+
fig.show()
46+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Demonstration of using norm to map colormaps onto data in non-linear ways.
3+
"""
4+
5+
import numpy as np
6+
import matplotlib.pyplot as plt
7+
import matplotlib.colors as colors
8+
from matplotlib.mlab import bivariate_normal
9+
10+
'''
11+
Lognorm: Instead of pcolor log10(Z1) you can have colorbars that have
12+
the exponential labels using a norm.
13+
'''
14+
N = 100
15+
X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)]
16+
17+
# A low hump with a spike coming out of the top right. Needs to have
18+
# z/colour axis on a log scale so we see both hump and spike. linear
19+
# scale only shows the spike.
20+
Z1 = bivariate_normal(X, Y, 0.1, 0.2, 1.0, 1.0) + \
21+
0.1 * bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
22+
23+
fig, ax = plt.subplots(2, 1)
24+
25+
pcm = ax[0].pcolor(X, Y, Z1,
26+
norm=colors.LogNorm(vmin=Z1.min(), vmax=Z1.max()),
27+
cmap='PuBu_r')
28+
fig.colorbar(pcm, ax=ax[0], extend='max')
29+
30+
pcm = ax[1].pcolor(X, Y, Z1, cmap='PuBu_r')
31+
fig.colorbar(pcm, ax=ax[1], extend='max')
32+
fig.show()

0 commit comments

Comments
 (0)