【问题标题】:Seaborn heatmap from group of columns?来自一组列的Seaborn热图?
【发布时间】:2021-11-01 22:01:07
【问题描述】:

需要使用 seaborn 创建热图,但似乎无法实现或完全掌握如何实现。

每个组件(行)都需要出现在热图上。左侧(y 轴)应显示每个组件的EID。有很多,所以如果每 10-20 个中只有 1 个被标记,那很好。 x 轴上应该是ROTATION1ROTATION2ROTATION3ROTATION4ROTATION5,它们代表数据集的 5 列。这里的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轴”元素应该是列的形式,而不是多行?如果有人能告诉我如何绕过那就太好了!

想要的结果:

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

我缺乏经验,只需要一点帮助。

使用 Python2.7 和 PANDAS 0.24.2 和 seaborn 0.9.1

【问题讨论】:

    标签: python pandas dataframe seaborn heatmap


    【解决方案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 种不同的颜色,而此颜色图是 one of the few,其中包含足够的颜色。
    然后就可以绘制热图了:

    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' 仅用于数值,白色用于nans,RGB 用于分类值:

      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))
      

    • 所有值的颜色图'plasma'

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

    【讨论】:

    • 这正是我所需要的,非常感谢。你会如何建议我得到一个“渐变”色条? (所以没有分离?)
    • 我更新了我的答案,让我知道它是否适合你。现在颜色条是 sequential(连续)而不是 qualitative(分类),因为我从 here 中选择了 'plasma' 颜色图。您可以随意选择另一个,例如'viridis'。但是,您会在热图右侧的颜色栏中看到n 并排的正方形数量,而不是连续阴影的好看颜色栏,因为您必须从中选择n 元素,所以阴影消失
    猜你喜欢
    • 1970-01-01
    • 2018-05-15
    • 2015-09-12
    • 2020-10-12
    • 1970-01-01
    • 2019-05-16
    • 2017-09-27
    • 2020-10-21
    • 1970-01-01
    相关资源
    最近更新 更多