Skill Tracer
Skills › Scientific Agent Skills › networkx › graph-basics.md

graph-basics.md

297 lines · skills/networkx/references/graph-basics.md at 5f2bc03

Open on GitHub
1# NetworkX Graph Basics
2
3API patterns below assume `import networkx as nx` and suitable existing nodes. See [review.md](review.md) for tested contracts.
4

NetworkX Graph Basics

API patterns below assume import networkx as nx and suitable existing nodes. See review.md for tested contracts.

Raw lines 1 to 4
5## Graph Types
6
7NetworkX supports four main graph classes:
8

Graph Types

NetworkX supports four main graph classes:

Raw lines 5 to 8
9### Graph (Undirected)
10```python
11import networkx as nx
12G = nx.Graph()
13```
14- Undirected graphs with single edges between nodes
15- No parallel edges allowed
16- Edges are bidirectional

Graph (Undirected)

import networkx as nx
G = nx.Graph()
  • Undirected graphs with single edges between nodes
  • No parallel edges allowed
  • Edges are bidirectional
Raw lines 9 to 17
18### DiGraph (Directed)
19```python
20G = nx.DiGraph()
21```
22- Directed graphs with one-way connections
23- Edge direction matters: (u, v) ≠ (v, u)
24- Used for modeling directed relationships

DiGraph (Directed)

G = nx.DiGraph()
  • Directed graphs with one-way connections
  • Edge direction matters: (u, v) ≠ (v, u)
  • Used for modeling directed relationships
Raw lines 18 to 25
26### MultiGraph (Undirected Multi-edge)
27```python
28G = nx.MultiGraph()
29```
30- Allows multiple edges between same node pairs
31- Useful for modeling multiple relationships

MultiGraph (Undirected Multi-edge)

G = nx.MultiGraph()
  • Allows multiple edges between same node pairs
  • Useful for modeling multiple relationships
Raw lines 26 to 32
33### MultiDiGraph (Directed Multi-edge)
34```python
35G = nx.MultiDiGraph()
36```
37- Directed graph with multiple edges between nodes
38- Combines features of DiGraph and MultiGraph
40All four classes allow self-loops. A repeated edge in `Graph`/`DiGraph` updates its attributes; it does not accumulate a count. In a multigraph, retain `(u, v, key)` identities and define an aggregation rule before using algorithms that require simple graphs.
42```python
43M = nx.MultiDiGraph()
44M.add_edge("A", "B", key="replicate-1", strength=2)
45M.add_edge("A", "B", key="replicate-2", strength=3)
46assert M.number_of_edges() == 2
47for u, v, key, attrs in M.edges(keys=True, data=True):
48 print(u, v, key, attrs["strength"])
49```

MultiDiGraph (Directed Multi-edge)

G = nx.MultiDiGraph()
  • Directed graph with multiple edges between nodes
  • Combines features of DiGraph and MultiGraph

All four classes allow self-loops. A repeated edge in Graph/DiGraph updates its attributes; it does not accumulate a count. In a multigraph, retain (u, v, key) identities and define an aggregation rule before using algorithms that require simple graphs.

M = nx.MultiDiGraph()
M.add_edge("A", "B", key="replicate-1", strength=2)
M.add_edge("A", "B", key="replicate-2", strength=3)
assert M.number_of_edges() == 2
for u, v, key, attrs in M.edges(keys=True, data=True):
    print(u, v, key, attrs["strength"])
Raw lines 33 to 50
51## Creating and Adding Nodes

Creating and Adding Nodes

Raw lines 51 to 52
53### Single Node Addition
54```python
55G.add_node(1)
56G.add_node("protein_A")
57G.add_node((0, 1)) # Tuples are hashable node IDs
58```

Single Node Addition

G.add_node(1)
G.add_node("protein_A")
G.add_node((0, 1))  # Tuples are hashable node IDs
Raw lines 53 to 59
60### Bulk Node Addition
61```python
62G.add_nodes_from([2, 3, 4])
63G.add_nodes_from(range(100, 110))
64```

Bulk Node Addition

G.add_nodes_from([2, 3, 4])
G.add_nodes_from(range(100, 110))
Raw lines 60 to 65
66### Nodes with Attributes
67```python
68G.add_node(1, time='5pm', color='red')
69G.add_nodes_from([
70 (4, {"color": "red"}),
71 (5, {"color": "blue", "weight": 1.5})
72])
73```

Nodes with Attributes

G.add_node(1, time='5pm', color='red')
G.add_nodes_from([
    (4, {"color": "red"}),
    (5, {"color": "blue", "weight": 1.5})
])
Raw lines 66 to 74
75### Important Node Properties
76- Nodes can be any hashable Python object except `None`: strings, tuples, numbers, custom objects
77- Node attributes stored as key-value pairs
78- Use meaningful node identifiers for clarity

Important Node Properties

  • Nodes can be any hashable Python object except None: strings, tuples, numbers, custom objects
  • Node attributes stored as key-value pairs
  • Use meaningful node identifiers for clarity
Raw lines 75 to 79
80## Creating and Adding Edges

Creating and Adding Edges

Raw lines 80 to 81
82### Single Edge Addition
83```python
84G.add_edge(1, 2)
85G.add_edge('gene_A', 'gene_B')
86```

Single Edge Addition

G.add_edge(1, 2)
G.add_edge('gene_A', 'gene_B')
Raw lines 82 to 87
88### Bulk Edge Addition
89```python
90G.add_edges_from([(1, 2), (1, 3), (2, 4)])
91G.add_edges_from(edge_list)
92```

Bulk Edge Addition

G.add_edges_from([(1, 2), (1, 3), (2, 4)])
G.add_edges_from(edge_list)
Raw lines 88 to 93
94### Edges with Attributes
95```python
96G.add_edge(1, 2, weight=4.7, relation='interacts')
97G.add_edges_from([
98 (1, 2, {'weight': 4.7}),
99 (2, 3, {'weight': 8.2, 'color': 'blue'})
100])
101```

Edges with Attributes

G.add_edge(1, 2, weight=4.7, relation='interacts')
G.add_edges_from([
    (1, 2, {'weight': 4.7}),
    (2, 3, {'weight': 8.2, 'color': 'blue'})
])
Raw lines 94 to 102
103### Adding from Edge List with Attributes
104```python
105# From pandas DataFrame
106import pandas as pd
107df = pd.DataFrame({'source': [1, 2], 'target': [2, 3], 'weight': [4.7, 8.2]})
108G = nx.from_pandas_edgelist(df, 'source', 'target', edge_attr='weight')
109```

Adding from Edge List with Attributes

# From pandas DataFrame
import pandas as pd
df = pd.DataFrame({'source': [1, 2], 'target': [2, 3], 'weight': [4.7, 8.2]})
G = nx.from_pandas_edgelist(df, 'source', 'target', edge_attr='weight')
Raw lines 103 to 110
111## Examining Graph Structure

Examining Graph Structure

Raw lines 111 to 112
113### Basic Properties
114```python
115# Get collections
116G.nodes # NodeView of all nodes
117G.edges # EdgeView of all edges
118G.adj # AdjacencyView for neighbor relationships
120# Count elements
121G.number_of_nodes() # Total node count
122G.number_of_edges() # Total edge count
123len(G) # Number of nodes (shorthand)
125# Degree information
126G.degree() # DegreeView of all node degrees
127G.degree(1) # Degree of specific node
128list(G.degree()) # List of (node, degree) pairs
129```

Basic Properties

# Get collections
G.nodes              # NodeView of all nodes
G.edges              # EdgeView of all edges
G.adj                # AdjacencyView for neighbor relationships

# Count elements
G.number_of_nodes()  # Total node count
G.number_of_edges()  # Total edge count
len(G)              # Number of nodes (shorthand)

# Degree information
G.degree()          # DegreeView of all node degrees
G.degree(1)         # Degree of specific node
list(G.degree())    # List of (node, degree) pairs
Raw lines 113 to 130
131### Checking Existence
132```python
133# Check if node exists
1341 in G # Returns True/False
135G.has_node(1)
137# Check if edge exists
138G.has_edge(1, 2)
139```

Checking Existence

# Check if node exists
1 in G              # Returns True/False
G.has_node(1)

# Check if edge exists
G.has_edge(1, 2)
Raw lines 131 to 140
141### Accessing Neighbors
142```python
143# Get neighbors of node 1
144list(G.neighbors(1))
145list(G[1]) # Dictionary-like access
147# For a DiGraph/MultiDiGraph only
148list(G.predecessors(1)) # Incoming edges
149list(G.successors(1)) # Outgoing edges
150```

Accessing Neighbors

# Get neighbors of node 1
list(G.neighbors(1))
list(G[1])          # Dictionary-like access

# For a DiGraph/MultiDiGraph only
list(G.predecessors(1))  # Incoming edges
list(G.successors(1))    # Outgoing edges
Raw lines 141 to 151
152### Iterating Over Elements
153```python
154# Iterate over nodes
155for node in G.nodes:
156 print(node, G.nodes[node]) # Access node attributes
158# Iterate over simple-graph edges (multigraphs need keys)
159for u, v in G.edges:
160 print(u, v, G[u][v]) # Access edge attributes
162# Iterate with attributes
163for node, attrs in G.nodes(data=True):
164 print(node, attrs)
166for u, v, attrs in G.edges(data=True):
167 print(u, v, attrs)
168```

Iterating Over Elements

# Iterate over nodes
for node in G.nodes:
    print(node, G.nodes[node])  # Access node attributes

# Iterate over simple-graph edges (multigraphs need keys)
for u, v in G.edges:
    print(u, v, G[u][v])  # Access edge attributes

# Iterate with attributes
for node, attrs in G.nodes(data=True):
    print(node, attrs)

for u, v, attrs in G.edges(data=True):
    print(u, v, attrs)
Raw lines 152 to 169
170## Modifying Graphs

Modifying Graphs

Raw lines 170 to 171
172### Removing Elements
173```python
174# Remove an existing edge before deleting its endpoints
175G.remove_edge(1, 2)
176G.remove_edges_from([(1, 2), (2, 3)]) # Missing edges ignored
177G.remove_node(1) # Also removes incident edges
178G.remove_nodes_from([1, 2, 3]) # Missing nodes ignored
179```

Removing Elements

# Remove an existing edge before deleting its endpoints
G.remove_edge(1, 2)
G.remove_edges_from([(1, 2), (2, 3)])  # Missing edges ignored
G.remove_node(1)  # Also removes incident edges
G.remove_nodes_from([1, 2, 3])  # Missing nodes ignored
Raw lines 172 to 180
181### Clearing Graph
182```python
183G.clear() # Remove all nodes and edges
184G.clear_edges() # Remove only edges, keep nodes
185```

Clearing Graph

G.clear()           # Remove all nodes and edges
G.clear_edges()     # Remove only edges, keep nodes
Raw lines 181 to 186
187## Attributes and Metadata

Attributes and Metadata

Raw lines 187 to 188
189### Graph-Level Attributes
190```python
191G.graph['name'] = 'Social Network'
192G.graph['date'] = '2025-01-15'
193print(G.graph)
194```

Graph-Level Attributes

G.graph['name'] = 'Social Network'
G.graph['date'] = '2025-01-15'
print(G.graph)
Raw lines 189 to 195
196### Node Attributes
197```python
198# Set at creation
199G.add_node(1, time='5pm', weight=0.5)
201# Set after creation
202G.nodes[1]['time'] = '6pm'
203nx.set_node_attributes(G, {1: 'red', 2: 'blue'}, 'color')
205# Get attributes
206G.nodes[1]
207G.nodes[1]['time']
208nx.get_node_attributes(G, 'color')
209```

Node Attributes

# Set at creation
G.add_node(1, time='5pm', weight=0.5)

# Set after creation
G.nodes[1]['time'] = '6pm'
nx.set_node_attributes(G, {1: 'red', 2: 'blue'}, 'color')

# Get attributes
G.nodes[1]
G.nodes[1]['time']
nx.get_node_attributes(G, 'color')
Raw lines 196 to 210
211### Edge Attributes
212```python
213# Set at creation
214G.add_edge(1, 2, weight=4.7, color='red')
216# Set after creation
217G[1][2]['weight'] = 5.0
218nx.set_edge_attributes(G, {(1, 2): 10.5}, 'weight')
220# Get attributes
221G[1][2]
222G[1][2]['weight']
223G.edges[1, 2]
224nx.get_edge_attributes(G, 'weight')
225```

Edge Attributes

# Set at creation
G.add_edge(1, 2, weight=4.7, color='red')

# Set after creation
G[1][2]['weight'] = 5.0
nx.set_edge_attributes(G, {(1, 2): 10.5}, 'weight')

# Get attributes
G[1][2]
G[1][2]['weight']
G.edges[1, 2]
nx.get_edge_attributes(G, 'weight')
Raw lines 211 to 226
227## Subgraphs and Views

Subgraphs and Views

Raw lines 227 to 228
229### Subgraph Creation
230```python
231# Create subgraph from node list
232nodes_subset = [1, 2, 3, 4]
233H = G.subgraph(nodes_subset) # Returns view (references original)
235# Independent structure and attribute dicts; nested mutable values remain shared
236H = G.subgraph(nodes_subset).copy()
238# Edge-induced subgraph
239edge_subset = [(1, 2), (2, 3)]
240H = G.edge_subgraph(edge_subset)
241```

Subgraph Creation

# Create subgraph from node list
nodes_subset = [1, 2, 3, 4]
H = G.subgraph(nodes_subset)  # Returns view (references original)

# Independent structure and attribute dicts; nested mutable values remain shared
H = G.subgraph(nodes_subset).copy()

# Edge-induced subgraph
edge_subset = [(1, 2), (2, 3)]
H = G.edge_subgraph(edge_subset)
Raw lines 229 to 242
243### Graph Views
244```python
245# Reverse view (for directed graphs)
246G_reversed = G.reverse(copy=False)
248# Convert between directed/undirected
249G_undirected = G.to_undirected()
250G_directed = G.to_directed()
251```
253Subgraph/reverse views share attributes with the original graph. `.copy()` is shallow for nested attribute values; use `copy.deepcopy` when those values must be independent. `to_undirected()` merges reciprocal directed edges and can discard differing attributes; define the merge rule first. Do not mutate graph size while iterating a live view.

Graph Views

# Reverse view (for directed graphs)
G_reversed = G.reverse(copy=False)

# Convert between directed/undirected
G_undirected = G.to_undirected()
G_directed = G.to_directed()

Subgraph/reverse views share attributes with the original graph. .copy() is shallow for nested attribute values; use copy.deepcopy when those values must be independent. to_undirected() merges reciprocal directed edges and can discard differing attributes; define the merge rule first. Do not mutate graph size while iterating a live view.

Raw lines 243 to 254
255## Graph Information and Diagnostics

Graph Information and Diagnostics

Raw lines 255 to 256
257### Basic Information
258```python
259print(G) # Summary string, e.g. "Graph with 5 nodes and 4 edges"
260 # (nx.info was removed in NetworkX 3.0)
262# Density (ratio of actual edges to possible edges)
263nx.density(G)
265# Check if graph is directed
266G.is_directed()
268# Check if graph is multigraph
269G.is_multigraph()
270```

Basic Information

print(G)            # Summary string, e.g. "Graph with 5 nodes and 4 edges"
                    # (nx.info was removed in NetworkX 3.0)

# Density (ratio of actual edges to possible edges)
nx.density(G)

# Check if graph is directed
G.is_directed()

# Check if graph is multigraph
G.is_multigraph()
Raw lines 257 to 271
272### Connectivity Checks
273```python
274# For nonempty undirected graphs
275nx.is_connected(G)
276nx.number_connected_components(G)
278# For nonempty directed graphs
279nx.is_strongly_connected(G)
280nx.is_weakly_connected(G)
281```
283Undirected self-loops contribute twice to degree; directed degree counts in- plus out-degree. Density and degree centrality can exceed one with self-loops/parallel edges (or total directed degree). Weighted degree is an edge-weight sum, not normalized degree centrality.

Connectivity Checks

# For nonempty undirected graphs
nx.is_connected(G)
nx.number_connected_components(G)

# For nonempty directed graphs
nx.is_strongly_connected(G)
nx.is_weakly_connected(G)

Undirected self-loops contribute twice to degree; directed degree counts in- plus out-degree. Density and degree centrality can exceed one with self-loops/parallel edges (or total directed degree). Weighted degree is an edge-weight sum, not normalized degree centrality.

Raw lines 272 to 284
285## Important Considerations

Important Considerations

Raw lines 285 to 286
287### Floating Point Precision
288Once graphs contain floating point numbers, all results are inherently approximate due to precision limitations. Small arithmetic errors can affect algorithm outcomes, particularly in minimum/maximum computations.

Floating Point Precision

Once graphs contain floating point numbers, all results are inherently approximate due to precision limitations. Small arithmetic errors can affect algorithm outcomes, particularly in minimum/maximum computations.

Raw lines 287 to 289
290### Memory Considerations
291Each time a script starts, graph data must be loaded into memory. For large datasets, this can cause performance issues. Consider:
292- Using efficient data formats (pickle for Python objects)
293- Loading only necessary subgraphs
294- Using graph databases for very large networks

Memory Considerations

Each time a script starts, graph data must be loaded into memory. For large datasets, this can cause performance issues. Consider:

  • Using efficient data formats (pickle for Python objects)
  • Loading only necessary subgraphs
  • Using graph databases for very large networks
Raw lines 290 to 295
296### Node and Edge Removal Behavior
297When a node is removed, all edges incident with that node are automatically removed as well.

Node and Edge Removal Behavior

When a node is removed, all edges incident with that node are automatically removed as well.

Raw lines 296 to 297