【问题标题】:How to plot and annotate a grouped bar chart如何绘制和注释分组条形图
【发布时间】:2025-11-26 17:50:02
【问题描述】:

我遇到了一个关于 Python 中的 matplotlib 的棘手问题。我想创建一个包含多个代码的分组条形图,但图表出错了。你能给我一些建议吗?代码如下。

import numpy as np
import pandas as pd
file="https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/DV0101EN/labs/coursera/Topic_Survey_Assignment.csv"
df=pd.read_csv(file,index_col=0)

df.sort_values(by=['Very interested'], axis=0,ascending=False,inplace=True)

df['Very interested']=df['Very interested']/2233
df['Somewhat interested']=df['Somewhat interested']/2233
df['Not interested']=df['Not interested']/2233
df

df_chart=df.round(2)
df_chart

labels=['Data Analysis/Statistics','Machine Learning','Data Visualization',
       'Big Data (Spark/Hadoop)','Deep Learning','Data Journalism']
very_interested=df_chart['Very interested']
somewhat_interested=df_chart['Somewhat interested']
not_interested=df_chart['Not interested']

x=np.arange(len(labels))
w=0.8

fig,ax=plt.subplots(figsize=(20,8))
rects1=ax.bar(x-w,very_interested,w,label='Very interested',color='#5cb85c')
rects2=ax.bar(x,somewhat_interested,w,label='Somewhat interested',color='#5bc0de')
rects3=ax.bar(x+w,not_interested,w,label='Not interested',color='#d9534f')

ax.set_ylabel('Percentage',fontsize=14)
ax.set_title("The percentage of the respondents' interest in the different data science Area",
            fontsize=16)
ax.set_xticks(x)
ax.set_xticklabels(labels)
ax.legend(fontsize=14)

def autolabel(rects):
    """Attach a text label above each bar in *rects*, displaying its height."""
    for rect in rects:
        height = rect.get_height()
        ax.annotate('{}'.format(height),
                    xy=(rect.get_x() + rect.get_width() / 3, height),
                    xytext=(0, 3),  # 3 points vertical offset
                    textcoords="offset points",
                    ha='center', va='bottom')


autolabel(rects1)
autolabel(rects2)
autolabel(rects3)

fig.tight_layout()

plt.show()

这个代码模块的输出真的是一团糟。但我期望的应该看起来像图片中的条形图。您能告诉我代码中哪一点不正确吗?

【问题讨论】:

    标签: python pandas matplotlib bar-chart


    【解决方案1】:

    导入和数据帧

    import pandas as pd
    import matplotlib.pyplot as plt
    
    # given the following code to create the dataframe
    file="https://s3-api.us-geo.objectstorage.softlayer.net/cf-courses-data/CognitiveClass/DV0101EN/labs/coursera/Topic_Survey_Assignment.csv"
    df=pd.read_csv(file, index_col=0)
    
    df.sort_values(by=['Very interested'], axis=0, ascending=False, inplace=True)
    
    # all columns are being divided by 2233 so those lines can be replace with the following single line
    df = df.div(2233)
    
    # display(df)
                                Very interested  Somewhat interested  Not interested
    Data Analysis / Statistics         0.755934             0.198836        0.026870
    Machine Learning                   0.729512             0.213614        0.033139
    Data Visualization                 0.600090             0.328706        0.045678
    Big Data (Spark / Hadoop)          0.596507             0.326467        0.056874
    Deep Learning                      0.565607             0.344828        0.060905
    Data Journalism                    0.192118             0.484102        0.273175
    

    使用自matplotlib v3.4.2

    # your colors
    colors = ['#5cb85c', '#5bc0de', '#d9534f']
    
    # plot with annotations is probably easier
    p1 = df.plot(kind='bar', color=colors, figsize=(20, 8), rot=0, ylabel='Percentage', title="The percentage of the respondents' interest in the different data science Area")
    
    for p in p1.containers:
        p1.bar_label(p, fmt='%.2f', label_type='edge')
    

    注释资源 - 来自matplotlib v3.4.2

    matplotlib v3.4.2之前使用

    • w = 0.8 / 3 将根据当前代码解决问题。
    • 但是,使用pandas.DataFrame.plot 可以更轻松地生成绘图
    # your colors
    colors = ['#5cb85c', '#5bc0de', '#d9534f']
    
    # plot with annotations is probably easier
    p1 = df.plot.bar(color=colors, figsize=(20, 8), ylabel='Percentage', title="The percentage of the respondents' interest in the different data science Area")
    p1.set_xticklabels(p1.get_xticklabels(), rotation=0)
    
    for p in p1.patches:
        p1.annotate(f'{p.get_height():0.2f}', (p.get_x() + p.get_width() / 2., p.get_height()), ha = 'center', va = 'center', xytext = (0, 10), textcoords = 'offset points')
    

    【讨论】: