带有自定义颜色图的 pyplot contourf 重复颜色而不是改变
pyplot contourf with custom colormap repeats color instead of changing
我想用对数颜色代码绘制一些数据,其中十进制限制由 white/black 界面指示。灰度级用于显示十年的一些细分。我的问题是,即使彩色地图的条目数量正确(至少我认为),每个十年都有两个白色相邻区域。有人可以帮忙吗?
同时我做了一些测试,发现没有使用重复图案的第二种颜色(灰色(0.25)),但我仍然不知道为什么。
这是代码的简短版本:
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 5 colors to create a colormap from
mapColS = [plt.cm.gray(0),plt.cm.gray(0.25),plt.cm.gray(0.50),
plt.cm.gray(0.7),plt.cm.gray(0.99)]
# repeat 3 times for the three decades
mapColS = mapColS + mapColS + mapColS
MyCmap=colors.ListedColormap(mapColS) # make color map
fig13g = plt.figure(1000) #create figure
ax13g = fig13g.add_subplot(111)
# plot lines
cax = plt.contour(im, levS, linewidths = 0.5,
norm=colors.LogNorm(), colors = 'k')
# fill with colors
cax = plt.contourf(im, levS, norm=colors.LogNorm(),
cmap=MyCmap) # plt.cm.jet OR MyCmap
# show log color bar
cbar = fig13g.colorbar(cax, orientation='vertical',
spacing='regular',ticks= levS)
结果如下:
对比一下,用'jet'没问题:
问题是您使用mapColS = mapColS + mapColS + mapColS
重复相同的颜色级别 mapColS
3 次。直接的解决方案是通过将 plt.cm.gray(0)
和 plt.cm.gray(0.99)
之间的比例线性划分为 15 个相等的级别
来创建 单个连续灰度
mapColS = [plt.cm.gray(i) for i in np.linspace(0, 0.99, 15)]
MyCmap=colors.ListedColormap(mapColS) # make color map
输出
问题是不同的值最终会产生相同的颜色。这是由于使用了非线性范数。
对于线性范数,contourf 图图层的颜色将取各级别之间的算术平均值。虽然这也可能在比较图像和等高线图时造成问题(如 所示),但它仍然会导致 N+1 级别使用 N 种独特的颜色。
对于 LogNorm,使用几何 平均值而不是算术平均值。
下面显示了用于从颜色图中生成颜色的值。可以看出,有几个最终进入了同一个垃圾箱。
增加颜色数量将使每个值都在其自己的色箱中。
原则上,这正是使用 'jet' 颜色图效果很好的原因,因为您有 256 种不同的颜色。
因此,一个可能的解决方案是使用更多颜色来创建颜色图,
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()
这样做的缺点是你失去了动态范围,因为最低的颜色不是黑色而是深灰色。
因此,一个不同的选择是计算这些图层值,并在这些位置创建具有相应颜色的颜色图。
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()
我想用对数颜色代码绘制一些数据,其中十进制限制由 white/black 界面指示。灰度级用于显示十年的一些细分。我的问题是,即使彩色地图的条目数量正确(至少我认为),每个十年都有两个白色相邻区域。有人可以帮忙吗?
同时我做了一些测试,发现没有使用重复图案的第二种颜色(灰色(0.25)),但我仍然不知道为什么。
这是代码的简短版本:
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 5 colors to create a colormap from
mapColS = [plt.cm.gray(0),plt.cm.gray(0.25),plt.cm.gray(0.50),
plt.cm.gray(0.7),plt.cm.gray(0.99)]
# repeat 3 times for the three decades
mapColS = mapColS + mapColS + mapColS
MyCmap=colors.ListedColormap(mapColS) # make color map
fig13g = plt.figure(1000) #create figure
ax13g = fig13g.add_subplot(111)
# plot lines
cax = plt.contour(im, levS, linewidths = 0.5,
norm=colors.LogNorm(), colors = 'k')
# fill with colors
cax = plt.contourf(im, levS, norm=colors.LogNorm(),
cmap=MyCmap) # plt.cm.jet OR MyCmap
# show log color bar
cbar = fig13g.colorbar(cax, orientation='vertical',
spacing='regular',ticks= levS)
结果如下:
对比一下,用'jet'没问题:
问题是您使用mapColS = mapColS + mapColS + mapColS
重复相同的颜色级别 mapColS
3 次。直接的解决方案是通过将 plt.cm.gray(0)
和 plt.cm.gray(0.99)
之间的比例线性划分为 15 个相等的级别
mapColS = [plt.cm.gray(i) for i in np.linspace(0, 0.99, 15)]
MyCmap=colors.ListedColormap(mapColS) # make color map
输出
问题是不同的值最终会产生相同的颜色。这是由于使用了非线性范数。
对于线性范数,contourf 图图层的颜色将取各级别之间的算术平均值。虽然这也可能在比较图像和等高线图时造成问题(如
对于 LogNorm,使用几何 平均值而不是算术平均值。
下面显示了用于从颜色图中生成颜色的值。可以看出,有几个最终进入了同一个垃圾箱。
增加颜色数量将使每个值都在其自己的色箱中。
原则上,这正是使用 'jet' 颜色图效果很好的原因,因为您有 256 种不同的颜色。
因此,一个可能的解决方案是使用更多颜色来创建颜色图,
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()
这样做的缺点是你失去了动态范围,因为最低的颜色不是黑色而是深灰色。
因此,一个不同的选择是计算这些图层值,并在这些位置创建具有相应颜色的颜色图。
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()