自定义冬季年时间序列X轴调整及Python代码优化求助
问题解决:冬季年度周数折线图X轴显示优化及代码改进
问题背景
需要绘制冬季年(当年8月至次年8月)的每日事件数量折线图,X轴按35-53、1-34的顺序显示周数,每条曲线对应一个冬季年度。现有代码已生成正确排序的周索引表,但图表X轴仍按常规ISO周1-53排序:
X轴显示问题解决方法
问题核心在于:即使重新索引了周数,pandas绘图时仍会按数字索引的自然顺序(1-53)渲染X轴。要实现自定义顺序,有两种可行方案:
方案1:将周索引转为字符串
把周数转换为字符串类型,让绘图时严格遵循列表定义的顺序:
order_weeks = [str(i) for i in range(35,54)] + [str(i) for i in range(1,35)] # 先按数字索引匹配数据,再替换为字符串索引 datapiv = datapiv.reindex([int(w) for w in order_weeks]) datapiv.index = order_weeks datapiv.plot(use_index=True)
方案2:手动指定X轴刻度与标签
保留数字索引,通过matplotlib API直接控制X轴显示内容:
import matplotlib.pyplot as plt ax = datapiv.plot(use_index=True) ax.set_xticks(range(len(order_weeks))) ax.set_xticklabels(order_weeks) plt.show()
代码优化建议
1. 用矢量化操作替代apply计算冬季年度
避免循环提升运行效率,直接基于日期索引的月份批量计算:
winter_base = np.where(data.index.month > 8, data.index.year, data.index.year - 1) data["winter_year"] = "Winter " + winter_base.astype(str) + "-" + (winter_base + 1).astype(str)
2. 简化周数顺序生成
合并列表推导式,精简代码:
order_weeks = list(range(35, 54)) + list(range(1, 35))
3. 移除冗余中间列
year、date列仅用于计算冬季年度,完成后可删除以减少内存占用:
data = data.drop(columns=["year", "date"])
4. 用groupby+unstack替代pivot_table
针对简单聚合需求,该组合比pivot_table更直观高效:
datapiv = data.groupby(["week", "winter_year"])["count"].sum().unstack()
完整优化后代码
import pandas as pd import numpy as np import matplotlib.pyplot as plt # 矢量化计算冬季年度 def get_winter_year(dates): winter_base = np.where(dates.month > 8, dates.year, dates.year - 1) return "Winter " + winter_base.astype(str) + "-" + (winter_base + 1).astype(str) # 生成随机数据 np.random.seed(10) data = pd.DataFrame({ "dates": pd.date_range("2017-07-12", "2022-08-10"), "count": np.random.randint(150, size=len(pd.date_range("2017-07-12", "2022-08-10"))) }).set_index("dates") # 计算周数与冬季年度 data["week"] = data.index.isocalendar().week data["winter_year"] = get_winter_year(data.index) # 聚合并按自定义周顺序排序 datapiv = data.groupby(["week", "winter_year"])["count"].sum().unstack() order_weeks = list(range(35, 54)) + list(range(1, 35)) datapiv = datapiv.reindex(order_weeks) # 绘图并设置X轴 ax = datapiv.plot(figsize=(12, 6)) ax.set_xticks(range(len(order_weeks))) ax.set_xticklabels(order_weeks) ax.set_xlabel("冬季年度周数") ax.set_ylabel("事件总数") plt.title("冬季年度每周事件数量趋势") plt.show()
内容的提问来源于stack exchange,提问作者Aytan
相关产品推荐
相关产品推荐

