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()
我正在尝试在 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()