gogv

package module
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 6, 2026 License: MIT Imports: 10 Imported by: 0

README

gogv

A Go implementation of the Graphviz dot program: it lays out graphs written in the DOT language and writes them as SVG and in the other output formats of dot. It needs no cgo, no embedded WebAssembly and no installed Graphviz, and it works as:

  • a Go library (gogv.Render), safe for concurrent use
  • a dot command line
  • a WebAssembly module (GOOS=js GOARCH=wasm)

The stages of gogv, laid out by gogv

The picture is gogv's SVG output for docs/example.gv. The landing page has a playground that lays out DOT in the browser, with the WebAssembly build of the latest release.

gogv is not affiliated with or endorsed by the Graphviz project.

Clean-room implementation

gogv is written from published papers, the Graphviz documentation and the observed behavior of Graphviz 16.1.0, used as a black box. It contains no code from Graphviz or from its ports and bindings. Every Go file names its sources in Provenance: lines (make provenance checks them):

  • Gansner, Koutsofios, North and Vo, "A Technique for Drawing Directed Graphs" (IEEE TSE, 1993): ranking, crossing minimization, positioning
  • Dobkin, Gansner, Koutsofios and North, "Implementing a General-Purpose Edge Router" (Graph Drawing 1997): edge routing
  • the Graphviz documentation (https://graphviz.org/documentation/)
  • outputs of Graphviz 16.1.0 for chosen inputs

Text is measured with tables generated from the Liberation 2.1.5 fonts, which are metrically compatible with Times New Roman, Arial and Courier New; no font is part of the module. Elementary functions come from a port of fdlibm, so that the output is the same, byte for byte, on every platform.

Status

gogv supports:

  • the whole DOT grammar, read as the reference reads it
  • the layout of graphs without compass points and HTML-like labels other than table labels: shapes rect, box, rectangle, box3d, plaintext, point, ellipse, oval, circle, diamond, hexagon, octagon, style=filled, and style=rounded on rect, and lists of styles such as filled,rounded; plain-text labels; width, height, fontname, fontsize, and color, fillcolor and fontcolor written #rrggbb; tooltip and id on nodes; minlen, weight, penwidth, constraint, style=invis, style=dotted, arrowhead and arrowtail (normal, empty, none), dir, arrowsize, tooltip and labeltooltip on edges; nodesep, ranksep, rankdir=LR, splines=spline|polyline, a graph label placed by labeljust
  • clusters, nested, with a plain-text label placed by labeljust (c, l, r), style=solid and color; rank=same|min|max|source|sink on subgraphs
  • edge labels, on edges between ranks, flat edges and loops, in the edge's fontname, fontsize and fontcolor; external labels: xlabel on nodes and edges, headlabel and taillabel; sametail
  • table labels (TABLE of rows of empty cells) on nodes, edges and clusters, with BORDER, CELLBORDER, CELLSPACING, CELLPADDING, BGCOLOR, COLOR, FIXEDSIZE, WIDTH, HEIGHT and PORT on the table, and BORDER, CELLPADDING, BGCOLOR, COLOR, COLSPAN, FIXEDSIZE, WIDTH, HEIGHT and PORT on its cells
  • node ports: edge ends written node:port, or set by tailport and headport, attach to the cell of a table label with that PORT, in the positioning, the order and the routes
  • the output formats: svg, svg_inline, plain, plain-ext, canon, dot, gv, xdot, xdot1.2, xdot1.4, json, json0, dot_json and xdot_json

Not supported yet, among others:

  • color names such as red (colors are written #rrggbb), bgcolor, penwidth on nodes and clusters
  • styles other than solid, filled and rounded on nodes and invis and dotted on edges, such as dashed and bold; peripheries
  • other shapes, such as record and Mrecord, and other arrow types, such as vee
  • rankdir=BT and rankdir=RL; splines other than spline and polyline, such as ortho
  • compass points (a:n -> b), compound with lhead and ltail, concentrate
  • HTML-like labels other than tables of empty cells: text in cells, and text markup such as <B> and <FONT>
  • fonts other than the Times, Helvetica and Courier families (including Times New Roman, Arial and Courier New), which are measured as Times
  • URL, href, target, tooltip on graphs and clusters, id on edges, graphs and clusters, and images
  • the other layout engines (-Kneato, -Kfdp, ...) and the other output formats, such as png, pdf and cmapx

A Graphviz feature that is not supported yet gives a warning that says so and names the default used instead; attributes that Graphviz does not document are ignored, as Graphviz ignores them.

Installation

Go 1.26 or later is needed. The command line:

go install github.com/ekalinin/gogv/cmd/dot@latest

The command is named dot, as Graphviz's is: when Graphviz is installed too, the dot found first in PATH runs. dot -V tells them apart (see Command line).

The library:

go get github.com/ekalinin/gogv

Building

go build -o dot ./cmd/dot
echo 'digraph { a -> b -> c; a -> c }' | ./dot -Tsvg > out.svg
./dot -V

Library

gogv.Render lays out every graph of DOT text and writes it in one of gogv.Formats(), with the bytes that dot -T<format> writes:

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/ekalinin/gogv"
)

func main() {
	out, warnings, err := gogv.Render(context.Background(), "digraph { a -> b }", "svg")
	if err != nil {
		log.Fatal(err)
	}
	for _, w := range warnings {
		fmt.Fprintln(os.Stderr, "warning:", w)
	}
	os.Stdout.Write(out)
}

The warnings are returned, not written: a gogv.Warning names the object, the feature that is not supported yet and the default used instead. A syntax error is a *gogv.SyntaxError with its line, and a format that Render does not write is a *gogv.FormatError. Render is safe for concurrent use and stops with the context's error when the context is canceled.

Command line

dot reads the files named on its command line, or standard input, and writes to standard output or to the file of -o. It accepts -T<format>, -o<file>, -V and -Kdot; it rejects the other flags of Graphviz's dot with exit status 1 instead of ignoring them. -V writes dot - graphviz version 16.1.0 (gogv VERSION), so that programs that read the Graphviz version from it find the version gogv follows.

Conformance

The outputs are compared with those of Graphviz 16.1.0 built without Pango, in a pinned container (tools/reference/Dockerfile), layer by layer: canon byte for byte, plain by nodes, edges and size (within 5%), and svg by size (within 5%) and the structural similarity of the rasterized documents (SSIM of at least 0.90). dot, xdot and JSON output are parsed and must have the reference's objects, attributes and drawing operations, with values equal but for the numbers of the layout, and a size within 5%; dot_json and xdot_json are compared byte for byte. The corpus is the curated cases of testdata/conformance/cases and, when collected with make harvest, the DOT that gopuml generates for its own conformance cases.

make harvest fetches gopuml at the version GOPUML_VERSION of the Makefile through the Go module proxy, and the Vega cases of its corpus with gopuml's own script, so it needs network access as well as Docker and the reference image; no gopuml checkout is needed. make harvest GOPUML=<dir> harvests from a local gopuml checkout instead. The report names the corpora of the run and the gopuml that each harvested corpus comes from.

make reference-image      # build the reference image (Docker)
make reference            # record the references of the curated cases
make harvest              # collect the gopuml corpus and record its references
tools/reference/fetch-tools.sh
go generate ./internal/textmetrics  # fetch the Liberation fonts
make conformance          # compare and write conformance-report.md
make determinism          # compare native, amd64 and WebAssembly outputs

conformance-report.md has the current results. Cases that use a feature that is not supported yet are reported as such; the remaining differences are listed in testdata/conformance/known-differences.yaml.

Releasing

A release is a tag vX.Y.Z on a commit of main that CI passed, with its notes in docs/releases/vX.Y.Z.md:

  1. Write docs/releases/vX.Y.Z.md, name vX.Y.Z on the landing page (site/index.html: its gogv-release meta tag, its installation commands and the conformance results of the notes), and merge them into main in a pull request. The tests fail until the page names the newest notes.

  2. Once CI has passed on the merge commit, run on an up-to-date main:

    make release VERSION=vX.Y.Z
    

    It checks the version, the notes, the branch, that tracked files have no uncommitted change (untracked files, such as an OpenSpec change not archived yet, do not count), that the tag does not exist yet and that CI passed, then tags the commit, pushes the tag and creates the GitHub release with the notes. It needs gh, logged in. The push of the tag deploys the landing page with the playground of the release.

A pushed tag is never moved: once the Go module proxy has fetched it, its content is fixed. The release is then installed with go install github.com/ekalinin/gogv/cmd/dot@vX.Y.Z.

Contributing

Contributions follow the clean-room rules, the checks and the conventions of CONTRIBUTING.md.

License

MIT. See LICENSE and NOTICE.

Documentation

Overview

Package gogv lays out graphs written in the Graphviz DOT language and renders them, as the Graphviz dot program does.

Index

Constants

View Source
const GraphvizVersion = output.GraphvizVersion

GraphvizVersion is the version of Graphviz that gogv follows, "16.1.0". `dot -V` names it before the version of gogv, and the SVG output names it in its "Generated by graphviz version" comment.

Variables

This section is empty.

Functions

func Formats

func Formats() []string

Formats returns the output formats Render writes, always in the same order. Each call returns a new slice, which the caller may change.

Types

type FormatError

type FormatError struct {
	Format string
}

FormatError is an output format that Render does not write.

func (*FormatError) Error

func (e *FormatError) Error() string

type SyntaxError

type SyntaxError struct {
	Line int
	Near string
	// contains filtered or unexported fields
}

SyntaxError is a syntax error in the input, worded as the reference words it.

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type Warning

type Warning struct {
	// Object names the graph, subgraph, node or edge, as "node a"; empty
	// for warnings about the input text.
	Object string
	// Feature names what is not supported yet, as "shape=record".
	Feature string
	// Default is what is used instead, or "".
	Default string
	// contains filtered or unexported fields
}

Warning reports something the caller may want to know about an input: mostly a Graphviz feature that is not supported yet, with the default used instead.

func Render

func Render(ctx context.Context, src string, format string) ([]byte, []Warning, error)

Render lays out every graph of DOT source text and writes it in format, as `dot -T<format>` writes it to standard output. It returns the output, the warnings, and an error for a format it does not write or a syntax error. After a syntax error, the output holds the graphs read before the one that contains the error. Render is safe for concurrent use.

func (Warning) NotSupportedYet

func (w Warning) NotSupportedYet() bool

NotSupportedYet reports whether the warning is about a feature that is not supported yet.

func (Warning) String

func (w Warning) String() string

String returns the warning as the command line writes it, without its "Warning: " prefix.

Directories

Path Synopsis
cmd
dot command
Command dot lays out graphs written in the DOT language, as Graphviz's dot does.
Command dot lays out graphs written in the DOT language, as Graphviz's dot does.
internal
attrs
Package attrs knows which attributes the Graphviz documentation describes and which of them, with which values, gogv supports; it reports the features that are not supported yet and gives the layout the values it acts on, with the documented defaults in place of unsupported ones.
Package attrs knows which attributes the Graphviz documentation describes and which of them, with which values, gogv supports; it reports the features that are not supported yet and gives the layout the values it acts on, with the documented defaults in place of unsupported ones.
cli
Package cli is the dot command line: it reads DOT files or standard input and writes their layouts in the format chosen with -T.
Package cli is the dot command line: it reads DOT files or standard input and writes their layouts in the format chosen with -T.
conformance
Package conformance compares the outputs of gogv with those of the reference dot (Graphviz 16.1.0 built without Pango), layer by layer, as the upstream-compatibility spec defines: canon byte for byte, plain by nodes, edges and size, svg by size and the structural similarity of the rasterized documents.
Package conformance compares the outputs of gogv with those of the reference dot (Graphviz 16.1.0 built without Pango), layer by layer, as the upstream-compatibility spec defines: canon byte for byte, plain by nodes, edges and size, svg by size and the structural similarity of the rasterized documents.
corpushash command
Command corpushash renders every case of a corpus directory as canon, plain and svg, and prints a SHA-256 of each output and of all of them, so that builds for different platforms can be compared.
Command corpushash renders every case of a corpus directory as canon, plain and svg, and prints a SHA-256 of each output and of all of them, so that builds for different platforms can be compared.
dotlang
Package dotlang reads graphs written in the DOT language: a lexer, a parser that produces a syntax tree, and the construction of the graph model with the semantics of attribute defaults, subgraphs, edge chains and strict graphs.
Package dotlang reads graphs written in the DOT language: a lexer, a parser that produces a syntax tree, and the construction of the graph model with the semantics of attribute defaults, subgraphs, edge chains and strict graphs.
fdlibm
Package fdlibm provides deterministic elementary functions: Sin, Cos, Atan and Atan2, a port of fdlibm 5.3 taken from gopuml.
Package fdlibm provides deterministic elementary functions: Sin, Cos, Atan and Atan2, a port of fdlibm 5.3 taken from gopuml.
graph
Package graph is the graph model that the DOT reader builds and that the layout and the outputs read: a root graph with nested subgraphs, nodes and edges, and attributes with the semantics observed on the reference:
Package graph is the graph model that the DOT reader builds and that the layout and the outputs read: a root graph with nested subgraphs, nodes and edges, and attributes with the semantics observed on the reference:
label
Package label turns plain-text label attributes into lines: it expands the escapes that name objects and splits the text at the line breaks, as the reference does.
Package label turns plain-text label attributes into lines: it expands the escapes that name objects and splits the text at the line breaks, as the reference does.
layout
Package layout computes the dot layout: ranks, the order of nodes within ranks, coordinates, and the routes of edges.
Package layout computes the dot layout: ranks, the order of nodes within ranks, coordinates, and the routes of edges.
output
Package output writes graphs in the output formats of dot.
Package output writes graphs in the output formats of dot.
playground command
Command playground is the WebAssembly entry point of the playground of the landing page.
Command playground is the WebAssembly entry point of the playground of the landing page.
textmetrics
Package textmetrics measures text with advance-width tables of the Liberation fonts, which are metrically compatible with Times New Roman, Arial and Courier New.
Package textmetrics measures text with advance-width tables of the Liberation fonts, which are metrically compatible with Times New Roman, Arial and Courier New.
wasmcheck command
Command wasmcheck renders the DOT text of its first argument as SVG on standard output; the library tests run it in the WebAssembly build.
Command wasmcheck renders the DOT text of its first argument as SVG on standard output; the library tests run it in the WebAssembly build.
tools
attrdoc command
Command attrdoc generates internal/attrs/documented.go, the list of the attributes that the Graphviz documentation describes, with the kinds of objects that use them, from the attribute table of https://graphviz.org/doc/info/attrs.html.
Command attrdoc generates internal/attrs/documented.go, the list of the attributes that the Graphviz documentation describes, with the kinds of objects that use them, from the attribute table of https://graphviz.org/doc/info/attrs.html.
clustervariant command
Command clustervariant writes a variant of the harvested gopuml graphs that have clusters: each HTML label that gopuml puts on a cluster is replaced by an empty label.
Command clustervariant writes a variant of the harvested gopuml graphs that have clusters: each HTML label that gopuml puts on a cluster is replaced by an empty label.
fontmetrics command
Command fontmetrics generates the advance-width tables of internal/textmetrics from the Liberation 2.1.5 fonts (SIL Open Font License 1.1).
Command fontmetrics generates the advance-width tables of internal/textmetrics from the Liberation 2.1.5 fonts (SIL Open Font License 1.1).
harvest command
Command harvest collects the DOT that gopuml generates for its conformance cases, so that gogv is checked against what its first consumer sends.
Command harvest collects the DOT that gopuml generates for its conformance cases, so that gogv is checked against what its first consumer sends.
metricscheck command
Command metricscheck measures, as a black box, how wide the reference dot sets each printable ASCII character in its Times, Helvetica and Courier metrics, and reports the differences with the tables of internal/textmetrics into .cache/metricscheck/report.md.
Command metricscheck measures, as a black box, how wide the reference dot sets each printable ASCII character in its Times, Helvetica and Courier metrics, and reports the differences with the tables of internal/textmetrics into .cache/metricscheck/report.md.
pprofcorpus command
Command pprofcorpus writes the corpus of DOT that go tool pprof writes: it builds the program of ./workload, runs it twice, and writes the DOT of go tool pprof -dot for its CPU and heap profiles with several option sets into the curated cases of pprof.
Command pprofcorpus writes the corpus of DOT that go tool pprof writes: it builds the program of ./workload, runs it twice, and writes the DOT of go tool pprof -dot for its CPU and heap profiles with several option sets into the curated cases of pprof.
pprofcorpus/workload command
Command workload is the program that tools/pprofcorpus profiles: hashing, sorting and string building under the pprof label work, for the CPU profile, then allocations of three sizes, for the heap profile.
Command workload is the program that tools/pprofcorpus profiles: hashing, sorting and string building under the pprof label work, for the CPU profile, then allocations of three sizes, for the heap profile.
provenance command
Command provenance checks that every non-test Go source file declares where its code comes from, so that the project stays clean-room: written from papers, the Graphviz documentation and the observed behavior of dot, never from the code of Graphviz or of its ports.
Command provenance checks that every non-test Go source file declares where its code comes from, so that the project stays clean-room: written from papers, the Graphviz documentation and the observed behavior of dot, never from the code of Graphviz or of its ports.
refgen command
Command refgen records the outputs of the reference dot for every case of a corpus: it runs `dot -Tcanon`, `-Tplain` and `-Tsvg` in the reference image (tools/reference/Dockerfile) with each case on stdin, and writes stdout, stderr and the exit status with conformance.WriteReference.
Command refgen records the outputs of the reference dot for every case of a corpus: it runs `dot -Tcanon`, `-Tplain` and `-Tsvg` in the reference image (tools/reference/Dockerfile) with each case on stdin, and writes stdout, stderr and the exit status with conformance.WriteReference.
site command
Command site assembles the landing page and the WebAssembly module of its playground into a directory that GitHub Pages or any static file server can serve.
Command site assembles the landing page and the WebAssembly module of its playground into a directory that GitHub Pages or any static file server can serve.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL