Pyplot Contourf With Custom Colormap Repeats Color Instead Of Changing
Solution 1:
The problem is that you were repeating the same color levelsmapColS
3 times by using mapColS = mapColS + mapColS + mapColS
. The straight forward solution is to create a single continuous grayscale by dividing linearly the scale between plt.cm.gray(0)
and plt.cm.gray(0.99)
into 15 equal levels as
mapColS = [plt.cm.gray(i) for i in np.linspace(0, 0.99, 15)]
MyCmap=colors.ListedColormap(mapColS) # make color map
Output
Solution 2:
The problem is that different values end up producing the same color. This is due to the non-linear norm in use. For a linear norm, the colors for the layers of the contourf plot would be taken at the arithmetic mean between the levels. While this may also cause problems when comparing images and contour plots (as shown in How does pyplot.contourf choose colors from a colormap?), it would still leed to N unique colors being used for N+1 levels.
For a LogNorm, the geometric mean is used instead of the arithmetic mean.
In the following the values used to produce the colors from the colormap are shown. As can be seen several end up in the same bin.
Increasing the number of colors will allow each value to be in its own colorbin.
This is in principle exactly why the use of the 'jet' colormap works fine, because you have 256 different colors.
Hence a possible solution is to use more colors for the colormap creation,
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
# generate data
x = y = np.linspace(-3, 3, 200)
im = 1800*np.exp(-(np.outer(x,x) + y**2))
im = im / im.max() # normalize# set logarithic levels (with small steps)
levS = np.array([1e-3,2e-3,4e-3,6e-3,8e-3,
1e-2,2e-2,4e-2,6e-2,8e-2,
0.1,0.2,0.4,0.6,0.8,
1])
# (5 intervals in one decade )# avoid white patches by filling up to lowest level
im[ im < levS.min() ] = levS.min()
# make a list of N colors to create a colormap from
N = 20
mapColS = list(plt.cm.gray(np.linspace(0,1,N)))
# repeat 3 times for the three decades
mapColR = mapColS + mapColS + mapColS
MyCmap=colors.ListedColormap(mapColR) # make color map
fig13g = plt.figure(1000) #create figure
ax13g = fig13g.add_subplot(111)
# plot lines
c = plt.contour(im, levS, linewidths = 0.5,
norm=colors.LogNorm(), colors = 'k')
# fill with colors
cf = plt.contourf(im, levS, norm=colors.LogNorm(),
cmap=MyCmap) # plt.cm.jet OR MyCmap
cbar = fig13g.colorbar(cf, orientation='vertical',
spacing='regular',ticks= levS)
plt.show()
The drawback of this is that you loose dynamic range because the lowest color is not black but dark grey.
A different option would hence be to calculate those layer values and create a colormap with the respective colors at exactly those positions.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors
# generate data
x = y = np.linspace(-3, 3, 200)
im = 1800*np.exp(-(np.outer(x,x) + y**2))
im = im / im.max() # normalize# set logarithic levels (with small steps)
levS = np.array([1e-3,2e-3,4e-3,6e-3,8e-3,
1e-2,2e-2,4e-2,6e-2,8e-2,
0.1,0.2,0.4,0.6,0.8,
1])
# (5 intervals in one decade )# avoid white patches by filling up to lowest level
im[ im < levS.min() ] = levS.min()
# make a list of N colors to create a colormap from
N = 5
mapColS = list(plt.cm.gray(np.linspace(0,1,N)))
# repeat 3 times for the three decades
mapColR = mapColS + mapColS + mapColS
#calculate layer values for lognorm
layers = np.sqrt(levS[:-1]) * np.sqrt(levS[1:])
norm = colors.LogNorm(levS.min(), levS.max())
#add outmost values and colors
lvals = np.concatenate(([0.], norm(layers), [1.]))
cvals = [mapColR[0]] + mapColR + [mapColR[-1]]
# make the colormap from values and colors
MyCmap=colors.LinearSegmentedColormap.from_list("", list(zip(lvals,cvals)))
fig13g = plt.figure(1000) #create figure
ax13g = fig13g.add_subplot(111)
# plot lines
c = plt.contour(im, levS, linewidths = 0.5,
norm=norm, colors = 'k')
# fill with colors
cf = plt.contourf(im, levS, norm=norm,
cmap=MyCmap)
cbar = fig13g.colorbar(cf, orientation='vertical',
spacing='regular',ticks= levS)
plt.show()
Post a Comment for "Pyplot Contourf With Custom Colormap Repeats Color Instead Of Changing"