【问题标题】:Matplotlib custom colormap doesn't respect coloringMatplotlib 自定义颜色图不尊重着色
【发布时间】:2017-03-04 16:10:59
【问题描述】:

(旧版问题如下)

我正在定义以下自定义颜色图,其中我将白色 (#ffffff) 分配给浮点数 zero_pt。

import matplotlib.colors as col
from matplotlib.colors import LinearSegmentedColormap

zero_pt = 0.98181818181818181

cmap = LinearSegmentedColormap.from_list(
    'mycmap', [(0, 'blue'), (zero_pt, 'white'), (1, 'red')])

但是当我尝试从相同的 zero_pt 值中检索十六进制颜色代码时,我没有得到 #ffffff(即:白色),正如我所期望的那样:

rgb = cmap(zero_pt)[:3]
print(col.rgb2hex(rgb))
> u'#ffdcdc'

为什么会这样?我该如何解决这个问题?




这里是老问题

我需要定义一个自定义颜色图,其中负值显示为蓝色,零值显示为白色,正值显示为红色。代码如下,必要的数据文件在这里(data.pkl)和这里(edges.pkl)。

import pickle
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap


with open('data.pkl', 'r') as f:
    H = pickle.load(f)
with open('edges.pkl', 'r') as f:
    edges = pickle.load(f)

# Define zero point for empty bins which should be colored in white.
zero_pt = 1. - H.max() / (H.max() - H.min())

print(H.min(), H.max(), zero_pt)

cmap = LinearSegmentedColormap.from_list(
    'mycmap', [(0, 'blue'), (zero_pt, 'white'), (1, 'red')])

Y, X = np.meshgrid(edges[0], edges[1])
plt.pcolormesh(X, Y, H, cmap=cmap, vmin=H.min(), vmax=H.max())

plt.show()

这会导致

如果我们检查H 数组,我们会看到很多零值应该显示为白色,而在上图中显示为粉红色。

这不会发生在我使用的所有数据中,它只是偶尔发生。我认为这个问题与四舍五入有关?有没有办法强制像这种情况一样以白色显示零值?

【问题讨论】:

  • 您在生成LinearSegmentedColormap.from_list(name, colors, N=256, gamma=1.0)时使用了默认的颜色数量;我会尝试指定N=20 左右,看看四舍五入是否适合人类感知。 (您可能需要将zero_pt 向下舍入一点,使其落在白色段的内部。)
  • 降低N 会使情况变得更糟(颜色变得更红)。如果我使用N=500,我会得到fffdfd,它足够接近白色,但我不确定我在用它做什么。
  • LinearSegmentedColormap.from_list() 的文档说 N is the number of rgb quantization levels,所以我想如果我需要更高的精度,我应该增加这个值?
  • 放入颜色条以查看升高/降低N 的作用。 (这是颜色段的数量。)

标签: python matplotlib


【解决方案1】:

正如在 cmets 中所说,如果 N 是颜色图中的颜色数,则需要将零点值四舍五入为 1/N 的倍数。当然,颜色图中的零点值与任何其他颜色之间的差异必须大于1/N。

所以这里有一个解决方案

import matplotlib.colors as col
from matplotlib.colors import LinearSegmentedColormap
import numpy as np 

N=256
zero_pt0 = 0.98181818181818181
zero_pt_rounded = np.ceil(zero_pt0*(N-1))/float(N-1)
print (zero_pt_rounded)

cmap = LinearSegmentedColormap.from_list(
    'mycmap', [(0, 'blue'), (zero_pt_rounded, 'white'), (1, 'red')], N=N)

# verify if original point zero_pt0 gives white color
rgb = cmap(zero_pt0)[:3]
print(col.rgb2hex(rgb))

关于你的老问题:不清楚zero_pt = 1. - H.max() / (H.max() - H.min()) 应该做什么。 我猜你需要放

data_value_for_white color = ...
zero_pt = (data_value_for_white color - H.min()) / (H.max() - H.min())

此外,为了确保所需值被颜色图中的白色覆盖,我们需要将颜色图中的两个相邻颜色设为白色。

N = 256 # number of colors in the colormap
zero_pt0 = np.floor(zero_pt*(N-1))/float(N-1)
zero_pt1 = np.ceil(zero_pt*(N-1))/float(N-1)
cmap = LinearSegmentedColormap.from_list('mycmap',
         [(0, 'blue'), (zero_pt0, 'white'),(zero_pt1, 'white'), (1, 'red')], N=N)

因此,一个完整的解决方案如下所示:

import pickle
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap, rgb2hex


with open('data.pkl', 'r') as f:
    H = pickle.load(f)
with open('edges.pkl', 'r') as f:
    edges = pickle.load(f)

# Define zero point for empty bins which should be colored in white.
data_value_for_white_color = 0.
zero_pt = (data_value_for_white_color - H.min()) / float(H.max() - H.min())

N=256
zero_pt0 = np.floor(zero_pt*(N-1))/float(N-1)
zero_pt1 = np.ceil(zero_pt*(N-1))/float(N-1)

cmap = LinearSegmentedColormap.from_list('mycmap',
     [(0, 'blue'), (zero_pt0, 'white'),(zero_pt1, 'white'), (1, 'red')], N=N)

Y, X = np.meshgrid(edges[0], edges[1])
plt.pcolormesh(X, Y, H, cmap=cmap, vmin=H.min(), vmax=H.max())
plt.show()

【讨论】:

  • zero_pt = 1. - H.max() / (H.max() - H.min()) 行用于在pcolormesh 图中制作空单元格,将其绘制为白色(请参阅“旧”问题)。您的解决方案在 zero_pt 的 rgb 返回为 #ffffff 的意义上有效,但它不是原始问题的意义,因为所有空单元格现在都是蓝色的。由于我修改了问题,如果没有更好的解决方案,我会接受你的回答。谢谢。
  • 我不明白。您是否使用zero_pt = (data_value_for_white color - H.min()) / (H.max() - H.min()) 并且仅将值设为蓝调?我猜你是因为你使用了这条 stange 线 zero_pt = 1. - H.max() / (H.max() - H.min()) 这没有多大意义。
  • 该行将H 中的0. 值(在H.min() 和H.max() 之间)映射为原始问题中定义的自定义颜色图中的白色。
  • 无论如何我编辑了答案,向你展示你真的应该使用zero_pt = (data_value_for_white_color - H.min()) / (H.max() - H.min()) 来解决你的问题。
  • 因为您需要将 data_value_for_white_color 标准化为颜色图的 0 到 1 之间的范围
猜你喜欢
  • 2021-05-03
  • 2020-09-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-19
  • 2020-09-28
  • 2013-01-06
相关资源
最近更新 更多