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#

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 do networkx

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
  • 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
  • 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

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