如何用Python实现柱状图内嵌套堆叠柱状图?
问题
我已经绘制出展示数据集中各字母(X轴)占比(Y轴)的柱状图,现在需要在每个柱子内部嵌入堆叠柱状图,以此展示每个字母对应的female、male、neutral、other、missing的占比(每类字母内部占比总和为100%)。以下是可复现代码及堆叠数据子集:
data = { 'L': 0.10128343899798979, 'A': 0.04587392402453482, 'G': 0.05204199096266515, 'V': 0.08343212549181313, 'E': 0.07848392694534645, 'S': 0.03242100922632854, 'I': 0.05353675927357696, 'K': 0.07614727763173719, 'R': 0.0878305241997835, 'D': 0.05932683882274109, 'T': 0.06166348813635036, 'P': 0.033915777537240344, 'N': 0.04120062539731629, 'Q': 0.03858907616445887, 'F': 0.033073896534542895, 'Y': 0.04503204302183736, 'M': 0.018126213425424805, 'H': 0.04008384447537069, 'C': 0.0014947683109118087, 'W': 0.016442451420029897 } import matplotlib.pyplot as plt plt.bar(range(len(data)), list(data.values()), align='center') plt.xticks(range(len(data)), list(data.keys())) # 堆叠柱状图数据子集 # index,female,male,neutral,other,missing # L,0.40816326530612246,0.30612244897959184,0.02040816326530612,0.0,0.2653061224489796 # A,0.34615384615384615,0.34615384615384615,0.0,0.0,0.3076923076923077 # G,0.2962962962962963,0.1111111111111111,0.037037037037037035,0.0,0.5555555555555556 # V,0.20833333333333334,0.5625,0.020833333333333332,0.0,0.20833333333333334 # E,0.5,0.225,0.025,0.0,0.25
解决方案
核心思路是用字母的总占比乘以对应分类的内部占比,得到每个分类在总柱子中的实际高度,再通过堆叠柱状图的方式逐层绘制。完整实现代码如下:
import matplotlib.pyplot as plt # 总占比数据 data = { 'L': 0.10128343899798979, 'A': 0.04587392402453482, 'G': 0.05204199096266515, 'V': 0.08343212549181313, 'E': 0.07848392694534645, 'S': 0.03242100922632854, 'I': 0.05353675927357696, 'K': 0.07614727763173719, 'R': 0.0878305241997835, 'D': 0.05932683882274109, 'T': 0.06166348813635036, 'P': 0.033915777537240344, 'N': 0.04120062539731629, 'Q': 0.03858907616445887, 'F': 0.033073896534542895, 'Y': 0.04503204302183736, 'M': 0.018126213425424805, 'H': 0.04008384447537069, 'C': 0.0014947683109118087, 'W': 0.016442451420029897 } # 堆叠占比数据(示例中补充了未给出的字母默认值,实际需替换为真实数据) stack_data = { 'L': {'female': 0.40816326530612246, 'male': 0.30612244897959184, 'neutral': 0.02040816326530612, 'other': 0.0, 'missing': 0.2653061224489796}, 'A': {'female': 0.34615384615384615, 'male': 0.34615384615384615, 'neutral': 0.0, 'other': 0.0, 'missing': 0.3076923076923077}, 'G': {'female': 0.2962962962962963, 'male': 0.1111111111111111, 'neutral': 0.037037037037037035, 'other': 0.0, 'missing': 0.5555555555555556}, 'V': {'female': 0.20833333333333334, 'male': 0.5625, 'neutral': 0.020833333333333332, 'other': 0.0, 'missing': 0.20833333333333334}, 'E': {'female': 0.5, 'male': 0.225, 'neutral': 0.025, 'other': 0.0, 'missing': 0.25}, 'S': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'I': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'K': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'R': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'D': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'T': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'P': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'N': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'Q': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'F': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'Y': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'M': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'H': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'C': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0}, 'W': {'female': 0.0, 'male': 0.0, 'neutral': 0.0, 'other': 0.0, 'missing': 1.0} } # 定义分类顺序和对应颜色 categories = ['female', 'male', 'neutral', 'other', 'missing'] colors = ['#FF9AA2', '#FFB7B2', '#FFDAC1', '#E2F0CB', '#B5EAD7'] # 获取字母列表和X轴索引 letters = list(data.keys()) x_indices = range(len(letters)) # 初始化堆叠底部位置 bottom = [0] * len(letters) # 逐个绘制分类的堆叠部分 for cat, color in zip(categories, colors): # 计算当前分类的实际高度:总占比 × 内部占比 heights = [data[letter] * stack_data[letter][cat] for letter in letters] # 绘制堆叠柱 plt.bar(x_indices, heights, bottom=bottom, color=color, label=cat) # 更新底部位置,为下一层堆叠做准备 bottom = [b + h for b, h in zip(bottom, heights)] # 设置X轴刻度和标签 plt.xticks(x_indices, letters) # 添加图例(放置在图表外侧避免遮挡) plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') # 添加轴标签 plt.xlabel('字母') plt.ylabel('总占比') # 调整布局,防止图例被截断 plt.tight_layout() plt.show()
关键说明
- 数据匹配:将堆叠数据整理为嵌套字典,确保每个字母的分类占比可以快速查找;如果有完整的CSV格式数据,也可以用
pandas读取后处理,效率更高。 - 堆叠逻辑:通过
bottom参数控制每一层堆叠的起始高度,最终每层高度之和等于原柱子的总高度。 - 样式优化:给不同分类分配差异化颜色,添加清晰的图例和轴标签,提升图表可读性。
内容的提问来源于stack exchange,提问作者Chiara
相关产品推荐
相关产品推荐

