Skip to content

Multi-Sheet Nodes ​

This guide demonstrates how to create networks where nodes appear on multiple sheets. This pattern is common for:

  • Overview diagrams showing the entire network at a glance
  • Detail sheets focusing on specific feeders or areas
  • Voltage level views separating HV, MV, and LV sections

Full Example

View the complete code: 10_multi_sheet_nodes.py

Concept ​

A single electrical node (one GUID) can have multiple visual representations across different sheets. This allows the same network element to appear in:

  • A high-level overview
  • A detailed feeder diagram
  • Both simultaneously

The electrical model remains unified: changes to the node affect all its presentations.

Example: Feeder Network ​

Create Sheets for Different Views ​

python
from pyptp import NetworkMV, configure_logging
from pyptp.elements.color_utils import CL_BLUE, CL_GRAY, CL_GREEN
from pyptp.elements.mv.sheet import SheetMV

configure_logging(level="INFO")

network = NetworkMV()

# Overview sheet shows entire network
overview_sheet = SheetMV(SheetMV.General(name="Overview", color=CL_GRAY))
overview_sheet.register(network)
overview_guid = overview_sheet.general.guid

# Detail sheets for individual feeders
feeder1_sheet = SheetMV(SheetMV.General(name="Feeder 1 Detail", color=CL_BLUE))
feeder1_sheet.register(network)
feeder1_guid = feeder1_sheet.general.guid

feeder2_sheet = SheetMV(SheetMV.General(name="Feeder 2 Detail", color=CL_GREEN))
feeder2_sheet.register(network)
feeder2_guid = feeder2_sheet.general.guid

Create Shared Busbar ​

The main busbar appears on all three sheets:

python
from pyptp.elements.mv.node import NodeMV
from pyptp.elements.mv.presentations import NodePresentation

busbar = NodeMV(
    NodeMV.General(name="Main_Busbar", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=200, y=200),
        NodePresentation(sheet=feeder1_guid, x=100, y=150),
        NodePresentation(sheet=feeder2_guid, x=100, y=150),
    ],
)
busbar.register(network)

Create Sheet-Specific Elements ​

Some elements only appear on specific sheets:

python
from pyptp.elements.mv.source import SourceMV
from pyptp.elements.mv.presentations import ElementPresentation

# Source node only on overview
source_node = NodeMV(
    NodeMV.General(name="Source", unom=10.0),
    presentations=[NodePresentation(sheet=overview_guid, x=200, y=100)],
)
source_node.register(network)

source = SourceMV(
    SourceMV.General(node=source_node.general.guid, sk2nom=100.0),
    presentations=[ElementPresentation(sheet=overview_guid, x=200, y=50)],
)
source.register(network)

Create Feeder Load Nodes ​

Feeder loads appear on both overview and their respective detail sheets:

python
# Feeder 1 load node - on overview and feeder1 detail
feeder1_load_node = NodeMV(
    NodeMV.General(name="F1_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=350, y=200),
        NodePresentation(sheet=feeder1_guid, x=400, y=150),
    ],
)
feeder1_load_node.register(network)

# Feeder 2 load node - on overview and feeder2 detail
feeder2_load_node = NodeMV(
    NodeMV.General(name="F2_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=50, y=200),
        NodePresentation(sheet=feeder2_guid, x=400, y=150),
    ],
)
feeder2_load_node.register(network)

Create Branches with Multiple Presentations ​

Branches between multi-sheet nodes need presentations on each common sheet:

python
from pyptp.elements.mv.link import LinkMV
from pyptp.elements.mv.presentations import BranchPresentation

# Feeder 1 connection - appears on both overview and feeder1 detail
link_f1 = LinkMV(
    LinkMV.General(node1=busbar.general.guid, node2=feeder1_load_node.general.guid),
    presentations=[
        # Overview presentation
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 200), (275, 200)],
            second_corners=[(350, 200)],
        ),
        # Detail presentation
        BranchPresentation(
            sheet=feeder1_guid,
            first_corners=[(100, 150), (250, 150)],
            second_corners=[(400, 150)],
        ),
    ],
)
link_f1.register(network)

Add Loads with Multiple Presentations ​

python
from pyptp.elements.mv.load import LoadMV

load1 = LoadMV(
    LoadMV.General(node=feeder1_load_node.general.guid, P=30.0, Q=15.0),
    presentations=[
        ElementPresentation(sheet=overview_guid, x=350, y=250),
        ElementPresentation(sheet=feeder1_guid, x=400, y=200),
    ],
)
load1.register(network)

Sheet Visibility Matrix ​

For the example above:

ElementOverviewFeeder 1Feeder 2
Main_Busbar✓✓✓
Source✓
F1_Load✓✓
F2_Load✓✓
Link_F1✓✓
Link_F2✓✓

Best Practices ​

Consistent Positioning ​

Keep element positions logical across sheets:

python
# Good: Busbar on left of detail sheets, center of overview
busbar_presentations = [
    NodePresentation(sheet=overview_guid, x=200, y=200),   # Center
    NodePresentation(sheet=detail_guid, x=100, y=150),      # Left
]

Clear Naming Convention ​

Use sheet names that indicate their purpose:

python
sheets = [
    ("Overview", CL_GRAY),
    ("Substation_A_Detail", CL_BLUE),
    ("Feeder_West_Detail", CL_GREEN),
]

Branch Presentation per Common Sheet ​

Always provide a branch presentation for each sheet where both endpoints are visible:

python
def create_multi_sheet_branch(node1, node2, corner_generator):
    """Create branch with presentations on all common sheets."""
    common_sheets = find_common_sheets(node1, node2)

    presentations = []
    for sheet_guid in common_sheets:
        pos1 = get_position_on_sheet(node1, sheet_guid)
        pos2 = get_position_on_sheet(node2, sheet_guid)
        first, second = corner_generator(pos1, pos2)
        presentations.append(
            BranchPresentation(sheet=sheet_guid, first_corners=first, second_corners=second)
        )

    return presentations

Complete Example ​

python
"""Nodes can appear on multiple sheets.

This is useful for creating overview diagrams or splitting large networks
across multiple sheets while maintaining connections.
"""

from pyptp import NetworkMV, configure_logging
from pyptp.elements.color_utils import CL_BLUE, CL_GRAY, CL_GREEN
from pyptp.elements.mv.link import LinkMV
from pyptp.elements.mv.load import LoadMV
from pyptp.elements.mv.node import NodeMV
from pyptp.elements.mv.presentations import BranchPresentation, ElementPresentation, NodePresentation
from pyptp.elements.mv.sheet import SheetMV
from pyptp.elements.mv.source import SourceMV
from pyptp.ptp_log import logger

configure_logging(level="INFO")

network = NetworkMV()

# Create sheets for different network sections
overview_sheet = SheetMV(SheetMV.General(name="Overview", color=CL_GRAY))
overview_sheet.register(network)
overview_guid = overview_sheet.general.guid

feeder1_sheet = SheetMV(SheetMV.General(name="Feeder 1 Detail", color=CL_BLUE))
feeder1_sheet.register(network)
feeder1_guid = feeder1_sheet.general.guid

feeder2_sheet = SheetMV(SheetMV.General(name="Feeder 2 Detail", color=CL_GREEN))
feeder2_sheet.register(network)
feeder2_guid = feeder2_sheet.general.guid

# Main busbar appears on all sheets
busbar = NodeMV(
    NodeMV.General(name="Main_Busbar", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=200, y=200),
        NodePresentation(sheet=feeder1_guid, x=100, y=150),
        NodePresentation(sheet=feeder2_guid, x=100, y=150),
    ],
)
busbar.register(network)

# Source only on overview
source_node = NodeMV(
    NodeMV.General(name="Source", unom=10.0),
    presentations=[NodePresentation(sheet=overview_guid, x=200, y=100)],
)
source_node.register(network)

source = SourceMV(
    SourceMV.General(node=source_node.general.guid, sk2nom=100.0),
    presentations=[ElementPresentation(sheet=overview_guid, x=200, y=50)],
)
source.register(network)

# Feeder nodes on overview and detail sheets
feeder1_load_node = NodeMV(
    NodeMV.General(name="F1_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=350, y=200),
        NodePresentation(sheet=feeder1_guid, x=400, y=150),
    ],
)
feeder1_load_node.register(network)

feeder2_load_node = NodeMV(
    NodeMV.General(name="F2_Load", unom=10.0),
    presentations=[
        NodePresentation(sheet=overview_guid, x=50, y=200),
        NodePresentation(sheet=feeder2_guid, x=400, y=150),
    ],
)
feeder2_load_node.register(network)

# Source connection (overview only)
link_source = LinkMV(
    LinkMV.General(node1=source_node.general.guid, node2=busbar.general.guid),
    presentations=[
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 100), (200, 150)],
            second_corners=[(200, 200)],
        )
    ],
)
link_source.register(network)

# Feeder 1 connection (overview + detail)
link_f1 = LinkMV(
    LinkMV.General(node1=busbar.general.guid, node2=feeder1_load_node.general.guid),
    presentations=[
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 200), (275, 200)],
            second_corners=[(350, 200)],
        ),
        BranchPresentation(
            sheet=feeder1_guid,
            first_corners=[(100, 150), (250, 150)],
            second_corners=[(400, 150)],
        ),
    ],
)
link_f1.register(network)

# Feeder 2 connection (overview + detail)
link_f2 = LinkMV(
    LinkMV.General(node1=busbar.general.guid, node2=feeder2_load_node.general.guid),
    presentations=[
        BranchPresentation(
            sheet=overview_guid,
            first_corners=[(200, 200), (125, 200)],
            second_corners=[(50, 200)],
        ),
        BranchPresentation(
            sheet=feeder2_guid,
            first_corners=[(100, 150), (250, 150)],
            second_corners=[(400, 150)],
        ),
    ],
)
link_f2.register(network)

# Loads with multiple presentations
load1 = LoadMV(
    LoadMV.General(node=feeder1_load_node.general.guid, P=30.0, Q=15.0),
    presentations=[
        ElementPresentation(sheet=overview_guid, x=350, y=250),
        ElementPresentation(sheet=feeder1_guid, x=400, y=200),
    ],
)
load1.register(network)

load2 = LoadMV(
    LoadMV.General(node=feeder2_load_node.general.guid, P=40.0, Q=20.0),
    presentations=[
        ElementPresentation(sheet=overview_guid, x=50, y=250),
        ElementPresentation(sheet=feeder2_guid, x=400, y=200),
    ],
)
load2.register(network)

network.save("multi_sheet.vnf")
logger.info("Multi-sheet network saved")