我想绘制堆叠条形图。前 3 个条是红色、黑色和蓝色,如下所示。
我想添加第四个条,它是红色、黑色和蓝色条的值的“总和”。
(在另一种情况下,我想添加第四个条,它是红色、黑色和蓝色条的“平均值”。)
例如,这是我的代码:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(19680801)
n_bins = 20
x = np.random.randn(1000, 3)
fig, ax0 = plt.subplots(nrows=1, ncols=1)
colors = ['red', 'black', 'blue']
ax0.hist(x, n_bins, density=True, histtype='bar', color=colors, label=colors)
ax0.legend(prop={'size': 10})
ax0.set_title('bars with legend')
fig.tight_layout()
plt.show()
关于如何在此堆栈条形图中显示第 4 个条有什么建议吗?
np.histogram
计算每组的hist
和bin_edges
,计算每组的总和和平均值,并绘制带有每个箱子绝对条高的条形图。
pandas.DataFrame
和 pandas.DataFrame.plot
.
测试于
python 3.11.2
、pandas 2.0.1
、matplotlib 3.7.1
、numpy 1.24.3
import numpy as np
import pandas as pd
# data
np.random.seed(19680801)
n_bins = 20
x = np.random.randn(1000, 3)
# calculate bin_edges for the combined values
_, be = np.histogram(x, bins=n_bins, density=True)
# calculate hist for each sample
data = {f's{i}': np.histogram(col, bins=be, density=True)[0] for i, col in enumerate(x.T)}
# round the values of the bin edges to be used as xtick labels in the plot
be = be.round(1)
# stack the arrays for each bin group
groups = np.column_stack(list(data.values()))
# calculate the total
data['tot'] = groups.sum(axis=1)
# calculate the mean
data['mean'] = groups.mean(axis=1)
# create a dataframe from data
df = pd.DataFrame(data=data)
# plot
ax = df.plot(kind='bar', width=0.85, ec='k', figsize=(11, 6), rot=0)
# update the xticks by shifting them to the right by 0.5, and updating the labels
ax.set_xticks(ticks=np.arange(0, len(be))-0.5, labels=be)
# add some cosmetics
ax.grid(axis='x')
ax.spines[['right', 'top']].set_visible(False)
_ = ax.legend(bbox_to_anchor=(1, 0.5), loc='center left', frameon=False)
.iloc
或 y=['s0', 's1', 's2', 'mean']
选择要绘制的特定列。# plot
ax = df.iloc[:, [0, 1, 2, 4]].plot(kind='bar', width=0.85, ec='k', figsize=(14, 6), rot=0)
# add some cosmetics
ax.set_xticks(ticks=np.arange(0, len(be))-0.5, labels=be)
ax.grid(axis='x')
ax.spines[['right', 'top']].set_visible(False)
_ = ax.legend(bbox_to_anchor=(1, 0.5), loc='center left', frameon=False)
# add some labels
for c in ax.containers:
ax.bar_label(c, fmt=lambda x: f'{x:0.3f}' if x > 0.005 else '', label_type='edge', fontsize=6, rotation=90, padding=3)
ax.margins(y=0.15)