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), using CurveFactory for Bézier conversion.
  • Styles.get_for_shape() (lines 88-98): Maps Graphviz shape names to draw.io style strings using the internal _shape_to_style dictionary.

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"]
}

  • fillcolor and style=filled control node background (processed by NodeFactory._extract_fill())
  • color sets border or edge stroke color (processed by EdgeFactory.from_svg() lines 33-41)
  • penwidth adjusts stroke width
  • style=dashed applies 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

Summary

  • Change layout engines using the -p flag or layout_prog parameter in the Python API.
  • Control visual styling by setting Graphviz attributes (fillcolor, color, penwidth, style) in your dot files, which NodeFactory and EdgeFactory parse automatically.
  • Add custom shapes by extending Styles._shape_to_style with new Shape-to-style mappings.
  • Inject custom XML by subclassing MxGraph and overriding add_node() or add_edge().
  • Use programmatically by importing convert() and passing AGraph objects 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →