Attribute types guaranteed to survive a round‑trip
When you convert a NetworkX graph to a Python‑dict representation with node_link_data and then serialize that dict to JSON (the typical path for write_json/read_json), only values that are natively JSON‑serializable survive unchanged. Those are:
- integers (
int)
- floating‑point numbers (
float)
- strings (
str)
- Booleans (
bool)
None
- lists and dicts whose elements are themselves JSON‑serializable
Other Python objects (e.g., datetime, Decimal, NumPy arrays, custom class instances) are either coerced to a JSON‑compatible surrogate (often a string or number) or lost entirely, so their original type is not guaranteed after node_link_graph reconstructs the graph.
Steps to verify persistence for your attributes
- Create a small test graph and assign the attribute you want to check.
- Call
data = nx.node_link_data(G).
- Serialize
data with json.dumps (or nx.write_json).
- Deserialize the JSON back to a dict.
- Re‑build the graph with
G2 = nx.node_link_graph(dict).
- Inspect the attribute:
type(G2.nodes[n]['your_attr']) and compare to the original.
If the type matches the original and the value is unchanged, the attribute is JSON‑serializable and therefore safe for a round‑trip.
Custom object serialization without external wrappers
NetworkX does not provide a built‑in mechanism to automatically pickle or otherwise encode arbitrary Python objects during the node_link_data → JSON path. To persist custom objects you must either:
- Convert the object to a JSON‑serializable representation (e.g., its
__dict__, a tuple of primitive fields, or a string) before calling node_link_data, and rebuild it after node_link_graph; or
- Use NetworkX’s native pickle‑based format (
write_gpickle/read_gpickle) which preserves the exact Python objects, keeping in mind the security considerations of loading untrusted pickle files.
There is no documented “custom encoder” hook inside node_link_data; you must handle the conversion yourself or switch to the pickle‑based functions.
import json, networkx as nx
G = nx.Graph()
G.add_node(1, attr=datetime(2026,1,1)) # custom object
data = nx.node_link_data(G)
json_str = json.dumps(data, default=lambda o: o.isoformat() if isinstance(o, datetime) else None)
# after loading json_str back to a dict, reconstruct datetime via the isoformat string