Draw the TRO flow to scale with neato via --use-cords
Adds a --use-cords switch to tro_flow.py (--use-coords accepted too). With it, every TRO node carries its plant coordinate as a pos attribute and the SVG is produced by "neato -n" instead of dot, so the diagram looks like the plant layout rather than a computed left-to-right flow. Scale is 0.25 pt/mm (COORD_SCALE), which turns the ~11 x 20 m plant into roughly 2800 x 5000 pt - large enough that the TRO boxes do not overlap. Without the switch the pos attributes stay in the DOT as information only, at 1:100, and dot ignores them; the default layout is unchanged. Two details neato -n needs: the legend gets a position of its own, placed below left of the plant bounding box, because with -n a node without pos would land at 0,0 in the middle of the drawing. And the switch is refused with a clear message if any TRO has no coordinate, since -n cannot lay out a graph with missing positions. Verified that neato -n reproduces the given coordinates: the positions it reports back differ from the input by a constant offset only (spread 0.08 pt, from Graphviz moving the drawing into the positive quadrant), and no node distance changes by more than 0.08 pt over spans of up to 3600 pt. graph_to_svg() in material_flow.py replaces dot_to_svg() to take an engine and the no-op flag; dot_to_svg() stays as a thin wrapper. It now also treats output on stderr as an error, so neato's "node has no position" warnings do not pass silently. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+39
-12
@@ -692,26 +692,53 @@ def find_dot() -> str | None:
|
||||
return shutil.which("dot")
|
||||
|
||||
|
||||
def dot_to_svg(dot_file: Path, svg_file: Path) -> None:
|
||||
"""SVG aus der .dot-Datei erzeugen (Graphviz)."""
|
||||
executable = find_dot()
|
||||
def find_engine(engine: str) -> str | None:
|
||||
"""Layout-Programm von Graphviz suchen ('dot', 'neato', ...)."""
|
||||
if engine == "dot":
|
||||
return find_dot()
|
||||
return shutil.which(engine)
|
||||
|
||||
|
||||
def graph_to_svg(
|
||||
dot_file: Path, svg_file: Path, engine: str = "dot", no_op: int = 0
|
||||
) -> None:
|
||||
"""
|
||||
SVG aus der .dot-Datei erzeugen.
|
||||
|
||||
engine Layout-Programm ('dot' fuer die berechnete Anordnung, 'neato' fuer
|
||||
vorgegebene Koordinaten)
|
||||
no_op nur fuer neato: 1 oder 2 setzt den No-op-Schalter (-n / -n2), dann
|
||||
werden die pos-Attribute der Knoten als Position uebernommen und
|
||||
nur die Kanten berechnet. Alle Knoten brauchen dann ein pos.
|
||||
"""
|
||||
executable = find_engine(engine)
|
||||
if not executable:
|
||||
raise RuntimeError(
|
||||
"Graphviz 'dot' nicht gefunden. Bitte Graphviz installieren "
|
||||
"(https://graphviz.org/download/) oder GRAPHVIZ_DOT auf die "
|
||||
"dot-Programmdatei setzen."
|
||||
f"Graphviz '{engine}' nicht gefunden. Bitte Graphviz installieren "
|
||||
f"(https://graphviz.org/download/)"
|
||||
+ (" oder GRAPHVIZ_DOT auf die dot-Programmdatei setzen."
|
||||
if engine == "dot" else ".")
|
||||
)
|
||||
|
||||
result = subprocess.run(
|
||||
[executable, "-Tsvg", str(dot_file), "-o", str(svg_file)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
command = [executable]
|
||||
if no_op:
|
||||
command.append(f"-n{no_op}")
|
||||
command += ["-Tsvg", str(dot_file), "-o", str(svg_file)]
|
||||
|
||||
result = subprocess.run(command, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError(
|
||||
f"'dot' ist mit Code {result.returncode} fehlgeschlagen:\n"
|
||||
f"'{engine}' ist mit Code {result.returncode} fehlgeschlagen:\n"
|
||||
f"{(result.stderr or result.stdout).strip()}"
|
||||
)
|
||||
# neato meldet fehlende Positionen nur als Warnung auf stderr
|
||||
if result.stderr.strip():
|
||||
raise RuntimeError(f"'{engine}' meldet: {result.stderr.strip()}")
|
||||
|
||||
|
||||
def dot_to_svg(dot_file: Path, svg_file: Path) -> None:
|
||||
"""SVG mit der berechneten Anordnung von 'dot' erzeugen."""
|
||||
graph_to_svg(dot_file, svg_file, engine="dot")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user