带有自定义颜色图的pyplot outlinef重复颜色而不是更改 [英] pyplot contourf with custom colormap repeats color instead of changing

查看:42
本文介绍了带有自定义颜色图的pyplot outlinef重复颜色而不是更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

与此同时,我进行了一些测试,发现它是未使用的重复图案的第二种颜色(灰色(0.25)),但我仍然不知道为什么.

这是代码的简短版本:

将 numpy 导入为 np导入matplotlib.pyplot作为plt从 matplotlib 导入颜色#生成数据x = y = np.linspace(-3、3、200)im = 1800*np.exp(-(np.outer(x,x) + y**2))im = im/im.max()#规范化#设置对数水平(小步)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次)# 通过填充到最低级别来避免白斑im [im<levS.min() ] = levS.min()# 列出 5 种颜色以从中创建颜色图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)]# 三个十年重复 3 次mapColS = mapColS + mapColS + mapColSMyCmap = colors.ListedColormap(mapColS)#制作颜色图fig13g = plt.figure(1000)#创建图形ax13g = fig13g.add_subplot(111)#绘图线cax = plt.contour(im, levS, linewidths = 0.5,norm = colors.LogNorm(),颜色="k")#填满颜色cax = plt.contourf(im,levS,norm = colors.LogNorm(),cmap=MyCmap) # plt.cm.jet 或 MyCmap#显示日志颜色栏cbar = fig13g.colorbar(cax,orientation='vertical',间距=常规",刻度= levS)

结果如下:

对于比较,使用'jet'没问题:

解决方案

问题在于,不同的值最终会产生相同的颜色.这是由于使用了非线性规范.
对于线性范数,contourf图各层的颜色将以级别之间的算术平均值获得.虽然这在比较图像和等高线图时也可能会导致问题(如

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

这就是原则上使用jet"颜色图可以正常工作的原因,因为您有 256 种不同的颜色.

因此,可能的解决方案是使用更多颜色来创建颜色图,

将 numpy 导入为 np导入matplotlib.pyplot作为plt从 matplotlib 导入颜色#生成数据x = y = np.linspace(-3、3、200)im = 1800*np.exp(-(np.outer(x,x) + y**2))im = im/im.max() # 标准化#设置对数水平(小步)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])#(10 年 5 次间隔)# 通过填充到最低级别来避免白斑我[我<levS.min()] = levS.min()#列出N种颜色,以从中创建颜色表N = 20mapColS = list(plt.cm.gray(np.linspace(0,1,N)))# 三个十年重复 3 次mapColR = mapColS + mapColS + mapColSMyCmap = colors.ListedColormap(mapColR)#制作颜色图fig13g = plt.figure(1000) #创建图形ax13g = fig13g.add_subplot(111)#绘图线c = plt.contour(im,levS,线宽= 0.5,norm=colors.LogNorm(), 颜色 = 'k')# 填充颜色cf = plt.contourf(im,levS,norm = colors.LogNorm(),cmap=MyCmap) # plt.cm.jet 或 MyCmapcbar = fig13g.colorbar(cf,orientation='vertical',间距=常规",刻度= levS)plt.show()

这样做的缺点是您失去了动态范围,因为最低的颜色不是黑色而是深灰色.

因此,另一种选择是计算这些图层值并在这些位置创建具有相应颜色的颜色图.

将 numpy 导入为 np导入matplotlib.pyplot作为plt从 matplotlib 导入颜色#生成数据x = y = np.linspace(-3、3、200)im = 1800 * np.exp(-(np.outer(x,x)+ y ** 2))im = im/im.max()#规范化#设置对数水平(小步)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次)#通过填充到最低水平来避免白色斑块我[我<levS.min() ] = levS.min()#列出N种颜色,以从中创建颜色表N = 5mapColS = list(plt.cm.gray(np.linspace(0,1,N)))#在三个十年中重复3次mapColR = mapColS + mapColS + mapColS#计算lognorm的图层值层数 = np.sqrt(levS[:-1]) * np.sqrt(levS[1:])范数 = 颜色.LogNorm(levS.min(), levS.max())#添加最外面的值和颜色lvals = np.concatenate(([0.], norm(layers), [1.]))cvals = [mapColR [0]] + mapColR + [mapColR [-1]]# 根据值和颜色制作颜色图MyCmap=colors.LinearSegmentedColormap.from_list("", list(zip(lvals,cvals)))fig13g = plt.figure(1000)#创建图形ax13g = fig13g.add_subplot(111)# 绘图线c = plt.contour(im,levS,线宽= 0.5,规范=规范,颜色='k')#填满颜色cf = plt.contourf(im,levS,norm = norm,cmap = MyCmap)cbar = fig13g.colorbar(cf,orientation='vertical',间距=常规",刻度= levS)plt.show()

I want to plot some data with a logarithmic color code where a decade limit is indicated by a white/black interface. Grey levels are used to show some subdivisions of a decade. My problem is that there are two white neighboring regions in each decade even though the color map has the right number of entries (at least I think). Could someone help please?

In the meantime I made some tests and I found that it's the second color of the repeating pattern that is not used (the gray(0.25)), but I still have no idea why.

Here is the short version of the code:

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)

Here are the results:

For comparisson, using 'jet' there is no problem:

解决方案

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

这篇关于带有自定义颜色图的pyplot outlinef重复颜色而不是更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆