Status: Implemented in PHART v1.5.x (current branch behavior documented below). Audience: CLI users, library users, and maintainers
PHART currently supports attribute-driven edge coloring via --edge-color-rule, but it is limited to direct edge-attribute equality matches. Users need richer conditions, including rules that combine edge attributes with endpoint node attributes (e.g. spouse edge color based on destination sex), while keeping simple cases ergonomic.
The design goal is a unified rule model that can style both nodes and edges without introducing multiple disconnected rule systems.
self.<attr>)edge.<attr>)u.<attr>)v.<attr>)--edge-color-rule).eval, no Python code execution).node, edge, connector, or panel_header).self: current target’s attributesedge: alias of self when target is edgenode: alias of self when target is nodeconnector: alias of self when target is connectorpanel_header: alias of self when target is panel_headeru: source-node attributes for an edgev: destination-node attributes for an edgeRules normalize into this internal structure:
id: spouse-male
priority: 100 # optional integer; higher runs first
target: edge # edge | node | connector | panel_header
when: role == "spouse" and v.sex == "M"
set:
color: blue # required field for color behavior
Notes:
priority is optional. If omitted, default priority is 0.set.Supported targets:
nodeedgeconnectorpanel_headerSupported set keys:
node: color, prefix, suffix, node_styleedge: color plus edge glyph keys (arrow_*, line_*, corner_*, tee_*, cross)connector: color, prefix, suffixpanel_header: color, prefix, suffix==, !=in, not inand, or, not(, )'text' or "text"true, falsenull["A", "B", "C"]self.role, edge.role, node.name, u.sex, v.sexrole) are shorthand for self.role.Resolution rules:
null.a.b.c).in/not in in v1.5.Default string comparisons are case-insensitive in v1.5 for compatibility with existing edge color rule normalization.
Keep existing:
--colors attr --edge-color-rule parenttype:father=bright_blue,mother=bright_magenta
This is compiled into equivalent advanced rules at parse time.
CLI supports repeated option:
--style-rule 'edge: role=="spouse" and v.sex=="M" -> color=blue'
--style-rule 'edge: role=="spouse" and v.sex=="F" -> color=green'
Optional file input for complex sets:
--style-rules-file rules.yaml
File format: YAML or JSON containing a rules array using canonical model.
LayoutOptions accepts raw canonical rule dicts via style_rules:
style_rules=[
{
"target": "edge",
"when": 'role == "spouse" and v.sex == "M"',
"set": {"color": "blue"},
}
]
Implementation note:
style_rules is the public/raw input field.LayoutOptions initialization into _compiled_style_rules for runtime evaluation._compiled_style_rules is internal and not part of the public stability contract.priority descendingwhen for matching target.set not yet assigned.v1.5 color behavior:
set.color affects edge color map.set.color affects node color map.Fallbacks:
source|target|path etc.).--edge-color-rule remains supported.edge_color_rules field remains accepted.Legacy mapping example:
--edge-color-rule role:spouse=blue
normalizes to:
- target: edge
when: edge.role == "spouse"
set: { color: blue }
foo) is rejected.Phase 1 completed:
--style-rule and --style-rules-file implemented.--edge-color-rule is compiled to canonical edge color rules.Phase 2 completed:
Phase 3 completed for current scope:
set supports node decorators (prefix, suffix, node_style) and edge glyph fields (arrow_*, line_*, corner_*, tee_*, cross).PHART has two historical styling tracks:
NodeStyle, box options, arrow glyph fields).The style-rule system should become the canonical per-element styling mechanism, while preserving backward compatibility for existing global options.
Node-target fields:
colorprefixsuffixnode_style (minimal|square|round|diamond|custom)Edge-target fields:
colorarrow_up, arrow_down, arrow_left, arrow_rightline_horizontal, line_verticalcorner_ul, corner_ur, corner_ll, corner_lrtee_up, tee_down, tee_left, tee_rightcrossLayoutOptions explicit global valuesStyle rules are last-write authority for the fields they set.
NodeStyle and existing decorator fields valid.custom_decorators valid for programmatic users.Execution board (feature branch: feature/style-rule-node-style):
| ID | Workstream | Status | Notes |
|---|---|---|---|
| A | Contracts and option model | Completed (Phase 3a) | Key/target validation active for node:{color,prefix,suffix,node_style} and edge:{color,glyphs} |
| B | Node rendering integration | Completed (Phase 3a) | Rule-driven prefix/suffix/node_style wired in shared node line resolution (layout + draw) |
| C | Edge rendering integration | Completed (Phase 3b) | Rule-driven arrow_*, line_*, corner_*, tee_*, and cross integrated into routing/merge |
| D | Legacy convergence path | Completed (Decision) | No implicit legacy-to-rule mapper in Phase 3; legacy globals remain, style-rules are authoritative |
| E | CLI / UX surface | Completed | CLI/docs cover style-rules plus global edge presets/arrow modes |
| F | Test plan | In Progress | Node-style + edge-glyph rule and validation tests added; parity tests pending |
| G | Rollout sequencing | Completed (Phase 3) | Steps 1-5 complete for style-rule/node-style/edge-glyph scope |
set keys per target.StyleSetKey validation in rule compilation (reject unknown keys early).arrow_up on node).LayoutOptions legacy fields unchanged for compatibility (node_style, custom_decorators, arrow glyph fields).Acceptance criteria:
target=node) that can resolve:
colorprefixsuffixnode_stylehpad, vpad) only when bboxes is true.Acceptance criteria:
target=edge) beyond color to support glyph keys:
arrow_up/down/left/rightline_horizontal/line_verticalcorner_*, tee_*Acceptance criteria:
NodeStyle, custom_decorators, edge glyph fields).LayoutOptions globalsAcceptance criteria:
--style-rule and --style-rules-file unchanged.set keys and target restrictions in README.md and docs/index.md.Acceptance criteria:
--help and docs without reading code.NodeStyle + custom_decorators parity vs pre-Phase-3 output--style-rule with new keysAcceptance criteria:
prefix/suffix/node_style) integration (implemented).--edge-color-rule output equals canonical rule output.and/or expressions.Simple edge attr:
rules:
- target: edge
when: role == "parent" and parenttype == "mother"
set: { color: bright_magenta }
Edge + endpoint attr:
rules:
- target: edge
when: role == "spouse" and v.sex == "M"
set: { color: blue }
- target: edge
when: role == "spouse" and v.sex == "F"
set: { color: green }
Node rule:
rules:
- target: node
when: sex == "F"
set: { color: bright_magenta }