問題由來
最近遇到了一類圖,非常好看,并且在其他論文中也多次遇到,比如,在 Trajectory data-based traffic flow studies: A revisit 一文中的圖 1 ,如下圖所示1:
由于原圖較長,這里僅參考了部分圖,從上圖中可以清楚的看出幾個關鍵資訊:
- 橫軸表示時間變化,說明資料需要是時間序列的
- 縱軸表示空間位置,可以理解為從離開某一道路截面后,車輛行駛的距離
- 每條軌跡線均表示一輛車的行駛路徑變化,而線條的顏色則表示瞬時速度值
因此,如果想要繪制出上圖,那么就需要有車輛的瞬時軌跡、速度、時間等資訊的資料集,
PS:如有需要Python學習資料的小伙伴可以加下方的群去找免費管理員領取
可以免費領取原始碼、專案實戰視頻、PDF檔案等
2. 準備資料
為了嘗試繪制出該影像,現在需要做兩個作業,第一,找到合適的資料;第二,找到順手的繪圖工具,
基礎資料
對于 NGSIM 資料集,作簡要介紹2:其中包含 4 個路段的車輛軌跡資料,任何一個均是采用在路段的周邊高層建筑上設定高清攝像機錄像,然后通過影像處理,將每輛車的軌跡變化采集出來,進而可計算出車輛所在的車道、瞬時速度、瞬時加速度、瞬時車頭時距等等,
作為與本次繪圖相關的關鍵資訊,我們僅需知道以下資料:
- 作為演示,僅使用一個車道的資料即可
- 每輛車從進入攝像區域到離開,中間的瞬時速度資訊,NGSIM 中對應的資料標簽是 v_Vel
- 每輛車從進入攝像區域到離開,中間的位置坐標變化,NGSIM 中對應的資料標簽是 Local_X、Local_Y
- 與之對應的時刻,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 來回圈繪制在同一坐標象限內,由于每輛車存在先后順序,因此無需擔心每輛車之間的軌跡重疊,
于是,這一步我們需要做的是:
- 讀取基礎資料集,并篩選出需要使用的某車道資料,比如車道 3
- 需要將該車道中所有的車輛 ID 提取出來,并且是依據時間先后順序排序,也就是根據資料標簽 Global_Time 來排序,這個是全域時間
于是,我們可寫出以下代碼(所有代碼可以左右滑動):
# 讀取資料 data = https://www.cnblogs.com/hhh188764/p/pd.read_csv(r'F:\NGSIMData.csv') # 提取車道資料 lanedata = https://www.cnblogs.com/hhh188764/p/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))
接下來就是回圈繪制軌跡圖了,這里有幾個問題需要解釋一下:
- 既然是回圈繪制,自然就是每次繪制的思路完全一致,具體體現在代碼中
- 對于單次繪圖,僅需通過第一個車輛 ID 索引對應所有的資料,然后將時間、位移、速度分別賦值給 x、y、v
- 注意,對于時間,NGSIM 給出的是時間戳格式,需要轉換
- 注意,對于距離和速度,NGSIM 給出的單位是英尺,需要轉換
- 時間將體現在 X 軸,距離將體現在 Y 軸,速度將體現在軌跡線的顏色上
其中,也有一個棘手的問題,那就是,假設某一車輛進入某車道一段時間后,換道至其他車道,隨后過了一段時間,該車輛又換道至當前車道,這樣就會出現,在時間的前半部分有軌跡線,中間部分沒有軌跡線,后半部分有軌跡線,
對于這種情況,如果我們選擇折線圖繪制,其便會將斷開的部分直接用線段連接起來,這是折線圖的特征,但是,對于這類現象,我們并不期望它們是連接的,也就是沒有軌跡的時間段內,最好是空白的,
為了解決這個問題,我選擇了散點圖,由于 NGSIM 采集資料的頻率是 0.1s,資料點非常密集,也就是說對于連續的軌跡,即便我們用散點圖繪制,出來的效果也是類似于折線的,比如:
注意,右上角是有斷開的區域的,如果是用折線圖繪制,就不會出現這種應該出現的效果,
另一個問題是顏色的處理,也就是需要將每輛車的速度值對應到同一時刻的軌跡點上,而這一點,散點圖中可以將散點的顏色映射給數值,也就是我們需要的,具體就是代碼中的 c=v,但這個命令僅是將速度值映射給顏色,
如果要將某一顏色主題應用于軌跡圖中,那么就需要做兩個作業:
- 定義顏色主題,也就是散點圖中的命令 cmap='jet_r'
- 因為后邊我們需要設定顏色條圖例,所以需要將顏色條中的顏色數值與軌跡圖中的顏色歸一化,讓其一一對應,
我們給出這一回圈繪制軌跡-速度圖的代碼:
i = 0 while i < (len(x_vehID)-1): # 回圈繪制軌跡圖 cardata = https://www.cnblogs.com/hhh188764/p/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 ,方便后邊對散點圖的屬性進行設定,
這里需要注意的是,對于散點的繪制,我們利用回圈解決,而對于坐標軸等的設定,只需設定一次,無需回圈,到這里,我們可以得到一個不完美的軌跡-速度圖:
不知為何,初步繪制出來的圖的兩側存在大量的空缺,猜測可能是由于我在資料篩選階段出了問題,又或者這些本就沒有資料點,無論怎樣,這樣不影響我們來學習繪制該類影像,
4. 美化影像
添加顏色條圖例
此時,需要再給上圖加一個顏色條圖例,以表示不同顏色對應的速度數值,這里只需要兩行代碼搞定:
# 添加顏色條 plt.clim(0, 25) plt.colorbar()
即可得到如下所示的影像,圖中修改了一下顏色主題:
這里需要注意在回圈繪圖的代碼內部的一行代碼:
# 設定每個圖的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),
最后,附上一個個人認為比較完美的影像,供大家參考:
忽略缺失資料后的效果:
將坐標軸設定為漢字,是因為漢字與英文同時出現時比較難處理,大家可以嘗試調一下,
本文的文字及圖片來源于網路,僅供學習、交流使用,不具有任何商業用途,著作權歸原作者所有,如有問題請及時聯系我們以作處理,
作者:小兵么么
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/61865.html
標籤:Python
