【问题标题】:How to create grouped bar plots in a single figure from a wide dataframe如何从宽数据框中在单个图中创建分组条形图
【发布时间】:2021-07-21 12:45:55
【问题描述】:

我有以下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])

【问题讨论】:

    标签: python pandas matplotlib seaborn bar-chart


    【解决方案1】:
    • 这可以使用seaborn.barplot 来完成,或者只使用pandas.DataFrame.plot,这样可以避免额外的导入。
    • 注解如How to plot and annotate a grouped bar chart所示
      • 使用.bar_label 添加注释,matplotlib 3.4.2 提供。
      • 该链接还显示了如果使用先前版本的 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'

    【讨论】:

      【解决方案2】:

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

      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

      【讨论】:

        猜你喜欢
        • 2018-12-22
        • 2021-12-23
        • 1970-01-01
        • 2019-11-11
        • 1970-01-01
        • 2022-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多