gpxファイルのグラフ化プログラム~ver.0~

どうもだそんです

今回は山行時に記録するgpxファイルの標高データをグラフ化したいためpythonでプログラムを作ってみた...途中経過を載せておきます

個人的な予定により今月末にかけて忙しくなる,にも関わらずこのプログラム作成と並列してもう一つやろうとしていることがあり,そちらに集中するためこちらは小休止することにしました

正直こんなに時間がかかるとは思っていなかったという・・・まぁそんな感じです

目標はヤマッ◯!


最終目標はこんな感じです

ルート情報はgoogle Mymapsを用いるので,下の標高図のように距離,時間などでグラフを別々に出力してくれるようにしたいです

GPXファイルとは?

GPX(ジーピーエックス、GPS eXchange Format)は、GPS/GNSS装置やGPS/GNSSソフトウェアなど、アプリケーション間でGPS/GNSSのデータをやりとりするためのデータフォーマットである。GPXは、XML Schemaベースでデザインされており、ウェイポイント軌跡、ルートなどを記述する。”
出典元:引用-Wikipedia

要はGPSデータ(緯度,経度,標高,時間,etc…)を決まったテキストデータで統一しいろいろな計算機や機械に使えるようにしたものだそうです

前回参考時のgpxファイルをgoogle Mymapsで開いてみるとこのようにルート情報が表示されます

直接テキストエディタで開いてみるとこんな感じで上記した情報がつらつらと書いてあります

<trk>
<name>冬山大山 その2</name>
<trkseg>
<trkpt lat="35.394167" lon="133.529682">
<ele>746.000000</ele>
<time>2019-03-01T22:52:09Z</time>
<speed>0.000000</speed>
<trueHeading>0.000000</trueHeading>
<magneticHeading>0.000000</magneticHeading>
<gpsHeading>0.000000</gpsHeading>
<haccuracy>17.312000</haccuracy>
<vaccuracy>17.312000</vaccuracy>
<internetconnect>2</internetconnect>
</trkpt>
...

とりあえずこのデータから今回必要となる,緯度,経度,標高,時間を抜き出そうと思います

gpxpyによる各データの抜き出し

“gpxファイル python”とググると真っ先に出るのが”gpxpy”

このライブラリを使えばgpxファイルから必要なデータを抜き出し,追加することができます

細かな使い方と参考にしたのはこちら

どちらもStravaというアプリを対象にしているようです

どのアプリもcsvで直接出力できないようなので,自作しているようです

アプリ側でcsvに変換する機能があれば便利な気もするのですが,そこは何か問題点があるのでしょうかね?(アプリの容量とか?)

とにかくこれでグラフ化まですぐだ!
ということで早速このプログラムを改造して標高を出力するプログラムにしてみました

このプログラムに必要なライブラリは以下の通りです(インストールの仕方は詳しいブログがあるのでそちらで〜)

  • matplotlib :グラフ描画用
  • gpxpy :gpxファイル用
# simple.py

import gpxpy
import matplotlib.pyplot as plt

gpx_file = open('20190302_daisen_winter_2.gpx', 'r')
gpx = gpxpy.parse(gpx_file)

ele = []

for track in gpx.tracks:
    for segment in track.segments:
        for point in segment.points:
            ele.append(point.elevation)

plt.figure()
plt.plot(ele, color = 'blue', lw = 1, alpha = 1)
plt.show()

縦軸が標高,横軸がデータ数となっています

ヤマップのデータと見比べると・・・縦横の縮尺比が微妙な感じですかね?

というか横軸がデータ数だから一致しないのは当たり前ですねー

てなわけで続いて横軸を距離におきかえます

ただし具体的に歩行距離はgpxファイルにはないので計算します

緯度,経度から距離を計算(ヒュベニの公式)

gpxファイルは基本的に記録したタイミングの座標を点としてそれを繋いで先程のようなグラフを作っています

ということでそれぞれの点の間(二点間の距離)を計算し,合計したものが歩行距離となります

二点間の距離の計算は三角関数で計算すれば簡単!と思っていましたが地球って平面ではなく丸いんですよね・・・しかも楕円

そういうことで地球が楕円であることを考慮した緯度,経度の二点間の距離を求める公式というものが色々あるそうです

今回は以下のサイトを参考にし,ヒュベニの公式を使ってみました

こちらにあるように有名な3D地図ソフトカシミール3Dに用いられている計算式が以下のとおりです

ヒュベニの公式

D=sqrt((M*dP)*(M*dP)+(N*cos(P)*dR)*(N*cos(P)*dR))

       D:  2点間の距離(m)
       P:  2点の平均緯度
       dP: 2点の緯度差
       dR: 2点の経度差
       M:  子午線曲率半径
       N:  卯酉線曲率半径
       M=6334834/sqrt((1-0.006674*sin(P)*sin(P))^3)
       N=6377397/sqrt(1-0.006674*sin(P)*sin(P))

ちなみにヒュベニの公式で用いられる緯度,経度はラジアン表記ですが生gpxファイルは度なので変換します

とりあえずこの公式を関数化して,縦軸を標高,横軸を距離として出力するグラフを追加したプログラムが以下のとおりです

このプログラムはnumpy:数値計算用ライブラリを追加しました

# simple_2.py

import gpxpy
import matplotlib.pyplot as plt
import numpy as np

# gpxファイルの指定
gpx_file = open('20190302_daisen_winter_2.gpx', 'r')
gpx = gpxpy.parse(gpx_file)

# ヒュベニの公式
def hyubeni(lat_old,lat_new,lon_old,lon_new):
	lat_old = lat_old * np.pi / 180
	lat_new = lat_new * np.pi / 180
	lon_old = lon_old * np.pi / 180
	lon_new = lon_new * np.pi / 180
	elat = lat_new - lat_old
	elon = lon_new - lon_old
	mlat = elat/2
	
	M = 6334834/ np.sqrt((1- 0.006674 * np.sin(mlat) * np.sin(mlat)**3))
	N = 6377397/ np.sqrt(1-0.006674 * np.sin(mlat) * np.sin(mlat))
	
	dis = np.sqrt((M * elon) * (M * elon) + (N * np.cos(mlat) * elon) * (N * np.cos(mlat) * elon))
	return(dis)

lat = []
lon = []
ele = []
dis = []
dis_all = []

# 緯度,経度,距離データの格納
for track in gpx.tracks:
    for segment in track.segments:
        for point in segment.points:
            lat.append(point.latitude)
            lon.append(point.longitude)
            ele.append(point.elevation)

# 二点間の距離を計算
for count in range(len(lon)):
	if count == 0:
		dis.append(0)
	else:
		lon_old = lon[count-1]
		lon_new = lon[count]
		lat_old = lat[count-1]
		lat_new = lat[count]
		dis.append(hyubeni(lat_old,lat_new,lon_old,lon_new))
# 距離を積算し,走行距離の計算と格納
for count in range(len(lon)):
	if count == 0:
		dis_all.append(dis[count])
	else:
		dis_all.append(dis_all[count-1]+dis[count])
# 距離の単位をkmに
for count in range(len(lon)):
		dis_all[count] = dis_all[count]/1000

# 数値を確認
print(dis_all)

# グラフの出力  
plt.figure()
#標高,データ数
plt.subplot(211)
plt.plot(ele, color = 'blue', lw = 1, alpha = 1)
#標高,距離
plt.subplot(212)
plt.plot(dis_all, ele, color = 'red', lw = 1, alpha = 1)
plt.show()

できた!・・・かぁ?

上が先程のグラフで,下が新しく作った縦が標高,横が距離のグラフとなります

最初のヤマッ◯のグラフと比べてなんだかいびつです・・・

総歩行距離もヤマッ◯だと7.5kmに対し,こちらは6.8kmです
約800mの誤差ですね・・・

こちらのサイトにあるようにヒュベニの公式を用いた場合二点間の距離が1000km程度で0.1%の誤差とあります
今回はどの二点間をとっても1kmないです

これはおかしい・・・なにか根本的にデータが足りないような気がします

てな感じで完全にドツボにハマりました

まとめと今後の目標

とりあえず今回以下までは形にしました

  • gpxファイルの取り込み
  • 標高グラフの作成
  • 緯度,経度から距離の計算(仮)

今後の目標は以下の通りです

  • 距離の誤差を修正
  • 縦軸標高,横軸時間のグラフ作成
  • プログラムのGUI,パッケージ化

縦軸を標高,横軸を時間にしたグラフには,途中休憩し,計測を止めた部分を補完するプログラムを作る必要があります(汗)

GUI,パッケージ化はそれぞれに対応するライブラリをすでに見つけているのでそれが適用できることを祈るばかりです

もう2,3個山を超える必要がありそうですね・・・

でも今は別にやりたいことがあるので一旦ストップで!

プログラミングの良いところは場所と時間を選ばないところだと思っているので,それに甘えるスタイルでいきます

それでは

コメントを残す