Coverage for src / graphable / views / tikz.py: 100%
45 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-16 21:32 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-16 21:32 +0000
1from dataclasses import dataclass
2from logging import getLogger
3from pathlib import Path
4from typing import Any, Callable
6from ..graph import Graph
7from ..graphable import Graphable
8from ..registry import register_view
10logger = getLogger(__name__)
13@dataclass
14class TikzStylingConfig:
15 """
16 Configuration for customizing TikZ diagram generation.
18 Attributes:
19 node_ref_fnc: Function to generate the node identifier.
20 node_label_fnc: Function to generate the node label.
21 node_options: Global TikZ options for nodes.
22 edge_options: Global TikZ options for edges.
23 use_graphs_lib: Whether to use the TikZ 'graphs' library syntax.
24 """
26 node_ref_fnc: Callable[[Graphable[Any]], str] = lambda n: f"node_{id(n)}"
27 node_label_fnc: Callable[[Graphable[Any]], str] = lambda n: str(n.reference)
28 node_options: str = "draw, circle"
29 edge_options: str = "->"
30 use_graphs_lib: bool = True
33def create_topology_tikz(graph: Graph, config: TikzStylingConfig | None = None) -> str:
34 """
35 Generate TikZ LaTeX code from a Graph.
37 Args:
38 graph (Graph): The graph to convert.
39 config (TikzStylingConfig | None): Styling configuration.
41 Returns:
42 str: The TikZ LaTeX code string.
43 """
44 config = config or TikzStylingConfig()
45 lines: list[str] = [r"\begin{tikzpicture}"]
47 if config.use_graphs_lib:
48 lines.append(r" \usetikzlibrary{graphs}")
49 lines.append(" \\graph [nodes={" + config.node_options + "}] {")
51 # Define nodes and edges in graph syntax
52 for node in graph.topological_order():
53 node_ref = config.node_ref_fnc(node)
54 node_label = config.node_label_fnc(node)
55 # TikZ graph syntax: alias/Label
56 lines.append(f' {node_ref} ["{node_label}"];')
58 for dependent, _ in graph.internal_dependents(node):
59 dep_ref = config.node_ref_fnc(dependent)
60 lines.append(f" {node_ref} -> {dep_ref};")
62 lines.append(" };")
63 else:
64 # Standard TikZ syntax (simplified placement)
65 for i, node in enumerate(graph.topological_order()):
66 node_ref = config.node_ref_fnc(node)
67 node_label = config.node_label_fnc(node)
68 lines.append(
69 f" \\node[{config.node_options}] ({node_ref}) at (0,{-i * 1.5}) {{{node_label}}};"
70 )
72 for node in graph.topological_order():
73 node_ref = config.node_ref_fnc(node)
74 for dependent, _ in graph.internal_dependents(node):
75 dep_ref = config.node_ref_fnc(dependent)
76 lines.append(
77 f" \\draw[{config.edge_options}] ({node_ref}) -- ({dep_ref});"
78 )
80 lines.append(r"\end{tikzpicture}")
81 return "\n".join(lines)
84@register_view(".tex", creator_fnc=create_topology_tikz)
85def export_topology_tikz(
86 graph: Graph, output: Path, config: TikzStylingConfig | None = None
87) -> None:
88 """
89 Export the graph to a TikZ (.tex) file.
91 Args:
92 graph (Graph): The graph to export.
93 output (Path): The output file path.
94 config (TikZStylingConfig | None): Styling configuration.
95 """
96 logger.info(f"Exporting TikZ definition to: {output}")
97 with open(output, "w+") as f:
98 f.write(create_topology_tikz(graph, config))