東海道新幹線のルートマップを描く

　国土数値情報の鉄道データと<font color="#9A6229">OpenStreetMap</font>を組み合わせて、東海道新幹線のルートマップを作成する。

  ## 1. 国土数値情報_鉄道データ とは
 　「<font color="#0000ff">国土数値情報</font>」は地形、土地利用、公共施設などの国土に関するGISデータで、国土情報整備事業によって作成されている。
  
　リンク：国土数値情報→ (https://nlftp.mlit.go.jp/ksj/index.html)
　
 　このうち、「鉄道データ」は全国の旅客鉄道・軌道の路線や駅について、路線形状や路線名、駅位置情報などを集めたデータで、路線経路情報を持つ「RailroadSection」データと駅位置情報を持つ「Station」データの二つが提供されている。
　なお、GISデータには様々な形式があるが、「国土数値情報_鉄道データ」ではshpデータとGeoJsonデータの利用が可能だ。

 ## 2. OpenStreetMapを使わない描写
 　「国土数値情報_鉄道データ」を用いて、<font color="#9A6229">OpenStreetMap</font>ではなく「<font>**Cartopy**</font>」など、Pythonの地図描画用ライブラリを利用することで白地図上に鉄道路線データを描写することも可能。

　スクリプトは以下の通り。
```python:map_railway_cartopy.py
#cartopyを用いて、国土数値情報を利用し特定の路線の経路を地図上に描写するスクリプト
#（GoogleColaboratoryでの実行では予めcartopyのinstallが必要）

import geopandas as gpd
import matplotlib.pyplot as plt
import cartopy.crs as ccrs

# .shpファイルの読み込み
shapefile_path = '/content/drive/MyDrive/国土数値情報_鉄道/N02-22_RailroadSection.shp'
railways = gpd.read_file(shapefile_path, encoding='utf-8')

# .shpファイルの読み込み
# shapefile = 'N02-20_RailroadSection.shp'
# railways = gpd.read_file(shapefile, encoding='SHIFT-JIS')

# 日本地図の作成
fig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})
ax.set_extent([135, 140, 34, 36])

# 海を描画
# ax.add_feature(cartopy.feature.OCEAN, facecolor='aqua')

# 陸地を描画
# ax.add_feature(cartopy.feature.LAND, facecolor='white')

# 海岸線の描画
ax.coastlines(resolution='10m', color='black', linewidth=0.8)

# shapefileの各レコードを取得し、属性N02_003が'東海道新幹線'である場合は青色、それ以外は赤色でプロットする
for i, row in railways.iterrows():
    if row['N02_003'] == '東海道新幹線':
        coords = row.geometry.coords
        lon = [c[0] for c in coords]
        lat = [c[1] for c in coords]
        ax.plot(lon, lat, color='blue', linewidth=1.5, transform=ccrs.PlateCarree())
    else:
        coords = row.geometry.coords
        lon = [c[0] for c in coords]
        lat = [c[1] for c in coords]
        ax.plot(lon, lat, color='red', linewidth=0.5, transform=ccrs.PlateCarree())

# 保存
plt.savefig('japan_map.png', dpi=300, bbox_inches='tight')

# 表示
plt.show()
```

　実行結果は以下の通り。
　白地図上に東海道新幹線は青太線で、その他の路線は赤線で描写できた。 
 ![japan_map.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325469/638a5429-6008-71b1-4d46-415898a10582.png)

## 3-i. 東海道新幹線のルートマップ（静止画）
　続いて、<font color="#9A6229">OpenStreetMap</font>上に東海道新幹線のルートを青線で描写する方法を考える。

　<font color="#9A6229">OpenStreetMap</font>自体は、鉄道路線の経路データを所持していない。このため、先ほどと同様に「国土数値情報_鉄道データ」の「RailroadSection」データから東海道新幹線のデータを抽出し、<font color="#9A6229">Leaflet</font>により<font color="#9A6229">OpenStreetMap</font>上に描写する。さらに、「RailroadSection」データのみならず、「Station」データを組み合わせることで、駅位置情報もマッピング可能だ。
 
 　スクリプトは以下の通り。

 ```python:map_railwayroute&station.py
# 東海道新幹線のルートを青線で描写し、各駅にマーカーを立てるスクリプト（folium/GeoJSON）

import geopandas as gpd
import folium

# 東海道新幹線の経路データの読み込み
geojson_path = '/content/drive/MyDrive/国土数値情報_鉄道/N02-22_RailroadSection.geojson'
railways = gpd.read_file(geojson_path)

# 東海道新幹線の駅の情報が含まれる GeoJSON ファイルの読み込み
stations_geojson_path = '/content/drive/MyDrive/国土数値情報_鉄道/N02-22_Station.geojson'
stations_data = gpd.read_file(stations_geojson_path)

# 東海道新幹線の駅の情報を抽出
tokaido_stations = stations_data[stations_data['N02_003'].str.contains('東海道新幹線')]

# foliumの地図を作成
m = folium.Map(location=[34.7101, 137.7256], zoom_start=8)  # 例として浜松の緯度経度を設定

# 東海道新幹線の経路を青色の線で表示
for feature in railways.iterrows():
    geometry = feature[1]['geometry']
    if geometry.geom_type == 'MultiLineString' and '東海道新幹線' in feature[1]['N02_003']:
        for line_string in geometry:
            coords = list(line_string.coords)
            coords = [(coord[1], coord[0]) for coord in coords]
            folium.PolyLine(locations=coords, color='blue', weight=5).add_to(m)
    elif '東海道新幹線' in feature[1]['N02_003']:
        coords = list(geometry.coords)
        coords = [(coord[1], coord[0]) for coord in coords]
        folium.PolyLine(locations=coords, color='blue', weight=5).add_to(m)

# 東海道新幹線の駅の位置情報をマップ上に追加
for i, row in tokaido_stations.iterrows():
    coords = (row.geometry.coords[0][1], row.geometry.coords[0][0])
    folium.Marker(location=coords, popup=row['N02_005']).add_to(m)

# 地図を保存
m.save('tokaido_map_with_stations_geojson.html')

# 地図を表示
m
```

　gistはこちら → [map_railway.py](https://gist.github.com/hamanasu12/4b1f753c267f9d5422c9c17c138ff7d3)

　実行結果のスクリーンショットは以下の通り。
![東海道新幹線_経路と駅(leafmap2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325469/7bb9df75-b1a6-c77e-0ef6-0e6790e07932.png)

　cartopyによる東海道新幹線のルートマップ作成では、
・全鉄道路線を白地図上に書き込む必要があるため実行に時間が掛かる
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;・県境や自治体名の情報は無し
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;・地図の拡大縮小はできない
といった短所があったが、<font color="#9A6229">OpenStreetMap</font>の利用によりこれらを克服している。

## 3-a. 東海道新幹線のルートマップ（マップアニメーション）
　前述のルートマップ（静止画）をマップアニメーション化することを考える。

### 3-a-1. スクリプト作成の方針
　スクリプトの作成方針は、基本的には
　[フライトマップ風の地図（マップアニメーション）をつくる](https://qiita.com/hamanasu/items/f42a944f8a41d8fc35ab)
 　に沿う。

　しかしながら、「フライトマップ風の地図」では始点と終点の２点を指定すれば地球上の２点間の経路は計算で定まるのに対し、鉄道路線の経路は、”国土数値情報_鉄道データ”からの抽出が必要となる点が異なる。
 　”国土数値情報_鉄道データ”の「RailroadSection」データ内の鉄道路線経路上の座標情報は、『始点→終点（例.東京→新大阪）』の順序で格納されている訳ではないため、座標順序を修正した上で、アニメーション描写用の配列に格納する作業が必要となる。

![東海道新幹線の経路座標情報.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325469/fe86e3fe-b047-c852-d28c-e14be4387f62.png)
（画像）RailroadSectionデータから’東海道新幹線’の経路座標情報を抽出すると、分割された区間毎の座標情報が部分配列の形で格納されていることが分かる

　これを踏まえて、東海道新幹線のルートマップ（マップアニメーション）生成スクリプトの作成方針をまとめると下記の通りとなる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325469/7510ebb6-ecf2-c046-83ec-2e634f5ddf35.png)

 　できれば「2.抽出した東海道新幹線の経路上座標を東京→新大阪の順序になるよう並べ替える」の作業もプログラムにやってもらいたいところだ。
 ### 3-a-2. 経路上座標順序の修正（『しりとり関数』の定義）
 　「抽出した東海道新幹線の経路上座標を東京→新大阪の順序になるよう並べ替える」プログラムを考える。

  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325469/c79a9bf1-6361-d9dc-bec8-0b1fcab2acd3.png)
  
　「RailroadSection」データから抽出した東海道新幹線の経路上座標を、「Station」データから抽出した東海道新幹線各駅の座標情報と比較すると、
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;●共通の座標群(部分配列)の数: 18
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（東海道新幹線の駅数：17、何故か新大阪駅の座標が二つ入っていた。）
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;●共通でない座標群(部分配列)の数: 26
　であることが分かる。

 　また、(更に観察すると)経路上で隣り合う座標群には、１座標だけ共通する座標が含まれていることも見つけられた。

　このデータの特徴を活かし、『しりとり関数』を定義することで東海道新幹線の経路上座標を目標の順序でアニメ描写用配列に格納することとする。
 
 ![スクリーンショット 2024-02-17 21.07.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325469/a6d64d2e-bbaa-f136-d756-399cbc810791.png)
 
　『しりとり関数』はその名の通り「RailroadSection」データから抽出した東海道新幹線の経路上座標情報を、あらかじめ指定した開始座標点（東京駅のもっとも東側の座標）から順にアニメ描写用配列に格納していくコードだ。

 ![スクリーンショット 2024-02-17 21.08.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3325469/2e759f6a-9bf7-80cc-c26d-39b3795b7140.png)

　一つの部分配列をアニメ描写用配列に格納し終わると、最後に格納した座標と同一の座標を持つ別の部分配列を見つけ今度はその部分配列をアニメ描写用配列に格納する。部分配列内の座標順が西から東の順になっている場合は、アニメ描写用配列に格納する際は逆順で格納する。最後に格納した座標と同一の座標を持つ別の部分配列が見つからなくなった、あるいは二つ以上見つかった時点でループが終了する。
 
 　この関数の定義により、経路上座標順序の修正が自動化できた。
  
### 3-a-3. スクリプト
　東海道新幹線のルートマップ（マップアニメーション）をつくるスクリプトは以下の通り。

https://gist.github.com/hamanasu12/bfd73b350bceb06e81935e1494d31227

 　実行結果をmp4化したものは以下の通り。
 <iframe width="560" height="315" src="https://www.youtube.com/embed/WNBEtZrzTHE?si=dAmHJQ8RyFZ4Scil" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

 　以上で、東海道新幹線のルートマップ（マップアニメーション）をつくることができた。

 ## 4. 参考文献
・[「GISファイルフォーマットの簡単なまとめ/地図のワークブック」](https://lonlat.info/gis-file-format/)
・[国土数値情報ダウンロードサイト](https://nlftp.mlit.go.jp/ksj/index.html)
・[Leaflet](https://leafletjs.com/)
・[Leafletの使い方（埼玉大学教育学部人文地理学　谷謙二研究室）](https://ktgis.net/service/leafletlearn/index.html)
・[OpenStreetMap Japan](https://openstreetmap.jp)
・[TRAINOCAMP「HTMLとJavaScriptを使いこなす！」](https://camp.trainocate.co.jp/magazine/howto-javascript-html/)
・[chatGPT 3.5](https://chat.openai.com/)