Matplotlib:同年份多系列柱状图并列且年份间留间隔实现求助
问题与解决方案
需求
实现同一年份下不同store_type的柱状图并列展示,且不同年份的柱状图组之间保留明显间隙。
原代码问题分析
原代码中x轴位置的计算直接按年份索引乘以月份数,导致年份组之间无间隙,且同一年份内不同store_type的柱状图未实现并列布局。
修改后的代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt import calendar def plot_monthly_multiple_store2(): df = order_merged.multi_store_monthly_count([2020,2021], [1,2,3,4], ['Crizac','Ucol']) df['year'] = df['date_added'].dt.year df['month'] = df['date_added'].dt.month # 按年份、月份、门店类型统计订单数 count_df = df.groupby(['year', 'month', 'store_type'])['order_id'].count().reset_index() # 透视数据,行是(年份,月份),列是门店类型 pivot_df = pd.pivot_table(count_df, values='order_id', index=['year', 'month'], columns=['store_type'], fill_value=0) fig, ax = plt.subplots(figsize=(10, 5)) colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd'] # 按同月份内的门店数量分配柱子宽度 num_stores = len(pivot_df.columns) width = 0.7 / num_stores # 年份组之间的间隙值,可按需调整 gap_between_years = 0.5 num_months_per_year = len(pivot_df.index.levels[1]) for year_idx, year in enumerate(pivot_df.index.levels[0]): # 计算当前年份组的基础x轴位置,加入年份间隙 base_x = year_idx * (num_months_per_year + gap_between_years) # 遍历每个月份 for month_idx, month in enumerate(pivot_df.loc[year].index): # 遍历每个门店类型,计算单根柱子的x位置 for store_idx, store_type in enumerate(pivot_df.columns): x_pos = base_x + month_idx + store_idx * width count_val = pivot_df.loc[(year, month), store_type] ax.bar(x_pos, count_val, width=width, color=colors[store_idx], alpha=0.7, edgecolor='black', linewidth=0.5, label=store_type if year_idx == 0 and month_idx == 0 else None) # 添加柱子顶部的数值标签 ax.text(x_pos + width/2, count_val, str(count_val), ha='center', va='bottom', fontsize=8) # 调整x轴刻度位置,放在每个月份所有柱子的中间 tick_positions = [] tick_labels = [] for year_idx, year in enumerate(pivot_df.index.levels[0]): base_x = year_idx * (num_months_per_year + gap_between_years) for month_idx, month in enumerate(pivot_df.loc[year].index): tick_pos = base_x + month_idx + (num_stores * width)/2 tick_positions.append(tick_pos) tick_labels.append(f"{calendar.month_abbr[month]}\n{year}") ax.set_xticks(tick_positions) ax.set_xticklabels(tick_labels, fontsize=8) ax.set_xlabel('年份-月份', fontsize=12) ax.set_ylabel('订单数量', fontsize=12) ax.set_title('各月份不同门店类型的订单数量', fontsize=14) ax.legend(loc='upper left', bbox_to_anchor=(1.0, 1.0)) plt.tight_layout() plt.show()
修改说明
- 柱子宽度适配:按同月份内的门店数量分配宽度,确保同月份的多门店柱子能并列排布
- 年份间隙控制:通过
gap_between_years参数自定义不同年份组之间的空白距离,数值越大间隙越宽 - x轴位置重构:每个年份组设置独立的基础x坐标,同月份内的不同门店柱子依次偏移宽度,实现并列效果
- 刻度对齐优化:将x轴刻度放在对应月份所有柱子的中间位置,保证标签与柱子组精准对齐
内容的提问来源于stack exchange,提问作者Prakket
相关产品推荐
相关产品推荐

