Skip to content

Diagram DOT Output

Vector diagrams — SVG and vector PDF — already contain the node/edge structure a raster diagram would need a detection model to infer: boxes are closed outlines, connectors are open strokes, and labels are text drawn on top. Xberg recovers that structure deterministically from the geometry and can render it as Graphviz DOT via output_format="dot".

diagram_dot_output.py
from xberg import ExtractInput, ExtractionConfig, extract
config = ExtractionConfig(output_format="dot")
output = await extract(ExtractInput(kind="uri", uri="architecture.svg"), config=config)
result = output.results[0]
print(result.content) # Graphviz DOT, or "" if no diagram was recovered

output_format="dot" replaces result.content with the DOT text — it does not append to or accompany the normal extracted content. If no diagram is recovered from the source, content is the empty string, not an error and not the document’s ordinary text. A caller relying on content for anything other than the recovered diagram must check output_format first.

The CLI’s --content-format flag does not currently expose registry renderers such as dot (it accepts plain, markdown, djot, html, json, doctags); use a language binding or the Rust API for DOT output today.

A vector drawing is not necessarily a diagram. Recovery requires at least one connector resolving to a pair of distinct shapes — a page of prose, a logo, or a bar chart yields no diagram and content comes back empty. When a diagram is found, each recovered node carries:

  • its outline shape, mapped onto Graphviz’s shape attribute (box, ellipse, diamond, or polygon for anything else),
  • the text drawn inside it, joined with \n in reading order,
  • fill and stroke colour (when they are a flat colour rather than a gradient or pattern),
  • stroke width and whether the outline is dashed.

Each recovered edge carries its direction (from the arrowhead, or from the connector’s own point order when it draws none), an optional label, and its own stroke colour and dash style. Recovery is deterministic: nodes are ordered top to bottom then left to right, edges are ordered by their endpoints, and duplicates of both are collapsed.

A source can draw more than one diagram — most often one per page of a vector PDF. Xberg recovers a diagram for every page that draws one; the DOT output emits one digraph block per recovered diagram, separated by a blank line.

Recovery is tested against real output from these tools, not hand-authored SVG:

  • Graphvizdot and neato layouts, shape=record, doublecircle, clusters, self-loops, orthogonal routing, undirected graphs, bidirectional edges
  • Mermaid (11.16.0) — flowcharts, including HTML labels in <foreignObject> and edge labels drawn on an opaque background box
  • PlantUML (1.2026.0) — activity diagrams and swimlanes
  • LibreOffice Draw (26.2.5.2) — draw:custom-shape enhanced geometry and glued connectors

Recovery is deliberately conservative. It returns nothing for:

  • Charts — a bar chart’s axes and gridlines look like connectors joining closed regions, but there is no arrowhead or shape-to-shape relationship to recover. A pie chart’s leader lines connecting a slice to its label look like edges to unlabelled decoration, not to another node.
  • Ruled tables — a table drawn with ruling lines has the same signature as a diagram: closed rectangular regions with text inside, joined by straight strokes running from one region to the next. Recovery distinguishes the two by whether an outline’s text is laid out as a grid (multiple rows and multiple columns); a table is rejected as a node candidate without disabling recovery for a genuine diagram elsewhere on the same page.
  • Edgeless drawings — icons, illustrations, and any collection of shapes with no connector between them. At least one connector resolving to two distinct shapes is required before anything is reported; an edgeless list of outlines is noise dressed up as structure, not a diagram.

Container shapes — Graphviz clusters, BPMN pools, PlantUML swimlanes — are recognized and dropped rather than reported as nodes, since a connector between two boxes inside a cluster is drawn to the boxes, not the cluster border around them.