# How to Customize the Graphviz to draw.io Conversion Process: A Complete Technical Guide

> Customize Graphviz to draw.io conversion by modifying dot files, extending Node and Edge factories, or subclassing MxGraph for custom XML attributes. Learn how to tailor your diagrams.

- Repository: [Harold Martin/graphviz2drawio](https://github.com/hbmartin/graphviz2drawio)
- Tags: how-to-guide
- Published: 2026-03-03

---

**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`](https://github.com/hbmartin/graphviz2drawio/blob/main/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`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/Arguments.py) (lines 46-48):

```bash
graphviz2drawio -p neato mygraph.dot -o mygraph.xml

```

Programmatically, supply the `layout_prog` parameter to the `convert()` function:

```python
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:

```dot
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:

```python
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:

```python
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:

```python
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`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/graphviz2drawio.py)**: Contains the core `convert()` function and `_load_pygraphviz_agraph()` helper.
- **[`graphviz2drawio/models/SvgParser.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/SvgParser.py)**: Implements `parse_nodes_edges_clusters()` for SVG traversal.
- **[`graphviz2drawio/mx/NodeFactory.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/NodeFactory.py)**: Handles node creation and fill/stroke extraction.
- **[`graphviz2drawio/mx/EdgeFactory.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/EdgeFactory.py)**: Processes edge geometry and styling.
- **[`graphviz2drawio/mx/Styles.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/Styles.py)**: Defines the `_shape_to_style` mapping dictionary (lines 88-98).
- **[`graphviz2drawio/mx/CurveFactory.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/CurveFactory.py)**: Converts SVG paths to draw.io curves.
- **[`graphviz2drawio/mx/MxGraph.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/mx/MxGraph.py)**: Assembles the final XML document structure.
- **[`graphviz2drawio/__main__.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/__main__.py)**: CLI entry point at lines 76-103.
- **[`graphviz2drawio/models/Arguments.py`](https://github.com/hbmartin/graphviz2drawio/blob/main/graphviz2drawio/models/Arguments.py)**: Command-line argument definitions.

## 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`](https://github.com/hbmartin/graphviz2drawio/blob/main/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.