
本文详解如何在保持 30 分钟数据分辨率的前提下,仅显示整点(如 00:00、01:00…23:00)作为 x 轴刻度,并确保这些刻度严格等距、从图表最左端延伸至最右端,彻底消除首尾空白。
本文详解如何在保持 30 分钟数据分辨率的前提下,仅显示整点(如 00:00、01:00…23:00)作为 x 轴刻度,并确保这些刻度严格等距、从图表最左端延伸至最右端,彻底消除首尾空白。
在使用 matplotlib 绘制时间序列图时,一个常见需求是:数据采样频率高(如每 30 分钟一条),但只需在 X 轴上展示关键时间点(如每小时整点),且要求这些刻度均匀分布、覆盖整个横轴可视范围(即首刻度对齐左边界,末刻度对齐右边界)。直接调用 plt.xticks() 设置固定标签(如 ["00:00", "01:00", ..., "23:00"])往往会导致刻度挤在中间、两端留白严重——这是因为 Matplotlib 默认将刻度位置映射到数据索引(0, 1, 2, ..., 47),而整点实际只出现在偶数索引(0, 2, 4, ..., 46),共 24 个点;若强行指定 24 个标签却不显式指定对应的位置坐标,系统无法自动拉伸分布。
✅ 正确解法是:先让 Matplotlib 自动完成初始绘图与刻度生成,再基于其生成的原始刻度标签动态筛选出整点位置,并重设 xticks 为等间距的数值序列(0, 2, 4, ..., 46),最后同步更新标签。这样既保留了数据完整性,又实现了视觉上的均匀铺展。
以下是推荐的完整实现方案(适配您原始代码):
import pandas as pd
import matplotlib.pyplot as plt
file_path = r"C:\Users\wi9632\Desktop\Results_End_MultiOpt\Load_Profile_Figure\Combined_Table.csv"
df = pd.read_csv(file_path, sep=';', encoding='latin-1')
methods = {
"Dichotomous Method [kW]": ("Dichotomous Method", "tab:orange"),
"Conventional Control [kW]": ("Conventional Control", "tab:purple"),
"NSGA-II [kW]": ("NSGA-II", "tab:cyan"),
"SPEA-II [kW]": ("SPEA-II", "gold"),
"PALSS [kW]": ("PALSS", "red"),
"RELAPALLS [kW]": ("RELAPALLS", "lawngreen")
}
fig, axes = plt.subplots(6, 1, figsize=(12, 20), sharex=True)
# 绘制第一行:6 种方法对比
for method, (name, color) in methods.items():
axes[0].plot(df["time of day"], df[method], label=name, color=color)
axes[0].set_ylabel("Power [kW]")
axes[0].set_title("Power Profiles for Different Methods")
axes[0].legend(loc='upper center', bbox_to_anchor=(0.5, 1.15), ncol=3)
# 绘制其余子图
variables = ["Space Heating [kW]", "DHW [kW]", "Availability of the EV",
"Outside Temperature [°C]", "Price [Cent/kWh]"]
for i, variable in enumerate(variables, start=1):
axes[i].plot(df["time of day"], df[variable], color='blue')
axes[i].set_ylabel(variable)
# ? 关键步骤:精简并均匀分布 X 轴刻度(整点)
# 1. 先触发绘图以生成默认刻度(重要!否则 get_xticklabels() 返回空)
plt.tight_layout()
# 2. 获取底部共享 X 轴的最后一个子图(或任一共享轴的 axes[i])的刻度标签
ax_bottom = axes[-1]
original_labels = [lbl.get_text() for lbl in ax_bottom.get_xticklabels()]
# 3. 找出所有以 ":00" 结尾的时间字符串对应的原始索引位置(即 0, 2, 4, ..., 46)
hour_indices = [i for i, lbl in enumerate(original_labels) if lbl.endswith(':00')]
# 4. 构造等间距的刻度位置:从 0 到 len(df)-1 均匀取 24 个点(对应 24 小时)
# 注意:df 有 48 行(0–47),整点位于索引 0,2,4,...,46 → 共 24 个位置
tick_positions = list(range(0, len(df), 2)) # [0, 2, 4, ..., 46]
tick_labels = [f"{h:02d}:00" for h in range(24)] # ["00:00", "01:00", ..., "23:00"]
# 5. 对所有共享 X 轴的子图统一设置刻度
for ax in axes:
ax.set_xticks(tick_positions)
ax.set_xticklabels(tick_labels, rotation=0, ha='center') # 水平居中更清晰
plt.xlabel("Time of Day")
plt.tight_layout()
# 可选:进一步压缩边距(消除残余空白)
plt.subplots_adjust(bottom=0.05, top=0.95)
combined_output_path = r"C:\Users\wi9632\Desktop\Results_End_MultiOpt\Load_Profile_Figure\ParetoFronts_combined.png"
plt.savefig(combined_output_path, dpi=200, bbox_inches='tight')
plt.show()? 关键说明与注意事项:
为什么必须先 tight_layout() 再获取标签?
get_xticklabels() 依赖于已渲染的布局信息。若在绘图未完成前调用,可能返回空列表或错误索引。务必在 plot() 后、set_xticks() 前执行一次 tight_layout() 或 draw()。range(0, len(df), 2) 是核心:
数据共 48 行(00:00 到 23:30),整点严格对应索引 0, 2, 4, ..., 46。该表达式精确生成这 24 个位置,确保刻度物理间距相等,自然铺满横轴。避免使用字符串标签直接设 xticks:
错误写法 plt.xticks(["00:00","01:00",...]) 会丢失位置映射,导致刻度堆积。必须同时指定数值位置和对应标签。旋转与对齐优化:
rotation=0 + ha='center' 保证时间标签水平居中对齐刻度线,提升可读性;若空间紧张,可改用 rotation=30 并调整 plt.subplots_adjust()。扩展性提示:
若未来数据频率变化(如 15 分钟/条),只需将 range(0, len(df), 2) 改为 range(0, len(df), 4) 即可适配整点(每 4 行一个整点)。
通过上述方法,您将获得专业级的时间轴呈现效果:X 轴刻度精准对应每小时整点,视觉上均匀延展至图表左右边界,彻底解决首尾空白与刻度偏移问题,同时完全兼容高分辨率原始数据。










