How graphviz2drawio Differentiates Between `graph` and `digraph`
graphviz2drawio uses pygraphviz's AGraph.directed boolean attribute to detect whether the input DOT defines a digraph (directed) or graph (undirected), propagating this flag through the conversion pipeline to set edge arrowheads accordingly.
Converting Graphviz DOT diagrams to Draw.io (mxGraph) format requires accurately preserving the semantic difference between directed and undirected relationships. The hbmartin/graphviz2drawio library handles this distinction by leveraging pygraphviz parsing capabilities to detect the graph type from the DOT source and apply the appropriate edge styling throughout the conversion process.
How graphviz2drawio Detects Graph Directionality
The detection begins in graphviz2drawio/graphviz2drawio.py, where the _load_pygraphviz_agraph function processes the input. This function first determines whether the supplied string is a DOT graph definition or a file path using a regular expression that explicitly matches both graph and digraph keywords:
pattern = re.compile(
r"^(?=(\s*))\1(strict)?(?=(\s*))\3(graph|digraph)[^{]*{",
flags=re.MULTILINE,
)
When this pattern matches, the text is passed to pygraphviz's AGraph(string=...) constructor. The resulting AGraph object exposes a directed boolean attribute that is True for digraph declarations and False for graph declarations. This attribute serves as the single source of truth for directionality throughout the library.
Propagating the Direction Flag Through the Conversion Pipeline
Once loaded, the direction flag flows through three critical stages to ensure the output Draw.io XML reflects the correct edge semantics.
From DOT Parsing to SVG Processing
After loading the DOT source, the main conversion function reads graph.directed and immediately passes it to the SVG parser:
nodes, edges, clusters = parse_nodes_edges_clusters(
svg_data=svg_graph,
is_directed=graph.directed,
)
This call in graphviz2drawio/graphviz2drawio.py (lines 34-38) ensures that the directionality information derived from the original DOT header is available during the SVG interpretation phase.
Edge Factory and Direction Assignment
Inside graphviz2drawio/models/SvgParser.py (lines 35-36), the parser instantiates an EdgeFactory with the direction flag:
edge_factory = EdgeFactory(coords=coords, is_directed=is_directed)
The factory subsequently creates Edge objects in graphviz2drawio/mx/Edge.py (lines 31-33), where the direction attribute is set based on the propagated flag:
self.dir = DotAttr.FORWARD if is_directed else DotAttr.NONE
This assignment determines whether the resulting Draw.io edges display directional arrowheads (forward) or terminate without arrows (none), preserving the visual semantics of the original Graphviz definition.
Practical Examples: Converting Directed and Undirected Graphs
The same convert function handles both graph types automatically. The library inspects the DOT header to determine directionality without requiring additional parameters.
Example 1: Directed Graph (digraph)
from graphviz2drawio import convert
dot = """
digraph G {
A -> B
B -> C
}
"""
drawio_xml = convert(dot) # graph.directed evaluates to True
print(drawio_xml) # Output contains edges with forward arrows
Example 2: Undirected Graph (graph)
from graphviz2drawio import convert
dot = """
graph G {
A -- B
B -- C
}
"""
drawio_xml = convert(dot) # graph.directed evaluates to False
print(drawio_xml) # Output contains edges without arrows
In both cases, graphviz2drawio automatically detects the graph type from the DOT syntax and generates the appropriate Draw.io representation.
Summary
- graphviz2drawio relies on pygraphviz to parse DOT files and determine directionality via the
AGraph.directedboolean attribute. - The
_load_pygraphviz_agraphfunction ingraphviz2drawio/graphviz2drawio.pyuses a regex pattern to identify valid DOT strings containing eithergraphordigraphkeywords. - The direction flag propagates through
parse_nodes_edges_clusterstoSvgParserand finally toEdgeFactory, ensuring consistent handling across the conversion stack. - In
graphviz2drawio/mx/Edge.py, edges are assignedDotAttr.FORWARDfor directed graphs andDotAttr.NONEfor undirected graphs, controlling arrowhead rendering in the final Draw.io output. - No manual configuration is required; the library automatically differentiates between
graphanddigraphbased solely on the DOT source declaration.
Frequently Asked Questions
Does graphviz2drawio support mixed directed and undirected graphs?
No, graphviz2drawio follows the standard Graphviz specification where a single DOT file must declare either graph (undirected) or digraph (directed) at the top level. The library uses a single is_directed flag for the entire conversion, so mixing edge types within one graph is not supported according to the source implementation in graphviz2drawio/mx/Edge.py.
What happens if the DOT file uses the strict keyword?
The regex pattern in graphviz2drawio/graphviz2drawio.py explicitly handles the optional strict modifier: r"^(?=(\s*))\1(strict)?(?=(\s*))\3(graph|digraph)[^{]*{". This ensures that both strict graph and strict digraph declarations are correctly identified and passed to pygraphviz for parsing, preserving the directionality detection regardless of strict mode.
Can I override the directionality to force arrows on an undirected graph?
The current implementation does not expose a public API to override the is_directed flag. The directionality is determined exclusively by pygraphviz's parsing of the DOT header and flows through private methods like parse_nodes_edges_clusters and EdgeFactory.__init__ without user intervention. To change edge directionality, you must modify the DOT source from graph to digraph.
Which pygraphviz attributes does graphviz2drawio use to detect graph type?
The library depends entirely on the directed attribute of the AGraph class provided by pygraphviz. As shown in graphviz2drawio/graphviz2drawio.py, the code accesses graph.directed immediately after instantiation, using this boolean to initialize the conversion pipeline's direction state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →