【问题标题】:Creating and Annotating a Grouped Barplot in Python [duplicate]在 Python 中创建和注释分组条形图 [重复]
【发布时间】:2021-08-01 07:57:14
【问题描述】:

我正在使用以下 DataFrame,

我想创建一个类似于下图的分组条形图

X 轴上的索引值'A','B','C','D','E' 及其各自的系列(早期、过期、准时、过期)。我还想注释每个条(在每个条上写数据值)

要复制我的 DataFrame,请使用以下 sn-p:

df = pd.DataFrame.from_dict({'Early': {'A': 824, 'B': 701, 'C': 1050, 'D': 764, 'E': 993},
 'Long Overdue': {'A': 238, 'B': 270, 'C': 489, 'D': 549, 'E': 471},
 'On Time': {'A': 1021, 'B': 1025, 'C': 120, 'D': 71, 'E': 57},
 'Overdue': {'A': 493, 'B': 580, 'C': 917, 'D': 1192, 'E': 1055}}
                      )

【问题讨论】:

    标签: python matplotlib seaborn


    【解决方案1】:

    还有其他方法可以将数据格式转换为垂直格式,但我们将为该垂直数据绘制条形图。然后获取该条的 x 轴位置和高度,并对其进行注释。在我的代码中,我将文本放置在一半的高度。

    df_long = df.unstack().to_frame(name='value')
    df_long = df_long.swaplevel()
    df_long.reset_index(inplace=True)
    df_long.columns = ['group', 'status', 'value']
    
    import matplotlib.pyplot as plt
    
    fig, ax = plt.subplots(figsize=(12, 8))
    
    g = sns.barplot(data=df_long, x='group', y='value', hue='status', ax=ax)
    
    for bar in g.patches:
        height = bar.get_height()
        ax.text(bar.get_x() + bar.get_width() / 2., 0.5 * height, int(height),
                    ha='center', va='center', color='white')
    
    plt.show()
    

    【讨论】:

      【解决方案2】:

      从 3.4 版开始。在 Matplotlib 中,添加了一个新方法 Axes.bar_label 来支持这种标记任务。此方法将包含条形的BarContainer 作为参数,通常作为plt.bar 的输出获得。绘制分组条形图,pandas的@​​987654328@函数更方便;但后者不返回BarContainer。这是一个无痛的解决方案:

      import pandas as pd
      import matplotlib.pyplot as plt # 3.4.
      
      df = ...
      df.plot.bar()
      
      ax = plt.gca()
      for container in ax.containers:
          ax.bar_label(container, padding=3)
      

      让我们稍微自定义一下:

      fig, ax = plt.subplots(figsize=(8, 4))
      
      df.plot.bar(rot=0, ax=ax, zorder=2,
          color=["cornflowerblue", "yellowgreen", "gold", "salmon"])
      for container in ax.containers:
          ax.bar_label(container, padding=3)
      
      plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left',
           ncol=4, mode="expand", borderaxespad=0.)
      plt.grid(True, axis='y', c="lightgrey", zorder=0)
      ax.spines['top'].set_color('none')
      ax.spines['right'].set_color('none')
      

      【讨论】:

        【解决方案3】:

        在 for 循环中遍历每一列并绘制它们非常重要。然后重新分配列名。这是一个完整的例子。您应该能够复制并粘贴此代码,然后运行它。

        import numpy as np
        import pandas as pd
        from matplotlib import pyplot as plt
        
        # your data
        df = pd.DataFrame(
            {
                'Early': {'A': 824, 'B': 701, 'C': 1050, 'D': 764, 'E': 993},
                'Long Overdue': {'A': 238, 'B': 270, 'C': 489, 'D': 549, 'E': 471},
                'On Time': {'A': 1021, 'B': 1025, 'C': 120, 'D': 71, 'E': 57},
                'Overdue': {'A': 493, 'B': 580, 'C': 917, 'D': 1192, 'E': 1055}
            })
        
        # set the figure size
        fig, ax = plt.subplots(figsize = (10,7), dpi = 200)
        
        # select the colors you would like to use for each category
        colors = ['skyblue','goldenrod','slateblue','seagreen']
        
        # used to set the title, y, and x labels
        ax.set_title('\nTrain Times\n', fontsize = 14)
        ax.set_xlabel('\nCategories\n', fontsize = 14)
        ax.set_ylabel('\nValues\n', fontsize = 14)
        
        # create an offsetting x axis to iterate over within each group
        x_axis = np.arange(len(df))+1 
        
        # center each group of columns
        offset = -0.3                 
        
        # iterate through each set of values and the colors associated with each 
        # category
        for index, col_name, color in zip(x_axis, df.columns, colors):
            
            x = x_axis+offset
            height = df[col_name].values
        
            ax.bar(
                x, 
                height, 
                width = 0.2, 
                color = color, 
                alpha = 0.8, 
                label = col_name
            )   
            
            offset += 0.2
            
            # set the annotations
            props = dict(boxstyle='round', facecolor='white', alpha=1)
            
            for horizontal, vertical in zip(x, height):
                
                ax.text(
                    horizontal-len(str(vertical))/30, 
                    vertical+26, 
                    str(vertical), 
                    fontsize=12, 
                    bbox=props)
                
        
        # set the y limits so the legend appears above the bars
        ax.set_ylim(0, df.to_numpy().max()*1.25)
        
        # relabel the x axis
        ax.set_xticks(x_axis)                   # offset values
        ax.set_xticklabels(df.index.to_list())  # set the labels for each group
        
        # the legend can be set to multiple values. 'Best' has Matplotlib automatically set the location.
        # setting ncol to the length of the dataframe columns sets the legend horizontally by the length 
        # of the columns
        plt.legend(loc = 'best', ncol=len(df.columns), fontsize = 12)                        
        plt.show()
        

        这应该给你下面的情节。我试图将颜色与您提供的图片尽可能匹配。但是,您可以选择自己的。这是一个图表链接,并列出了所有可供您使用的颜色。 Chart of available Matplotlib colors

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-12-09
          • 2017-10-18
          • 2020-04-22
          • 1970-01-01
          • 2016-10-13
          • 2014-06-28
          • 1970-01-01
          相关资源
          最近更新 更多