Visualizing commerce stream in Python maps — Half I: Bi-directional commerce stream maps | by Himalaya Bir Shrestha | Dec, 2023
Within the commerce stream maps, I aimed to characterize two-way commerce relationships between nations. For instance, the export from Nepal to India can be represented by the primary arrow (A1-A2) and the import by Nepal from India can be represented by a second arrow (A3-A4). On this means, every nation pair relationship would require 4 coordinate factors to outline the beginning and finish factors of arrows to characterize exports and imports respectively.
Whereas it is usually potential to imagine a coordinate that may be detected robotically (for instance, the centroid of a rustic geometry), I meant to mark the factors in a map and get their coordinates individually. For this function, it’s potential to create a venture in an utility comparable to Google Earth, export a KML file, and extract the coordinates with a converter (for instance, the GIS knowledge converter within the web site of MyGeodata Cloud).
Keyhole Markup Language (KML) is a file format used to show geographic knowledge in an utility comparable to Google Earth. It makes use of a tag-based construction with nested components and attributes and is predicated on the XML normal (Google, 2023).
The construction of my enter knowledge appears as proven within the picture beneath. It accommodates 5 completely different commerce relationships between neighboring nations: Nepal-India, Nepal-Bangladesh, Nepal-China, India-Pakistan, and India-Sri Lanka. For every nation pair, there are 4 coordinate factors for the beginning and finish factors of the 2 arrows. Value1 represents the export from Country1 to Country2. Value2 represents the import by Country1 from Country2. The purpose is to show this relationship in a Python map.
I learn the above knowledge as a pandas dataframe df
. Moreover, I created dictionary objects comparable to transfers
containing the export and import quantity between every nation pair, and startarrow1_dict
containing the coordinate of place to begin of the primary arrow.
On this part, I’ll describe the code used to visualise the commerce stream maps. I’ll primarily use the matplotlib and cartopy packages. I’ve additionally used the identical packages to visualise the worldwide floor temperature anomaly in one of my earlier posts.
- Import required packages
I began with importing the principle required packages and dependencies as proven beneath:
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreaderimport matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib import colormaps
from matplotlib.colours import Normalize
from matplotlib.cm import ScalarMappable
import numpy as np
import pandas as pd
import os
2. Learn the form file
As a form file, I used the Pure Earth Vector. The vector file may be learn immediately by the shapereader module of the cartopy bundle.
# get the nation border file (10m decision) and extract
shpfilename = shpreader.natural_earth(
decision=”10m”,
class=”cultural”,
title=”admin_0_countries”,
)
reader = shpreader.Reader(shpfilename)
nations = reader.data()
Utilizing a bundle known as Fiona, it’s potential to learn the checklist of all nations as proven beneath.
3. Extract the data of solely required nations
Subsequent, I created required
, which is an inventory of six nations having commerce relationships. I additionally created a dictionary object c
, which contained the FionaRecord i.e., all related info of the nations that can be utilized for plotting.
# required nations
required = [“Nepal”, “India”, “Bangladesh”,”China”,”Pakistan”,”Sri Lanka”]# extract the precise nation info
c = {
co.attributes["ADMIN"]: co
for co in nations if co.attributes["ADMIN"] in required
}
4. Plot the required
nations and clipping
On this step, first, I plotted the geometries of required
nations in a PlateCarree projection as proven beneath:
Subsequent, I needed to clip off the geometries of the remainder of the world in order that I may have a magnified view of the six nations alone. I made up my mind the extent of the utmost and minimal longitude and latitude values respectively that might cowl all six nations, set the extent for the axes plot, and plotted the nations. Within the for loop, I additionally added an code that might show the names of the nations over the centroid geometry of every nation.
The zorder
attribute of the matplotlib bundle would decide the drawing order of the artists. Artists with larger zorder
are drawn on the highest.
# get general boundary field from nation bounds
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())
# get nation centroids
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)
# Add nation names
centroid = cn.geometry.centroid
ax.textual content(
centroid.x,
centroid.y,
key, # Assuming 'title' is the attribute containing the nation names
horizontalalignment='heart',
verticalalignment='heart',
rework=ccrs.PlateCarree(),
fontsize=8, # Modify the font dimension as wanted
colour='black', # Set the colour of the textual content
zorder = 2
)
plt.axis("off")
plt.present()
5. Arrange colormap, add arrow patches, and colour bar.
That is an important part of the code. First, I chosen viridis_r
i.e., the reverse colour palette of viridis
as my colormap. Subsequent, I made up my mind the minimal and most worth of any commerce values between nations as tmin
and tmax
respectively. These values are normalized such that the tmin
corresponds to the bottom finish (0) and tmax
corresponds to the best finish (1) of the colormap cmap
and used accordingly within the succeeding code.
Then I looped by the transfers
and used the FancyArrowPatch object to plot the arrows between nations. Every arrow object is related to a novel colour col
that represents the commerce stream from one nation to a different. Whereas it is usually potential to make use of an offset from the coordinates of the primary arrow to plot the second arrow, I’ve specified the coordinates for the second arrow in my code. Within the code, the mutation_scale
attribute is used to regulate the size of the top of the arrow, and the linewidth
attribute is used to regulate the width of the principle line.
Lastly, I added the horizontal colorbar beneath the principle plot.
ax = plt.axes(projection=ccrs.PlateCarree())# get nation centroids
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)
# Add nation names
centroid = cn.geometry.centroid
ax.textual content(
centroid.x,
centroid.y,
key, # Assuming 'title' is the attribute containing the nation names
horizontalalignment='heart',
verticalalignment='heart',
rework=ccrs.PlateCarree(),
fontsize=8, # Modify the font dimension as wanted
colour='black', # Set the colour of the textual content
zorder = 2
)
# arrange a colormap
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.break up(",")
startarrow1 = startarrow1_dict[tr]
endarrow1 = endarrow1_dict[tr]
startarrow2 = startarrow2_dict[tr]
endarrow2 = endarrow2_dict[tr]
t1 = transfers[tr][0]
col = cmap(norm(t1))
# Use the arrow operate to attract arrows
arrow = mpatches.FancyArrowPatch(
(startarrow1[0], startarrow1[1]),
(endarrow1[0], endarrow1[1]),
mutation_scale=20, #management the size of head of arrow
colour=col,
arrowstyle='-|>',
linewidth=2, # You possibly can regulate the linewidth to regulate the arrow physique width
zorder = 3
)
ax.add_patch(arrow)
#OTHER WAY
offset = 1
t2 = transfers[tr][1]
col = cmap(norm(t2))
arrow = mpatches.FancyArrowPatch(
(startarrow2[0], startarrow2[1]),
(endarrow2[0], endarrow2[1]),
mutation_scale=20,
colour=col,
arrowstyle='-|>',
linewidth=2, # You possibly can regulate the linewidth to regulate the arrow physique width
zorder = 4
)
ax.add_patch(arrow)
sm = ScalarMappable(norm, cmap)
fig = plt.gcf()
cbar = fig.colorbar(sm, ax=ax,
orientation = "horizontal",
pad = 0.05, #distance between important plot and colorbar
shrink = 0.8, #management size
side = 20 #management width
)
cbar.set_label("Commerce stream")
plt.title("Commerce stream in South Asia")
plt.axis("off")
plt.savefig("trade_flow2_with_labels.jpeg",
dpi = 300)
plt.present()
The top product is proven beneath. In my dummy dataset, the least commerce stream is export from Sri Lanka to India (53 items), which is represented by yellow colour. The best commerce stream is export from Bangladesh to Nepal (98 items), which is represented by violet colour.
On this publish, I demonstrated how the commerce stream between nations together with export and import relationships may be visualized in a Python map utilizing two arrows. I’ve used the cartopy and matplotlib packages for this function. Within the second a part of this collection, I’ll showcase how the “web” commerce stream relationship may be visualized whereas highlighting the online exporter and web importer nations.
The pocket book for this publish is on the market on this GitHub repository. Thanks for studying!
References
Google Builders, 2023. KML Tutorial | Keyhole Markup Language | Google for Developers. The content material of this web page is licensed below the Creative Commons Attribution 4.0 License