
本文详解如何在保持 30 分钟数据分辨率的前提下,仅显示整点(如 00:00、01:00…23:00)的 x 轴刻度,并确保刻度从图表最左端精确延伸至最右端,彻底消除首尾空白。
本文详解如何在保持 30 分钟数据分辨率的前提下,仅显示整点(如 00:00、01:00…23:00)的 x 轴刻度,并确保刻度从图表最左端精确延伸至最右端,彻底消除首尾空白。
在使用 Matplotlib 绘制时间序列多子图时,一个常见痛点是:原始数据按 30 分钟采样(共 48 个时间点),但用户只需在 X 轴上展示 24 个整点时刻(00:00, 01:00, ..., 23:00),且要求这些刻度均匀分布、严格对齐图表边界——即首个刻度位于横轴最左像素,末个刻度紧贴最右像素。直接调用 plt.xticks() 设置 24 个标签虽能显示整点,却因底层坐标映射未同步调整,导致图表两侧出现明显空白,视觉上刻度“收缩”在中间区域。
根本原因在于:Matplotlib 默认将横轴视为数值索引(0, 1, 2, ..., 47),而 plt.xticks(range(0, 24), [...]) 仅覆盖前 24 个位置,后半段数据(索引 24–47)仍占据空间,造成右侧冗余;同时,X 轴范围(xlim)默认由数据自动设定,未强制拉伸至全部索引范围。
✅ 正确解法需三步协同:
- 明确设置 X 轴数值范围:使用 plt.xlim() 显式指定横轴起止为 0 和 len(df)-1(即索引 0 到 47),确保绘图区域完整覆盖全部数据点;
- 精准定位整点刻度位置:利用 ax.get_xticks() 获取当前自动生成的刻度位置(对应数据索引),再筛选出对应 "xx:00" 标签的索引位置;
- 统一应用到所有共享 X 轴的子图:避免仅设置最后一个子图(axes[-1])导致其他子图刻度不一致。
以下是优化后的核心代码段(已整合进完整绘图流程):
# ...(前面的数据加载与子图创建代码保持不变)...
# 关键修正:先统一设置 xlim,确保横轴铺满全宽
plt.xlim(0, len(df) - 1)
# 遍历所有子图(因 sharex=True,只需设置一次,但为保险可全设)
for ax in axes:
# 获取当前 X 轴刻度位置及对应标签
tick_locs = ax.get_xticks()
tick_labels = [label.get_text() for label in ax.get_xticklabels()]
# 筛选以 ":00" 结尾的时间标签对应的刻度位置(注意:需确保标签已生成)
# 更稳健做法:基于 df["time of day"] 字段直接提取整点索引
hour_indices = [i for i, t in enumerate(df["time of day"]) if t.endswith("00")]
# 设置新刻度位置与标签
ax.set_xticks(hour_indices)
ax.set_xticklabels([df["time of day"].iloc[i] for i in hour_indices], rotation=0)
# 共享 X 轴标签
plt.xlabel("Time of Day")
plt.tight_layout()⚠️ 注意事项:
- 不要依赖 get_xticklabels() 的初始状态:在 plt.tight_layout() 或 plt.show() 前,刻度标签可能尚未完全渲染,直接调用 .get_text() 可能返回空字符串或旧值。推荐采用 df["time of day"] 列主动查找整点索引(如上例 hour_indices),100% 可靠;
- 旋转角度建议设为 0:整点共 24 个,水平排列完全可读;若强制 rotation=90 反而加剧拥挤,且破坏对齐感;
- sharex=True 下的刻度同步:虽然逻辑上所有子图共享 X 轴,但 Matplotlib 有时不会自动同步 set_xticks 效果,因此显式遍历 axes 并设置更稳妥;
- 字体与间距微调(可选):若标签仍显拥挤,可添加 plt.rcParams['xtick.labelsize'] = 9 或使用 ax.tick_params(axis='x', pad=10) 增加标签与横轴距离。
最终效果:X 轴严格显示 24 个整点刻度,从最左侧(00:00)平滑过渡至最右侧(23:00),无任何首尾空白,所有子图横轴对齐一致,专业清晰,符合科研图表规范。










