matplotlib 如何将热图设置为灰度并使用蒙版进行注解

z0qdvdin  于 2023-10-24  发布在  其他
关注(0)|答案(2)|浏览(92)

我有一个矩阵A:

A = np.array([[ 0.        ,  0.00066748, -0.00097412, -0.00748846,  0.00305338],
       [-0.00157652,  0.        ,  0.0048117 ,  0.01069083, -0.0137888 ],
       [-0.00713212, -0.00170574,  0.        ,  0.00096385,  0.00212367],
       [-0.00186541,  0.00351104, -0.00590608,  0.        , -0.00448311],
       [-0.00929146,  0.00157808,  0.01300444, -0.00078593,  0.        ]])

使用下面的代码,我创建了一个热图,将空白(白色)分配给零值,将绿色分配给正值,将红色分配给负值:

import matplotlib.pyplot as plt
import seaborn as sns

rdgn = sns.diverging_palette(h_neg=10, h_pos=130, s=99, l=55, sep=3, as_cmap=True)
fig = plt.figure()
sns.heatmap(A, mask=(A == 0), cmap=rdgn, center=0)
plt.xticks(np.arange(0, 5, 1) + 0.5, [i + 1 for i in range(5)])
plt.yticks(np.arange(0, 5, 1) + 0.5, [i + 1 for i in range(5)], rotation=0)
plt.tick_params(axis='both', which='major', labelsize=10, labelbottom=False, bottom=False, top=False, labeltop=True)
plt.show()

我得到这个:

现在,我的目标是将此图片转换为灰度。一种方法是将较深的颜色分配给红色,将较浅的颜色分配给绿色,但我想突出显示从负值到正值的过渡,使零值与其他值非常不同,理想情况下保持空白。如果我尝试使用

fig = plt.figure()
sns.heatmap(A, mask=(A == 0), cmap = 'gray', center = 0)
plt.xticks(np.arange(0, 5, 1) + 0.5, [i + 1 for i in range(5)])
plt.yticks(np.arange(0, 5, 1) + 0.5, [i + 1 for i in range(5)], rotation=0)
plt.tick_params(axis='both', which='major', labelsize=10, labelbottom=False, bottom=False, top=False, labeltop=True)
plt.show()


我没有得到我想要的。使用mask==0,我可以将零保留为空白,但这不会反映在右边的颜色栏中。我想做的基本上是将颜色“拆分”为2:从漆黑到“半”灰色的底片(从最远到最接近零),白色表示零,从白色到“半”灰色表示正(由最接近零至最远离零)。有没有办法达到这个目标?我欢迎任何有关解决这个问题的建议

dy1byipe

dy1byipe1#

颜色渐变的想法是能够直接比较值。如果使用不同的灰色阴影来表示负/正,可能很难比较绝对值。
相反,为什么不绘制绝对值并添加额外的信息来区分负值和正值呢?

sns.heatmap(abs(A), annot=np.where(A<0, '−', ''), fmt='', cmap = 'gray_r', vmin=0)

或者:

sns.heatmap(abs(A), annot=np.select([A<0, A>0], ['−', '+'], ''),
            fmt='', cmap = 'gray_r', vmin=0)

使用符号/阴影

您可以使用Unicode符号来简化可视化:

sns.heatmap(abs(A), annot=np.where(A<0, '▽', ''), fmt='',
            cmap = 'gray_r', vmin=0, annot_kws={'size': 30})

输出量:

如果需要,您也可以添加图案填充,如here所示:

sns.heatmap(abs(A), cmap = 'gray_r', vmin=0)
zm = np.ma.masked_greater_equal(A, 0)
plt.pcolor(np.arange(A.shape[0])+0.5,
           np.arange(A.shape[1])+0.5,
           zm, hatch='//', alpha=0, zorder=3)

输出量:

pexxcrt2

pexxcrt22#

在@mozway的回答之后,我想到了这个:

plt.rcParams['hatch.linewidth'] = 0.15
x = np.arange(0, A.shape[1]+1, 1)
y = np.arange(0, A.shape[1]+1, 1)
zm = np.ma.masked_greater_equal(A, 0)
fig = plt.figure()
sns.heatmap(abs(A), cmap = 'gray_r', vmin=0)
plt.xticks(np.arange(0, 5, 1) + 0.5, [i + 1 for i in range(5)])
plt.yticks(np.arange(0, 5, 1) + 0.5, [i + 1 for i in range(5)], rotation=0)
plt.tick_params(axis='both', which='major', labelsize=10, labelbottom=False, bottom=False, top=False, labeltop=True)
plt.pcolor(x, y, zm, hatch='+', alpha  = 0)
plt.show()

这基本上是相同的解决方案,但不是放置+或-符号,而是在数字为负数的区域中填充x1c 0d1x
我希望这能帮助一些人

相关问题