Pythonの地図を使って貿易流をビジュアライズする – 第1部:双方向貿易流マップ

「Pythonと地図で貿易流をビジュアライズする - Part 1 双方向貿易マップ」

財産とサービスの交換は、それらに対応する価値との交換が私たちの日常生活の複雑な部分です。同様に、国々は電力、エネルギー商品、原材料、加工品、観光などの製品とサービスの交換のために、様々な種類の貿易関係に従事しています。国々間の貿易フロー(輸入および輸出)を理解することは、国の収支や支出、経済力、供給の安全性、および国と国の関係の性質の評価に重要です。

この2部作では、Pythonを使用して国々間の貿易フローを地図で可視化する方法を共有します。このシリーズの最初の部分では、国々間の輸入と輸出の双方向の貿易フローに焦点を当てます。2部では、国々間の純貿易フローを可視化します。この可視化には、仮想的な製品のダミーデータセットを使用します。デモンストレーションの目的として、私の国と地域(ネパール/南アジア)を強調します。さあ始めましょう。

GeoJango Mapsの写真by Unsplash

矢印の座標を見つける

貿易フローマップでは、国々間の双方向の貿易関係を表現することを目指しました。たとえば、ネパールからインドへの輸出は最初の矢印(A1-A2)によって表され、ネパールからインドへの輸入は2番目の矢印(A3-A4)によって表されます。このように、各国間の関係は、輸出および輸入をそれぞれ表現するために矢印の始点と終点の4つの座標点が必要です。

自動的に検出できる座標を想定することも可能です(たとえば、国のジオメトリの重心)。しかし、私は地図上のポイントをマークし、個別に座標を取得することを意図しました。この目的のために、Google Earthなどのアプリケーションでプロジェクトを作成し、KMLファイルをエクスポートし、コンバーター(たとえば、MyGeodata CloudのGISデータコンバーター)で座標を抽出することが可能です。

Keyhole Markup Language(KML)は、Google Earthなどのアプリケーションで地理データを表示するために使用されるファイル形式です。タグベースの構造を採用し、ネストされた要素と属性を持ち、XML標準に基づいています(Google、2023年)。

データ

入力データの構造は以下の画像のようになっています。隣国間の5つの異なる貿易関係が含まれています:ネパール-インド、ネパール-バングラデシュ、ネパール-中国、インド-パキスタン、インド-スリランカ。各国のペアごとに、2つの矢印の始点と終点の座標点があります。Value1はCountry1からCountry2への輸出を表し、Value2はCountry1からCountry2への輸入を表します。この関係をPythonの地図に表示することが目的です。

貿易フローマップのデータ入力。著者によるイメージ。

上記のデータをpandasのデータフレームdfとして読み込みました。さらに、国のペアごとに輸出および輸入量を含むtransfersや、最初の矢印の始点の座標を含むstartarrow1_dictなどの辞書オブジェクトを作成しました。

必要な辞書オブジェクトの作成。著者によるイメージ。

コードの説明

このセクションでは、トレードフローマップを視覚化するために使用されるコードについて説明します。主にmatplotlibとcartopyのパッケージを使用します。以前の投稿の1つで、同じパッケージを使用して地球の表面温度異常を視覚化しました。

  1. 必要なパッケージのインポート

次のように、主要な必要なパッケージと依存関係のインポートから始めました:

import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib import colormaps
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable
import numpy as np
import pandas as pd
import os

2. シェイプファイルの読み込み

シェイプファイルとして、Natural Earthのベクトルを使用しました。ベクトルファイルは、cartopyパッケージのshapereaderモジュールによって直接読み込むことができます。

# 国境ファイル(10mの解像度)の取得と抽出
shpfilename = shpreader.natural_earth(
                           resolution=”10m”,
                           category=”cultural”,
                           name=”admin_0_countries”,
                          )
reader = shpreader.Reader(shpfilename)
countries = reader.records()

Fionaというパッケージを使用することで、以下のようにすべての国のリストを読み込むことができます。

Fionaパッケージは、シェイプファイルを開き、すべての国名のリストを抽出するために使用されます。 Image by Author.

3. 必要な国の情報を抽出する

次に、トレード関係を持つ国を持つ6つの国のリストrequiredを作成しました。また、各国のFionaRecordである関連する情報をプロットに使用することができる辞書オブジェクトcも作成しました。

# 必要な国々
required = [“Nepal”, “India”, “Bangladesh”,”China”,”Pakistan”,”Sri Lanka”]
# 特定の国の情報を抽出
c = { co.attributes["ADMIN"]: co for co in countries if co.attributes["ADMIN"] in required }

4. 必要な国をプロットし、クリッピングする

このステップでは、requiredの国のジオメトリ(地形)をPlateCarree投影でプロットしました:

必要な国のプロット。 Image by Author.

次に、残りの世界のジオメトリをクリップして、6つの国だけを拡大表示するために、最頻値と最小値の経度と緯度の範囲を決定し、軸プロットの範囲を設定し、国をプロットしました。forループでは、各国の重心ジオメトリ上に国の名前を表示するコードも追加しました。

matplotlibパッケージのzorder 属性は、アーティストの描画順序を決定します。より高いzorderを持つアーティストが上に描画されます。

# 国の境界ボックスを取得
extents = np.array([c[cn].bounds for cn in c])
lon = [extents.min(0)[0], extents.max(0)[2]]
lat = [extents.min(0)[1], extents.max(0)[3]]
ax = plt.axes(projection=ccrs.PlateCarree())
# 国の重心を取得
ax.set_extent([lon[0] - 1, lon[1] + 1, lat[0] - 1, lat[1] + 1])
for key, cn in zip(c.keys(),c.values()):
    ax.add_geometries(cn.geometry,
                      crs=ccrs.PlateCarree(),
                      edgecolor="gray",
                      facecolor="whitesmoke",
                      zorder = 1)
    # 国名を追加
    centroid = cn.geometry.centroid
    ax.text(
        centroid.x,
        centroid.y,
        key,  # 国名を属性に持つと仮定して
        horizontalalignment='center',
        verticalalignment='center',
        transform=ccrs.PlateCarree(),
        fontsize=8,  # 必要に応じてフォントサイズを調整
        color='black',  # テキストの色を設定
        zorder = 2
    )
plt.axis("off")
plt.show()

5. カラーマップの設定、矢印パッチの追加、およびカラーバーの追加。

これはコードの最も重要なセクションです。まず、viridisの逆のカラーパレットであるviridis_rをカラーマップとして選択しました。次に、国の間のすべての貿易値の最小値と最大値をtminおよびtmaxとして決定しました。これらの値は、tminがカラーマップcmapの最低端(0)に対応し、tmaxが最高端(1)に対応するように正規化され、後続のコードで使用されます。

次に、transfersをループして、FancyArrowPatchオブジェクトを使用して国と国の間の矢印をプロットしました。各矢印オブジェクトは、貿易フローを表す一意の色colに関連付けられています。2番目の矢印をプロットするために最初の矢印の座標からオフセットを使用することも可能ですが、私のコードでは2番目の矢印の座標を指定しています。コードでは、mutation_scale属性を使用して矢印の先端の長さを制御し、linewidth属性を使用して主線の幅を制御しています。

最後に、メインプロットの下に水平のカラーバーを追加しました。

ax = plt.axes(projection=ccrs.PlateCarree())# 国の中心点を取得ax.set_extent([lon[0] - 1, lon[1] + 1, lat[0] - 1, lat[1] + 1])for key, cn in zip(c.keys(),c.values()):    ax.add_geometries(cn.geometry,                      crs=ccrs.PlateCarree(),                      edgecolor="grey",                      facecolor="whitesmoke",                     zorder = 1)        # 国名を追加    centroid = cn.geometry.centroid        ax.text(        centroid.x,        centroid.y,        key,  # 国名を含む属性('name'と仮定)        horizontalalignment='center',        verticalalignment='center',        transform=ccrs.PlateCarree(),        fontsize=8,  # 必要に応じてフォントサイズを調整        color='black',  # テキストの色を設定        zorder = 2       )# カラーマップの設定cmap = colormaps.get("viridis_r")tmin = np.array([v for v in transfers.values()]).min()tmax = np.array([v for v in transfers.values()]).max()norm = Normalize(tmin, tmax)for tr in transfers:    c1, c2 = tr.split(",")    startarrow1 = startarrow1_dict[tr]    endarrow1 = endarrow1_dict[tr]        startarrow2 = startarrow2_dict[tr]    endarrow2 = endarrow2_dict[tr]            t1 = transfers[tr][0]    col = cmap(norm(t1))        # 矢印を描画するためにarrow関数を使用    arrow = mpatches.FancyArrowPatch(        (startarrow1[0], startarrow1[1]),        (endarrow1[0], endarrow1[1]),        mutation_scale=20,    # 矢印の先端の長さを制御        color=col,        arrowstyle='-|>',        linewidth=2,  # 矢印の体の幅を制御するためにlinewidthを調整        zorder = 3    )    ax.add_patch(arrow)        # 別の方法    offset = 1    t2 = transfers[tr][1]    col = cmap(norm(t2))    arrow = mpatches.FancyArrowPatch(        (startarrow2[0], startarrow2[1]),        (endarrow2[0], endarrow2[1]),        mutation_scale=20,        color=col,        arrowstyle='-|>',        linewidth=2,  # 矢印の体の幅を制御するためにlinewidthを調整        zorder = 4    )    ax.add_patch(arrow)    sm = ScalarMappable(norm, cmap)fig = plt.gcf()cbar = fig.colorbar(sm, ax=ax,            orientation = "horizontal",            pad = 0.05,  # メインプロットとカラーバーの間の距離            shrink = 0.8, # 長さを制御            aspect = 20  # 幅を制御            )cbar.set_label("貿易フロー")plt.title("南アジアの貿易フロー")plt.axis("off")plt.savefig("trade_flow2_with_labels.jpeg",           dpi = 300)plt.show()

下記に製品の最終結果が表示されます。ダミーデータセットでは、最も少ない取引量はスリランカからインドへの輸出(53ユニット)で、黄色で表されます。最も高い取引量はバングラデシュからネパールへの輸出(98ユニット)で、紫色で表されます。

国と国の間の矢印で表される国と国の間の双方向の貿易フロー。画像提供:著者

結論

この記事では、輸出と輸入の関係を含む国と国の貿易フローをPythonの地図上で2本の矢印を使って可視化する方法を示しました。このために、cartopyとmatplotlibのパッケージを使用しました。このシリーズの第2部では、「ネット」の貿易フロー関係を強調しながら、ネット輸出国とネット輸入国を可視化する方法を紹介します。

この記事のノートブックは、GitHubのリポジトリで入手できます。お読みいただきありがとうございました!

参考文献

Google Developers, 2023. KMLチュートリアル | Keyhole Markup Language | Google for Developers.このページの内容は、クリエイティブ・コモンズ・表示4.0ライセンスの下で提供されています。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more