Skip to content

layout

Layout managers position objects automatically. Select one with the layout= argument to Patcher ("grid", "flow", "columnar"/"matrix", "horizontal", "vertical") and call optimize_layout().

p = Patcher('patch.maxpat', layout="flow", flow_direction="vertical")
# ... add objects and lines ...
p.optimize_layout()

Layout management for py2max patches.

This subpackage provides various layout managers for automatic positioning of Max objects in patches:

  • LayoutManager: Basic horizontal layout (deprecated)
  • GridLayoutManager: Grid-based layout with clustering
  • FlowLayoutManager: Signal flow-based hierarchical layout
  • MatrixLayoutManager: Matrix/columnar layout for signal chains
  • HorizontalLayoutManager: Legacy alias for GridLayoutManager (horizontal)
  • VerticalLayoutManager: Legacy alias for GridLayoutManager (vertical)

LayoutManager

Bases: AbstractLayoutManager

Basic horizontal layout manager.

Provides simple left-to-right object positioning with wrapping. This is a legacy layout manager; consider using GridLayoutManager for new projects.

Parameters:

Name Type Description Default
parent AbstractPatcher

The parent patcher object.

required
pad Optional[int]

Padding between objects (default: 48.0).

None
box_width Optional[int]

Default object width (default: 66.0).

None
box_height Optional[int]

Default object height (default: 22.0).

None
comment_pad Optional[int]

Padding for comments (default: 2).

None

patcher_rect property

patcher_rect: Rect

return rect coordinates of the parent patcher

get_rect_from_maxclass

get_rect_from_maxclass(maxclass: str) -> Optional[Rect]

Retrieve default rectangle for a Max object class.

Parameters:

Name Type Description Default
maxclass str

The Max object class name.

required

Returns:

Type Description
Optional[Rect]

Default Rect for the object class, or None if not found.

box_dims

box_dims(obj: object) -> tuple[float, float]

Return an object's own (width, height) for repositioning.

Optimizers place objects on a uniform grid sized by box_width / box_height, but they must not write back those defaults as the object's size -- doing so squashes every UI object (dial, scope~, function, live.*, comments) down to text-box dimensions (L2). Read the object's existing rect and keep its real w/h, falling back to the manager defaults only when it has no usable rect. Works whether the rect is a Rect namedtuple (programmatic) or a plain list (loaded).

get_absolute_pos

get_absolute_pos(rect: Rect) -> Rect

returns an absolute position for the object

get_relative_pos

get_relative_pos(rect: Rect) -> Rect

returns a relative position for the object

get_pos

get_pos(maxclass: Optional[str] = None) -> Rect

Get the next position for object placement.

Calculates the next position for an object based on the current layout state and optional object class defaults.

Parameters:

Name Type Description Default
maxclass Optional[str]

Optional Max object class for size defaults.

None

Returns:

Type Description
Rect

Rect specifying the position and size for the next object.

above

above(rect: Rect) -> Rect

Return a position of a comment above the object

below

below(rect: Rect) -> Rect

Return a position of a comment below the object

left

left(rect: Rect) -> Rect

Return a position of a comment left of the object

right

right(rect: Rect) -> Rect

Return a position of a comment right of the object

prevent_overlaps

prevent_overlaps(
    min_gap: float = 10.0, max_iterations: int = 50
) -> int

Iteratively push overlapping objects apart.

This method should be called after layout optimization to ensure no objects overlap. It uses an iterative approach where overlapping objects are pushed apart in the direction of their center offset.

Parameters:

Name Type Description Default
min_gap float

Minimum gap between objects in pixels.

10.0
max_iterations int

Maximum number of iterations to prevent infinite loops.

50

Returns:

Type Description
int

Number of iterations performed (0 if no overlaps found).

place_params

place_params(
    direction: Optional[str] = None, gap: float = 8.0
) -> None

Dock value/UI 'param' objects next to the single object they drive.

A param (number box, toggle, slider, dial, message, live.*) whose outgoing connections all go to one non-param target is repositioned adjacent to that target, perpendicular to the signal flow -- above the target for a horizontal flow, to its left for a vertical flow -- and aligned to the inlet it feeds. This keeps value controls with their object instead of spread through the signal graph.

Runs after the main layout as the final placement pass. direction defaults to the manager's flow_direction.

optimize_layout

optimize_layout() -> None

Arrange every object in the patch (batch, whole-patch layout).

This is py2max's batch layout entry point: it always performs a full layout of the entire patch. Subclasses implement their algorithm in _full_layout().

Interactive, per-edit ("incremental") relayout is intentionally out of scope for py2max; it belongs to the editor/server that owns the live editing session. See docs/auto-layout.md in py2max-server.

FlowLayoutManager

Bases: LayoutManager

Advanced layout manager that analyzes signal flow topology.

This layout manager: - Analyzes patchline connections to understand signal flow - Groups related objects based on connection patterns - Uses hierarchical positioning with signal flow left-to-right or top-to-bottom - Minimizes line crossings and connection distances - Balances layout aesthetically while respecting functional relationships

get_relative_pos

get_relative_pos(rect: Rect) -> Rect

Returns a flow-optimized position for the object.

GridLayoutManager

Bases: LayoutManager

Utility class to help with object layout in a grid pattern.

This layout manager supports both horizontal and vertical grid layouts: - Horizontal: objects fill from left to right and wrap to next row - Vertical: objects fill from top to bottom and wrap to next column

get_relative_pos

get_relative_pos(rect: Rect) -> Rect

Returns a relative position for the object based on flow direction.

HorizontalLayoutManager

Bases: GridLayoutManager

Legacy horizontal layout manager. Use GridLayoutManager with flow_direction="horizontal" instead.

VerticalLayoutManager

Bases: GridLayoutManager

Legacy vertical layout manager. Use GridLayoutManager with flow_direction="vertical" instead.

ColumnarLayoutManager

Bases: MatrixLayoutManager

Functional-column layout: Controls -> Generators -> Processors -> Outputs.

A thin specialization of :class:MatrixLayoutManager pinned to column mode, where objects are grouped by functional category into vertical columns rather than by signal chain. Selected via Patcher(..., layout="columnar").

MatrixLayoutManager

Bases: LayoutManager

Unified matrix/columnar layout manager with configurable flow direction.

This layout manager can organize objects in two different patterns based on flow_direction:

When flow_direction="column" (Columnar Layout):

Column 0: Controls/Inputs  | Column 1: Generators | Column 2: Processors | Column 3: Outputs
[control0]                 | [gen0]               | [proc0]              | [output0]
[input0]                   | [gen1]               | [proc1]              | [output1]
[control1]                 | [gen2]               | [proc2]              | [output2]

When flow_direction="row" (Matrix Layout):

Row 0 (Inputs/Controls): [input0/control0] [input1/control1] [input2/control2] ...
Row 1 (Generators):     [gen0]             [gen1]             [gen2]             ...
Row 2 (Processors):     [proc0]            [proc1]            [proc2]            ...
Row 3 (Outputs):        [output0]          [output1]          [output2]          ...

In column mode, objects are grouped by functional category into vertical columns. In row mode, signal chains form columns while functional categories form rows.

Parameters:

Name Type Description Default
parent AbstractPatcher

The parent patcher object.

required
pad Optional[int]

Padding between objects (default: 48.0).

None
box_width Optional[int]

Default object width (default: 66.0).

None
box_height Optional[int]

Default object height (default: 22.0).

None
comment_pad Optional[int]

Padding for comments (default: 2).

None
flow_direction str

Layout direction - "column" or "row" (default: "row").

'row'
num_dimensions int

Number of columns (in column mode) or rows (in row mode) (default: 4).

4
dimension_spacing float

Extra spacing between dimensions (default: 100.0).

100.0

num_columns property writable

num_columns: int

Number of functional columns (column mode); alias of num_dimensions.

column_spacing property writable

column_spacing: float

Get column spacing (legacy property).

row_spacing property writable

row_spacing: float

Get row spacing (legacy property).

get_relative_pos

get_relative_pos(rect: Rect) -> Rect

Returns a position based on flow_direction setting.

get_signal_chain_info

get_signal_chain_info() -> Dict[str, Any]

Get information about detected signal chains.

Returns:

Type Description
Dict[str, Any]

Dictionary with signal chain analysis results.

GraphLayoutManager

Bases: LayoutManager

Position boxes with an external graph-layout engine.

Parameters:

Name Type Description Default
parent AbstractPatcher

the parent patcher.

required
algorithm str

one of :attr:ALGORITHMS (e.g. "hola", "cola", "ogdf-sugiyama").

required
span Optional[float]

target size in px for the longest side of the normalized layout. Defaults to a value scaled by object count so boxes do not overlap.

None