How to Customize the Graphviz to draw.io Conversion Process: A Complete Technical Guide
You can customize the Graphviz to draw.io conversion by modifying Graphviz attributes in your dot files, extending the NodeFactory and EdgeFactory classes, adding entries to the Styles mapping, or subclassing MxGraph to inject custom XML attributes.
The graphviz2drawio library transforms Graphviz diagrams into draw.io-compatible XML through a modular pipeline. Because each stage is implemented as discrete Python classes and functions, you can hook into the conversion process at multiple points without forking the entire repository.
Understanding the Conversion Architecture
The conversion follows a five-step pipeline defined in graphviz2drawio/graphviz2drawio.py. Each step exposes specific extension points for customization.
Input Loading and SVG Rendering
The _load_pygraphviz_agraph() function accepts strings, filenames, streams, or pygraphviz.AGraph objects and normalizes them into an AGraph instance. The convert() function then calls AGraph.draw(prog=layout_prog, format="svg") (lines 29-30) to invoke Graphviz's layout engine.
You can specify any Graphviz layout program via the layout_prog parameter. The default is dot, but neato, twopi, circo, fdp, and sfdp are fully supported.
SVG Parsing and Extraction
The graphviz2drawio.models.SvgParser.parse_nodes_edges_clusters() method (lines 23-81) walks the generated SVG using an xml.etree.ElementTree parser with a custom CommentedTreeBuilder. This stage extracts gradients, groups (classified as node, edge, or cluster), and delegates geometry to specialized factories.
Object Factory Layer
Three factories transform SVG primitives into draw.io objects:
NodeFactory.from_svg()(lines 25-94): Reads SVG<g>elements, detects shapes (ellipse, rect, polygon), and extracts visual properties via_extract_fill()(lines 99-107) and_extract_stroke().EdgeFactory.from_svg()(lines 18-55): Parses path geometry, stroke colors, widths, and dash styles (lines 33-41), usingCurveFactoryfor Bézier conversion.Styles.get_for_shape()(lines 88-98): Maps Graphviz shape names to draw.io style strings using the internal_shape_to_styledictionary.
XML Assembly
The graphviz2drawio.mx.MxGraph class (lines 13-71) assembles the final document. It provides add_node() and add_edge() methods that you can override to inject custom XML attributes or modify cell properties before serialization.
Customization Methods
Change the Layout Engine
Pass a different layout program via the CLI --program (or -p) flag defined in graphviz2drawio/models/Arguments.py (lines 46-48):
graphviz2drawio -p neato mygraph.dot -o mygraph.xml
Programmatically, supply the layout_prog parameter to the convert() function:
from graphviz2drawio.graphviz2drawio import convert
from pygraphviz import AGraph
dot = "digraph { A -> B }"
agraph = AGraph(string=dot)
xml_output = convert(agraph, layout_prog="twopi")
Customize Visual Attributes via Graphviz
The factories read standard Graphviz attributes directly from the SVG output. Define these in your dot file:
digraph G {
node [style=filled, shape=box, fillcolor="#ffcc00", color="#003366", fontcolor="#003366"]
A -> B [color="#ff6600", penwidth=2, style=dashed]
A [label="Start"]
B [label="End"]
}
fillcolorandstyle=filledcontrol node background (processed byNodeFactory._extract_fill())colorsets border or edge stroke color (processed byEdgeFactory.from_svg()lines 33-41)penwidthadjusts stroke widthstyle=dashedapplies dash patterns to edges
Extend Shape Mappings
To map custom Graphviz shapes to specific draw.io styles, modify graphviz2drawio.mx.Styles._shape_to_style. For example, to render Graphviz record shapes as draw.io tables:
from graphviz2drawio.mx import Styles, Shape
Styles.TABLE = "shape=table;..." # Define your draw.io style string
Styles._shape_to_style[Shape.RECORD] = Styles.TABLE
Insert this configuration before calling convert() to affect all nodes declared with shape=record.
Modify XML Output with Custom Attributes
Subclass MxGraph to inject additional XML attributes into every node:
from graphviz2drawio.mx.MxGraph import MxGraph
class CustomMxGraph(MxGraph):
def add_node(self, node):
super().add_node(node)
cell = self.root[-1]
cell.set("userData", "custom-value")
cell.set("metadata", "department-x")
Instantiate CustomMxGraph in your conversion wrapper to enrich the output without modifying the core library.
Programmatic API Usage
For full control, bypass the CLI and use the Python API directly:
from graphviz2drawio.graphviz2drawio import convert
from pygraphviz import AGraph
dot = """
digraph {
X [shape=hexagon, style=filled, fillcolor=lightblue]
Y [shape=ellipse, color=red]
X -> Y [style=bold]
}
"""
agraph = AGraph(string=dot)
drawio_xml = convert(agraph, layout_prog="dot")
The convert function accepts AGraph instances, strings, file paths, or stream objects (type signature: graph_to_convert: AGraph | str | TextIOBase | Path | TextIO at line 14).
Key Source Files for Reference
graphviz2drawio/graphviz2drawio.py: Contains the coreconvert()function and_load_pygraphviz_agraph()helper.graphviz2drawio/models/SvgParser.py: Implementsparse_nodes_edges_clusters()for SVG traversal.graphviz2drawio/mx/NodeFactory.py: Handles node creation and fill/stroke extraction.graphviz2drawio/mx/EdgeFactory.py: Processes edge geometry and styling.graphviz2drawio/mx/Styles.py: Defines the_shape_to_stylemapping dictionary (lines 88-98).graphviz2drawio/mx/CurveFactory.py: Converts SVG paths to draw.io curves.graphviz2drawio/mx/MxGraph.py: Assembles the final XML document structure.graphviz2drawio/__main__.py: CLI entry point at lines 76-103.graphviz2drawio/models/Arguments.py: Command-line argument definitions.
Summary
- Change layout engines using the
-pflag orlayout_progparameter in the Python API. - Control visual styling by setting Graphviz attributes (
fillcolor,color,penwidth,style) in your dot files, whichNodeFactoryandEdgeFactoryparse automatically. - Add custom shapes by extending
Styles._shape_to_stylewith new Shape-to-style mappings. - Inject custom XML by subclassing
MxGraphand overridingadd_node()oradd_edge(). - Use programmatically by importing
convert()and passingAGraphobjects directly for dynamic diagram generation.
Frequently Asked Questions
How do I change the Graphviz layout engine used during conversion?
Pass the --program (or -p) flag via the CLI: graphviz2drawio -p neato input.dot. According to the source code in graphviz2drawio/graphviz2drawio.py (line 29-30), this value passes directly to AGraph.draw(). Valid options include dot, neato, twopi, circo, fdp, and sfdp.
Can I customize node colors and border styles?
Yes. Set standard Graphviz attributes in your dot file: fillcolor for background, color for borders, and fontcolor for text. The NodeFactory._extract_fill() method (lines 99-107) and NodeFactory._extract_stroke() parse these from the SVG output generated by Graphviz. For edges, use color, penwidth, and style=dashed.
Is it possible to add custom XML attributes to the output?
Yes. Subclass graphviz2drawio.mx.MxGraph and override the add_node() or add_edge() methods. After calling super().add_node(node), access the last appended cell via self.root[-1] and use .set() to inject custom attributes. This allows you to embed metadata or user data without modifying the core library files.
How can I support custom or non-standard Graphviz shapes?
Extend the graphviz2drawio.mx.Styles class. Add a new entry to the _shape_to_style dictionary (defined at lines 88-98) mapping your custom Shape enum to a draw.io style string. For example: Styles._shape_to_style[Shape.MY_CUSTOM] = "shape=customStyle;...". Nodes declared with that shape will then render using your specified style template.
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 →