
本文教你如何基于离散行程数据(起止时间、单程距离)构建平滑、物理意义明确的累计距离-时间曲线,正确呈现行驶段(斜线)与静止段(水平线),避免断点或错误连接。
在交通轨迹分析或车队管理中,常需将多段独立行程(Trip)可视化为一条连续的时间序列曲线:横轴为真实时间(如 08:00 → 11:10),纵轴为累计行驶距离。关键在于——行驶过程中距离随时间线性增长(斜线),而车辆停驶时距离保持不变(水平线)。原始尝试中直接连接起点/终点并混用 shift() 和 repeat(),导致线条断裂、逻辑错位,无法反映真实运动状态。
下面提供一个结构清晰、可扩展的解决方案,使用 pandas + matplotlib 实现端到端绘制:
✅ 正确建模思路
- 时间标准化:将 'HH:MM' 字符串转为浮点小时(如 '08:00' → 8.0, '10:30' → 10.5),便于数值计算与绘图;
- 构建事件时间点序列:对每趟行程,按时间顺序插入 Trip_Start(距离不变→起点累计值)和 Trip_end(距离更新→新增累计值);
-
生成对应累计距离数组:
- 起点时刻:取前一段结束后的累计距离(初始为 0);
- 终点时刻:加上当前行程距离;
- 同一行程内,起点与终点间呈线性变化(但本例中因无中间采样点,可视作瞬时完成;若需匀速行驶效果,可插值);
- 绘制分段线性曲线:plt.plot() 自动连接相邻点,天然形成“水平→斜升→水平”的阶梯式上升形态。
? 完整可运行代码
import pandas as pd
import matplotlib.pyplot as plt
# 原始数据(建议用 DataFrame 而非 dict,便于后续扩展)
df = pd.DataFrame({
'veh_ID': [102, 102],
'Trip_ID': [1, 2],
'Trip_Start': ['08:00', '11:00'],
'Trip_end': ['10:00', '11:10'],
'Travel distance': [12, 1]
})
def plot_cumulative_distance(df, vehicle_id=None):
# 可选:筛选特定车辆
if vehicle_id is not None:
df = df[df['veh_ID'] == vehicle_id].copy()
# 时间解析函数:HH:MM → 小时数(float)
def time_to_hours(t_str):
h, m = map(int, t_str.split(':'))
return h + m / 60.0
# 构建事件序列:每个 Trip 产生两个时间点(Start → End)
times = []
distances = []
cum_dist = 0.0
# 按 Trip_Start 排序确保时间顺序
df = df.sort_values('Trip_Start').reset_index(drop=True)
for _, row in df.iterrows():
start_time = time_to_hours(row['Trip_Start'])
end_time = time_to_hours(row['Trip_end'])
# 【关键】添加起点:此时距离仍为上一段结束值(初始为 0)
times.append(start_time)
distances.append(cum_dist)
# 【关键】添加终点:距离累加当前行程
times.append(end_time)
cum_dist += row['Travel distance']
distances.append(cum_dist)
# 绘图
plt.figure(figsize=(10, 5))
plt.plot(times, distances, marker='o', linestyle='-', linewidth=2, markersize=6)
plt.xlabel('Time (hours from midnight)', fontsize=12)
plt.ylabel('Cumulative Distance (km)', fontsize=12)
plt.title(f'Cumulative Distance vs Time — Vehicle {vehicle_id or "All"}', fontsize=14)
plt.grid(True, alpha=0.3)
# 可选:美化 x 轴刻度显示为 HH:MM
def hours_to_hm(x, _):
h = int(x)
m = int((x - h) * 60)
return f'{h:02d}:{m:02d}'
plt.gca().xaxis.set_major_formatter(plt.FuncFormatter(hours_to_hm))
plt.tight_layout()
plt.show()
# 调用绘图
plot_cumulative_distance(df, vehicle_id=102)⚠️ 注意事项与进阶提示
- 时间格式鲁棒性:生产环境中建议使用 pd.to_datetime() 处理更复杂格式(含日期),再提取 .dt.hour + .dt.minute/60;
- 匀速行驶可视化:若需体现“行程中距离随时间均匀增加”,可在 start_time 与 end_time 之间插入等间距时间点,并线性插值距离(使用 np.linspace);
- 多车对比:外层循环遍历 df['veh_ID'].unique(),配合 plt.gca().set_prop_cycle() 切换颜色;
- 性能优化:大数据量时,避免逐行循环,改用 apply + explode 构造长格式事件表。
该方法直击问题本质——将离散行程建模为时间轴上的“状态跃迁事件”,生成的曲线严格符合物理运动逻辑,是交通时序可视化中的标准实践。










