【问题标题】:Display the value of the bar on each bar, wrong place在每根柱子上显示柱子的值,位置不对
【发布时间】:2020-08-09 15:19:57
【问题描述】:

我有一个这样的 DF:


    Day Destiny Flight  Year
0   10    AJU    1504   2019
1   10    AJU    1502   2020
2   10    FOR    1524   2019
3   10    FOR    1522   2020
4   10    FOR    1528   2019

我正在使用此代码绘制图表以并排比较每个目的地的年份。它运行良好。

df.groupby(["Destiny","Year"])["Flight"].count().unstack().plot.bar(figsize=(12, 3))

我有另一个在条形顶部绘制值。但它在错误的地方密谋。

a = df.groupby(["Destiny","Year"])["Flight"].count().unstack().plot.bar(figsize=(12, 3))

for i, v in enumerate(df.groupby(["Destiny","Year"])["Flight"].count()):
     a.text(v, i, str(v))

如何正确显示每个条上的条值?

我一直在寻找类似的东西,但我没有找到它。

【问题讨论】:

标签: matplotlib seaborn


【解决方案1】:

更新:

matplotlib 3.4 版本增加了函数bar_label,可以在下面的代码中合并如下:

for bar_group in ax.containers:
    ax.bar_label(bar_group, fmt='%.0f', size=18)

旧答案:

您可以遍历生成的条,并使用它们的 x、高度和宽度来定位文本。在字符串中添加空行有助于独立于比例定位文本。 ax.margins() 可以在条形上方添加一些空间以使文本适合。

from matplotlib import pyplot as plt
import pandas as pd

df = pd.DataFrame({'Destiny': ['AJU','AJU','FOR','FOR','FOR' ],
                   'Flight':range(1501,1506),
                   'Year':[2019,2020,2019,2020,2019]})
ax = df.groupby(["Destiny","Year"])["Flight"].count().unstack().plot.bar(figsize=(12, 3))

for p in ax.patches:
    x = p.get_x()
    h = p.get_height()
    w = p.get_width()
    ax.annotate(f'{h:.0f}\n', (x + w/2, h), ha='center', va='center', size=18)
plt.margins(y=0.2)
plt.tight_layout()
plt.show()

【讨论】:

    【解决方案2】:

    下面的add_value_labels函数来自justfortherec,非常好用,只需将matplotlib.axes.Axes对象传递给它:

    import pandas as pd
    import matplotlib.pyplot as plt
    
    
    def add_value_labels(ax, spacing=5):
        """Add labels to the end of each bar in a bar chart.
    
        Arguments:
            ax (matplotlib.axes.Axes): The matplotlib object containing the axes
                of the plot to annotate.
            spacing (int): The distance between the labels and the bars.
        """
    
        # For each bar: Place a label
        for rect in ax.patches:
            # Get X and Y placement of label from rect.
            y_value = rect.get_height()
            x_value = rect.get_x() + rect.get_width() / 2
    
            # Number of points between bar and label. Change to your liking.
            space = spacing
            # Vertical alignment for positive values
            va = 'bottom'
    
            # If value of bar is negative: Place label below bar
            if y_value < 0:
                # Invert space to place label below
                space *= -1
                # Vertically align label at top
                va = 'top'
    
            # Use Y value as label and format number with one decimal place
            label = "{:.1f}".format(y_value)
    
            # Create annotation
            ax.annotate(
                label,                      # Use `label` as label
                (x_value, y_value),         # Place label at end of the bar
                xytext=(0, space),          # Vertically shift label by `space`
                textcoords="offset points", # Interpret `xytext` as offset in points
                ha='center',                # Horizontally center label
                va=va)                      # Vertically align label differently for
                                            # positive and negative values.
    
    df = pd.read_csv("1.csv")
    
    ax = df.groupby(["Destiny","Year"])["Flight"].count().unstack().plot.bar(figsize=(12, 3))
    
    # Call the function above. All the magic happens there.
    add_value_labels(ax)
    
    plt.show()
    

    【讨论】:

    • 非常感谢您的时间和回答。非常感谢
    【解决方案3】:

    我认为我们可以调整@JohanC 引用的this answer 来解决您的问题。

    import pandas as pd
    import seaborn as sn
    import matplotlib.pyplot as plt
    from decimal import Decimal
    
    df = pd.DataFrame({'Day':[10]*5, 'Destiny':['AJU']*2+['FOR']*3, 'Flight':[1504,1502,1524,1522,1528],'Year':[2019,2020,2019,2020,2019]})
    df.groupby(["Destiny","Year"])["Flight"].count().unstack().plot.bar(figsize=(12, 3))
    
    a = df.groupby(["Destiny","Year"])["Flight"].count().unstack().plot.bar(figsize=(12, 3))
    
    for p in a.patches:
        a.annotate('{}'.format(Decimal(str(p.get_height()))), (p.get_x(), p.get_height()))
    
    plt.show()
    

    【讨论】:

    • 非常感谢您的时间和回答。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2022-11-12
    • 2018-12-11
    • 1970-01-01
    • 1970-01-01
    • 2018-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多