Skip to content

NetworkX Integration

GrafitoDB provides bidirectional integration with NetworkX for graph algorithms and analysis.

Export to NetworkX

Convert a GrafitoDB database to a NetworkX MultiDiGraph.

Basic Export

from grafito import GrafitoDatabase

# Create database with data
db = GrafitoDatabase(':memory:')
alice = db.create_node(labels=['Person'], properties={'name': 'Alice', 'age': 30})
bob = db.create_node(labels=['Person'], properties={'name': 'Bob', 'age': 25})
db.create_relationship(alice.id, bob.id, 'KNOWS', {'since': 2020})

# Export to NetworkX
graph = db.to_networkx()

print(f'Nodes: {graph.number_of_nodes()}')  # 2
print(f'Edges: {graph.number_of_edges()}')  # 1

Node Attributes

Node attributes in NetworkX include: - labels: List of node labels - properties: Dictionary of node properties - Original node ID is stored as grafito_id

# Access node attributes
for node_id, attrs in graph.nodes(data=True):
    print(f'Node {node_id}:')
    print(f'  Labels: {attrs["labels"]}')
    print(f'  Properties: {attrs["properties"]}')

Edge Attributes

Edge attributes include: - type: Relationship type - properties: Dictionary of relationship properties

# Access edge attributes
for u, v, key, attrs in graph.edges(data=True, keys=True):
    print(f'Edge {u} -> {v}:')
    print(f'  Type: {attrs["type"]}')
    print(f'  Properties: {attrs["properties"]}')

Import from NetworkX

Import a NetworkX graph into GrafitoDB.

Basic Import

import networkx as nx
from grafito import GrafitoDatabase

# Create NetworkX graph
graph = nx.MultiDiGraph()
graph.add_node('alice', labels=['Person'], properties={'name': 'Alice'})
graph.add_node('bob', labels=['Person'], properties={'name': 'Bob'})
graph.add_edge('alice', 'bob', type='KNOWS', properties={'since': 2020})

# Import into Grafito
db = GrafitoDatabase(':memory:')
node_map = db.from_networkx(graph)

# node_map maps NetworkX node IDs to Grafito node IDs
print(f'Created {len(node_map)} nodes')
print(f'Alice ID: {node_map["alice"]}')

Import with Custom Mapping

# Import and then work with the data
node_map = db.from_networkx(graph)

# Query imported data
alice_id = node_map['alice']
neighbors = db.get_neighbors(alice_id, direction='outgoing')
for n in neighbors:
    print(f'Alice knows: {n.properties["name"]}')

Using NetworkX Algorithms

Once exported, use any NetworkX algorithm.

Centrality Analysis

import networkx as nx

# Export graph
graph = db.to_networkx()

# Degree centrality
degree_cent = nx.degree_centrality(graph)
print('Most connected:', max(degree_cent, key=degree_cent.get))

# Betweenness centrality
betweenness = nx.betweenness_centrality(graph)
print('Key connectors:', sorted(betweenness.items(), key=lambda x: -x[1])[:5])

# PageRank
pagerank = nx.pagerank(graph)
print('Highest PageRank:', max(pagerank, key=pagerank.get))

Path Finding

# Shortest path
try:
    path = nx.shortest_path(graph, source=alice.id, target=bob.id)
    print(f'Path: {path}')
except nx.NetworkXNoPath:
    print('No path exists')

# All simple paths
paths = list(nx.all_simple_paths(graph, alice.id, bob.id, cutoff=3))
print(f'Found {len(paths)} paths')

Community Detection

# Weakly connected components
components = list(nx.weakly_connected_components(graph))
print(f'{len(components)} components')

# Communities using Louvain (undirected)
undirected = graph.to_undirected()
communities = nx.community.louvain_communities(undirected)
print(f'{len(communities)} communities')

Cycle Detection

# Find cycles
cycles = list(nx.simple_cycles(graph))
print(f'{len(cycles)} cycles found')

# Check if DAG
is_dag = nx.is_directed_acyclic_graph(graph)
print(f'Is DAG: {is_dag}')

Data Transformation

Converting to Undirected

# For algorithms requiring undirected graphs
undirected = graph.to_undirected()

# Check connectivity
is_connected = nx.is_connected(undirected)
print(f'Connected: {is_connected}')

Extracting Subgraphs

# Subgraph by nodes
node_subset = list(graph.nodes())[:10]
subgraph = graph.subgraph(node_subset)

# Egocentric network (1-hop around a node)
egonet = nx.ego_graph(graph.to_undirected(), alice.id, radius=1)
print(f'Egonet has {egonet.number_of_nodes()} nodes')

Roundtrip Example

# Create in Grafito
db = GrafitoDatabase(':memory:')
alice = db.create_node(labels=['Person'], properties={'name': 'Alice'})
bob = db.create_node(labels=['Person'], properties={'name': 'Bob'})
db.create_relationship(alice.id, bob.id, 'KNOWS')

# Export to NetworkX
graph = db.to_networkx()

# Run algorithms
scores = nx.pagerank(graph)

# Enrich graph with scores
for node_id, score in scores.items():
    graph.nodes[node_id]['pagerank'] = score

# Import back to Grafito
db2 = GrafitoDatabase(':memory:')
node_map = db2.from_networkx(graph)

# Query enriched data
for old_id, new_id in node_map.items():
    node = db2.get_node(new_id)
    print(f"{node.properties['name']}: PageRank = {node.properties.get('pagerank')}")

Best Practices

1. Memory Considerations

# For large graphs, process in batches
batch_size = 1000
all_nodes = list(db.match_nodes())

for i in range(0, len(all_nodes), batch_size):
    batch = all_nodes[i:i+batch_size]
    # Process batch

2. Algorithm Selection

# Use appropriate graph type
graph = db.to_networkx()

# Some algorithms need undirected
if not nx.is_directed_acyclic_graph(graph):
    print('Graph has cycles')

# Some need specific attributes
for u, v, attrs in graph.edges(data=True):
    if 'weight' not in attrs.get('properties', {}):
        # Add default weight
        attrs['properties']['weight'] = 1.0

3. Preserving Data Integrity

# Node ID mapping is preserved
node_map = db.from_networkx(graph)

# Store original IDs if needed
for old_id, new_id in node_map.items():
    db.update_node_properties(new_id, {'original_id': old_id})

Limitations

  • NetworkX graphs are in-memory; large graphs may require significant RAM
  • Some NetworkX algorithms require specific graph types (undirected, weighted)
  • Relationship direction is preserved in MultiDiGraph