Skip to content

Commit f862ce0

Browse files
committed
make pre-commit happy
1 parent b9b816f commit f862ce0

File tree

1 file changed

+122
-56
lines changed

1 file changed

+122
-56
lines changed

content/exploratory_notebooks/world_trade/world_trade_network.md

Lines changed: 122 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jupytext:
44
extension: .md
55
format_name: myst
66
format_version: 0.13
7-
jupytext_version: 1.14.5
7+
jupytext_version: 1.15.0
88
kernelspec:
99
display_name: Python 3 (ipykernel)
1010
language: python
@@ -31,47 +31,53 @@ from mpl_toolkits.basemap import Basemap as Basemap
3131
For the sake of convenience and scope of this tutorial, the data for trade flows of three product categories - Natural Gas (Hs6: 271111), Coffee (Hs6: 090111) and Diamonds (Hs6: 710210) was extracted to three separate CSV files. These are now imported as pandas dataframe, from where they can be converted to NetworkX Graph objects.
3232

3333
```{code-cell} ipython3
34-
natural_gas = pd.read_csv('data/natural_gas.csv')
35-
coffee = pd.read_csv('data/coffee.csv')
36-
diamonds = pd.read_csv('data/diamonds.csv')
34+
natural_gas = pd.read_csv("data/natural_gas.csv")
35+
coffee = pd.read_csv("data/coffee.csv")
36+
diamonds = pd.read_csv("data/diamonds.csv")
3737
3838
# latitude longitudes information of countries
39-
country_locations = pd.read_csv('data/locations.csv')
39+
country_locations = pd.read_csv("data/locations.csv")
4040
```
4141

4242
```{code-cell} ipython3
4343
edges_natural_gas = pd.DataFrame(
4444
{
45-
"source": list(natural_gas['exporter']),
46-
"target": list(natural_gas['importer']),
47-
"value": list(natural_gas['value']),
48-
"quantity": list(natural_gas['quantity'])
45+
"source": list(natural_gas["exporter"]),
46+
"target": list(natural_gas["importer"]),
47+
"value": list(natural_gas["value"]),
48+
"quantity": list(natural_gas["quantity"]),
4949
}
5050
)
5151
5252
edges_diamonds = pd.DataFrame(
5353
{
54-
"source": list(diamonds['exporter']),
55-
"target": list(diamonds['importer']),
56-
"value": list(diamonds['value']),
57-
"quantity": list(diamonds['quantity'])
54+
"source": list(diamonds["exporter"]),
55+
"target": list(diamonds["importer"]),
56+
"value": list(diamonds["value"]),
57+
"quantity": list(diamonds["quantity"]),
5858
}
5959
)
6060
6161
edges_coffee = pd.DataFrame(
6262
{
63-
"source": list(coffee['exporter']),
64-
"target": list(coffee['importer']),
65-
"value": list(coffee['value']),
66-
"quantity": list(coffee['quantity'])
63+
"source": list(coffee["exporter"]),
64+
"target": list(coffee["importer"]),
65+
"value": list(coffee["value"]),
66+
"quantity": list(coffee["quantity"]),
6767
}
6868
)
6969
```
7070

7171
```{code-cell} ipython3
72-
G_natural_gas = nx.from_pandas_edgelist(edges_natural_gas, edge_attr=True, create_using=nx.DiGraph())
73-
G_coffee = nx.from_pandas_edgelist(edges_coffee, edge_attr=True, create_using=nx.DiGraph())
74-
G_diamonds = nx.from_pandas_edgelist(edges_diamonds, edge_attr=True, create_using=nx.DiGraph())
72+
G_natural_gas = nx.from_pandas_edgelist(
73+
edges_natural_gas, edge_attr=True, create_using=nx.DiGraph()
74+
)
75+
G_coffee = nx.from_pandas_edgelist(
76+
edges_coffee, edge_attr=True, create_using=nx.DiGraph()
77+
)
78+
G_diamonds = nx.from_pandas_edgelist(
79+
edges_diamonds, edge_attr=True, create_using=nx.DiGraph()
80+
)
7581
```
7682

7783
The trade network of each commodity is represented as a directed graph comprising countries (vertices) and trade relationships (edges), with the edges starting from the export countries and pointing to the import countries. Each edge consists of two attributes - value of the trade and the quantity of the traded commodity, that can act as weights for the edges.
@@ -99,7 +105,7 @@ Let us look at the trade network of coffee to understand this further.
99105
outdeg_dict = nx.out_degree_centrality(G_coffee)
100106
outdeg_dict = dict(sorted(outdeg_dict.items(), key=lambda item: item[1], reverse=True))
101107
plt.figure(figsize=(25, 10))
102-
plt.plot(outdeg_dict.keys(), outdeg_dict.values(), marker='o', linestyle='-', color='b')
108+
plt.plot(outdeg_dict.keys(), outdeg_dict.values(), marker="o", linestyle="-", color="b")
103109
plt.show()
104110
```
105111

@@ -124,31 +130,52 @@ A quite natural visualization of trade flows is through the use of a cartogram a
124130
# parameter "geo" determines whether it will be a geographic or topological view
125131
# default value of "geo" is False i.e. default view is topological
126132
133+
127134
def draw_pretty(G, geo=False):
128135
indeg_dict = nx.in_degree_centrality(G)
129136
outdeg_dict = nx.out_degree_centrality(G)
130137
low, *_, high = sorted(indeg_dict.values())
131138
norm = mpl.colors.Normalize(vmin=low, vmax=high, clip=True)
132139
mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.coolwarm)
133-
nsize = [x*20000 for x in outdeg_dict.values()]
134-
plt.figure(figsize=(40,20))
135-
lat_long = dict([(i,[a,b]) for i, a,b in zip(country_locations.country, country_locations.long, country_locations.lat)])
136-
if(geo):
137-
postemp=lat_long
138-
m = Basemap(projection='merc',llcrnrlon=-180,llcrnrlat=-80,urcrnrlon=180, urcrnrlat=80, lat_ts=0, resolution='l',suppress_ticks=True)
139-
m.drawcountries(linewidth = 1.5)
140-
m.drawstates(linewidth = 0.1)
140+
nsize = [x * 20000 for x in outdeg_dict.values()]
141+
plt.figure(figsize=(40, 20))
142+
lat_long = {
143+
i: [a, b]
144+
for i, a, b in zip(
145+
country_locations.country, country_locations.long, country_locations.lat
146+
)
147+
}
148+
if geo:
149+
postemp = lat_long
150+
m = Basemap(
151+
projection="merc",
152+
llcrnrlon=-180,
153+
llcrnrlat=-80,
154+
urcrnrlon=180,
155+
urcrnrlat=80,
156+
lat_ts=0,
157+
resolution="l",
158+
suppress_ticks=True,
159+
)
160+
m.drawcountries(linewidth=1.5)
161+
m.drawstates(linewidth=0.1)
141162
m.drawcoastlines(linewidth=1.5)
142163
latitudes = [lat_long[country][1] for country in lat_long]
143164
longitudes = [lat_long[country][0] for country in lat_long]
144165
mx, my = m(longitudes, latitudes)
145166
pos = {}
146167
for count, (key, value) in enumerate(postemp.items()):
147-
if(key in G.nodes):
168+
if key in G.nodes:
148169
pos[key] = (mx[count], my[count])
149170
else:
150-
pos=nx.spring_layout(G, seed=1231)
151-
nx.draw(G, pos, with_labels=True, node_size=nsize, node_color=[mapper.to_rgba(i) for i in indeg_dict.values()])
171+
pos = nx.spring_layout(G, seed=1231)
172+
nx.draw(
173+
G,
174+
pos,
175+
with_labels=True,
176+
node_size=nsize,
177+
node_color=[mapper.to_rgba(i) for i in indeg_dict.values()],
178+
)
152179
plt.show()
153180
```
154181

@@ -197,7 +224,7 @@ Now, when we remove the trade link between Russia and Japan, we can observe chan
197224

198225
```{code-cell} ipython3
199226
# removing trade link between Russia and Japan
200-
G_natural_gas.remove_edge('RUS', 'JPN')
227+
G_natural_gas.remove_edge("RUS", "JPN")
201228
draw_pretty(G_natural_gas, geo=False)
202229
```
203230

@@ -214,7 +241,12 @@ Closeness centrality is an indicator of the distance of a node from other nodes
214241
In betweenness centrality, the location of the node in the network is more essential than the number of nodes linked. It indicates how important a country is in terms of connecting other countries. Countries having a high betweenness centrality operate as a commercial bridge with other countries in the trade network. Betweenness centrality therefore quantifies the extent to which a certain node operates as an intermediate or gatekeeper in the network.
215242

216243
```{code-cell} ipython3
217-
total_outgoing_weight = {node: sum(data['value']/1000000 for _, _, data in G_coffee.out_edges(node, data=True)) for node in G_coffee}
244+
total_outgoing_weight = {
245+
node: sum(
246+
data["value"] / 1000000 for _, _, data in G_coffee.out_edges(node, data=True)
247+
)
248+
for node in G_coffee
249+
}
218250
219251
closeness = nx.closeness_centrality(G_coffee)
220252
betweenness = nx.betweenness_centrality(G_coffee)
@@ -224,21 +256,24 @@ outdegree = nx.out_degree_centrality(G_coffee)
224256

225257
```{code-cell} ipython3
226258
# combining both dicts into one dataframe
227-
df1 = pd.DataFrame(indegree.items(), columns=['country', 'indegree'])
228-
df2 = pd.DataFrame(outdegree.items(), columns=['country', 'outdegree'])
229-
df3 = pd.DataFrame(closeness.items(), columns=['country', 'closeness'])
230-
df4 = pd.DataFrame(betweenness.items(), columns=['country', 'betweenness'])
231-
df5 = pd.DataFrame(total_outgoing_weight.items(), columns=['country', 'export_value'])
232-
merged_df = pd.merge(df1, df2, on='country', how='inner')
233-
merged_df = pd.merge(merged_df, df3, on='country', how='inner')
234-
merged_df = pd.merge(merged_df, df4, on='country', how='inner')
235-
merged_df = pd.merge(merged_df, df5, on='country', how='inner')
236-
237-
merged_df.sort_values(by=['export_value'], inplace=True, ascending=False)
238-
239-
with pd.option_context('display.max_rows', None,
240-
'display.max_columns', None,
241-
):
259+
df1 = pd.DataFrame(indegree.items(), columns=["country", "indegree"])
260+
df2 = pd.DataFrame(outdegree.items(), columns=["country", "outdegree"])
261+
df3 = pd.DataFrame(closeness.items(), columns=["country", "closeness"])
262+
df4 = pd.DataFrame(betweenness.items(), columns=["country", "betweenness"])
263+
df5 = pd.DataFrame(total_outgoing_weight.items(), columns=["country", "export_value"])
264+
merged_df = pd.merge(df1, df2, on="country", how="inner")
265+
merged_df = pd.merge(merged_df, df3, on="country", how="inner")
266+
merged_df = pd.merge(merged_df, df4, on="country", how="inner")
267+
merged_df = pd.merge(merged_df, df5, on="country", how="inner")
268+
269+
merged_df.sort_values(by=["export_value"], inplace=True, ascending=False)
270+
271+
with pd.option_context(
272+
"display.max_rows",
273+
None,
274+
"display.max_columns",
275+
None,
276+
):
242277
print(merged_df)
243278
```
244279

@@ -269,9 +304,19 @@ Here, we detect communities in the trade network of Diamonds such that the modul
269304
community = nx.community.greedy_modularity_communities(G_diamonds)
270305
271306
# function to create node colour list
307+
308+
272309
def create_community_node_colors(graph, communities):
273310
number_of_colors = len(communities[0])
274-
colors = ["#D4FCB1", "#CDC5FC", "#FFC2C4", "#F2D140", "#F57160", "#2894F5", "#577D32"][:number_of_colors]
311+
colors = [
312+
"#D4FCB1",
313+
"#CDC5FC",
314+
"#FFC2C4",
315+
"#F2D140",
316+
"#F57160",
317+
"#2894F5",
318+
"#577D32",
319+
][:number_of_colors]
275320
node_colors = []
276321
for node in graph:
277322
current_community_index = 0
@@ -287,16 +332,37 @@ def create_community_node_colors(graph, communities):
287332
def visualize_communities(graph, communities):
288333
node_colors = create_community_node_colors(graph, communities)
289334
# Calculate the total incoming weight for each node
290-
total_incoming_weight = {node: sum(data['value'] for _, _, data in graph.out_edges(node, data=True)) for node in graph}
335+
total_incoming_weight = {
336+
node: sum(data["value"] for _, _, data in graph.out_edges(node, data=True))
337+
for node in graph
338+
}
291339
# Get the maximum and minimum incoming weight values
292340
max_weight = max(total_incoming_weight.values())
293341
min_weight = min(total_incoming_weight.values())
294342
# Normalize the incoming weights to the desired node size range
295-
normalized_weights = {node: 10 + ((total_incoming_weight[node] - min_weight) / (max_weight - min_weight)) * 90 for node in graph}
296-
pos = dict([(i,[a,b]) for i, a,b in zip(country_locations.country, country_locations.long, country_locations.lat)])
297-
nx.draw(graph, pos=pos, node_size=[100*normalized_weights[node] for node in graph], node_color=node_colors, with_labels=True, font_size=15, font_color="black")
298-
299-
plt.figure(figsize=(30,20))
343+
normalized_weights = {
344+
node: 10
345+
+ ((total_incoming_weight[node] - min_weight) / (max_weight - min_weight)) * 90
346+
for node in graph
347+
}
348+
pos = {
349+
i: [a, b]
350+
for i, a, b in zip(
351+
country_locations.country, country_locations.long, country_locations.lat
352+
)
353+
}
354+
nx.draw(
355+
graph,
356+
pos=pos,
357+
node_size=[100 * normalized_weights[node] for node in graph],
358+
node_color=node_colors,
359+
with_labels=True,
360+
font_size=15,
361+
font_color="black",
362+
)
363+
364+
365+
plt.figure(figsize=(30, 20))
300366
visualize_communities(G_diamonds, community)
301367
plt.show()
302368
```

0 commit comments

Comments
 (0)