NetworkX é um pacote Python utilizado para manipulação de grafos e redes complexas. A documentação da biblioteca, além de exemplos mais aprofundados, estão disponíveis em: https://networkx.org/. Neste artigo, apresentaremos como manipular grafos usando essa biblioteca. A antes de nos aprofundarmos no Networkx, precisamos explorar o conceito de grafos.
Grafos
Grafos são estruturas que representam um conjunto de itens e o relacionamento entre eles. Um grafo G(V, E) é composto por vértices (também conhecidos como nós) que se conectar por meio das arestas (também conhecidos como links ou pares de nós).
Primeiros passos
Instalação
No Python 3, você pode instalá-lo com o comando:
pip3 install networkx
No Python 2, use:
pip install networkx
No Anaconda use:
conda install networkx
Criando um objeto networkx
Como apresentado anteriormente, um grafo é composto por vértices conectados por arestas. NetworkX permite que vértices possam ser strings de texto, números, etc.
O código a seguir cria um objeto networkx:
import networkx as nx
G = nx.Graph()
Adicionando vértices
Agora vamos adicionar dois vértices e criar uma aresta para conectá-los:
import networkx as nx
G = nx.Graph()
# adicionando vertices
G.add_node(1)
G.add_node(2)
# Visualizando os vertices
print(G.nodes())
#[1, 2]
#adicionando arestas
G.add_edge(1, 2)
# total de vertices e arestas
n_vertices = G.number_of_nodes()
n_arestas = G.number_of_edges()
print('vertices: ', n_vertices, '\narestas: ', n_arestas)
#vertices: 2
#arestas: 1
Note que ao executar o comando:
G.add_edge(4, 5)
print(G.nodes()) # [4, 5]
Networkx irá criar os vértices 4 e 5, e depois irá criar uma aresta os conectando.
Você pode visualizar as arestas acessando o atributo edges:
print(G.edges) # [(4, 5)]
Removendo vértices
Podemos remover um vértice usando a função remove_node( ):
# adicionando vertices
G.add_node(1)
G.add_node(2)
print(G.nodes()) #[1, 2]
# remove o nó 2
G.remove_node(2)
print(G.nodes())
#[1]
Desenhando o grafo
Podemos imprimir o grafo usando o comando draw. Veja:
nx.draw(G)
Podemos ainda adicionar arestas sem a necessidade de incluir cada um dos itens:
G.add_edge(3, 4)
G.add_edge(1, 3)
G.add_edge(5, 6)
G.add_edge(5, 9)
G.add_edge(7, 8)
G.add_edge(1, 8)
G.add_edge(1, 4)
nx.draw(G) # imprimindo o grafo
Veja como ficará o grafo apresentado:
Podemos adicionar rótulos aos nós usando o atributo with_labels. Veja:
nx.draw(G, with_labels=True)
Podemos ainda alterar a cor e o tamanho dos vértices com as propriedades node_size e node_color, respectivamente. No exemplo a seguir, iremos aumentar o tamanho dos nós e alterar a cor para vermelho.
nx.draw(G, with_labels=True, node_size=1200, node_color='red')
Subgrafos
Na figura apresentada acima, podemos perceber visualmente que há duas partes do grafo que não se conectam entre si. Denominamos essas partes como subgrafos. Podemos obtê-las utilizando o código:
subgrafos = [G.subgraph(s) for s in nx.connected_components(G)]
print(len(subgrafos)) # verificando a quantidade de subgrafos
Podemos ainda plotar os diferentes subgrafos com cores distintas, como por exemplo, verde e vermelho. Veja:
nx.draw(
subgrafos[0], # subgrafo na posição 0
with_labels=True, # mostrar rótulos
node_size=800, # aumentar tamanho
node_color='red' # cor vermelha
)
nx.draw(
subgrafos[1], # subgrafo na posição 0
with_labels=True, # mostrar rótulos
node_size=800, # aumentar tamanho
node_color='green' # cor verde
)
Isso irá gerar a seguinte figura:
Perceba que alguns nós se sobrepõe. A definição da posição de impressão é aleatória. Entretanto, podemos utilizar algumas variações da função draw para alterar a forma de plotagem. Vamos ilustrar isso usando duas dessas variações: draw_circular e draw_random.
# grafo vermelho - circular
nx.draw_circular(
subgrafos[0],
with_labels=True,
node_size=800,
node_color='red'
)
# grafo verde - posições aleatórias
nx.draw_random(
subgrafos[1],
with_labels=True,
node_size=800,
node_color='green'
)
Note pelo exemplo acima que a função draw_circular força os vértices a se posicionarem em forma de círculo. A outra função, draw_random, posiciona os pontos de forma aleatória.
Convertendo um CSV em um grafo
Em alguns casos, você precisará criar um grafo usando como entrada o conteúdo de um arquivo CSV. Podemos fazer isso usando a networkx e a biblioteca pandas através do método from_pandas_edgelist( ). Para ilustrar isso, vamos primeiro criar um arquivo CSV para ilustrar o grafo a seguir:
Observe como uma tabela com os pares de nós do grafo acima:
Nó 1 | Nó 2 |
---|---|
1 | 2 |
1 | 5 |
2 | 3 |
2 | 5 |
3 | 4 |
4 | 5 |
4 | 6 |
O formato CSV (Comma Separated Values) é comumente utilizado para armazenamento de informações. Nesse arquivo, cada entrada é representada por uma linha, enquanto seus atributos são separados por vírgula (ou ponto e vírgula). Uma variação também bastante comum desse formato é o TSV (Tab-Separated Values), que utiliza tabulações para separar os atributos.
Veja como os pares de links poderiam ser representados em um arquivo CSV (aqui denominado grafo.csv):
Nó 1,Nó 2
1,2
1,5
2,3
2,5
3,4
4,5
4,6
Observe que a primeira linha é destinada ao cabeçalho, que indica o que irá descrever um representante para cada uma das entradas.
Carregando um CSV com pandas
Agora vamos utilizar a biblioteca pandas para carregar esse arquivo para um script Python.
import pandas as pd # importa o pandas
# carregar os nós
with open("grafo.csv") as f:
pares = f.read().splitlines()
# pega os nós em duas listas separadas
node_1 = []
node_2 = []
# separando os nós em listas separadas
for i, cont in zip(pares, range(len(pares))):
if cont == 0:
continue # ignora a primeira linha
node_1.append(i.split(',')[0])
node_2.append(i.split(',')[1])
# cria um dataframe PANDAS para armazenar os dados
df = pd.DataFrame({'node_1': node_1, 'node_2': node_2})
print(df)
'''
node_1 node_2
0 1 2
1 1 5
2 2 3
3 2 5
4 3 4
5 4 5
6 4 6
'''
A biblioteca pandas converte nosso CSV em um objeto de DataFrame. Observe que cada linha contém o índice da posição. Na primeira linha vemos os títulos das colunas (optamos por chamá-los de “node_1” e “node_2” no lugar de “Nó 1” e “Nó 2” para evitar possíveis problemas com codificação).
Convertendo um DataFrame do pandas em um grafo do networkx
Agora vamos carregar o grafo usando networkx e imprimi-lo usando a biblioteca Matplotlib.
Podemos converter um DataFrame do pandas para um grafo do networkx usando o método nx.from_pandas_edgelist( ). Esse método deve receber como entrada: (i) um dataframe; (ii) o nome da coluna com o primeiro nó; (iii) o nome da coluna com o segundo nó; (iv) o método de criação
Observe como podemos converter o DataFrame criado anteriormente em um grafo:
import networkx as nx
import matplotlib.pyplot as plt
G = nx.from_pandas_edgelist(
df,
"node_1",
"node_2",
create_using=nx.Graph()
)
# plota o grafo
nx.draw(G, with_labels=True, node_size = 1000)
plt.show()
Ao executar esse código obteremos a seguinte imagem:
Salvando grafos em CSV
Podemos salvar um grafo em um arquivo CSV usando a função write_edgelist( ):
gravando um grafo como arquivo csv
nx.write_edgelist(
G, # grafo
"grafo2.csv", # nome do arquivo
delimiter=",", # separador
data=False, # se True, grava dados do peso das arestas
encoding='utf-8' # codificação
)
Lendo arquivos CSV como grafos
Vimos anteriormente como gerar grafos a partir de arquivos CSV passando por DataFrames gerados com pandas. Entretanto, podemos ler um arquivo CSV diretamente usando networkx:
G2 = nx.read_edgelist("grafo2.csv", delimiter=",")
Resumo
Descrição | Comando |
---|---|
Iniciar um grafo | G = nx.Graph() |
Criar um novo vértice (nó) | G.add_node(1) G.add_node(2) |
Ver todos os vértices | G.nodes() |
Cria uma aresta | G.add_edge(1, 2) |
Contar total de vértices | G.number_of_nodes() |
Contar total de arestas | G.number_of_edges() |
Remover vértice | G.remove_node(2) |
Desenhando | nx.draw(G) |
Criando um grafo a partir de um DataFrame do pandas. | from_pandas_edgelist( dataframe, node_1, node_2, create_using=nx.Graph() ) |
Salvando um grafo em CSV | nx.write_edgelist( grafo, nome, delimitador ) |
Lendo um grafo a partir de um CSV | G2 = nx.read_edgelist( “[nome-arquivo].csv”, delimiter=”,” ) |
Principais atributos e métodos para manipulação de grafos com networkx
add_edge
add_edges_from
add_node
add_nodes_from
add_weighted_edges_from
adj
adjacency
adjlist_inner_dict_factory
adjlist_outer_dict_factory
clear
clear_edges
copy
degree
edge_attr_dict_factory
edge_subgraph
edges
get_edge_data
graph
graph_attr_dict_factory
has_edge
has_node
is_directed
is_multigraph
name
nbunch_iter
neighbors
node_attr_dict_factory
node_dict_factory
nodes
number_of_edges
number_of_nodes
order
remove_edge
remove_edges_from
remove_node
remove_nodes_from
size
subgraph
to_directed
to_directed_class
to_undirected
to_undirected_class
update
Cursos profissionalizantes à partir de R$ 22,90
Leia também
- Fator de impacto e Qualis de periódicosAtualizado em 2024
- Como ler um arquivo mmCIFusando Python
- O guia de sobrevivência de expressões regulares em PythonEste material faz parte do livro “Python para Bioinformática” (ainda não publicado). Para mais informações, consulte o autor. Expressões regulares são ferramentas poderosas para buscas de padrões em textos. Logo, todo o bioinformata deve conhecê-las. Neste artigo, você irá conhecer os principais metacaracteres e irá aprender a manipular expressões regulares usando Python. Bons estudos! Expressões…
- SVD – Decomposição por Valores Singulares com PythonEste material faz parte do livro “Python para Bioinformática” (ainda não publicado). Para mais informações, consulte o autor. Decomposição por valores singulares, do inglês Singular Value Decomposition (SVD) é uma técnica da álgebra linear usada para recuperação de informações, redução dimensional e remoção de ruídos. Nessa técnica, uma matriz A de tamanho MxN é decomposta…
- Como ler arquivos com JavaScript de forma síncronaasyn & await
- Parâmetros do DataTablesVeja como ordenar colunas, alterar a quantidade de itens em uma página e alterar o alinhamento no DataTables
- Exportando tabelas do DataTablesDataTables é uma biblioteca JavaScript fantástica para lidar com tabelas dinâmicas em páginas da web. Entretanto, podemos estender ainda mais suas funcionalidades, inserindo botões que permitem a exportação dos dados da tabela em múltiplos formatos, como por exemplo, tabular (para cópia), CSV, Excel, PDF e até mesmo HTML para impressão. Veja um exemplo: Observe o…
- Método every()Usando o método every() para ler todos os itens de um array JavaScript
- Análise de CorrelaçãoCorrelação de Pearson
- Curso de Escrita CientíficaAprenda a escrever monografias, TCCs, teses, dissertações, projetos e artigos científicos