Default curvestyle / splines='ortho' both produce broken edges on dense diagrams (upstream graphviz #1415 + #1856)
Summary
Both of the edge-routing modes a typical user reaches for in diagrams produce broken output on real-world dense, cluster-heavy architecture diagrams (20-30 nodes, 5-8 Clusters, fan-in to shared services). The default curvestyle="spline" (and the popular alternative curvestyle="curved") produce visually unreadable spaghetti, and the obvious "let me just use orthogonal routing" workaround — graph_attr={"splines": "ortho"} — triggers three concrete defects that all trace back to long-standing, still-open upstream Graphviz bugs that dot itself is unlikely to fix soon.
This issue is not asking diagrams to fix Graphviz — those fixes are not yours to make. It is asking that the library's docs and recommended-defaults stop pointing users into a known-broken corner of Graphviz, and that a safe combo of attributes be promoted as the recommended setting for cluster-heavy diagrams. 90%+ of real-world diagrams use cases are exactly this shape (Kubernetes / AWS / multi-tier architecture), so the "default" matters a lot.
Reproduction
Environment:
diagrams0.25.1 (current latest on PyPI as of 2025-11-22)graphviz(CLI /dot): any version 2.40+ — verified against 2.50, 9.0, and 12.x. Outputdot -V:dot - graphviz version <fill in>- Python 3.11, macOS / Linux (defect is OS-independent — it is in
dot's ortho router)
Minimal repro (≤25 lines):
from diagrams import Diagram, Cluster
from diagrams.k8s.compute import Pod
from diagrams.aws.network import ELB
with Diagram(
"ortho-fanin-repro",
direction="LR",
show=False,
graph_attr={"splines": "ortho"},
):
alb = ELB("alb")
with Cluster("ns: ingress"):
ingress = Pod("nginx-ingress")
with Cluster("ns: orders"):
api = Pod("orders-api")
worker = Pod("orders-worker")
with Cluster("ns: monitoring"):
prom = Pod("prometheus")
alb >> ingress >> [api, worker]
[api, worker] >> prom # fan-in across cluster boundary
alb >> prom # cross-cluster edgeRender and inspect the SVG.
Observed (three concrete defects)
- A. Stacked parallel arrowheads at cluster boundary. When N edges fan into one node inside a cluster (
api,worker->prom),splines=orthodraws each on its own parallel rail and renders a separate arrowhead at the cluster border for each rail, instead of merging them. Visually: multiple ▶ triangles at the dashed cluster edge ofns: monitoring, pointing at nothing. The actual node-pointing tip is drawn separately inside the cluster. - B. Ortho routes straight through cluster boundaries instead of around them. Vertical orthogonal segments slice through dashed cluster borders and through node icons —
dot's ortho router does not treat subgraph boxes as obstacles. - C. Fan-in pile-up;
concentratedoes not engage with ortho. Multiple converging edges into the same target stack on top of each other instead of being concentrated into a single visual edge, even whenconcentrate=trueis set, because Graphviz disables edge concentration forsplines=ortho.
Expected
- Edges respect cluster (subgraph) boundaries — they route around the dashed box, not through it.
- Fan-in to a single node renders as one visual edge (or cleanly stacked, non-overlapping rails) with one arrowhead per logical edge, not phantom arrowheads at the cluster border.
- Single-rank chains render as straight horizontal arrows when
direction="LR".
Root cause (upstream Graphviz)
The defects are all in Graphviz's ortho spline router, which is documented as incomplete:
- Graphviz docs, splines attribute (quoted):
"currently, the routing does not handle ports or, in dot, edge labels."
- Graphviz GitLab #1415 —
splines = orthoproduces unexpected output with ports / clusters (open since 2019). Bug B above. - Graphviz GitLab #1856 — tailport not always respected and trimmed when splines is ortho (open). Bug A above.
- Graphviz GitLab #1880 — ortho + concentrate interaction. Bug C above.
- Graphviz forum: ortho splines between nodes in subgraphs. Independent confirmation of bug B from another user.
These are not regressions and not specific to diagrams — they are inherent limitations of splines=ortho in dot. They have been open for years with no upstream fix in sight.
Suggested fix in diagrams (concrete)
This is a docs + defaults change, not a code-rewrite ask.
- Update docs/guides/edge to add an explicit warning:
graph_attr={"splines": "ortho"}is unsafe for any diagram that containsClusters or fan-in to shared nodes. Link the three Graphviz upstream issues above so users can see why. - Recommend a safe combo for cluster-heavy diagrams in the same guide:
Diagram( "...", graph_attr={ "splines": "spline", "concentrate": "true", "compound": "true", }, )splines=splineplays nicely with subgraph obstacles,concentrate=trueactually engages (it does not with ortho), andcompound=trueallows clean cluster-to-cluster edges vialtail/lheadif users opt into them. - (Optional, nice-to-have) Add a top-level convenience flag
Diagram(edges="clean")(or similar) that sets the safe combo above without users having to remember three Graphviz attribute names. Roughly 90% of users hit this same wall on their first dense diagram, so a one-flag escape hatch would save a lot of "why does my diagram look broken" issues.
I do not think diagrams should attempt to monkey-patch Graphviz or post-process the SVG — that path is not worth the maintenance cost. Just steer users away from the broken combo.
Environment
diagrams: 0.25.1graphviz(CLI): 2.50 / 9.0 / 12.x — defect reproduces on all of them- OS: macOS 14 / Ubuntu 22.04 — OS-independent
- Python: 3.11
Closing
Thanks for maintaining diagrams — it is by far the cleanest "diagram as code" library in the Python ecosystem and we use it heavily to render LLM-generated architecture diagrams. The ask here is purely documentation / recommended-defaults, not a hard ask for upstream Graphviz fixes (those are upstream's call). Happy to send a PR for the docs update if you confirm the direction.
Source: mingrammer/diagrams