Tutorial: Importing Ports from Excel#

For assemblies with many connection points it is more convenient to define ports in a spreadsheet than to hard-code them in Python. Port includes a class method that reads an Excel file and returns a list of Port objects.

Which spreadsheet import should I use?

This page covers the ports-only path: from_xlsx_stream() reads a flat list of ports, and you assemble pipe types and pairings in Python. If you want to define complete specifications — pipe types, start and end ports, all in one file — use from_xlsx() / from_csv() instead; see Tutorial: Defining Specifications in a Spreadsheet.

Excel Format#

The Excel file must have the following columns (in order) in the first worksheet. A row whose first cell contains name is skipped, which drops the header row — and any port whose name contains name, such as port_name_2: keep that word out of port names.

Column

Header name

Description

A

name

Port identifier string (e.g. "port_inlet_1")

B

coordinates_x

X coordinate in metres

C

coordinates_y

Y coordinate in metres

D

coordinates_z

Z coordinate in metres

E

direction_x

X component of the pipe exit direction

F

direction_y

Y component

G

direction_z

Z component

H

length

Minimum straight length at the port before the first turn (metres)

Direction vectors do not need to be unit vectors — they are normalized automatically.

Example spreadsheet:

name          | coordinates_x | coordinates_y | coordinates_z | direction_x | direction_y | direction_z | length
inlet_port    | 0.05          | -0.4          | 0.1           | 0           | 1           | 0           | 0.1
outlet_port   | 0.05          | 0.8           | 0.1           | 0           | -1          | 0           | 0.1
branch_port_A | 0.37          | -0.4          | 0.3           | 0           | 1           | 0           | 0.08
branch_port_B | 0.45          | 0.8           | 0.18          | 0           | -1          | 0           | 0.04

Reading Ports from a File#

from routing.core.core import Port

with open("ports.xlsx", "rb") as f:
    ports = Port.from_xlsx_stream(f)

# ports is a list of Port objects
for port in ports:
    print(port.name, port.coordinates, port.direction)

The method returns a flat list[Port]. If your spreadsheet defines port pairs (start + end for each pipe), you will need to pair them manually.

Pairing Ports into Specifications#

A common pattern is to store ports in consecutive pairs (start, end) and pair them in a loop:

from routing.core.core import Port, PipeType, Specification
import routing.core.legacy_piping as piping

with open("ports.xlsx", "rb") as f:
    ports = Port.from_xlsx_stream(f)

# Pair consecutive ports as (start, end)
port_pairs = [(ports[i], ports[i + 1]) for i in range(0, len(ports), 2)]

# One pipe type for all
pipe_type = PipeType(
    section=piping.Section(radius_equivalent=0.015),
    name="HydraulicLine",
    radius_of_curvature_ratio_min=1.5,
    color=(0, 100, 200),
    type_="Hydraulic",
)

specifications = [
    Specification(start, end, pipe_type, name=f"route_{i}")
    for i, (start, end) in enumerate(port_pairs)
]

Alternatively, use naming conventions to match starts and ends:

# Ports named "inlet_<id>" pair with "outlet_<id>"
port_dict = {p.name: p for p in ports}
ids = [name.removeprefix("inlet_") for name in port_dict if name.startswith("inlet_")]
specifications = [
    Specification(
        port_dict[f"inlet_{i}"],
        port_dict[f"outlet_{i}"],
        pipe_type,
        name=f"route_{i}",
    )
    for i in ids
]

Next Steps#