Dataviz Code Session: Redes Complexas
Contents
14. Dataviz Code Session: Redes Complexas#
14.1. Objetivos da DCS#
Aplicar técnicas de dataviz para plotagem e manipulação de representações visuais de redes simples e complexas.
Elaborar RV para dados do comércio exterior, enfatizando fluxos de importação/exportação por meio de grafos.
14.2. Ferramentas utilizadas#
Módulos Python
pandas
numpy
matplotlib
networkx
sys
14.3. Aplicação do modelo referencial#
Vide Capítulo 3.
from matplotlib.patches import Patch
import pandas as pd, matplotlib.pyplot as plt, seaborn as sb, numpy as np, networkx as nx
import sys; sys.path.insert(1,'../dcs')
import dcs24, dcs25
14.3.1. Dados de entrada pré-processados#
Carregamento de dados
# carrega valores para ano y
y = 2020
# planilhas
# imp: importação; exp: exportação; cc: códigos de países/blocos; tgt_dir: diretório-fonte dos dados
imp, exp, cc, via, tgt_dir = dcs24.get_comex(y)
# remove entradas duplicadas de países
cc = cc.drop_duplicates()
COMEX files successfuly loaded from: ../data/comex-2020
14.3.1.1. Processamento adicional#
Fusões por código de país e meio de transporte
# meio de transporte
via = via.rename(columns={'Código da via':'Meio de transporte'})
# importação
imp = imp.rename(columns={'País de origem':'Código do país'})
imp = imp.merge(cc,on='Código do país')
imp = imp.merge(via,on='Meio de transporte')
# exportação
exp = exp.rename(columns={'País de destino':'Código do país'})
exp = exp.merge(cc,on='Código do país')
exp = exp.merge(via,on='Meio de transporte')
via
Meio de transporte | Descrição da via | |
---|---|---|
0 | 0 | VIA NAO DECLARADA |
1 | 1 | MARITIMA |
2 | 2 | FLUVIAL |
3 | 3 | LACUSTRE |
4 | 4 | AEREA |
5 | 5 | POSTAL |
6 | 6 | FERROVIARIA |
7 | 7 | RODOVIARIA |
8 | 8 | CONDUTO/REDE DE TRANSMISSAO |
9 | 9 | MEIOS PROPRIOS |
10 | 10 | ENTRADA/SAIDA FICTA |
11 | 99 | VIA DESCONHECIDA |
12 | 13 | POR REBOQUE |
13 | 11 | COURIER |
14 | 15 | VICINAL FRONTEIRICO |
15 | 14 | DUTOS |
16 | 12 | EM MAOS |
Restrição de dados por escolha de via e bloco geográfico
Nota: execute imp['Nome do bloco'].unique()
para a listagem de blocos.
# seletor de via e bloco
via_e = 'AEREA'
bloco_e = 'União Europeia - UE'
# filtros
imp_p_via = imp[(imp['Descrição da via'] == via_e) & (imp['Nome do bloco'] == bloco_e)]
exp_p_via = exp[(exp['Descrição da via'] == via_e) & (exp['Nome do bloco'] == bloco_e)]
#imp['Nome do bloco'].unique()
Agrupamento por FOB
imp_p_via_e = imp_p_via.groupby('Nome do país')['Valor Free On Board'].sum()
exp_p_via_e = exp_p_via.groupby('Nome do país')['Valor Free On Board'].sum()
df_g = pd.merge(imp_p_via_e,exp_p_via_e,on='Nome do país',how='outer').reset_index()
df_g = df_g.rename(columns={'Valor Free On Board_x':'FOB_imp','Valor Free On Board_y':'FOB_exp'})
df_g
Nome do país | FOB_imp | FOB_exp | |
---|---|---|---|
0 | Aland, Ilhas | 5.570000e+03 | 140.0 |
1 | Alemanha | 2.408373e+09 | 445676987.0 |
2 | Bulgária | 1.048810e+07 | 1095139.0 |
3 | Bélgica | 3.579592e+08 | 264325328.0 |
4 | Chipre | 1.090164e+06 | 456850.0 |
5 | Croácia | 5.911743e+06 | 197694.0 |
6 | Dinamarca | 2.452543e+08 | 17600298.0 |
7 | Eslováquia | 1.487331e+07 | 2123435.0 |
8 | Eslovênia | 2.733640e+07 | 791051.0 |
9 | Espanha | 3.249332e+08 | 128140171.0 |
10 | Estônia | 1.922603e+07 | 3237512.0 |
11 | Finlândia | 8.944374e+07 | 4228748.0 |
12 | França | 1.677680e+09 | 339518847.0 |
13 | Grécia | 4.758132e+06 | 1795332.0 |
14 | Guernsey | NaN | 30.0 |
15 | Hungria | 8.063740e+07 | 9166220.0 |
16 | Ilha de Man | 1.840790e+05 | NaN |
17 | Irlanda | 4.763710e+08 | 32553334.0 |
18 | Itália | 1.057513e+09 | 386954098.0 |
19 | Jersey | NaN | 6349.0 |
20 | Letônia | 3.166250e+06 | 158234.0 |
21 | Lituânia | 5.960187e+06 | 1363212.0 |
22 | Luxemburgo | 6.236162e+06 | 15671276.0 |
23 | Malta | 5.745938e+06 | 125299.0 |
24 | Países Baixos (Holanda) | 2.040769e+08 | 119144128.0 |
25 | Polônia | 1.597044e+08 | 23621094.0 |
26 | Portugal | 4.647189e+07 | 96051457.0 |
27 | Romênia | 3.919266e+07 | 5494574.0 |
28 | Suécia | 1.918735e+08 | 23023034.0 |
29 | Tcheca, República | 9.571066e+07 | 8638781.0 |
30 | Terras Austrais Francesas | 8.118000e+03 | 13848.0 |
31 | Áustria | 2.756209e+08 | 9135070.0 |
14.4. Mapeamento#
Criação de grafo para visualizar a rede de parcerias bilaterais do Brasil;
Cada nó representa um país e cada aresta dirigida o fluxo de mercadorias;
Para cada nó de origem \(v_i\) e de destino \(v_j\), a aresta \(e_{ij}\) liga \(v_i\) a \(v_j\) nesta direção;
Logo, fazemos o seguinte:
tomando \(i \in I = \{0\}\), \(v_0\) passa a ser o nó correspondente ao Brasil e \(e_{0j}\) são arestas de exportação;
\(e_{j0}\) são arestas de importação;
Separação de conjuntos para criação de lista de arestas e atributos
Notas:
Como o modelo trata-se de um grafo dirigido, a criação de dois conjuntos independentes é necessária para fins de visualização.
Valores de FOB como
nan
significam que não houve fluxo entre o Brasil e o país \(j\).
# grafo de importação
df_g_imp = pd.DataFrame({'node_from': np.arange(len(df_g))+1,
'node_to': [0]*len(df_g),
'FOB':df_g['FOB_imp'],
'from_name':df_g['Nome do país'],
'to_name':['Brasil']*len(df_g)})
# grafo de exportação
df_g_exp = pd.DataFrame({'node_to': np.arange(len(df_g))+1,
'node_from': [0]*len(df_g),
'FOB':df_g['FOB_exp'],
'from_name':['Brasil']*len(df_g),
'to_name':df_g['Nome do país']})
df_g_imp
node_from | node_to | FOB | from_name | to_name | |
---|---|---|---|---|---|
0 | 1 | 0 | 5.570000e+03 | Aland, Ilhas | Brasil |
1 | 2 | 0 | 2.408373e+09 | Alemanha | Brasil |
2 | 3 | 0 | 1.048810e+07 | Bulgária | Brasil |
3 | 4 | 0 | 3.579592e+08 | Bélgica | Brasil |
4 | 5 | 0 | 1.090164e+06 | Chipre | Brasil |
5 | 6 | 0 | 5.911743e+06 | Croácia | Brasil |
6 | 7 | 0 | 2.452543e+08 | Dinamarca | Brasil |
7 | 8 | 0 | 1.487331e+07 | Eslováquia | Brasil |
8 | 9 | 0 | 2.733640e+07 | Eslovênia | Brasil |
9 | 10 | 0 | 3.249332e+08 | Espanha | Brasil |
10 | 11 | 0 | 1.922603e+07 | Estônia | Brasil |
11 | 12 | 0 | 8.944374e+07 | Finlândia | Brasil |
12 | 13 | 0 | 1.677680e+09 | França | Brasil |
13 | 14 | 0 | 4.758132e+06 | Grécia | Brasil |
14 | 15 | 0 | NaN | Guernsey | Brasil |
15 | 16 | 0 | 8.063740e+07 | Hungria | Brasil |
16 | 17 | 0 | 1.840790e+05 | Ilha de Man | Brasil |
17 | 18 | 0 | 4.763710e+08 | Irlanda | Brasil |
18 | 19 | 0 | 1.057513e+09 | Itália | Brasil |
19 | 20 | 0 | NaN | Jersey | Brasil |
20 | 21 | 0 | 3.166250e+06 | Letônia | Brasil |
21 | 22 | 0 | 5.960187e+06 | Lituânia | Brasil |
22 | 23 | 0 | 6.236162e+06 | Luxemburgo | Brasil |
23 | 24 | 0 | 5.745938e+06 | Malta | Brasil |
24 | 25 | 0 | 2.040769e+08 | Países Baixos (Holanda) | Brasil |
25 | 26 | 0 | 1.597044e+08 | Polônia | Brasil |
26 | 27 | 0 | 4.647189e+07 | Portugal | Brasil |
27 | 28 | 0 | 3.919266e+07 | Romênia | Brasil |
28 | 29 | 0 | 1.918735e+08 | Suécia | Brasil |
29 | 30 | 0 | 9.571066e+07 | Tcheca, República | Brasil |
30 | 31 | 0 | 8.118000e+03 | Terras Austrais Francesas | Brasil |
31 | 32 | 0 | 2.756209e+08 | Áustria | Brasil |
df_g_exp
node_to | node_from | FOB | from_name | to_name | |
---|---|---|---|---|---|
0 | 1 | 0 | 140.0 | Brasil | Aland, Ilhas |
1 | 2 | 0 | 445676987.0 | Brasil | Alemanha |
2 | 3 | 0 | 1095139.0 | Brasil | Bulgária |
3 | 4 | 0 | 264325328.0 | Brasil | Bélgica |
4 | 5 | 0 | 456850.0 | Brasil | Chipre |
5 | 6 | 0 | 197694.0 | Brasil | Croácia |
6 | 7 | 0 | 17600298.0 | Brasil | Dinamarca |
7 | 8 | 0 | 2123435.0 | Brasil | Eslováquia |
8 | 9 | 0 | 791051.0 | Brasil | Eslovênia |
9 | 10 | 0 | 128140171.0 | Brasil | Espanha |
10 | 11 | 0 | 3237512.0 | Brasil | Estônia |
11 | 12 | 0 | 4228748.0 | Brasil | Finlândia |
12 | 13 | 0 | 339518847.0 | Brasil | França |
13 | 14 | 0 | 1795332.0 | Brasil | Grécia |
14 | 15 | 0 | 30.0 | Brasil | Guernsey |
15 | 16 | 0 | 9166220.0 | Brasil | Hungria |
16 | 17 | 0 | NaN | Brasil | Ilha de Man |
17 | 18 | 0 | 32553334.0 | Brasil | Irlanda |
18 | 19 | 0 | 386954098.0 | Brasil | Itália |
19 | 20 | 0 | 6349.0 | Brasil | Jersey |
20 | 21 | 0 | 158234.0 | Brasil | Letônia |
21 | 22 | 0 | 1363212.0 | Brasil | Lituânia |
22 | 23 | 0 | 15671276.0 | Brasil | Luxemburgo |
23 | 24 | 0 | 125299.0 | Brasil | Malta |
24 | 25 | 0 | 119144128.0 | Brasil | Países Baixos (Holanda) |
25 | 26 | 0 | 23621094.0 | Brasil | Polônia |
26 | 27 | 0 | 96051457.0 | Brasil | Portugal |
27 | 28 | 0 | 5494574.0 | Brasil | Romênia |
28 | 29 | 0 | 23023034.0 | Brasil | Suécia |
29 | 30 | 0 | 8638781.0 | Brasil | Tcheca, República |
30 | 31 | 0 | 13848.0 | Brasil | Terras Austrais Francesas |
31 | 32 | 0 | 9135070.0 | Brasil | Áustria |
Construção do grafos como objetos
Graph
donetworkx
G_imp = nx.from_pandas_edgelist(df_g_imp,source='node_from',target='node_to',edge_attr='FOB')
for index, row in df_g_imp.iterrows():
G_imp.nodes[row['node_from']]['country'] = row['from_name']
G_exp = nx.from_pandas_edgelist(df_g_exp,source='node_from',target='node_to',edge_attr='FOB')
for index, row in df_g_exp.iterrows():
G_exp.nodes[row['node_from']]['country'] = row['from_name']
# impressão auxiliar
#G_imp.nodes(data=True), G_exp.edges(data=True)
14.5. Visualização#
14.5.1. Iterando em RVs primárias#
Vamos plotar os grafos de importação e exportação para a via e bloco escolhidos
Nós e arestas com cores padronizadas
Legendas por número (pouco claras)
Fluxo (“pesos”) não especificados
fig, ax = plt.subplots(1,2,figsize=(10,4))
nx.draw_networkx(G_imp,ax=ax[0])
nx.draw_networkx(G_exp,ax=ax[1])
ax[0].set_title(f'Rede de importação: {bloco_e} $\\rightarrow$ Brasil')
ax[1].set_title(f'Rede de exportação: Brasil $\\rightarrow$ {bloco_e}');
![../_images/25-dcs-redes_26_0.png](../_images/25-dcs-redes_26_0.png)
Controle de layout, tamanho de nós e legendas
fig, ax = plt.subplots(1,2,figsize=(10,4))
# controle de randomização das coordenadas dos vértices/nós
seed = 12
coords = nx.spring_layout(G_imp,seed=seed) # layout
# --- IMPORTAÇÃO
# plotagem de nós
nx.draw_networkx_nodes(G_imp,
pos=coords, # controle de layout
node_size = 800, # tamanho do nó
node_color='gray', # cor do nó
ax=ax[0]
)
nx.draw_networkx_edges(G_imp,
pos=coords,
edge_color='red', # cor de aresta
ax=ax[0]
)
nx.draw_networkx_labels(G_imp,
pos=coords,
labels=nx.get_node_attributes(G_imp,'country'), # atributo (nome do país)
font_size=7, # tamanho da fonte
ax=ax[0],
);
ax[0].set_title(f'Rede de importação: {bloco_e} $\\rightarrow$ Brasil')
# --- EXPORTAÇÃO
# plotagem de nós
nx.draw_networkx_nodes(G_exp,
pos=coords, # controle de layout
node_size = 400, # tamanho do nó
node_color='gray', # cor do nó
ax=ax[1]
)
nx.draw_networkx_edges(G_exp,
pos=coords,
edge_color='green', # cor de aresta
ax=ax[1]
)
nx.draw_networkx_labels(G_exp,
pos=coords,
labels=nx.get_node_attributes(G_imp,'country'), # atributo (nome do país)
font_size=7, # tamanho da fonte
ax=ax[1],
)
ax[1].set_title(f'Rede de exportação: Brasil $\\rightarrow$ {bloco_e}');
![../_images/25-dcs-redes_28_0.png](../_images/25-dcs-redes_28_0.png)
Sobrepondo os grafos
fig, ax = plt.subplots(figsize=(12,8),constrained_layout=True)
# --- IMPORTAÇÃO
fob, edge_colors, coords = dcs25.base_data(G_imp,fob_scale=1e8,seed=12)
cmap = plt.cm.Reds
# opções de nós
nodes = nx.draw_networkx_nodes(G_imp,
pos=coords,
node_color='grey',
alpha=0.3,
edgecolors= 'red',
linewidths=2,
node_size=800,
ax=ax)
# opções de arestas
edges = nx.draw_networkx_edges(G_imp,
pos=coords,
arrowstyle='->',
edge_color=edge_colors,
edge_cmap=cmap,
width=fob,
ax=ax)
# # opções de legendas de nós
labels = nx.draw_networkx_labels(G_imp,
pos=coords,
labels=nx.get_node_attributes(G_imp,'country'),
font_color='k',
alpha=0.7,
verticalalignment='bottom',
bbox = {'ec': 'k', 'fc': 'white', "alpha": 0.2},
font_size=10,
ax=ax)
edge_labels = nx.draw_networkx_edge_labels(G_imp,
pos=coords,
font_size=6,
verticalalignment='top',
bbox = {'fc': 'white', "alpha": 0.05},
font_color='#aa0000')
# # --- EXPORTAÇÃO
fob, edge_colors, coords = dcs25.base_data(G_exp,fob_scale=1e8,seed=12)
cmap = plt.cm.Greens
nodes = nx.draw_networkx_nodes(G_exp,
pos=coords,
node_color='grey',
alpha=0.3,
edgecolors='green',
linewidths=2,
node_size=400,
ax=ax)
edges = nx.draw_networkx_edges(G_exp,
pos=coords,
arrowstyle='->',
edge_color=edge_colors,
edge_cmap=cmap,
width=fob,
ax=ax)
labels = nx.draw_networkx_labels(G_exp,
pos=coords,
labels=nx.get_node_attributes(G_exp,'country'),
font_size=16,
font_color='k')
edge_labels = nx.draw_networkx_edge_labels(G_exp,
pos=coords,
font_size=6,
verticalalignment='bottom',
font_color='#00aa00')
ax.set_axis_off()
![../_images/25-dcs-redes_30_0.png](../_images/25-dcs-redes_30_0.png)
14.6. RV finalística#
Graph plot com adaptações
Inclusão de legenda via patches
Remoção do indicador FOB
Onde colocar?
fig, ax = plt.subplots(figsize=(12,8),constrained_layout=True)
# --- IMPORTAÇÃO
fob, edge_colors, coords = dcs25.base_data(G_imp,fob_scale=1e8,seed=12)
cmap = plt.cm.Reds
# opções de nós
nodes = nx.draw_networkx_nodes(G_imp,
pos=coords,
node_color='grey',
alpha=0.3,
edgecolors= 'red',
linewidths=2,
node_size=800,
ax=ax)
# opções de arestas
edges = nx.draw_networkx_edges(G_imp,
pos=coords,
arrowstyle='->',
edge_color=edge_colors,
edge_cmap=cmap,
width=fob,
ax=ax)
# opções de legendas de nós
labels = nx.draw_networkx_labels(G_imp,
pos=coords,
labels=nx.get_node_attributes(G_imp,'country'),
font_color='k',
alpha=0.7,
verticalalignment='bottom',
bbox = {'ec': 'k', 'fc': 'white', "alpha": 0.05},
font_size=10,
ax=ax)
# edge_labels = nx.draw_networkx_edge_labels(G_imp,
# pos=coords,
# font_size=6,
# verticalalignment='top',
# bbox = {'fc': 'white', "alpha": 0.05},
# font_color='#aa0000')
# --- EXPORTAÇÃO
fob, edge_colors, coords = dcs25.base_data(G_exp,fob_scale=1e8,seed=12)
cmap = plt.cm.Greens
nodes = nx.draw_networkx_nodes(G_exp,
pos=coords,
node_color='grey',
alpha=0.3,
edgecolors='green',
linewidths=2,
node_size=400,
ax=ax)
edges = nx.draw_networkx_edges(G_exp,
pos=coords,
arrowstyle='->',
edge_color=edge_colors,
edge_cmap=cmap,
width=fob,
ax=ax)
labels = nx.draw_networkx_labels(G_exp,
pos=coords,
labels=nx.get_node_attributes(G_exp,'country'),
font_size=16,
font_color='k')
# desativa eixos
ax.set_axis_off()
# legenda
leg = [Patch(facecolor='#00aa00', edgecolor='g', label='Fluxo de exportação'),
Patch(facecolor='#aa0000', edgecolor='r', label='Fluxo de importação')]
ax.legend(handles=leg, loc='upper right')
# título
fig.suptitle('Rede bilateral: Brasil/países (Fluxo de importação/exportação FOB em bi USD)',fontsize=16)
ax.set_title(f'Via de transporte: {via_e}; Bloco:{bloco_e}; Ano: {y}',fontsize=13);
![../_images/25-dcs-redes_33_0.png](../_images/25-dcs-redes_33_0.png)