Визуализация потока торговли на картах Python – Часть I Двусторонние карты потока торговли

Визуализация потока торговли на картах Python - Часть I Карты двустороннего потока торговли

Обмен товаров и услуг взамен их соответствующих стоимостей является неотъемлемой частью нашей повседневной жизни. Аналогично, страны вовлекаются в разные виды торговых отношений для обмена продуктами и услугами, такими как электричество, энергетические товары, сырьевые материалы, обработанные товары, туризм и т. д. Понимание торгового потока между странами (импорта и экспорта) является важным для оценки доходов и расходов страны, экономической мощи, обеспечения поставок и характера отношений между странами.

В этой двухчастной серии я поделюсь тем, как торговый поток между странами можно визуализировать на картах с использованием языка программирования Python. Первая часть этой серии будет посвящена визуализации двустороннего торгового потока (импорта и экспорта) между странами. Вторая часть будет посвящена визуализации чистого торгового потока между странами. Для этой визуализации я буду использовать фиктивные наборы данных о гипотетическом товаре. В качестве примера для демонстрации я выделила мою страну и регион (Непал/Южная Азия). Давайте начнем.

Фото от GeoJango Maps на Unsplash

Поиск координат стрелок

На картах торговых потоков я стремилась отобразить двусторонние торговые отношения между странами. Например, экспорт из Непала в Индию будет представлен первой стрелкой (A1-A2), а импорт Непала из Индии – второй стрелкой (A3-A4). Таким образом, для каждой пары стран необходимы четыре координатные точки для определения начальной и конечной точек стрелок, представляющих экспорт и импорт соответственно.

Хотя также можно предположить координату, которую можно автоматически обнаружить (например, центроид геометрии страны), я хотела отметить точки на карте и получить их координаты отдельно. Для этого можно создать проект в приложении, таком как Google Earth, экспортировать KML-файл и извлечь координаты с помощью конвертера (например, конвертера геоданных на сайте MyGeodata Cloud).

Keyhole Markup Language (KML) – это формат файла, используемый для отображения географических данных в приложении, таком как Google Earth. Он использует структуру на основе тегов с вложенными элементами и атрибутами и основан на стандарте XML (Google, 2023).

Данные

Структура моих входных данных выглядит как показано на изображении ниже. Она содержит пять различных торговых отношений между соседними странами: Непал-Индия, Непал-Бангладеш, Непал-Китай, Индия-Пакистан и Индия-Шри-Ланка. Для каждой пары стран имеются четыре координатные точки – начальная и конечная точки двух стрелок. Value1 представляет экспорт из Country1 в Country2. Value2 представляет импорт от Country1 из Country2. Целью является отображение этого отношения на карте Python.

Входные данные для карт торгового потока. Изображение от автора.

Я считала вышеуказанные данные как объект pandas dataframe df. Кроме того, я создала словарные объекты, такие как transfers, содержащий объем экспорта и импорта между каждой парой стран, и startarrow1_dict, содержащий координаты начальной точки первой стрелки.

Создание необходимых словарных объектов. Изображение от автора.

Описание кода

В этом разделе я расскажу о коде, используемом для визуализации карт торгового потока. В основном я буду использовать пакеты matplotlib и cartopy. Я также использовал те же пакеты для визуализации глобальной аномалии поверхностной температуры в одном из предыдущих постов.

  1. Импорт необходимых пакетов

Я начал с импорта основных необходимых пакетов и зависимостей, как показано ниже:

import cartopy.crs as ccrsimport cartopy.io.shapereader as shpreaderimport matplotlib.pyplot as pltimport matplotlib.patches as mpatchesfrom matplotlib import colormapsfrom matplotlib.colors import Normalizefrom matplotlib.cm import ScalarMappableimport numpy as npimport pandas as pdimport os

2. Чтение shape-файла

В качестве shape-файла я использовал естественный векторный файл Natural Earth Vector. Векторный файл может быть прочитан непосредственно с помощью модуля shapereader из пакета cartopy.

# получение файла границы стран (10 метровое разрешение) и извлечениеshpfilename = shpreader.natural_earth(                           resolution="10m",                           category="cultural",                           name="admin_0_countries",                          )reader = shpreader.Reader(shpfilename)countries = reader.records()

С помощью пакета Fiona можно прочитать список всех стран, как показано ниже.

Пакет Fiona используется для открытия shape-файла и извлечения списка всех названий стран. Изображение автора.

3. Извлечение информации только о необходимых странах

Затем я создал список required, который содержит шесть стран, имеющих торговые отношения. Я также создал объект словаря c, который содержит FionaRecord, то есть всю необходимую информацию о странах, которая может быть использована для построения графика.

# требуемые страныrequired = ["Непал", "Индия", "Бангладеш","Китай","Пакистан","Шри-Ланка"]# извлечение информации о конкретной странеc = {     co.attributes["ADMIN"]: co     for co in countries if co.attributes["ADMIN"] in required    }

4. Отображение required стран и обрезка

На этом этапе сначала я построил геометрию стран required в проекции PlateCarree, как показано ниже:

Построение требуемых стран. Изображение автора.

Затем я хотел обрезать геометрию остального мира, чтобы у меня был увеличенный вид только шести стран. Я определил диапазон максимальных и минимальных значений широты и долготы, которые могут охватить все шесть стран, установил диапазон для осях графика и построил страны. В цикле for я также добавил код, который будет отображать названия стран над геометрией центроида каждой страны.

Aтрибут zorder пакета matplotlib определяет порядок рисования художников. Художники с более высоким 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,  # Предполагается, что 'name' - это атрибут, содержащий названия стран        horizontalalignment='center',        verticalalignment='center',        transform=ccrs.PlateCarree(),        fontsize=8,  # Подстроить размер шрифта по необходимости        color='black',  # Установить цвет текста        zorder = 2        )  plt.axis("off")plt.show()

5. Настройка цветовой карты, добавление патчей стрелок и цветовой шкалы.

Это самый важный раздел кода. Сначала я выбрала цветовую палитру viridis_r, то есть обратную цветовую палитру viridis, как мою цветовую карту. Затем я определила минимальное и максимальное значение любых значений торговли между странами как tmin и tmax соответственно. Эти значения нормализуются таким образом, что tmin соответствует самому низкому концу (0), а tmax соответствует самому высокому концу (1) цветовой карты cmap, и используются в последующем коде.

Затем я прохожу через цикл transfers и использую объект FancyArrowPatch, чтобы отображать стрелки между странами. Каждый объект стрелки ассоциирован с уникальным цветом col, который представляет поток торговли от одной страны к другой. Хотя также возможно использование смещения от координат первой стрелки для отображения второй стрелки, я указал координаты для второй стрелки в своем коде. В коде атрибут 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,  # Можно настроить ширину линии для управления шириной тела стрелки        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,  # Можно настроить ширину линии для управления шириной тела стрелки        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 с использованием двух стрелок. Для этой цели я использовал библиотеки cartopy и matplotlib. Во второй части этой серии я продемонстрирую, как можно визуализировать отношение «чистого» потока торговли, выделяя страны-экспортеры и страны-импортеры.

Тетрадка для этой статьи доступна в этом репозитории на GitHub: repository. Спасибо за чтение!

Ссылки

Google Developers, 2023. KML Руководство | Язык разметки Keyhole | Google для разработчиков. Содержимое этой страницы лицензировано в соответствии с Лицензией Creative Commons Attribution 4.0