带有自定义颜色图的pyplot outlinef重复颜色而不是更改

时间:2018-09-25 13:01:37

标签: python python-3.x matplotlib colormap contourf

我想用对数颜色代码绘制一些数据,其中白/黑界面表示十进制极限。灰度用于显示十年的一些细分。我的问题是,即使颜色映射表中的条目数正确(至少我认为),每十年也有两个白色相邻区域。有人可以帮忙吗?

同时,我进行了一些测试,发现它是未使用的重复图案的第二种颜色(灰色(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)

以下是结果:

The plot with the problem

对于比较,使用'jet'没问题:
using 'jet' there is no problem

2 个答案:

答案 0 :(得分:2)

问题是您使用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

输出

enter image description here

答案 1 :(得分:0)

问题在于,不同的值最终会产生相同的颜色。这是由于使用了非线性规范。
对于线性范数,轮廓线图各层的颜色将以级别之间的算术平均值获得。尽管这在比较图像和轮廓图时也会引起问题(如How does pyplot.contourf choose colors from a colormap?所示),但仍会导致N + 1个级别使用N种唯一颜色。

对于LogNorm,使用 geometric 平均值代替算术平均值。

以下显示了用于从颜色图中产生颜色的值。可以看出,几个最终都位于同一容器中。

enter image description here

增加颜色数量将使每个值都位于其自己的色标中。

enter image description here

从原理上讲,这正是为什么使用“喷射”色图可以正常工作的原因,因为您有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()

enter image description here

这样做的缺点是您会降低动态范围,因为最低的颜色不是黑色,而是深灰色。

因此,一个不同的选择是计算那些图层值,并使用恰好在那些位置的各个颜色创建一个颜色图。

enter image description here

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()

enter image description here