189 8069 5689

怎么利用Python绘制酷炫的车辆轨迹

本篇内容主要讲解“怎么利用Python绘制酷炫的车辆轨迹”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么利用Python绘制酷炫的车辆轨迹”吧!

创新互联建站专注于企业成都营销网站建设、网站重做改版、洛隆网站定制设计、自适应品牌网站建设、成都h5网站建设成都商城网站开发、集团公司官网建设、成都外贸网站制作、高端网站制作、响应式网页设计等建站业务,价格优惠性价比高,为洛隆等各大城市提供网站开发制作服务。

问题由来

最近遇到了一类图,非常好看,并且在其他论文中也多次遇到。比如,在 Trajectory data-based traffic flow studies: A revisit 一文中的图 1 ,如下图所示1:

怎么利用Python绘制酷炫的车辆轨迹

由于原图较长,这里仅引用了部分图。从上图中可以清楚的看出几个关键信息:

  1. 横轴表示时间变化,说明数据需要是时间序列的

  2. 纵轴表示空间位置,可以理解为从离开某一道路截面后,车辆行驶的距离

  3. 每条轨迹线均表示一辆车的行驶路径变化,而线条的颜色则表示瞬时速度值

因此,如果想要绘制出上图,那么就需要有车辆的瞬时轨迹、速度、时间等信息的数据集。

2. 准备数据

为了尝试绘制出该图像,现在需要做两个工作。第一,找到合适的数据;第二,找到顺手的绘图工具。

基础数据

对于 NGSIM 数据集,作简要介绍2:其中包含 4 个路段的车辆轨迹数据,任何一个均是采用在路段的周边高层建筑上设置高清摄像机录像,然后通过图像处理,将每辆车的轨迹变化采集出来,进而可计算出车辆所在的车道、瞬时速度、瞬时加速度、瞬时车头时距等等。

作为与本次绘图相关的关键信息,我们仅需知道以下数据:

  1. 作为演示,仅使用一个车道的数据即可

  2. 每辆车从进入摄像区域到离开,中间的瞬时速度信息,NGSIM 中对应的数据标签是 v_Vel

  3. 每辆车从进入摄像区域到离开,中间的位置坐标变化,NGSIM 中对应的数据标签是 Local_X、Local_Y

  4. 与之对应的时刻,NGSIM 中对应的数据标签是 Global_Time

好了,知道了上述三个关键数据后,就可以利用绘图工具绘制了。

绘图工具

考虑到可重复性、可移植性和方便程度,本次采用 Python 中的 Matplotlib 包来绘制

3. 开始绘图

在开始绘图之前,需要在 Python 环境中已经配置好以下三个包:

Pandas,本文主要作用在于读取、处理数据

Numpy,本文主要用于科学计算

Matplotlib,本文主要用于绘图

导入必要的包

毫无疑问,这几个包是会被用到的,因此,我们先在程序中导入它们:

import pandas as pd
import numpy as np
import matplotlib
import matplotlib.pyplot as plt

准备数据

然后,我们需要将包含时间、位移、速度的数据导入 Python 中。这里需要注意,按照常规思路,我们只需将这三类数据赋值给不同变量即可,但本次绘制的图则不能直接这样做。

因为,从图 1 中我们可以看出,该图是有很多轨迹线组成的,也就是说每辆车都是一组数据,并且依赖于时间变化,且存在先后顺序。

比如,同一车道内,1 号先进入研究区域,那么它的数据则被记录;随后,2 号车进入研究区域,同样被记录位置变化、瞬时速度、时间。但是,这里的时间是不同的,是逐渐推移的。

一个思路是同时将所有车辆绘制在:X 轴是时间变化,Y 轴是位置变化的图像中。但是,这个操作需要将每辆车的数据均准备好,这对于同时绘制 300~400 辆车的轨迹图是不现实的。

为了解决这个问题,一个可行的思路是:循环绘制每辆车的轨迹随时间变化。这样可以只读取一次数据,然后依据车辆 ID 来循环绘制在同一坐标象限内。由于每辆车存在先后顺序,因此无需担心每辆车之间的轨迹重叠。

于是,这一步我们需要做的是:

  1. 读取基础数据集,并筛选出需要使用的某车道数据,比如车道 3

  2. 需要将该车道中所有的车辆 ID 提取出来,并且是依据时间先后顺序排序,也就是根据数据标签 Global_Time 来排序,这个是全局时间

于是,我们可写出以下代码(所有代码可以左右滑动):

# 读取数据
data = pd.read_csv(r'F:\NGSIMData.csv')
# 提取车道数据
lanedata = data[data.Lane_ID == 3]
# 提取车辆编号
x_vehID = lanedata.drop_duplicates(['Vehicle_ID'])
# 依据 Global_Time 按照时间先后顺序排序
x_vehID = x_vehID.sort_values(by='Global_Time')
# 对排序后的车辆 ID 的索引进行重置,方便索引
x_vehID = x_vehID.reset_index(drop = True)

基本设置与绘图

到这里,我们已经将某个车道的数据提取了出来,并且将其中所有的车辆编号也提取出来了,且按照时间先后顺序。此时,仅需要按照前文说的:循环绘制每辆车的轨迹即可。在开始之前,我们需要先预设一下图的大小,以及字体属性。

# 导入字体属性相关的包或类 
from matplotlib.font_manager import FontProperties
# 预设字体类型、大小
font = FontProperties(fname=r"C:\Windows\Fonts\times.TTF", size=10)
#设置画布的尺寸
plt.figure(figsize=(10, 4))

接下来就是循环绘制轨迹图了。这里有几个问题需要解释一下:

  1. 既然是循环绘制,自然就是每次绘制的思路完全一致,具体体现在代码中

  2. 对于单次绘图,仅需通过第一个车辆 ID 索引对应所有的数据,然后将时间、位移、速度分别赋值给 x、y、v

  3. 注意,对于时间,NGSIM 给出的是时间戳格式,需要转换

  4. 注意,对于距离和速度,NGSIM 给出的单位是英尺,需要转换

  5. 时间将体现在 X 轴,距离将体现在 Y 轴,速度将体现在轨迹线的颜色上

其中,也有一个棘手的问题。那就是,假设某一车辆进入某车道一段时间后,换道至其他车道,随后过了一段时间,该车辆又换道至当前车道。这样就会出现,在时间的前半部分有轨迹线,中间部分没有轨迹线,后半部分有轨迹线。

对于这种情况,如果我们选择折线图绘制,其便会将断开的部分直接用线段连接起来,这是折线图的特征。但是,对于这类现象,我们并不期望它们是连接的,也就是没有轨迹的时间段内,最好是空白的。

为了解决这个问题,我选择了散点图。由于 NGSIM 采集数据的频率是 0.1s,数据点非常密集,也就是说对于连续的轨迹,即便我们用散点图绘制,出来的效果也是类似于折线的。比如:

怎么利用Python绘制酷炫的车辆轨迹

注意,右上角是有断开的区域的,如果是用折线图绘制,就不会出现这种应该出现的效果。

另一个问题是颜色的处理,也就是需要将每辆车的速度值对应到同一时刻的轨迹点上。而这一点,散点图中可以将散点的颜色映射给数值,也就是我们需要的,具体就是代码中的 c=v,但这个命令仅是将速度值映射给颜色。

如果要将某一颜色主题应用于轨迹图中,那么就需要做两个工作:

  1. 定义颜色主题,也就是散点图中的命令 cmap='jet_r'

  2. 因为后边我们需要设置颜色条图例,所以需要将颜色条中的颜色数值与轨迹图中的颜色归一化,让其一一对应。

我们给出这一循环绘制轨迹-速度图的代码:

i = 0
while i < (len(x_vehID)-1):
    # 循环绘制轨迹图
    cardata = lanedata[lanedata.Vehicle_ID == x_vehID[i]]
    # 将时间赋值给变量 x
    x = cardata['Global_Time']
    # 计算相对移动距离,并赋值给变量 y
    y = np.sqrt(np.square(cardata['Local_Y']) + np.square(cardata['Local_X']) )
    # 将速度赋值给变量 v,同时定义速度为颜色映射
    v = cardata['v_Vel']
    #设定每个图的colormap和colorbar所表示范围是一样的,即归一化
    norm = matplotlib.colors.Normalize(vmin=0, vmax=25)
    # 绘制散点图
    ax = plt.scatter(x,y, marker = '.', s=1, c=v, cmap='jet_r', norm = norm)

    print(i)
    i = i + 1

其中,我们对 y 值求了平方和的开方,也就是根据车辆的横纵坐标计算位移。我们还将绘制的散点图 ax = plt.scatter 赋给了 ax ,方便后边对散点图的属性进行设置。

这里需要注意的是,对于散点的绘制,我们利用循环解决。而对于坐标轴等的设置,只需设置一次,无需循环。到这里,我们可以得到一个不完美的轨迹-速度图:

三维数据用二维图像呈现,如何利用 Python 绘制酷炫的 车辆轨迹

不知为何,初步绘制出来的图的两侧存在大量的空缺,猜测可能是由于我在数据筛选阶段出了问题,又或者这些本就没有数据点。无论怎样,这样不影响我们来学习绘制该类图像。

4. 美化图像

添加颜色条图例

此时,需要再给上图加一个颜色条图例,以表示不同颜色对应的速度数值,这里只需要两行代码搞定:

# 添加颜色条
plt.clim(0, 25)
plt.colorbar()

即可得到如下所示的图像,图中修改了一下颜色主题:

怎么利用Python绘制酷炫的车辆轨迹

这里需要注意在循环绘图的代码内部的一行代码:

# 设定每个图的colormap和colorbar所表示范围是一样的,即归一化
norm = matplotlib.colors.Normalize(vmin=0, vmax=25)

该行代码决定了颜色条图例中的颜色和左边轨迹图中的颜色是一致的,也就是必须按照颜色条设定的色阶来绘制轨迹和呈现色彩。

如果没有该行代码,就算添加了颜色条的代码,绘制出来的颜色条和左边的轨迹图也不对应,大家可以试试看~

添加横纵坐标轴及刻度值

这个操作就比较常规了,根据自己需要添加即可,常规的代码随便网上搜一个就有,包括刻度值得设置等等。

这一步仅重点说明一点:就是 X 轴绘制时利用的是时间戳数据,由于数值太密集,所以图中我关掉了 X 轴的刻度值。如果想要显示如图 1 所示的时间格式,一个可行的办法是向图像中添加文字。

也就是说,手动将时间放置在想要防止的刻度下,我们先看一组代码:

# 设置 X 坐标轴刻度
plt.text(x, y, '8:05', fontproperties=font2)  
plt.text(x, y, '8:10', fontproperties=font2) 
plt.text(x, y, '8:15', fontproperties=font2)  
plt.text(x, y, '8:20', fontproperties=font2)

通过这组代码,我们便可以将制定的时间放置在图中指定的位置,基于坐标(x,y)。

最后,附上一个个人认为比较完美的图像,供大家参考:

怎么利用Python绘制酷炫的车辆轨迹

将坐标轴设置为汉字,是因为汉字与英文同时出现时比较难处理,大家可以尝试调一下。

到此,相信大家对“怎么利用Python绘制酷炫的车辆轨迹”有了更深的了解,不妨来实际操作一番吧!这里是创新互联网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!


网页名称:怎么利用Python绘制酷炫的车辆轨迹
网页路径:http://cdxtjz.cn/article/pohiod.html

其他资讯