如何使用 Matplotlib 或 Seaborn 根据不同的组指定图例

Posted

技术标签:

【中文标题】如何使用 Matplotlib 或 Seaborn 根据不同的组指定图例【英文标题】:How to specify legend based on different groups with Matplotlib or Seaborn 【发布时间】:2021-10-14 08:17:34 【问题描述】:

我有一个如下所示的数据集:

df =  'tic': 0: 'A',
      1: 'AAPL',
      2: 'ABC',
      3: 'ABT',
      4: 'ADBE',
      5: 'ADI',
      6: 'ADM',
      7: 'ADP',
      8: 'ADSK',
      9: 'AEE',
     'Class': 0: 'Manufacturing',
      1: 'Tech',
      2: 'Trade',
      3: 'Manufacturing',
      4: 'Services',
      5: 'Tech',
      6: 'Manufacturing',
      7: 'Services',
      8: 'Services',
      9: 'Electricity and Transportation',
     'Color': 0: 'blue',
      1: 'teal',
      2: 'purple',
      3: 'blue',
      4: 'red',
      5: 'teal',
      6: 'blue',
      7: 'red',
      8: 'red',
      9: 'orange',
     'Pooled 1': 0: 0.0643791550056838,
      1: 0.05022103288830682,
      2: 0.039223739393748916,
      3: 0.036366693834970217,
      4: 0.05772708899447428,
      5: 0.05969899935101172,
      6: 0.04568101605219955,
      7: 0.04542272002937567,
      8: 0.07138013872431757,
      9: 0.029987722053015278

我想用存储在Pooled 1 中的值生成一个蝙蝠图。但我想用存储在Color 中的颜色为条形着色。相同Class 的所有条形应具有相同的颜色并应绘制在一起。我只展示了上面数据集的一部分。

我使用的代码如下:

fig, axs = plt.subplots(1,1,figsize = (24, 5))
tmp_df = df.sort_values('Class')
plt.bar(np.arange(len(df)), tmp_df['Pooled 1'], color = tmp_df['Color'])

它几乎产生了所需的输出:

我想要一个名称为Class 和颜色为Color 的图例。我知道 seaborn 可以使用 barplot 做到这一点,但它不会遵循所需的颜色。我不知道为什么,但barplot 需要很长时间来绘制数据集。不过 Matplotlib 超级快。

在这种情况下添加图例的最佳方法是什么?提前致谢!

【问题讨论】:

【参考方案1】:

您可以为每个类的第一个条分配一个标签。 Matplotlib 将使用这些标签来创建图例:

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

df = pd.DataFrame('tic': 0: 'A', 1: 'AAPL', 2: 'ABC', 3: 'ABT', 4: 'ADBE', 5: 'ADI', 6: 'ADM', 7: 'ADP', 8: 'ADSK', 9: 'AEE', 'Class': 0: 'Manufacturing', 1: 'Tech', 2: 'Trade', 3: 'Manufacturing', 4: 'Services', 5: 'Tech', 6: 'Manufacturing', 7: 'Services', 8: 'Services', 9: 'Electricity and Transportation', 'Color': 0: 'blue', 1: 'teal', 2: 'purple', 3: 'blue', 4: 'red', 5: 'teal', 6: 'blue', 7: 'red', 8: 'red', 9: 'orange', 'Pooled 1': 0: 0.0643791550056838, 1: 0.05022103288830682, 2: 0.039223739393748916, 3: 0.036366693834970217, 4: 0.05772708899447428, 5: 0.05969899935101172, 6: 0.04568101605219955, 7: 0.04542272002937567, 8: 0.07138013872431757, 9: 0.029987722053015278)
fig, ax = plt.subplots(1, 1, figsize=(14, 5))
tmp_df = df.sort_values('Class')
bars = ax.bar(tmp_df['tic'], tmp_df['Pooled 1'], color=tmp_df['Color'])
prev = None
for cl, color, bar in zip(tmp_df['Class'], tmp_df['Color'], bars):
    if cl != prev:
        bar.set_label(cl)
        prev = cl
ax.margins(x=0.01)
ax.legend(title='Class', bbox_to_anchor=(1.01, 1.01), loc='upper left')
plt.tight_layout()
plt.show()

PS:请注意,您也可以使用 Seaborn 并让着色自动进行:

import seaborn as sns

sns.barplot(data=tmp_df, x='tic', y='Pooled 1', hue='Class', palette='tab10', dodge=False, saturation=1, ax=ax)

【讨论】:

感谢您的回答! seaborn 解决方案当然更好。但是,绘制我的数据集需要一段时间。为什么 seaborn 比普通的 matplotlib 慢得多? 也许 seaborns 会为每个 x 值尝试所有可能的色调值?

以上是关于如何使用 Matplotlib 或 Seaborn 根据不同的组指定图例的主要内容,如果未能解决你的问题,请参考以下文章

如何在 matplotlib 或 seaborn 中创建带有系列的堆叠条形图? [复制]

使用 seaborn 或 matplotlib 分组箱线图的数据格式

使用 pandas/matplotlib 或 seaborn 排序的条形图

创建使用百分比而不是计数的 matplotlib 或 seaborn 直方图?

Matplotlib 直方图或 Seaborn 分布图的 bin 上没有轮廓

如何在不更改 matplotlib 默认值的情况下使用 seaborn?