在 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()
首先,我生成了一些虚拟数据(x
、y1
和 y2
)。然后,我定义了所需的标签文本(label_y1
和 label_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
我有一个堆积条形图,它非常适合我正在寻找的内容。我的问题是处理标签。
我可以在其值(数字)之后标记每个堆叠条,但我希望在其名称(在图例上)之后标记它。
有没有人知道如何解决这个问题?
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()
首先,我生成了一些虚拟数据(x
、y1
和 y2
)。然后,我定义了所需的标签文本(label_y1
和 label_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