【问题标题】:How to plot and annotate grouped bars如何绘制和注释分组条
【发布时间】:2022-01-11 19:36:24
【问题描述】:

我有以下代码

import numpy as np
import matplotlib.pyplot as plt

oct_data = [10, 24, 25, 30]
nov_data = [12, 42, 21, 78]

labels = ['Account_1', 'Account_2', 'Account_3', 'Account_4']
bar_width = 0.4

rect_1 = np.arange(0, len(oct_data)*2 ,2) 
rect_2 = [x + bar_width for x in rect_1]

plt.bar(rect_1, oct_data, color='#7f6d5f', width=bar_width, edgecolor='white', label='Month_1')
plt.bar(rect_2, nov_data, color='#557f2d', width=bar_width, edgecolor='white', label='Month_2')

plt.ylabel('Cost ($)', fontsize=10)

plt.legend()
plt.show()

这给了我下图:

如您所见,我的xticks (Account_1, Account_2, ...) 没有居中。 据我了解,这个命令应该可以完成这项工作,但它没有。

plt.xticks([r + bar_width for r in range(0, len(oct_data)*2, 2)], labels)

我还想在条形图内添加高度值。通常,这就是我使用“单条”图的方式:

  for i in range(len(labels)):
    plt.text(i, oct_data[i]//2, oct_data[i], ha = 'center', color = 'black')

但这在这里不起作用。

任何帮助将不胜感激。我是 Matplotlib 的初学者。

【问题讨论】:

    标签: python matplotlib annotations bar-chart


    【解决方案1】:
    • 最简单的解决方案是使用 pandas。这将数据放在一个易于进一步分析的对象中,并且绘图 API 可以正确管理分组条的间距。
      • 与 18 行相比,此实现仅使用 6 行代码。
    • 使用pandas.DataFrame.plot,它使用matplotlib 作为默认的绘图后端。列绘制为条形组,索引是独立轴。
    • 来自matplotlib 3.4.2.bar_label 应用于条形图上的注释。
    • 有关使用.bar_label 的其他信息和示例,请参阅Adding value labels on a matplotlib bar chart,有关分组条的其他示例,请参阅How to plot and annotate a grouped bar chart
    • python 3.9.7pandas 1.3.4matplotlib 3.4.3中测试
    import pandas as pd
    import matplotlib.pyplot as plt
    
    # create a dict with the data
    data = {'October': oct_data, 'November': nov_data}
    
    # create the dataframe with the labels as the index
    df = pd.DataFrame(data, index=labels)
    
    # display(df)
               October  November
    Account_1       10        12
    Account_2       24        42
    Account_3       25        21
    Account_4       30        78
    
    # plot the dataframe
    ax = df.plot(kind='bar', figsize=(10, 6), rot=0, ylabel='Cost ($)', color=['#7f6d5f', '#557f2d'])
    
    # iterate through each group of container (bar) objects
    for c in ax.containers:
    
        # annotate the container group
        ax.bar_label(c, label_type='center')
    
    plt.show()
    

    【讨论】:

    • ....这应该是国际海事组织接受的答案。
    【解决方案2】:

    您可以使用align 选项:

    # number of data points
    num_data = len(labels)
    
    bars1 = plt.bar(range(num_data), oct_data, color='#7f6d5f', 
                    align='edge', width=-bar_width,    # align and negative width for left bars
                    edgecolor='white', label='Month_1')
    bars1 = plt.bar(range(num_data), nov_data, color='#557f2d', 
                    align='edge', width=bar_width,     # align and positive width for right bars
                    edgecolor='white', label='Month_2')
    
    # set xticks
    plt.xticks(range(num_data), labels)
    

    对于注释,建议有一个轴实例:

    fig, ax = plt.subplots()
    # other plot commands
    
    for patch in ax.patches:
        ax.text(patch.get_x() + patch.get_width()/2,
                patch.get_height()/2,
                f'{patch.get_height()}',
                verticalalignment='center', horizontalalignment='center')
    

    输出:


    更新:所有代码:

    oct_data = [10, 24, 25, 30]
    nov_data = [12, 42, 21, 78]
    
    labels = ['Account_1', 'Account_2', 'Account_3', 'Account_4']
    bar_width = 0.4
    
    fig, ax = plt.subplots()
    
    # number of data points
    num_data = len(labels)
    
    bars1 = plt.bar(range(num_data), oct_data, color='#7f6d5f', 
                    align='edge', width=-bar_width,    # align and negative width for left bars
                    edgecolor='white', label='Month_1')
    bars1 = plt.bar(range(num_data), nov_data, color='#557f2d', 
                    align='edge', width=bar_width,     # align and positive width for right bars
                    edgecolor='white', label='Month_2')
    
    for patch in ax.patches:
        ax.text(patch.get_x() + patch.get_width()/2,
                patch.get_height()/2,
                f'{patch.get_height()}',
                verticalalignment='center', horizontalalignment='center')
    
    # set xticks
    plt.xticks(range(num_data), labels)
    plt.ylabel('Cost ($)', fontsize=10)
    
    plt.legend()
    plt.show()
    

    【讨论】:

    • 感谢@Quang Hoang!我实际上无法使用您发布的代码获得与您相同的结果。您介意发布您的整个解决方案吗?
    • @Mornor 查看更新的答案
    • 在 matplotlib 3.5 中使用 bar_label 变得更加容易
    猜你喜欢
    • 2020-12-09
    • 2020-11-23
    • 2021-12-20
    • 2021-01-12
    • 2020-11-17
    • 2018-01-06
    • 2021-11-25
    • 1970-01-01
    相关资源
    最近更新 更多