Skip to content

NetworkX Integration

This guide covers converting PyPtP networks to NetworkX graphs for analysis, visualization, and export to other formats.

Full Example

View the complete code: 07_NetworkX.py

Overview

Converting to NetworkX lets you:

  • Analyze topology (connectivity, paths, cycles)
  • Detect isolated sections
  • Visualize networks with matplotlib
  • Export to standard graph formats (GraphML, GEXF, JSON)
  • Apply graph algorithms (shortest path, centrality, clustering)

Converting Networks

Balanced Networks (VNF/Vision)

python
from pyptp.graph.networkx_converter import NetworkxConverter
from pyptp.IO.importers.vnf_importer import VnfImporter

# Load balanced network
vnf_importer = VnfImporter()
mv_network = vnf_importer.import_vnf("network.vnf")

# Convert to NetworkX graph
mv_graph = NetworkxConverter.graph_mv(mv_network)

Unbalanced Networks (GNF/Gaia)

python
from pyptp.IO.importers.gnf_importer import GnfImporter

# Load unbalanced network
gnf_importer = GnfImporter()
lv_network = gnf_importer.import_gnf("network.gnf")

# Convert to NetworkX graph
lv_graph = NetworkxConverter.graph_lv(lv_network)

Using the High-Level API

python
from pyptp import NetworkMV, NetworkLV

# Alternative: use the Network classes directly
mv_network = NetworkMV.from_file("network.vnf")  # Balanced model
lv_network = NetworkLV.from_file("network.gnf")  # Unbalanced model

# Then convert
mv_graph = NetworkxConverter.graph_mv(mv_network)
lv_graph = NetworkxConverter.graph_lv(lv_network)

Graph Structure

The converter represents all network elements as graph nodes:

Graph Node TypePyPtP Element
Network nodeBusbar, junction
BranchCable, link, transformer, reactance coil
ElementLoad, source, generator, battery, PV, etc.
SecondaryFuse, load switch, circuit breaker, measure field

Edges represent connections between these nodes:

  • Network nodes connect to branches via edges
  • Elements connect to their parent network node via an edge
  • Secondary elements are inserted in the path between network nodes and branches
python
# Example graph structure for a simple network:
# NetworkNode1 ─── Cable ─── NetworkNode2
#                              │
#                            Load

# Becomes this graph:
# Nodes: [NetworkNode1, Cable, NetworkNode2, Load]
# Edges: [NetworkNode1-Cable, Cable-NetworkNode2, NetworkNode2-Load]

This design makes it easy to:

  • Find all elements connected to a network node
  • Trace paths through the network
  • Identify equipment between any two points
python
print(f"MV Network: {mv_graph.number_of_nodes()} nodes, {mv_graph.number_of_edges()} edges")
print(f"LV Network: {lv_graph.number_of_nodes()} nodes, {lv_graph.number_of_edges()} edges")

Network Analysis

Connectivity Check

python
import networkx as nx

# Check if entire network is connected
is_connected = nx.is_connected(mv_graph)
print(f"Network is connected: {is_connected}")

Find Disconnected Sections

python
# Get all connected components
components = list(nx.connected_components(mv_graph))
print(f"Number of separate sections: {len(components)}")

# Largest component
largest = max(components, key=len)
print(f"Largest section has {len(largest)} nodes")

Path Analysis

python
# Find shortest path between two nodes
source_node = "node_guid_1"
target_node = "node_guid_2"

if nx.has_path(mv_graph, source_node, target_node):
    path = nx.shortest_path(mv_graph, source_node, target_node)
    print(f"Path length: {len(path)} nodes")
else:
    print("No path exists between nodes")

Network Statistics

python
# Degree distribution (connections per node)
degrees = dict(mv_graph.degree())
avg_degree = sum(degrees.values()) / len(degrees)
print(f"Average connections per node: {avg_degree:.2f}")

# Find nodes with most connections
max_degree_node = max(degrees, key=degrees.get)
print(f"Most connected node: {max_degree_node} ({degrees[max_degree_node]} connections)")

# Network diameter (longest shortest path)
if nx.is_connected(mv_graph):
    diameter = nx.diameter(mv_graph)
    print(f"Network diameter: {diameter}")

Querying by Element Type

Each graph node stores its element type:

python
# Get element type for a node
node_type = mv_graph.nodes[node_guid].get('type')

# Find all cables
cables = [n for n, d in mv_graph.nodes(data=True) if d.get('type') == 'CableMV']

# Find all transformers
transformers = [n for n, d in mv_graph.nodes(data=True)
                if d.get('type') in ('TransformerMV', 'ThreewindingTransformerMV')]

# Count elements by type
from collections import Counter
type_counts = Counter(d.get('type') for n, d in mv_graph.nodes(data=True))
for element_type, count in type_counts.most_common():
    print(f"{element_type}: {count}")

Cycle Detection

python
# Find all cycles (loops in network)
cycles = nx.cycle_basis(mv_graph)
print(f"Number of loops: {len(cycles)}")

# Networks with loops may need special handling for load flow

Visualization

Basic Plot

python
import matplotlib.pyplot as plt
import networkx as nx

plt.figure(figsize=(12, 8))
nx.draw(mv_graph, with_labels=True, node_size=300, font_size=8)
plt.title("Network Topology")
plt.savefig("network_graph.png", dpi=150)
plt.show()

Custom Layout

python
# Spring layout (force-directed)
pos = nx.spring_layout(mv_graph, k=2, iterations=50)

# Or use spectral layout for cleaner visualization
pos = nx.spectral_layout(mv_graph)

nx.draw(mv_graph, pos, with_labels=True)

Export Formats

NetworkX supports many export formats for interoperability:

GraphML (XML-based)

python
nx.write_graphml(mv_graph, "network.graphml")

GEXF (Gephi format)

python
nx.write_gexf(mv_graph, "network.gexf")

JSON (Web-friendly)

python
from networkx.readwrite import json_graph
import json

data = json_graph.node_link_data(mv_graph)
with open("network.json", "w") as f:
    json.dump(data, f, indent=2)

Adjacency List

python
nx.write_adjlist(mv_graph, "network.adjlist")

Complete Example

python
"""NetworkX Usage Examples.

Demonstrates how to convert electrical networks to NetworkX graphs
for analysis and visualization.

Graph Structure:
- All network elements (nodes, branches, elements) become graph NODES
- Edges represent connections between elements
- Each graph node has a 'type' attribute with the element class name
"""

from pyptp.graph.networkx_converter import NetworkxConverter
from pyptp.IO.importers.gnf_importer import GnfImporter
from pyptp.IO.importers.vnf_importer import VnfImporter

# Convert MV network to NetworkX graph
vnf_importer = VnfImporter()
mv_network = vnf_importer.import_vnf("PATH_TO_VNF")
mv_graph = NetworkxConverter.graph_mv(mv_network)

# Convert LV network to NetworkX graph
gnf_importer = GnfImporter()
lv_network = gnf_importer.import_gnf("PATH_TO_GNF")
lv_graph = NetworkxConverter.graph_lv(lv_network)

# Basic statistics
print(f"MV Network: {mv_graph.number_of_nodes()} nodes, {mv_graph.number_of_edges()} edges")
print(f"LV Network: {lv_graph.number_of_nodes()} nodes, {lv_graph.number_of_edges()} edges")

# Example: Use NetworkX algorithms
import networkx as nx

# Check if network is connected
is_connected = nx.is_connected(mv_graph)
print(f"Network is connected: {is_connected}")

# Query element types from the graph
# Each node has a 'type' attribute with the element class name
for node, attrs in mv_graph.nodes(data=True):
    print(f"Node {node}: type={attrs.get('type')}")

# Find all nodes of a specific type
cables = [n for n, d in mv_graph.nodes(data=True) if d.get('type') == 'CableMV']
print(f"Found {len(cables)} cables")

# Find shortest path between nodes
# path = nx.shortest_path(mv_graph, source_node, target_node)

# Export to various NetworkX formats
# nx.write_gexf(mv_graph, "network.gexf")
# nx.write_graphml(mv_graph, "network.graphml")