与heatmap-like plot, but for categorical variables相同的问题,但使用python和seaborn而不是R:
想象一下,我有以下数据框:
df = pd.DataFrame({"John":"No Yes Maybe".split(),
"Elly":"Yes Yes Yes".split(),
"George":"No Maybe No".split()},
index="Mon Tue Wed".split())
现在我想绘制一个热图并用相应的值为每个单元格着色。那是"是","否","可能",例如变成"绿","格雷", "黄色&#34 ;.图例应该有这三种颜色和相应的值。
我自己用以下方式解决了这个问题。我似乎无法将分类颜色图传递给seaborn的热图,因此我用数字替换所有文本,然后重新构建seaborn内部使用的颜色图,即:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
# create dictionary with value to integer mappings
value_to_int = {value: i for i, value in enumerate(sorted(pd.unique(df.values.ravel())))}
f, ax = plt.subplots()
hm = sns.heatmap(df.replace(value_to_int).T, cmap="Pastel2", ax=ax, cbar=False)
# add legend
box = ax.get_position()
ax.set_position([box.x0, box.y0, box.width * 0.7, box.height])
legend_ax = f.add_axes([.7, .5, 1, .1])
legend_ax.axis('off')
# reconstruct color map
colors = plt.cm.Pastel2(np.linspace(0, 1, len(value_to_int)))
# add color map to legend
patches = [mpatches.Patch(facecolor=c, edgecolor=c) for c in colors]
legend = legend_ax.legend(patches,
sorted(value_to_int.keys()),
handlelength=0.8, loc='lower left')
for t in legend.get_texts():
t.set_ha("left")
我的问题:是否有更简洁的方法制作此热图?如果没有,这可能是一个值得实施的功能,在这种情况下,我会将其发布在seaborn问题跟踪器上。
答案 0 :(得分:2)
您可以使用离散的颜色图并修改颜色栏,而不必使用图例。
value_to_int = {j:i for i,j in enumerate(pd.unique(df.values.ravel()))} # like you did
n = len(value_to_int)
# discrete colormap (n samples from a given cmap)
cmap = sns.color_palette("Pastel2", n)
ax = sns.heatmap(df.replace(value_to_int), cmap=cmap)
# modify colorbar:
colorbar = ax.collections[0].colorbar
r = colorbar.vmax - colorbar.vmin
colorbar.set_ticks([colorbar.vmin + r / n * (0.5 + i) for i in range(n)])
colorbar.set_ticklabels(list(value_to_int.keys()))
plt.show()
颜色栏部分改编自this answer
HTH
答案 1 :(得分:0)
我可能会将散景用于此目的,因为它内置了分类热图.Y轴标签也是水平书写的,更具可读性。
http://bokeh.pydata.org/en/0.11.1/docs/gallery/heatmap_chart.html