
本文详解如何基于时间序列数据,绘制一条连续的累计距离-时间曲线,准确反映行驶(斜线)、停驶(原始答案中的“平段”实为行程间静止期)、停驶(水平线)及行程起止点,解决多趟行程拼接不连贯、时间解析错误等常见问题。
在交通轨迹分析或车队调度可视化中,常需将离散的行程记录(如 Trip_Start、Trip_end、Travel distance)转化为连续的时间-累计距离曲线:行驶阶段呈上升斜线(距离随时间增加),行程间隔期呈水平线(距离不变,即车辆静止)。原始代码因未正确构建时间-距离对应点序列,导致图形断裂、逻辑错位。下面提供一套健壮、可扩展的实现方案。
✅ 核心思路:构造分段线性时间序列点
我们需要将每趟行程拆解为两个关键事件点:
- 起点:(Trip_Start, 当前累计距离)
- 终点:(Trip_end, 当前累计距离 + 本趟距离)
同时,为体现“行程间停驶”,需在上一趟终点与下一趟起点之间插入一个隐式静止段——即在 (Trip_end, 累计距离) 和 (下一趟 Trip_Start, 同一累计距离) 之间画水平线。因此,完整点序列为:
[ (t0_start, 0), (t0_end, d0), (t1_start, d0), ← 停驶开始(距离不变) (t1_end, d0+d1), ... ]
✅ 完整可运行代码(支持任意多趟行程)
import matplotlib.pyplot as plt
import pandas as pd
from datetime import datetime
import numpy as np
# 示例数据(建议使用 DataFrame,便于扩展)
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, time_col_start='Trip_Start', time_col_end='Trip_end',
dist_col='Travel distance', title='Journey Plot'):
# ✅ 步骤1:按出发时间排序,确保时序正确
df = df.sort_values(by=time_col_start).reset_index(drop=True)
# ✅ 步骤2:将时间字符串转为 matplotlib 可识别的数值(单位:小时),支持跨日可扩展为 datetime
def time_to_hours(t_str):
h, m = map(int, t_str.strip().split(':'))
return h + m / 60.0
times_start = df[time_col_start].apply(time_to_hours)
times_end = df[time_col_end].apply(time_to_hours)
# ✅ 步骤3:构建 x(时间)和 y(累计距离)坐标点列表
xs, ys = [], []
cumulative = 0.0
for i, row in df.iterrows():
t_start = times_start.iloc[i]
t_end = times_end.iloc[i]
dist = float(row[dist_col])
# 行程起点:(t_start, cumulative)
xs.append(t_start)
ys.append(cumulative)
# 行程终点:(t_end, cumulative + dist)
xs.append(t_end)
ys.append(cumulative + dist)
# 更新累计距离(用于下一段)
cumulative += dist
# ✅ 关键:若非最后一趟,添加停驶过渡点 —— 下一趟开始前保持距离不变
if i < len(df) - 1:
next_t_start = times_start.iloc[i + 1]
xs.append(next_t_start)
ys.append(cumulative) # 距离不变,形成水平线
# ✅ 步骤4:绘图(使用 line plot 自动连接所有点)
plt.figure(figsize=(10, 5))
plt.plot(xs, ys, marker='o', markersize=4, linewidth=2, color='#2E86AB')
# ✅ 可选:标注行程起止点(增强可读性)
for i, (x, y) in enumerate(zip(xs, ys)):
if i % 2 == 0 and i < len(xs)-1: # 每趟起点(偶数索引)
plt.annotate(f'Start {i//2+1}', (x, y), textcoords="offset points",
xytext=(0,10), ha='center', fontsize=9, color='darkblue')
elif i % 2 == 1: # 每趟终点(奇数索引)
plt.annotate(f'End {i//2+1}', (x, y), textcoords="offset points",
xytext=(0,-15), ha='center', fontsize=9, color='crimson')
# ✅ 设置坐标轴与标题
plt.xlabel('Time (hours from 00:00)', fontsize=11)
plt.ylabel('Cumulative Distance (km)', fontsize=11)
plt.title(title, fontsize=13, fontweight='bold')
plt.grid(True, alpha=0.3)
plt.xticks(np.arange(0, 25, 1)) # 每小时刻度
plt.tight_layout()
plt.show()
# 调用绘图函数
plot_cumulative_distance(df)⚠️ 注意事项与进阶提示
- 时间格式鲁棒性:当前示例仅处理 HH:MM。若含日期(如 '2024-05-20 08:00'),应改用 pd.to_datetime() 并以 matplotlib.dates 模块处理 X 轴。
- 多车区分:对 veh_ID 分组后循环调用该函数,并用不同颜色/图例区分。
- 性能优化:大数据量时,避免 for 循环构建点;可用 np.repeat + np.concatenate 向量化生成 xs/ys。
- 视觉增强:可对行驶段用实线、停驶段用虚线,或用 plt.fill_between() 高亮活动区间。
该方法确保曲线物理意义清晰、数学连续、视觉直观,是时间序列行程可视化的核心范式。
立即学习“Python免费学习笔记(深入)”;










