Python 中间色热图(百分位)

Python heatmap with intermediate color by percentile

我正在尝试在 python 中使用 50% 百分位数的中间颜色制作热图。我经常使用 excel 执行此操作,但无法在我的自动化 python 代码上使用它。

在 (red,yellow,Green) 中你可以看到我的 excel 版本,黄色和蓝色是我的 python 版本。

澄清一下,我不介意它是两种颜色的退化,我只是想对 50% 的最高百分位数给予与底部相同的重要性。

我的代码简化后的代码是:

import pandas as pd
import seaborn as sns

data = {
        'row1': [90,95,99,50,50,45,0],
        'row2': [99,98,100,100,98,99,80],
        'row3': [98,97,99,100,96,95,98],
        'row4': [99,98,100,100,98,99,100]
        }
fig, ax = plt.subplots(figsize=(9, 4))
df = pd.DataFrame.from_dict(data,orient='index')
sns.heatmap(df.round(), annot=True,ax=ax, cmap="YlGnBu")

在此先感谢您的帮助!

你可以这样做:

import matplotlib as mpl
fig, ax = plt.subplots(figsize=(9, 4))
df = pd.DataFrame.from_dict(data,orient='index')
cmap1 = mpl.colors.ListedColormap(['y'])
sns.heatmap(df.round(), annot=True,ax=ax, cmap="YlGnBu")
sns.heatmap(df.round(), mask=df.round() > 50, cmap=cmap1, cbar=True)
plt.show()

根据@StefanS 提供的link,我想出了以下注册自己的 cmap 的方法,在我的例子中,使用中位数:

median = df.median().median()/100.0
c_red_yl_ = {'red':   ((0.0, 0.8, 0.8),
                   (median, 1.0, 1.0),
                   (1.0, 0.0, 0.0)),

         'green': ((0.0, 0.0, 0.0),
                   (median, 1.0, 1.0),
                   (1.0, 0.8, 0.8)),

         'blue':  ((0.0, 0.0, 0.0),
                   (median, 0.0, 0.0),
                   (1.0, 0.0, 0.0))
        }
plt.register_cmap(name='custom', data=cdict1)

我希望它对其他人有用。

通常不希望更改颜色图本身。相反,人们会将值的规范化更改为颜色。为此,可以使用 midpoint normalization。明显的优势是这个概念适用于任何颜色图,无需为每个使用的不同中值创建自定义颜色图。

不幸的是,seaborn 不允许使用自定义规范化。但是使用 matplotlib 本身创建热图同样容易,如 annotated_heatmap 示例所示。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors

class MidpointNormalize(colors.Normalize):
    def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
        self.midpoint = midpoint
        colors.Normalize.__init__(self, vmin, vmax, clip)

    def __call__(self, value, clip=None):
        # I'm ignoring masked values and all kinds of edge cases to make a
        # simple example...
        x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
        return np.ma.masked_array(np.interp(value, x, y))

data = {
        'row1': [90,95,99,50,50,45,0],
        'row2': [99,98,100,100,98,99,80],
        'row3': [98,97,99,100,96,95,98],
        'row4': [99,98,100,100,98,99,100]
        }
fig, ax = plt.subplots(figsize=(9, 4))
df = pd.DataFrame.from_dict(data,orient='index')

norm =  MidpointNormalize(midpoint=np.median(df.values))

im = ax.imshow(df.values, cmap="YlGnBu", norm=norm)
fig.colorbar(im)

# Loop over data dimensions and create text annotations.
textcolors = ["k" ,"w"]
threshold = 55
for i in range(len(df)):
    for j in range(len(df.columns)):
        text = ax.text(j, i, df.values[i, j],
                       ha="center", va="center", 
                       color=textcolors[df.values[i, j] > threshold])

plt.show()