Matplotlib绘制含多子图的DataFrame柱状图技术问询
基于月度分组数据绘制嵌套柱状图
原始数据
Date & Time Amount Count Aug 2022 $10.50 53 $14.00 1 $3.50 416 $35.00 186 Jul 2022 $14.00 1 $3.50 844 $35.00 307 Jun 2022 $14.00 1 $3.50 797 $35.00 323
需求
用Matplotlib绘制图表:主X轴为年月,每个年月下以金额(Amount)为子X轴,Y轴展示对应计数(Count),解决不同月份Amount数量不一致的布局问题。
解决方案
1. 数据预处理
先补全数据结构,清理金额列的符号并转为数值类型:
import pandas as pd import matplotlib.pyplot as plt # 构建示例DataFrame data = [ ["Aug 2022", "$10.50", 53], ["Aug 2022", "$14.00", 1], ["Aug 2022", "$3.50", 416], ["Aug 2022", "$35.00", 186], ["Jul 2022", "$14.00", 1], ["Jul 2022", "$3.50", 844], ["Jul 2022", "$35.00", 307], ["Jun 2022", "$14.00", 1], ["Jun 2022", "$3.50", 797], ["Jun 2022", "$35.00", 323] ] df = pd.DataFrame(data, columns=["Date & Time", "Amount", "Count"]) # 清理金额列,转为数值 df["Amount"] = df["Amount"].str.replace("$", "").astype(float) # 按月份分组 month_groups = df.groupby("Date & Time")
2. 绘制动态宽度的嵌套柱状图
核心是为每个月份分配主X轴位置,再根据该月的Amount数量动态调整子柱子宽度,避免重叠:
# 设置画布 fig, ax = plt.subplots(figsize=(10, 6)) # 主X轴的位置和月份标签 month_labels = list(month_groups.groups.keys()) month_positions = range(len(month_labels)) # 每个月份组占用的总宽度 total_group_width = 0.8 # 遍历每个月份分组 for month_idx, (month, group) in enumerate(month_groups): # 对该月的金额排序,保证柱子顺序一致 sorted_group = group.sort_values("Amount") amounts = sorted_group["Amount"] counts = sorted_group["Count"] num_bars = len(amounts) # 计算每个子柱子的宽度和位置 bar_width = total_group_width / num_bars sub_positions = [month_positions[month_idx] - total_group_width/2 + bar_width*(i + 0.5) for i in range(num_bars)] # 绘制柱子 bars = ax.bar(sub_positions, counts, width=bar_width) # 在柱子上方标注计数 for bar in bars: height = bar.get_height() ax.text(bar.get_x() + bar.get_width()/2, height, f"{int(height)}", ha="center", va="bottom") # 设置主X轴刻度和标签 ax.set_xticks(month_positions) ax.set_xticklabels(month_labels) # 设置轴标签和标题 ax.set_xlabel("年月") ax.set_ylabel("计数") ax.set_title("各月不同金额的计数分布") # 添加金额图例 unique_amounts = sorted(df["Amount"].unique()) from matplotlib.patches import Patch legend_handles = [Patch(facecolor=plt.cm.tab10(i), label=f"${amt:.2f}") for i, amt in enumerate(unique_amounts)] ax.legend(handles=legend_handles, title="金额") plt.tight_layout() plt.show()
效果说明
- 每个月份的柱子总宽度固定,子柱子宽度随该月Amount数量自动调整,保证布局紧凑且不重叠
- 金额按从小到大排序,不同月份的同金额柱子颜色统一,便于对比
- 柱子上方标注具体计数,数据展示更直观
内容的提问来源于stack exchange,提问作者javery1337
相关产品推荐
相关产品推荐

