Graph Basics
This tutorial covers the fundamentals of creating and manipulating graphs in egraph.
Creating Graphs
egraph provides two main graph types: Graph (undirected) and DiGraph (directed).
Creating an Empty Graph
import egraph as eg
# Create an undirected graph
graph = eg.Graph()
# Create a directed graph
digraph = eg.DiGraph()
Adding Nodes
Nodes can be added with associated data:
import egraph as eg
graph = eg.Graph()
# Add nodes with data
node0 = graph.add_node("Alice")
node1 = graph.add_node("Bob")
node2 = graph.add_node("Charlie")
print(f"Added {graph.node_count()} nodes")
Added 3 nodes
The add_node() method returns a node index that you use to reference the node later.
Adding Edges
Edges connect nodes and can also carry data:
import egraph as eg
graph = eg.Graph()
# Add nodes
alice = graph.add_node("Alice")
bob = graph.add_node("Bob")
charlie = graph.add_node("Charlie")
# Add edges with data (e.g., relationship type)
graph.add_edge(alice, bob, "friend")
graph.add_edge(bob, charlie, "colleague")
graph.add_edge(alice, charlie, "friend")
print(f"Graph has {graph.node_count()} nodes and {graph.edge_count()} edges")
Graph has 3 nodes and 3 edges
Accessing Graph Data
Retrieving Node Data
import egraph as eg
graph = eg.Graph()
alice = graph.add_node("Alice")
bob = graph.add_node("Bob")
# Get node data
print(f"Node {alice}: {graph.node_weight(alice)}")
print(f"Node {bob}: {graph.node_weight(bob)}")
Node 0: Alice
Node 1: Bob
Iterating Over Nodes
import egraph as eg
graph = eg.Graph()
graph.add_node("Alice")
graph.add_node("Bob")
graph.add_node("Charlie")
# Iterate over all nodes
for node_idx in graph.node_indices():
data = graph.node_weight(node_idx)
print(f"Node {node_idx}: {data}")
Node 0: Alice
Node 1: Bob
Node 2: Charlie
Iterating Over Edges
import egraph as eg
graph = eg.Graph()
alice = graph.add_node("Alice")
bob = graph.add_node("Bob")
charlie = graph.add_node("Charlie")
graph.add_edge(alice, bob, "friend")
graph.add_edge(bob, charlie, "colleague")
# Iterate over all edges
for edge_idx in graph.edge_indices():
source, target = graph.edge_endpoints(edge_idx)
data = graph.edge_weight(edge_idx)
print(f"Edge {source} -> {target}: {data}")
Edge 0 -> 1: friend
Edge 1 -> 2: colleague
Working with NetworkX
egraph integrates seamlessly with NetworkX for graph creation and analysis.
Converting from NetworkX
import networkx as nx
import egraph as eg
# Create a NetworkX graph
nx_graph = nx.karate_club_graph()
# Convert to egraph
graph = eg.Graph()
node_map = {}
for node in nx_graph.nodes:
node_map[node] = graph.add_node(node)
for u, v in nx_graph.edges:
graph.add_edge(node_map[u], node_map[v], (u, v))
print(f"Converted graph: {graph.node_count()} nodes, {graph.edge_count()} edges")
Converted graph: 34 nodes, 78 edges
Using NetworkX Algorithms
You can use NetworkX for graph analysis and egraph for layout:
import networkx as nx
import egraph as eg
# Create and analyze with NetworkX
nx_graph = nx.karate_club_graph()
communities = nx.community.greedy_modularity_communities(nx_graph)
# Convert to egraph for layout
graph = eg.Graph()
node_map = {}
for node in nx_graph.nodes:
node_map[node] = graph.add_node(node)
for u, v in nx_graph.edges:
graph.add_edge(node_map[u], node_map[v], (u, v))
# Apply layout
drawing = eg.DrawingEuclidean2d.initial_placement(graph)
sm = eg.StressMajorization(graph, drawing, lambda _: 100)
sm.run(drawing)
print(f"Found {len(communities)} communities")
print(f"Layout computed for {graph.node_count()} nodes")
Found 3 communities
Layout computed for 34 nodes
Directed Graphs
DiGraph works similarly to Graph but maintains edge direction:
import egraph as eg
digraph = eg.DiGraph()
# Add nodes
a = digraph.add_node("A")
b = digraph.add_node("B")
c = digraph.add_node("C")
# Add directed edges
digraph.add_edge(a, b, "depends_on")
digraph.add_edge(b, c, "depends_on")
digraph.add_edge(c, a, "depends_on") # Creates a cycle
print(f"DiGraph: {digraph.node_count()} nodes, {digraph.edge_count()} edges")
DiGraph: 3 nodes, 3 edges
Best Practices
Use meaningful node data: Store relevant information in nodes for later reference
Keep track of node indices: Store the mapping between your data and node indices
Choose the right graph type: Use DiGraph only when direction matters
Leverage NetworkX: Use NetworkX for graph algorithms and egraph for layout
Next Steps
Layout Algorithms - Learn about different layout algorithms
Drawing and Visualization - Explore drawing spaces and visualization
Examples - See more complex examples