在 Pandas/Matplotlib 上输入图例后命名堆叠条

Name stacked bars after legend entry on Pandas/Matplotlib

我有一个堆积条形图,它非常适合我正在寻找的内容。我的问题是处理标签。

我可以在其值(数字)之后标记每个堆叠条,但我希望在其名称(在图例上)之后标记它。

有没有人知道如何解决这个问题?

ps.: 不幸的是我还不能 post 图片。

I have something like this:
    ####
    #15#
    ####
    oooo        ####
    oooo        #35#
    o55o        ####
    oooo        ####
    oooo        o12o


And need like this:
    ####
    #### A
    ####
    oooo        ####
    oooo B      #### A
    oooo        ####
    oooo        oooo B

我写了一个简短的例子,请看下面的代码:

import numpy as np
import matplotlib.pyplot as plt

# Some data
x  = np.array([0, 1, 2])
y1 = np.array([3, 4, 1])
y2 = np.array([2, 2, 4])

# label text
label_y1 = 'y1'
label_y2 = 'y2'

# Create the base plot
fig, ax = plt.subplots()

bars_y1 = ax.bar(x, y1, width=0.5, label=label_y1)
bars_y2 = ax.bar(x, y2, width=0.5, label=label_y2, bottom=y1)

# Function to add labels to the plot
def add_labels(ax, bars, label):
    for bar in bars:
        # Get the desired x and y locations
        xloc = bar.get_x() + 1.05 * bar.get_width()
        yloc = bar.get_y() + bar.get_height() / 2
        
        ax.annotate(label, xy=(xloc, yloc), va='center', ha='left', color=bar.get_facecolor())


# Add the labels in the plot
add_labels(ax, bars_y1, label_y1)
add_labels(ax, bars_y2, label_y2)

plt.show()

首先,我生成了一些虚拟数据(xy1y2)。然后,我定义了所需的标签文本(label_y1label_y2),最后我使用 Axes.bar 制作基本条形图。请注意,我存储了来自 Axes.bar 调用的 return 值,它是一个包含所有柱的容器!

现在,我们进入有趣的部分。我定义了一个名为 add_labels 的函数。作为输入,它采用感兴趣的轴、一个包含所有条形图和所需标签文本的容器。在函数体中,我遍历所有条形并确定标签文本所需的 x 和 y 位置。使用这些值,我使用 Axes.annotate 方法将标签文本放置在这些坐标处。在脚本的末尾,我只需调用带有所需参数的 add_labels 函数即可获得以下输出:

这是您要找的吗?

根据 Dex 的回答,我想出了一个解决方案。 使用补丁,它将从图表中获取每一个柱。这些条按行排列。所以如果你有一个 4x3 数据框:

   zero  um  dois
0     a   b     c
1     d   e     f
2     g   h     i
3     j   k     l

bars.patches 将每一列依次排列:[a,d,g,j,b,e,h,k,c,f,i,l]

因此,每 4 个项目(行),它会重新启动。为此,我们可以根据 df:

上的行数使用 mod 函数 (%)
i % len(df.index)  == 0   #moves position counter to the next column name

代码最终是这样的:

import pandas as pd
import numpy as np

# Some data
x  = np.array(['zero', 'um', 'dois'])
y = np.array([[3, 4, 8],[2, 2, 4],[6, 7, 8]])

df = pd.DataFrame(y, columns = x)

print(df)

   zero  um  dois
0     3   4     8
1     2   2     4
2     6   7     8



title = 'Chart Title'
bars = df.plot.bar(ax = ax, stacked = True, title = title, legend = False)

plt.xlabel('x axis label')

pos = -1
for i, bar in enumerate(bars.patches):     #runs through every single bar on the chart
    if i % len(df.index) == 0:             #based on lenght of the index, gets which label 
        pos += 1                           #to use from the columns. Returning to the 
                                           #first after completing a row
        
    xloc = bar.get_x()                     
    yloc = bar.get_y() + bar.get_height() / 2
    if bar.get_height() > 30:
        ax.annotate(str(df.columns[pos]), xy = (xloc, yloc), va='center', ha='left')

                        #df.columns[pos] will get the correct column name


因此,无论数据框的大小如何,它都会在条形旁边绘制列名称

图表示例: https://i.stack.imgur.com/2iHau.png