本程序用于根据提供的列车时刻表数据(trainP.txt)和车站里程数据(stations.txt),模拟生成指定时间段内的列车运行图动画帧序列。程序支持多车型显示、上下行区分、实时在线统计以及底部信息面板显示。
主要特性:
- 多日模拟支持:支持跨天或长时间段的模拟。
- 车型统计可视化:实时统计在线车型数量,支持“Other”分类聚合(当车型超过39种时)。
- 全程信息显示:信息面板显示列车的全程始发站和终到站(非运行线片段起止站)。
- 图形化生成:自动生成高分辨率 PNG 图片序列,可用于合成视频。
- Python 版本:建议 Python 3.7 或更高版本。
程序依赖以下 Python 库,请在运行前通过 pip 安装:
pip install pandas matplotlib pillow numpypandas: 用于读取和处理车站数据。matplotlib: 用于绑定绘图引擎。Pillow (PIL): 用于加载和处理列车图标图片。numpy: 用于数值计算。
程序会自动尝试加载以下中文字体:SimHei (黑体), Microsoft YaHei (微软雅黑), PingFang SC 等。
- Windows: 通常自带微软雅黑,无需额外配置。
- Linux/Mac: 请确保系统已安装中文字体,否则文字可能显示为方块(Tofu)。
请确保工作目录下包含以下文件和文件夹:
/项目根目录
│
├── trainGraph_v2.py # 主程序脚本
├── stations.txt # 车站里程数据
├── trainP.txt # 列车时刻表数据
└── gallery/ # 列车图标库文件夹
├── CRH380A.png
├── CR400AF.png
├── Other.png # 必须包含,用于车型过多时的聚合显示
└── ... (其他车型图片)
用于定义线路的车站顺序和里程。
- 格式:
车站名 里程(以空格分隔) - 编码:UTF-8 或 GBK
- 里程单位:公里
- 示例:
注意:里程必须单调递增或递减,程序通过首尾站里程差判断运行方向。
上海虹桥 0 杭州东 159 南昌西 480 ...
用于定义列车时刻表。
- 格式:
- 第1行(车次头行):
车次号 始发站 终到站 停站数量 车型代码 - 后续N行(站点行):
站名 序号 到达时间 发车时间
- 第1行(车次头行):
- 时间格式:
HH:MM(24小时制),0表示不办理客运业务(如始发站无到达时间)。 - 示例:
注意:停站数量必须与后续行数一致。始发站和终到站信息用于在底部面板显示,即使该运行片段不包含全程。
G4917 上海虹桥 南昌西 6 CRH380A2710 上海虹桥 1 0 05:44 杭州东 2 06:29 06:34 衢州 3 07:43 07:45 ...
- 图片格式:仅支持
.png格式。 - 文件命名:必须与
trainP.txt中的车型代码一致(去除后四位数字后的部分,如CRH380A2710对应CRH380A.png)。 - 必须包含
Other.png:当同屏在线车型种类超过 39 种时,程序会将第 39 种及之后的车型合并为 "Other",此图片必须存在,否则聚合图标将无法显示。
在终端或命令行中执行:
python trainGraph_v2.py程序将提示输入以下参数:
- 线路名称:例如
沪昆高速铁路(直接回车使用默认名称 "线路")。 - 开始模拟时间:格式
YYYY-MM-DD HH:MM,例如2023-10-01 08:00。 - 结束模拟时间:格式
YYYY-MM-DD HH:MM,例如2023-10-01 12:00。 程序开始运行后,将在控制台输出进度,并在当前目录下生成frames文件夹(或您指定的文件夹)存放图片。
问题:旧版代码提取 stops_data 的首尾站作为始发终到,导致跨线列车或片段数据仅显示片段起止站(如仅显示 "金华->衢州")。
修复:代码现解析车次头行(parts[1] 和 parts[2])作为 origin_station 和 dest_station,并存入字典:
# 解析时刻表时
origin_station = parts[1]
dest_station = parts[2]
schedules[train_id] = {
...
'start_station': origin_station, # 全程始发
'end_station': dest_station # 全程终到
}这确保了底部信息表显示的是 G869 苍南 -> 西安北 而非 G869 金华 -> 衢州。
问题:当车型种类极多时,固定间距绘制会导致图标溢出画布,且最后一个车型标签显示异常。 修复:
- 数量判断:使用
len(sorted_models)判断车型总数。 - 聚合规则:
- 车型数 ≤ 39:全部显示。
- 车型数 > 39:保留数量最多的前 38 种车型,剩余车型合并为
Other,总数显示为 39 项。
- 图标加载:显式查找
Other.png图标。
if len(sorted_models) > 39:
first_38 = sorted_models[:38]
other_count = sum(count for _, count in sorted_models[38:])
sorted_models = first_38 + [('Other', other_count)]- 间距固定:车型图标间距强制设为
0.025,不再根据数量动态计算,保证了界面的整齐划一,也引出了上述数量限制的需求。 - 层级管理:使用
zorder管理绘图层级,确保表格线条 (25) > 表格背景 (20) > 文字 (26) > 列车图标 (5)。
如需调整界面效果,可在代码中修改以下常量:
FIG_W_INCH,FIG_H_INCH,DPI: 控制图片分辨率(默认 19.2x16.0 inch, 300 DPI,即 5760x4800 像素)。Y_DOWN_NEW,Y_UP_NEW: 控制上下行轨道的 Y 轴位置。train_spacing:draw_model_statistics函数中,控制车型图标的水平间距(默认0.025)。
TRAIN_IMG_ZOOM: 列车图标缩放比例 (默认0.168)。LABEL_FONTSIZE: 列车车次标签字号 (默认4.2)。STATION_FONTSIZE: 站名字号 (默认7)。
程序运行结束后,将在 frames 文件夹中生成序列图片:
- 文件名格式:
frame_0000.png,frame_0001.png, ... - 对应时间:每张图片对应 1 分钟的时间推进。 视频合成建议: 生成图片后,可使用 FFmpeg 等工具合成视频:
ffmpeg -framerate 30 -i frames/frame_%04d.png -c:v libx264 -r 30 -pix_fmt yuv420p output.mp4- 车型图标显示为空白:
- 检查
gallery文件夹路径是否正确。 - 检查图片文件名是否与数据中的车型代码匹配(如
CRH380A对应CRH380A.png)。 - 如果车型数超过39种,必须确保有
Other.png。
- 检查
- 站点重叠或错乱:
- 检查
stations.txt中的里程数据是否递增或递减。 - 确保
trainP.txt中的站点名在stations.txt中都能找到(程序会尝试去除“站”字匹配)。
- 检查
- 运行线消失或不连续:
- 检查时间数据是否正确,特别是跨天列车的时间逻辑。
- 检查速度计算阈值
MIN_SPEED_THRESHOLD,若某区间速度过低(如停靠时间异常长),程序会判定为异常数据而跳过该线段。