如何在宽数据框中的单个图中创建分组条形图

How to create grouped bar plots in a single figure from a wide dataframe

我有以下 df:

test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})

我想绘制(理想情况下,在一个图表中)数据,因此我可以分别比较每一行(每个名称)的 res1 和 res2。

我曾尝试实现类似的东西,但我想有一个更简单、更优雅的解决方案,它还可以让我将所有内容都放在一个图表中,并在 x 轴上将名称作为一个组。

    plt.subplot(1, 3, i+1)
    sns.barplot(x=test_df.iloc[i,1:].index.tolist(), y=test_df.iloc[i,1:].values.tolist())
    plt.title(test_df.iloc[i,0])

可以更轻松地格式化数据,但可以通过将数据格式转换为垂直格式并指定条形图来将其表示为单个图形。

import pandas as pd
import seaborn as sns

test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})
df = test_df.set_index('name').unstack().to_frame(name='values')
df.reset_index(inplace=True)
df.rename(columns={'level_0':'categ'}, inplace=True)
sns.barplot(x='name', y='values', hue='categ', data=df)
categ name values
0 res1 a 1
1 res1 b 2
2 res1 c 3
3 res2 a 4
4 res2 b 5
5 res2 c 6

  • 这可以通过 seaborn.barplot 或仅使用 pandas.DataFrame.plot 来完成,这样可以避免额外的导入。
  • 所示标注
    • 使用 .bar_label 添加注释,matplotlib 3.4.2 可用。
    • link 还展示了在使用 matplotlib 的早期版本时如何添加注释。
  • 使用 pandas 1.3.0matplotlib 3.4.2seaborn 0.11.1

pandas.DataFrame.plot

  • 此选项需要将 name 作为索引值,或将 res1res2 作为索引。
import pandas as pd

test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})

# display(test_df)
  name  res1  res2
0    a     1     4
1    b     2     5
2    c     3     6

# set name as the index
test_df.set_index('name', inplace=True)

# display(test_df)
      res1  res2
name            
a        1     4
b        2     5
c        3     6

# plot and annotate
p1 = test_df.plot(kind='bar', rot=0)

for p in p1.containers:
    p1.bar_label(p, fmt='%.1f', label_type='edge')

import pandas as pd

test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})

# set name as the index and then Transpose the dataframe
test_df = test_df.set_index('name').T

# display(test_df)
name  a  b  c
res1  1  2  3
res2  4  5  6

# plot and annotate
p1 = test_df.plot(kind='bar', rot=0)

for p in p1.containers:
    p1.bar_label(p, fmt='%.1f', label_type='edge')

seaborn.barplot

import pandas as pd
import seaborn as sns

test_df = pd.DataFrame({'name': ['a', 'b', 'c'], 'res1': [1,2,3], 'res2': [4,5,6]})

# melt the dataframe into a long form
test_df = test_df.melt(id_vars='name')

# display(test_df.head())
  name variable  value
0    a     res1      1
1    b     res1      2
2    c     res1      3
3    a     res2      4
4    b     res2      5

# plot the barplot using hue; switch the columns assigned to x and hue if you want a, b, and c on the x-axis.
p1 = sns.barplot(data=test_df, x='variable', y='value', hue='name')

# add annotations
for p in p1.containers:
    p1.bar_label(p, fmt='%.1f', label_type='edge')
  • x='variable', hue='name'

  • x='name', hue='variable'