PR

【Python×旅・ハイキング 第2回】高尾山のルートデータを大解剖!区間距離と方位角を自動計算して「登山計画レポート」を作ろう 🥾

Python

「前回、高尾山のルートから緯度・経度・標高を抜き出せたけど、これを使って何ができるの?」
「『次のチェックポイントまであと何メートル?』『どの方角に進めばいい?』を自動で計算させたい!」
「前に学んだ地理計算の知識を、実際のルートデータに応用してみたい!」

こんにちは! Pythonプログラミング探検隊、隊長のPythonistaです! 前回の第1回では、世界一登山客が多い山「高尾山」の1号路ルートを題材に、GPXファイルから各経由地の座標や標高をPythonで抜き出す方法を学びましたね。

データの抜き出しに成功した私たちが次に知りたくなるのは、それぞれのスポットの「間」の情報です。つまり、「清滝駅からかすみ台展望台まではどれくらい歩くの?」「どの方角に向かって進めばいいの?」という、より実践的なルート情報です。

そこで第2回となる今回は、以前のシリーズで大活躍した高精度地理計算ライブラリpyprojを再召喚します!前回パースした高尾山の座標データ同士を繋ぎ、区間ごとの「正確な距離」と「進むべき方位角」をPythonに自動計算させて、誰が見ても分かりやすい本格的な「登山計画レポート」を作り上げていきましょう!


1. 今回の作戦:点と点を繋いで「区間」を計算する

前回のスクリプトでは、for文を使って地点1、地点2、地点3……と、それぞれの点を単発で表示していました。 しかし、区間の距離や方角を計算するには、「現在の点(出発地)」と「次の点(目的地)」の2つの座標のペアが必要になります。

プログラムの中で、この「隣り合う2つの点」を上手にペアにするために、Pythonのループ処理に少し工夫を加えます。そして、ペアにした座標をpyprojGeod.inv()メソッドに放り込むことで、地球の丸みを考慮した正確な距離と方位角を一瞬ではじき出します。


2. 実践!区間ルート解析スクリプト

それでは、前回のXMLパース処理に、pyprojによる計算ロジックを組み込んだ完成版のスクリプトです。お手元の環境にpyprojがインストールされていることを確認(pip install pyproj)して、実行してみてください!

import xml.etree.ElementTree as ET
from pyproj import Geod
import os

def generate_hiking_report(file_path):
    """
    GPXファイルを読み込み、隣り合う地点間の距離・方位角・高低差を
    計算して登山計画レポートを表示する関数。
    """
    # 1. ファイルが存在するかチェック
    if not os.path.exists(file_path):
        print(f"エラー: '{file_path}' が見つかりません。")
        print("先に前回のGPX自動生成スクリプトを実行して、ファイルを準備してください。")
        return

    # 2. GPXファイルをパースして、全地点のデータを一度リストに格納する
    tree = ET.parse(file_path)
    root = tree.getroot()
    ns = {'gpx': 'http://www.topografix.com/GPX/1/1'}
    track_points = root.findall('.//gpx:trkpt', ns)

    points_data = []
    for pt in track_points:
        lat = float(pt.attrib['lat'])
        lon = float(pt.attrib['lon'])
        ele = float(pt.find('gpx:ele', ns).text)
        name_tag = pt.find('gpx:name', ns)
        name = name_tag.text if name_tag is not None else "経由地"
        
        # あとで計算しやすいように辞書型にしてリストに追加
        points_data.append({'name': name, 'lat': lat, 'lon': lon, 'ele': ele})

    # 3. 高精度な地球モデル(WGS84回転楕円体)を設定
    geod = Geod(ellps='WGS84')

    print(f"=============================================")
    print(f" 📋 Python自動生成:高尾山1号路 登山計画レポート")
    print(f"=============================================\n")

    # 4. ループを回して「現在の点(i)」と「次の点(i+1)」のペアで区間を計算
    # リストの末尾より1つ手前までループ(最後の点には「次の点」がないため)
    for i in range(len(points_data) - 1):
        current_pt = points_data[i]
        next_pt = points_data[i + 1]

        # pyprojで2点間の距離と方位角を計算 
        # ※重要※ 引数は (経度1, 緯度1, 経度2, 緯度2) の順序
        fwd_azimuth, _, distance = geod.inv(
            current_pt['lon'], current_pt['lat'], 
            next_pt['lon'], next_pt['lat']
        )

        # 前方方位角(-180〜180度)を一般的な方位角(0〜360度)に正規化
        if fwd_azimuth < 0:
            fwd_azimuth += 360

        # 標高の差(高低差)を計算
        ele_diff = next_pt['ele'] - current_pt['ele']

        # 区間レポートの出力
        print(f"🚩 【区間 {i+1}】")
        print(f"  出 発 : {current_pt['name']} (標高: {current_pt['ele']:.0f}m)")
        print(f"  到 着 : {next_pt['name']} (標高: {next_pt['ele']:.0f}m)")
        print(f"  -------------------------------------------")
        print(f"  ・区間距離 : {distance:.1f} メートル")
        print(f"  ・進む方角 : {fwd_azimuth:.1f} 度 (真北を0度とした時計回り)")
        print(f"  ・高低差   : {ele_diff:+.0f} メートル")
        print(f"=============================================\n")

if __name__ == "__main__":
    # 解析対象のGPXファイル名を指定
    target_file = "takao_templated.gpx"
    
    # レポート生成関数を実行
    generate_hiking_report(target_file)

3. レポート出力結果の確認

このスクリプトを実行すると、コンソールに以下のような美しい登山計画レポートが出力されます!

=============================================
 📋 Python自動生成:高尾山1号路 登山計画レポート
=============================================

🚩 【区間 1】
  出 発 : 清滝駅(スタート) (標高: 201m)
  到 着 : かすみ台展望台 (標高: 465m)
  -------------------------------------------
  ・区間距離 : 841.0 メートル
  ・進む方角 : 255.4 度 (真北を0度とした時計回り)
  ・高低差   : +264 メートル
=============================================

🚩 【区間 2】
  出 発 : かすみ台展望台 (標高: 465m)
  到 着 : 高尾山薬王院 (標高: 520m)
  -------------------------------------------
  ・区間距離 : 621.5 メートル
  ・進む方角 : 234.3 度 (真北を0度とした時計回り)
  ・高低差   : +55 メートル
=============================================

🚩 【区間 3】
  出 発 : 高尾山薬王院 (標高: 520m)
  到 格 : 高尾山山頂(ゴール) (標高: 599m)
  -------------------------------------------
  ・区間距離 : 1076.0 メートル
  ・進む方角 : 260.6 度 (真北を0度とした時計回り)
  ・高低差   : +79 メートル
=============================================

※注:本簡易データは直線距離をベースにしているため、実際のうねうねとした登山道の歩行距離(山道の実質的な長さ)より短く計算されていますが、各チェックポイント間の「大まかな位置関係」や「どれくらい一気に登るのか(高低差)」がバッチリ可視化されました!

区間1の「清滝駅 〜 かすみ台展望台」は、距離のわりには高低差が+264mもあり、かなりの急勾配をグイグイ登ることがデータからも一目で分かります。逆に展望台から薬王院までは、なだらかな道が続いていることが推測できますね。これこそがデータ分析の面白さです!


4. 技術的な解説:隣り合うデータのペアリング方法

今回のコードで一番のプログラミングのポイントは、ループの回し方です。

<span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(len(points_data) - <span class="hljs-number">1</span>):
    current_pt = points_data[i]
    next_pt = points_data[i + <span class="hljs-number">1</span>]

全地点が格納されたリストの長さを len(points_data) で取得していますが、そこから - 1 を引いた範囲でループさせています。 もし - 1 を忘れて最後まで回してしまうと、一番最後の「高尾山山頂(ゴール)」の処理のときに points_data[i + 1](つまり存在しない次の点)を読み込もうとしてしまい、IndexError というエラーでプログラムが止まってしまいます。

このように、「1つ先のデータと組み合わせて計算する」というテクニックは、時系列データの分析や、株価の移動平均線の計算、ログデータの差分抽出など、あらゆるデータ分析の現場で頻出する重要なアルゴリズムです。


まとめと次回予告

今回は、「プログラミング×旅・ハイキング」シリーズの第2回として、前回抽出した高尾山のGPXデータに地理計算ロジックを組み合わせ、実用的な「登山計画レポート」を自動生成しました。

  • リスト内のインデックス(ii+1)を工夫することで、隣り合う経由地同士を正しくペアリングできること。
  • pyprojを使うことで、各区間の正確な距離、進むべき方位角が数行で計算できること。
  • 標高データの差分を取ることで、その区間が「きつい登りなのか」「穏やかな道なのか」を数値化できること。

文字と数値だけのレポートでも十分にワクワクしますが、せっかくなら「このルートを実際の地図上に綺麗に線として描いて、ブラウザで眺めてみたい!」と思いませんか?

そこで次回、第3回(ビジュアル編)では、Pythonの地図可視化ライブラリfolium(フォリウム)を導入します!今回扱った高尾山のGPXルートデータを、実際のインタラクティブな地図(拡大・縮小できるWeb地図)の上に、鮮やかな赤い線でプロットし、さらに経由地にピンを立てるという、本格的な「マイマップアプリ」の作成に挑戦します。あなたのコードが、ついに美しい地図として画面に広がります。お楽しみに!

Happy Analyzing and Happy Trails! ⛰️🐍

コメント

タイトルとURLをコピーしました