从一组列生成 Seaborn 热力图?

3
需要使用seaborn创建热力图,但似乎无法理解如何操作。
每个组件(行)都需要在热力图上显示。在左侧(y轴)应显示每个组件的EID。由于有很多组件,因此仅标记每10-20个组件中的1个即可。x轴应显示数据集的5个列:ROTATION1 ROTATION2 ROTATION3 ROTATION4 ROTATION5。这里的EXTRA列对于热力图不相关。
热力图应表示的值为“ROT”、“STILL”、“FLIP”或介于160-180之间且间隔为2的任何数字(如160、162、164等)。
某些行在ROTATION1-ROTATION5的所有列中都为空,但仍应在热力图中包含这些组件(并且不为它们显示颜色)。
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| EID    | EXTRA | ROTATION1 | ROTATION2 | ROTATION3 | ROTATION4 | ROTATION5 |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| AB1178 | POS   | FLIP      |           | STILL     | 172       |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| EC8361 | NEG   |           |           |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| QS7229 | POS   |           |           | 160       |           | ROT       |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| SE0447 | NEG   | ROT       | STILL     |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| YT5489 | NEG   |           |           |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| SZ2548 | NEG   | 164       |           |           | FLIP      |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| OT6892 | POS   | FLIP      |           |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| PL3811 | POS   |           |           |           | STILL     |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| WQ0893 | POS   |           |           | ROT       |           | 170       |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| TY3551 | NEG   | 160       | FLIP      |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| PC6466 | POS   |           | 180       | 176       |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| YH5912 | POS   |           |           |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| BK6245 | NEG   |           |           |           | STILL     |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| GQ2081 | POS   |           |           |           | 162       | FLIP      |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| GF8633 | NEG   |           |           |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| FJ4895 | NEG   |           | 174       |           | ROT       |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| YD2504 | POS   |           |           |           |           | 162       |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| RF3510 | POS   |           |           |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| PN6167 | NEG   |           | 168       | FLIP      |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| RB9747 | POS   | FLIP      |           | STILL     | 178       | STILL     |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| BQ0841 | NEG   |           | ROT       |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| HJ5187 | NEG   |           |           |           |           |           |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| BP2359 | POS   | 168       | STILL     |           |           | ROT       |
+--------+-------+-----------+-----------+-----------+-----------+-----------+
| FN6198 | POS   | ROT       |           |           | 172       | FLIP      |
+--------+-------+-----------+-----------+-----------+-----------+-----------+

我尝试过的内容:
df = pd.read_csv('DATA.csv')
df = pd.DataFrame(df, columns = ['EID', 'ROTATION1','ROTATION2', 'ROTATION3', 'ROTATION4', 'ROTATION5'])

in_range = list(range(160,181, 2))
direction = ['ROT', 'FLIP', 'STILL']
elements = direction + ([str(num) for num in num_range])

sensing = sns.load_dataset("df")
sensing = sensing.pivot("EID", ['EID', 'ROTATION1','ROTATION2', 'ROTATION3', 'ROTATION4', 'ROTATION5'], elements)

heatmap = sns.heatmap(sensing)

这段代码无法工作,我认为“x-axis”元素应该以列的形式而不是多行出现。如果有人能告诉我如何解决这个问题就太好了!

期望的结果:

一个热图,右侧带有颜色图例栏,其中包含ROT STILL FLIP和160-180之间以2为间隔的数字,如果可能的话按照这个顺序排列。 如前所述,左侧的y轴应该是EID,但实际数据集有大约200行,因此每10或20个代表一个即可。 热图中应该有5列,每一列分别代表ROTATION1ROTATION5

我经验不足,只需要一点帮助。

使用Python2.7和PANDAS 0.24.2以及seaborn 0.9.1

1个回答

1

首先,你需要将数据中的所有值转换为数值类型,例如 int

replacements = {np.nan: 157, 'FLIP': 182, 'STILL': 184, 'ROT': 187}
inv_replacements = {value: key for key, value in replacements.items()}

df = pd.read_csv(r'data/data.csv')
df = df.drop('EXTRA', axis = 1).set_index('EID')
annot = df.values

df = df.replace(replacements).astype(int)

        ROTATION1  ROTATION2  ROTATION3  ROTATION4  ROTATION5
EID                                                          
AB1178        182        157        184        172        157
EC8361        157        157        157        157        157
QS7229        157        157        160        157        187
SE0447        187        184        157        157        157
YT5489        157        157        157        157        157
SZ2548        164        157        157        182        157
OT6892        182        157        157        157        157
PL3811        157        157        157        184        157
WQ0893        157        157        187        157        170
TY3551        160        182        157        157        157
PC6466        157        180        176        157        157
YH5912        157        157        157        157        157
BK6245        157        157        157        184        157
GQ2081        157        157        157        162        182
GF8633        157        157        157        157        157
FJ4895        157        174        157        187        157
YD2504        157        157        157        157        162
RF3510        157        157        157        157        157
PN6167        157        168        182        157        157
RB9747        182        157        184        178        184
BQ0841        157        187        157        157        157
HJ5187        157        157        157        157        157
BP2359        168        184        157        157        187
FN6198        187        157        157        172        182

然后,您应该将每个数字值映射到相应的标签,并准备一个颜色映射表:
values = list(replacements.values())
values.extend(list(range(160, 181, 2)))
values = sorted(values)
vmap = {value: str(value) if value not in inv_replacements.keys() else inv_replacements[value] for value in values}
n = len(vmap)
cmap = sns.color_palette('tab20', n)
cmap[0] = (1, 1, 1, 1)

我选择了 'tab20' 色图,因为你需要15种不同的颜色,而这个色图是其中之一,它包含足够多的颜色。
然后你就可以绘制热力图:

ax = sns.heatmap(df, cmap = cmap, annot = annot, fmt = '')

最后,您需要调整色图:
colorbar = ax.collections[0].colorbar
r = colorbar.vmax - colorbar.vmin
colorbar.set_ticks([colorbar.vmin + 0.5*r/(n) + r*i/(n) for i in range(n)])
colorbar.set_ticklabels(list(vmap.values()))

完整代码

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np


replacements = {np.nan: 157, 'FLIP': 182, 'STILL': 184, 'ROT': 187}
inv_replacements = {value: key for key, value in replacements.items()}

df = pd.read_csv(r'data/data.csv')
df = df.drop('EXTRA', axis = 1).set_index('EID')
annot = df.values

df = df.replace(replacements).astype(int)


values = list(replacements.values())
values.extend(list(range(160, 181, 2)))
values = sorted(values)
vmap = {value: str(value) if value not in inv_replacements.keys() else inv_replacements[value] for value in values}
n = len(vmap)
cmap = sns.color_palette('tab20', n)
cmap[0] = (1, 1, 1, 1)


ax = sns.heatmap(df, cmap = cmap, annot = annot, fmt = '')

colorbar = ax.collections[0].colorbar
r = colorbar.vmax - colorbar.vmin
colorbar.set_ticks([colorbar.vmin + 0.5*r/(n) + r*i/(n) for i in range(n)])
colorbar.set_ticklabels(list(vmap.values()))
 
plt.show()
  • 带有注释的热力图以进行检查:

    输入图像描述

  • 不带注释的热力图:

    输入图像描述


我不建议使用连续的颜色映射:这可能会使一个值与下一个值难以区分。
但是,如果您想要,可以使用连续的颜色映射,无论是针对所有值还是仅针对数值。
(当然,您可以保留或删除注释)
  • colormap 'plasma' only for numerical values, white for nans, RGB for categorical ones:

    cmap = sns.color_palette('plasma', n - 4)
    cmap.insert(0, (1, 1, 1, 1))
    cmap.append((1, 0, 0, 1))
    cmap.append((0, 1, 0, 1))
    cmap.append((0, 0, 1, 1))
    

    enter image description here

  • colormap 'plasma' for all values:

    cmap = sns.color_palette('plasma', n - 1)
    cmap.insert(0, (1, 1, 1, 1))
    

    enter image description here


这正是我需要的,非常感谢。您如何建议我获得“逐渐”的颜色条?(所以没有分离?) - Thedone
我更新了我的答案,请告诉我它是否适用于您。现在,色条是连续的而不是分类的,因为我从这里选择了“plasma”颜色映射。您可以选择其他颜色映射,例如“viridis”。但是,在热图右侧的色条中,您将看到n个正方形并排放置,而不是连续阴影的漂亮色条,因为您必须从中选择n个元素,所以阴影消失了。 - Zephyr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接