Skill Tracer
Skills › Scientific Agent Skills › networkx › io.md

io.md

493 lines · skills/networkx/references/io.md at 5f2bc03

Open on GitHub
1# NetworkX Input/Output
2
3API patterns assume `import networkx as nx`, suitable input files and the optional packages named below. See [review.md](review.md) for tested round trips. Preserve a separate node table, graph class, node-ID schema, units and attribute schema; compare them after every conversion. Edge tables alone omit isolated nodes.
4

NetworkX Input/Output

API patterns assume import networkx as nx, suitable input files and the optional packages named below. See review.md for tested round trips. Preserve a separate node table, graph class, node-ID schema, units and attribute schema; compare them after every conversion. Edge tables alone omit isolated nodes.

Raw lines 1 to 4
5## Reading Graphs from Files
6

Reading Graphs from Files

Raw lines 5 to 6
7### Adjacency List Format
8```python
9# Read adjacency list (simple text format)
10G = nx.read_adjlist('graph.adjlist')
12# With node type conversion
13G = nx.read_adjlist('graph.adjlist', nodetype=int)
15# For directed graphs
16G = nx.read_adjlist('graph.adjlist', create_using=nx.DiGraph())
18# Write adjacency list
19nx.write_adjlist(G, 'graph.adjlist')
20```
22Example adjacency list format:
23```
24# node neighbors
250 1 2
261 0 3 4
272 0 3
283 1 2 4
294 1 3
30```

Adjacency List Format

# Read adjacency list (simple text format)
G = nx.read_adjlist('graph.adjlist')

# With node type conversion
G = nx.read_adjlist('graph.adjlist', nodetype=int)

# For directed graphs
G = nx.read_adjlist('graph.adjlist', create_using=nx.DiGraph())

# Write adjacency list
nx.write_adjlist(G, 'graph.adjlist')

Example adjacency list format:

# node neighbors
0 1 2
1 0 3 4
2 0 3
3 1 2 4
4 1 3
Raw lines 7 to 31
32### Edge List Format
33```python
34# Read edge list
35G = nx.read_edgelist('graph.edgelist')
37# With node types and edge data
38G = nx.read_edgelist('graph.edgelist',
39 nodetype=int,
40 data=(('weight', float),))
42# Read weighted edge list
43G = nx.read_weighted_edgelist('weighted.edgelist')
45# Write edge list
46nx.write_edgelist(G, 'graph.edgelist')
48# Write weighted edge list
49nx.write_weighted_edgelist(G, 'weighted.edgelist')
50```
52Example edge list format:
53```
54# source target
550 1
561 2
572 3
583 0
59```
61Example weighted edge list:
62```
63# source target weight
640 1 0.5
651 2 1.0
662 3 0.75
67```

Edge List Format

# Read edge list
G = nx.read_edgelist('graph.edgelist')

# With node types and edge data
G = nx.read_edgelist('graph.edgelist',
                     nodetype=int,
                     data=(('weight', float),))

# Read weighted edge list
G = nx.read_weighted_edgelist('weighted.edgelist')

# Write edge list
nx.write_edgelist(G, 'graph.edgelist')

# Write weighted edge list
nx.write_weighted_edgelist(G, 'weighted.edgelist')

Example edge list format:

# source target
0 1
1 2
2 3
3 0

Example weighted edge list:

# source target weight
0 1 0.5
1 2 1.0
2 3 0.75
Raw lines 32 to 68
69### GML (Graph Modelling Language)
70```python
71# Read GML (supported GML attributes; default label="label")
72G = nx.read_gml('graph.gml')
74# Write GML
75nx.write_gml(G, 'graph.gml')
76```
78GML is a text format, not XML. It supports a constrained attribute/type schema; reserved keys such as `id`/`label` have structural meanings. It is not an arbitrary Python-object round trip.

GML (Graph Modelling Language)

# Read GML (supported GML attributes; default label="label")
G = nx.read_gml('graph.gml')

# Write GML
nx.write_gml(G, 'graph.gml')

GML is a text format, not XML. It supports a constrained attribute/type schema; reserved keys such as id/label have structural meanings. It is not an arbitrary Python-object round trip.

Raw lines 69 to 79
80### GraphML Format
81```python
82# Read GraphML (XML-based format)
83G = nx.read_graphml('graph.graphml')
85# Write GraphML
86nx.write_graphml(G, 'graph.graphml')
88# With specific encoding
89nx.write_graphml(G, 'graph.graphml', encoding='utf-8')
90```
92GraphML supports scalar strings, booleans and numeric attributes, not arbitrary lists/dicts/arrays/None. Node IDs are strings on read unless `node_type=` is specified. Use `force_multigraph=True` and an explicit `edge_key_type` to preserve a multigraph class with no parallel edges. GraphML defaults stay in `G.graph`; they are not filled into every node/edge. Mixed directed/undirected graphs and hyperedges are unsupported.

GraphML Format

# Read GraphML (XML-based format)
G = nx.read_graphml('graph.graphml')

# Write GraphML
nx.write_graphml(G, 'graph.graphml')

# With specific encoding
nx.write_graphml(G, 'graph.graphml', encoding='utf-8')

GraphML supports scalar strings, booleans and numeric attributes, not arbitrary lists/dicts/arrays/None. Node IDs are strings on read unless node_type= is specified. Use force_multigraph=True and an explicit edge_key_type to preserve a multigraph class with no parallel edges. GraphML defaults stay in G.graph; they are not filled into every node/edge. Mixed directed/undirected graphs and hyperedges are unsupported.

Raw lines 80 to 93
94### GEXF (Graph Exchange XML Format)
95```python
96# Read GEXF
97G = nx.read_gexf('graph.gexf')
99# Write GEXF
100nx.write_gexf(G, 'graph.gexf')
101```
103GEXF has reserved attribute names and requires compatible attribute types across nodes/edges; mixed types can raise. Validate dynamic attributes separately. GraphML/GEXF readers use XML parsers: only parse trusted files or sanitize XML before this workflow.

GEXF (Graph Exchange XML Format)

# Read GEXF
G = nx.read_gexf('graph.gexf')

# Write GEXF
nx.write_gexf(G, 'graph.gexf')

GEXF has reserved attribute names and requires compatible attribute types across nodes/edges; mixed types can raise. Validate dynamic attributes separately. GraphML/GEXF readers use XML parsers: only parse trusted files or sanitize XML before this workflow.

Raw lines 94 to 104
105### Pajek Format
106```python
107# Read Pajek .net files
108G = nx.read_pajek('graph.net')
110# Write Pajek format
111nx.write_pajek(G, 'graph.net')
112```

Pajek Format

# Read Pajek .net files
G = nx.read_pajek('graph.net')

# Write Pajek format
nx.write_pajek(G, 'graph.net')
Raw lines 105 to 113
114### LEDA Format
115```python
116# Read LEDA format (read-only; NetworkX has no LEDA writer)
117G = nx.read_leda('graph.leda')
118```

LEDA Format

# Read LEDA format (read-only; NetworkX has no LEDA writer)
G = nx.read_leda('graph.leda')
Raw lines 114 to 119
120## Working with Pandas

Working with Pandas

Raw lines 120 to 121
122### From Pandas DataFrame
123```python
124import pandas as pd
126# Create graph from edge list DataFrame
127df = pd.DataFrame({
128 'source': [1, 2, 3, 4],
129 'target': [2, 3, 4, 1],
130 'weight': [0.5, 1.0, 0.75, 0.25]
131})
133# Create graph
134G = nx.from_pandas_edgelist(df,
135 source='source',
136 target='target',
137 edge_attr='weight')
139# With multiple edge attributes: columns must actually exist
140df["color"] = "blue"
141df["type"] = "interaction"
142G = nx.from_pandas_edgelist(df,
143 source='source',
144 target='target',
145 edge_attr=['weight', 'color', 'type'])
147# Create directed graph
148G = nx.from_pandas_edgelist(df,
149 source='source',
150 target='target',
151 edge_attr='weight',
152 create_using=nx.DiGraph())
153```
155Specify `create_using=nx.MultiDiGraph()` and `edge_key="edge_id"` when repeated directed observations are separate edges. Simple graphs overwrite duplicate edge attributes; they do not sum them. Import the node table with `add_nodes_from` to retain isolates and node attributes. Check ID dtypes and missing IDs before conversion, especially mixed numeric tables.

From Pandas DataFrame

import pandas as pd

# Create graph from edge list DataFrame
df = pd.DataFrame({
    'source': [1, 2, 3, 4],
    'target': [2, 3, 4, 1],
    'weight': [0.5, 1.0, 0.75, 0.25]
})

# Create graph
G = nx.from_pandas_edgelist(df,
                            source='source',
                            target='target',
                            edge_attr='weight')

# With multiple edge attributes: columns must actually exist
df["color"] = "blue"
df["type"] = "interaction"
G = nx.from_pandas_edgelist(df,
                            source='source',
                            target='target',
                            edge_attr=['weight', 'color', 'type'])

# Create directed graph
G = nx.from_pandas_edgelist(df,
                            source='source',
                            target='target',
                            edge_attr='weight',
                            create_using=nx.DiGraph())

Specify create_using=nx.MultiDiGraph() and edge_key="edge_id" when repeated directed observations are separate edges. Simple graphs overwrite duplicate edge attributes; they do not sum them. Import the node table with add_nodes_from to retain isolates and node attributes. Check ID dtypes and missing IDs before conversion, especially mixed numeric tables.

Raw lines 122 to 156
157### To Pandas DataFrame
158```python
159# Convert graph to edge list DataFrame
160df = nx.to_pandas_edgelist(G)
162# Rename endpoint columns (this does not select edge attributes)
163df = nx.to_pandas_edgelist(G, source='node1', target='node2')
164```

To Pandas DataFrame

# Convert graph to edge list DataFrame
df = nx.to_pandas_edgelist(G)

# Rename endpoint columns (this does not select edge attributes)
df = nx.to_pandas_edgelist(G, source='node1', target='node2')
Raw lines 157 to 165
166### Adjacency Matrix with Pandas
167```python
168# Create DataFrame from adjacency matrix
169df = nx.to_pandas_adjacency(G, dtype=float)
171# Create graph from adjacency DataFrame
172G = nx.from_pandas_adjacency(df)
174# For directed graphs
175G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph())
176```

Adjacency Matrix with Pandas

# Create DataFrame from adjacency matrix
df = nx.to_pandas_adjacency(G, dtype=float)

# Create graph from adjacency DataFrame
G = nx.from_pandas_adjacency(df)

# For directed graphs
G = nx.from_pandas_adjacency(df, create_using=nx.DiGraph())
Raw lines 166 to 177
178## NumPy and SciPy Integration

NumPy and SciPy Integration

Raw lines 178 to 179
180### Adjacency Matrix
181```python
182import numpy as np
184# Simple directed weighted fixture, including a zero-cost edge and an isolate
185G = nx.DiGraph()
186G.add_nodes_from(["A", "B", "isolate"])
187G.add_edge("A", "B", weight=0.0)
188nodelist = list(G)
189A = nx.to_numpy_array(G, nodelist=nodelist, dtype=float, nonedge=np.nan)
190# NetworkX 3.7 supports nonedge= on import too
191H = nx.from_numpy_array(
192 A, nodelist=nodelist, create_using=nx.DiGraph, nonedge=np.nan
194assert H.has_edge("A", "B") and H["A"]["B"]["weight"] == 0.0
195assert set(nx.isolates(H)) == {"isolate"}
196```
198Dense arrays default to zero meaning **no edge**; a different `nonedge` sentinel is needed for genuine zero-weight edges. `dtype=int` truncates fractional weights. Matrices omit most attributes and aggregate parallel weights (sum by default); integer entries become edge counts only with a multigraph plus `parallel_edges=True`. For directed graphs, row i / column j represents i -> j.

Adjacency Matrix

import numpy as np

# Simple directed weighted fixture, including a zero-cost edge and an isolate
G = nx.DiGraph()
G.add_nodes_from(["A", "B", "isolate"])
G.add_edge("A", "B", weight=0.0)
nodelist = list(G)
A = nx.to_numpy_array(G, nodelist=nodelist, dtype=float, nonedge=np.nan)
# NetworkX 3.7 supports nonedge= on import too
H = nx.from_numpy_array(
    A, nodelist=nodelist, create_using=nx.DiGraph, nonedge=np.nan
)
assert H.has_edge("A", "B") and H["A"]["B"]["weight"] == 0.0
assert set(nx.isolates(H)) == {"isolate"}

Dense arrays default to zero meaning no edge; a different nonedge sentinel is needed for genuine zero-weight edges. dtype=int truncates fractional weights. Matrices omit most attributes and aggregate parallel weights (sum by default); integer entries become edge counts only with a multigraph plus parallel_edges=True. For directed graphs, row i / column j represents i -> j.

Raw lines 180 to 199
200### Sparse Matrix (SciPy)
201```python
202from scipy import sparse
204# Preserve ordering and directedness explicitly
205nodelist = list(G)
206A = nx.to_scipy_sparse_array(G, nodelist=nodelist, format="csr")
207H = nx.from_scipy_sparse_array(A, create_using=type(G))
208H = nx.relabel_nodes(H, dict(enumerate(nodelist)))
209# Explicitly stored zeros become edges. Call A.eliminate_zeros() only
210# when those entries really mean absent edges, not zero-weight edges.
211```

Sparse Matrix (SciPy)

from scipy import sparse

# Preserve ordering and directedness explicitly
nodelist = list(G)
A = nx.to_scipy_sparse_array(G, nodelist=nodelist, format="csr")
H = nx.from_scipy_sparse_array(A, create_using=type(G))
H = nx.relabel_nodes(H, dict(enumerate(nodelist)))
# Explicitly stored zeros become edges. Call A.eliminate_zeros() only
# when those entries really mean absent edges, not zero-weight edges.
Raw lines 200 to 212
213## JSON Format
215### Node-Link Format
216```python
217import json
219# To node-link format (good for d3.js)
220data = nx.node_link_data(G, edges="edges")
221with open('graph.json', 'w') as f:
222 json.dump(data, f)
224# From node-link format
225with open('graph.json', 'r') as f:
226 data = json.load(f)
227G = nx.node_link_graph(data, edges="edges")
229# Since NetworkX 3.6 the edge list is stored under the "edges" key.
230# Older files (and some d3.js examples) use "links" — pass edges="links"
231# to read or write that layout:
232legacy_data = nx.node_link_data(G, edges="links")
233G = nx.node_link_graph(legacy_data, edges="links")
234```
236Node-link includes graph class flags, node records (including isolates), edge keys and attributes. JSON values must be serializable; attribute keys become strings. Reserve `id` for node IDs and `source`/`target`/`key` for edge structure, or choose noncolliding keyword names consistently for both directions. Do not feed an `edges` document to a `links` reader.

Node-Link Format

import json

# To node-link format (good for d3.js)
data = nx.node_link_data(G, edges="edges")
with open('graph.json', 'w') as f:
    json.dump(data, f)

# From node-link format
with open('graph.json', 'r') as f:
    data = json.load(f)
G = nx.node_link_graph(data, edges="edges")

# Since NetworkX 3.6 the edge list is stored under the "edges" key.
# Older files (and some d3.js examples) use "links" — pass edges="links"
# to read or write that layout:
legacy_data = nx.node_link_data(G, edges="links")
G = nx.node_link_graph(legacy_data, edges="links")

Node-link includes graph class flags, node records (including isolates), edge keys and attributes. JSON values must be serializable; attribute keys become strings. Reserve id for node IDs and source/target/key for edge structure, or choose noncolliding keyword names consistently for both directions. Do not feed an edges document to a links reader.

Raw lines 215 to 237
238### Adjacency Data Format
239```python
240# To adjacency format
241data = nx.adjacency_data(G)
242with open('graph.json', 'w') as f:
243 json.dump(data, f)
245# From adjacency format
246with open('graph.json', 'r') as f:
247 data = json.load(f)
248G = nx.adjacency_graph(data)
249```

Adjacency Data Format

# To adjacency format
data = nx.adjacency_data(G)
with open('graph.json', 'w') as f:
    json.dump(data, f)

# From adjacency format
with open('graph.json', 'r') as f:
    data = json.load(f)
G = nx.adjacency_graph(data)
Raw lines 238 to 250
251### Tree Data Format
252```python
253# Requires a directed outward tree rooted at root (not an arbitrary Graph)
254T = nx.bfs_tree(nx.path_graph(4), source=0)
255data = nx.tree_data(T, root=0)
256with open('tree.json', 'w') as f:
257 json.dump(data, f)
259# From tree format
260with open('tree.json', 'r') as f:
261 data = json.load(f)
262G = nx.tree_graph(data)
263```
265Tree JSON preserves node attributes but omits graph/edge attributes. Use node-link when those matter.

Tree Data Format

# Requires a directed outward tree rooted at root (not an arbitrary Graph)
T = nx.bfs_tree(nx.path_graph(4), source=0)
data = nx.tree_data(T, root=0)
with open('tree.json', 'w') as f:
    json.dump(data, f)

# From tree format
with open('tree.json', 'r') as f:
    data = json.load(f)
G = nx.tree_graph(data)

Tree JSON preserves node attributes but omits graph/edge attributes. Use node-link when those matter.

Raw lines 251 to 266
267## Pickle Format
269### Binary Pickle
270```python
271import pickle
273# Write pickle (preserves all Python objects)
274with open('graph.pkl', 'wb') as f:
275 pickle.dump(G, f)
277# Read pickle
278with open('graph.pkl', 'rb') as f:
279 G = pickle.load(f)
280```
282Note: `nx.write_gpickle` / `nx.read_gpickle` were removed in NetworkX 3.0 — use the standard `pickle` module as shown above. Only unpickle files from trusted sources; pickle can execute arbitrary code on load.

Binary Pickle

import pickle

# Write pickle (preserves all Python objects)
with open('graph.pkl', 'wb') as f:
    pickle.dump(G, f)

# Read pickle
with open('graph.pkl', 'rb') as f:
    G = pickle.load(f)

Note: nx.write_gpickle / nx.read_gpickle were removed in NetworkX 3.0 — use the standard pickle module as shown above. Only unpickle files from trusted sources; pickle can execute arbitrary code on load.

Raw lines 269 to 283
284## CSV Files
286### Custom CSV Reading
287```python
288import csv
290# Read a simple undirected edge table; reject duplicate observations
291import math
292G = nx.Graph()
293with open("edges.csv", newline="", encoding="utf-8") as f:
294 reader = csv.DictReader(f)
295 fields = reader.fieldnames or []
296 if len(fields) != len(set(fields)) or not {"source", "target", "weight"} <= set(fields):
297 raise ValueError("Missing or duplicate CSV headers")
298 for row in reader:
299 u, v = row["source"], row["target"]
300 if None in row or not u or not v or row["weight"] is None:
301 raise ValueError("Malformed edge record")
302 if G.has_edge(u, v):
303 raise ValueError("Repeated edge: choose aggregation or a multigraph explicitly")
304 weight = float(row["weight"])
305 if not math.isfinite(weight):
306 raise ValueError("Nonfinite weight")
307 G.add_edge(u, v, weight=weight)
309# Write edges to CSV
310with open('edges.csv', 'w', newline='') as f:
311 writer = csv.writer(f)
312 writer.writerow(['source', 'target', 'weight'])
313 for u, v, data in G.edges(data=True):
314 writer.writerow([u, v, data['weight']])
315```

Custom CSV Reading

import csv

# Read a simple undirected edge table; reject duplicate observations
import math
G = nx.Graph()
with open("edges.csv", newline="", encoding="utf-8") as f:
    reader = csv.DictReader(f)
    fields = reader.fieldnames or []
    if len(fields) != len(set(fields)) or not {"source", "target", "weight"} <= set(fields):
        raise ValueError("Missing or duplicate CSV headers")
    for row in reader:
        u, v = row["source"], row["target"]
        if None in row or not u or not v or row["weight"] is None:
            raise ValueError("Malformed edge record")
        if G.has_edge(u, v):
            raise ValueError("Repeated edge: choose aggregation or a multigraph explicitly")
        weight = float(row["weight"])
        if not math.isfinite(weight):
            raise ValueError("Nonfinite weight")
        G.add_edge(u, v, weight=weight)

# Write edges to CSV
with open('edges.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(['source', 'target', 'weight'])
    for u, v, data in G.edges(data=True):
        writer.writerow([u, v, data['weight']])
Raw lines 286 to 316
317## Database Integration

Database Integration

Raw lines 317 to 318
319### SQL Databases
320```python
321import sqlite3
322import pandas as pd
324# Read from SQL database via pandas
325conn = sqlite3.connect('network.db')
326df = pd.read_sql_query("SELECT source, target, weight FROM edges", conn)
327G = nx.from_pandas_edgelist(df, 'source', 'target', edge_attr='weight')
328conn.close()
330# When filtering on user-supplied values, always use parameterized queries —
331# never interpolate user input into the SQL string:
332conn = sqlite3.connect('network.db')
333df = pd.read_sql_query(
334 "SELECT source, target, weight FROM edges WHERE weight > ?",
335 conn, params=(min_weight,)
337G = nx.from_pandas_edgelist(df, "source", "target", edge_attr="weight")
338conn.close()
340# Write to SQL database
341df = nx.to_pandas_edgelist(G)
342conn = sqlite3.connect('network.db')
343df.to_sql('edges', conn, if_exists='replace', index=False)
344conn.close()
345```

SQL Databases

import sqlite3
import pandas as pd

# Read from SQL database via pandas
conn = sqlite3.connect('network.db')
df = pd.read_sql_query("SELECT source, target, weight FROM edges", conn)
G = nx.from_pandas_edgelist(df, 'source', 'target', edge_attr='weight')
conn.close()

# When filtering on user-supplied values, always use parameterized queries —
# never interpolate user input into the SQL string:
conn = sqlite3.connect('network.db')
df = pd.read_sql_query(
    "SELECT source, target, weight FROM edges WHERE weight > ?",
    conn, params=(min_weight,)
)
G = nx.from_pandas_edgelist(df, "source", "target", edge_attr="weight")
conn.close()

# Write to SQL database
df = nx.to_pandas_edgelist(G)
conn = sqlite3.connect('network.db')
df.to_sql('edges', conn, if_exists='replace', index=False)
conn.close()
Raw lines 319 to 346
347## Graph Formats for Visualization

Graph Formats for Visualization

Raw lines 347 to 348
349### DOT Format (Graphviz)
350```python
351# Write DOT file for Graphviz
352nx.drawing.nx_pydot.write_dot(G, 'graph.dot')
354# Read DOT file
355G = nx.drawing.nx_pydot.read_dot('graph.dot')
357# Generate directly to image (requires pydot and the Graphviz executable)
358from networkx.drawing.nx_pydot import to_pydot
359pydot_graph = to_pydot(G)
360pydot_graph.write_png('graph.png')
361```

DOT Format (Graphviz)

# Write DOT file for Graphviz
nx.drawing.nx_pydot.write_dot(G, 'graph.dot')

# Read DOT file
G = nx.drawing.nx_pydot.read_dot('graph.dot')

# Generate directly to image (requires pydot and the Graphviz executable)
from networkx.drawing.nx_pydot import to_pydot
pydot_graph = to_pydot(G)
pydot_graph.write_png('graph.png')
Raw lines 349 to 362
363## Cytoscape Integration

Cytoscape Integration

Raw lines 363 to 364
365### Cytoscape JSON
366```python
367# Export for Cytoscape
368data = nx.cytoscape_data(G)
369with open('cytoscape.json', 'w') as f:
370 json.dump(data, f)
372# Import from Cytoscape
373with open('cytoscape.json', 'r') as f:
374 data = json.load(f)
375G = nx.cytoscape_graph(data)
376```

Cytoscape JSON

# Export for Cytoscape
data = nx.cytoscape_data(G)
with open('cytoscape.json', 'w') as f:
    json.dump(data, f)

# Import from Cytoscape
with open('cytoscape.json', 'r') as f:
    data = json.load(f)
G = nx.cytoscape_graph(data)
Raw lines 365 to 377
378## Specialized Formats

Specialized Formats

Raw lines 378 to 379
380### Matrix Market Format
381```python
382from scipy.io import mmread, mmwrite
384# Read Matrix Market
385A = mmread('graph.mtx', spmatrix=False)
386G = nx.from_scipy_sparse_array(A) if sparse.issparse(A) else nx.from_numpy_array(A)
388# Write Matrix Market
389A = nx.to_scipy_sparse_array(G)
390mmwrite('graph.mtx', A)
391```

Matrix Market Format

from scipy.io import mmread, mmwrite

# Read Matrix Market
A = mmread('graph.mtx', spmatrix=False)
G = nx.from_scipy_sparse_array(A) if sparse.issparse(A) else nx.from_numpy_array(A)

# Write Matrix Market
A = nx.to_scipy_sparse_array(G)
mmwrite('graph.mtx', A)
Raw lines 380 to 392
393### Geographic Networks (Shapefiles, GeoDataFrames)
394`nx.read_shp` / `nx.write_shp` were removed in NetworkX 3.0. Use GeoPandas with momepy (or osmnx for street networks) instead:
395```python
396# uv pip install geopandas momepy
397import geopandas as gpd
398import momepy
400# Read line geometries from a shapefile and convert to a graph
401gdf = gpd.read_file('roads.shp')
402# Choose an appropriate projected CRS; lengths are in its axis units
403if gdf.crs is None or not gdf.crs.is_projected:
404 raise ValueError("Reproject roads to an appropriate local projected CRS first")
405G = momepy.gdf_to_nx(gdf, approach="primal", preserve_index=True)
407# Convert back to GeoDataFrames
408nodes_gdf, edges_gdf = momepy.nx_to_gdf(G)
409```
411This momepy route uses pre-noded LineStrings: crossings are not automatically intersections. It defaults to an undirected MultiGraph and stores segment length as `mm_len` in CRS units. For directed networks, coordinate order sets direction; use the documented `oneway_column` semantics. Geometry and tuple node IDs need conversion before GraphML export.

Geographic Networks (Shapefiles, GeoDataFrames)

nx.read_shp / nx.write_shp were removed in NetworkX 3.0. Use GeoPandas with momepy (or osmnx for street networks) instead:

# uv pip install geopandas momepy
import geopandas as gpd
import momepy

# Read line geometries from a shapefile and convert to a graph
gdf = gpd.read_file('roads.shp')
# Choose an appropriate projected CRS; lengths are in its axis units
if gdf.crs is None or not gdf.crs.is_projected:
    raise ValueError("Reproject roads to an appropriate local projected CRS first")
G = momepy.gdf_to_nx(gdf, approach="primal", preserve_index=True)

# Convert back to GeoDataFrames
nodes_gdf, edges_gdf = momepy.nx_to_gdf(G)

This momepy route uses pre-noded LineStrings: crossings are not automatically intersections. It defaults to an undirected MultiGraph and stores segment length as mm_len in CRS units. For directed networks, coordinate order sets direction; use the documented oneway_column semantics. Geometry and tuple node IDs need conversion before GraphML export.

Raw lines 393 to 412
413## Format Selection Guidelines

Format Selection Guidelines

Raw lines 413 to 414
415### Choose Based on Requirements
417**Adjacency List** - Simple, human-readable, no attributes
418- Best for: Simple unweighted graphs, quick viewing
420**Edge List** - Simple, supports weights, human-readable; isolates/node metadata need a sidecar
421- Best for: Weighted graphs, importing/exporting data
423**GML/GraphML** - Typed text formats; GraphML is XML, GML is not
424- Best for: Interchange of supported scalar attributes after a schema/identity round-trip check
426**JSON** - Web-friendly, JavaScript integration
427- Best for: Web applications, d3.js visualizations
429**Pickle** - Fast, preserves Python objects, binary
430- Best for: Python-only storage, complex attributes
432**Pandas** - Data analysis integration, DataFrame operations
433- Best for: Data processing pipelines, statistical analysis
435**NumPy/SciPy** - Numerical computation, sparse matrices
436- Best for: Matrix operations, scientific computing
438**DOT** - Visualization, Graphviz integration
439- Best for: Creating visual diagrams

Choose Based on Requirements

Adjacency List - Simple, human-readable, no attributes

  • Best for: Simple unweighted graphs, quick viewing

Edge List - Simple, supports weights, human-readable; isolates/node metadata need a sidecar

  • Best for: Weighted graphs, importing/exporting data

GML/GraphML - Typed text formats; GraphML is XML, GML is not

  • Best for: Interchange of supported scalar attributes after a schema/identity round-trip check

JSON - Web-friendly, JavaScript integration

  • Best for: Web applications, d3.js visualizations

Pickle - Fast, preserves Python objects, binary

  • Best for: Python-only storage, complex attributes

Pandas - Data analysis integration, DataFrame operations

  • Best for: Data processing pipelines, statistical analysis

NumPy/SciPy - Numerical computation, sparse matrices

  • Best for: Matrix operations, scientific computing

DOT - Visualization, Graphviz integration

  • Best for: Creating visual diagrams
Raw lines 415 to 440
441## Performance Considerations

Performance Considerations

Raw lines 441 to 442
443### Large Graphs
444For large graphs, consider:
445```python
446# Use compressed formats
447# NetworkX handles compression from the suffix; file handles must be binary
448nx.write_adjlist(G, "graph.adjlist.gz")
449H = nx.read_adjlist("graph.adjlist.gz")
451# Use binary formats (faster than text formats)
452with open('graph.pkl', 'wb') as f:
453 pickle.dump(G, f)
455# Use sparse matrices for adjacency
456A = nx.to_scipy_sparse_array(G, format='csr') # Memory efficient
457```

Large Graphs

For large graphs, consider:

# Use compressed formats
# NetworkX handles compression from the suffix; file handles must be binary
nx.write_adjlist(G, "graph.adjlist.gz")
H = nx.read_adjlist("graph.adjlist.gz")

# Use binary formats (faster than text formats)
with open('graph.pkl', 'wb') as f:
    pickle.dump(G, f)

# Use sparse matrices for adjacency
A = nx.to_scipy_sparse_array(G, format='csr')  # Memory efficient
Raw lines 443 to 458
459### Incremental Loading
460Linewise parsing reduces temporary input storage, but the final NetworkX graph still resides in memory. This two-column pattern does not preserve attributes or isolates:
461```python
462# Load graph incrementally from edge list
463G = nx.Graph()
464with open('huge_graph.edgelist') as f:
465 for line in f:
466 if not line.strip() or line.lstrip().startswith("#"):
467 continue
468 u, v = line.strip().split()
469 G.add_edge(u, v)
471 # Progress only; this does not free a chunk
472 if G.number_of_edges() % 100000 == 0:
473 print(f"Loaded {G.number_of_edges()} edges")
474```

Incremental Loading

Linewise parsing reduces temporary input storage, but the final NetworkX graph still resides in memory. This two-column pattern does not preserve attributes or isolates:

# Load graph incrementally from edge list
G = nx.Graph()
with open('huge_graph.edgelist') as f:
    for line in f:
        if not line.strip() or line.lstrip().startswith("#"):
            continue
        u, v = line.strip().split()
        G.add_edge(u, v)

        # Progress only; this does not free a chunk
        if G.number_of_edges() % 100000 == 0:
            print(f"Loaded {G.number_of_edges()} edges")
Raw lines 459 to 475
476## Error Handling

Error Handling

Raw lines 476 to 477
478### Robust File Reading
479```python
480try:
481 G = nx.read_graphml('graph.graphml')
482except nx.NetworkXError as e:
483 print(f"Error reading GraphML: {e}")
484except FileNotFoundError:
485 raise # A missing file is not evidence of an empty network
487# Illustrative input inspection: parsing errors may include XML/type errors
488import os
489if os.path.exists('graph.txt'):
490 with open('graph.txt') as f:
491 first_line = f.readline()
492 # Detect format and read accordingly
493```

Robust File Reading

try:
    G = nx.read_graphml('graph.graphml')
except nx.NetworkXError as e:
    print(f"Error reading GraphML: {e}")
except FileNotFoundError:
    raise  # A missing file is not evidence of an empty network

# Illustrative input inspection: parsing errors may include XML/type errors
import os
if os.path.exists('graph.txt'):
    with open('graph.txt') as f:
        first_line = f.readline()
        # Detect format and read accordingly
Raw lines 478 to 493