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.

Excel Format#

The Excel file must have the following columns (in order) in the first worksheet. The first row is treated as a header and is automatically skipped:

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            | coord_x | coord_y | coord_z | dir_x | dir_y | dir_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
from piping_3d import 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}
specifications = [
    Specification(
        port_dict[f"inlet_{i}"],
        port_dict[f"outlet_{i}"],
        pipe_type,
        name=f"route_{i}",
    )
    for i in range(n_pipes)
]

Next Steps#