Fork me on GitHub

matplotlib's figures, in pure Go.
Tested equal where they can be equal.

go-plot is the plotting library of the Go scientific stack built on go-ndarray. Its object model and defaults are matplotlib's โ€” figure size, fonts, colour cycle, margins, tick placement and tick labels โ€” so a figure looks the way a matplotlib user expects. It writes SVG and PNG, sets labels with a real TeX math typesetter, and needs no Python and no cgo: one static binary, js/wasm included.

408 axes of ticks, bit for bit6 kinds of check against matplotlib100% test coverage
main.go
func main() {
	x := make([]float64, 200)
	for i := range x {
		x[i] = float64(i) / 199 * 10
	}
	sin, damped := make([]float64, len(x)), make([]float64, len(x))
	for i, v := range x {
		sin[i] = math.Sin(v)
		damped[i] = math.Exp(-v/4) * math.Cos(2*v)
	}

	fig, axs := plot.Subplots(1, 1, plot.FigSize(6.4, 4))
	ax := axs[0][0]
	ax.Plot(x, sin, plot.Label(`$\sin t$`))
	ax.Plot(x, damped, plot.Label(`$e^{-t/4}\cos 2t$`), plot.LineStyle("--"))
	ax.FillBetween(x, damped, nil, plot.Alpha(0.2))
	ax.SetTitle(`Two signals, labelled in TeX`)
	ax.SetXLabel(`time $t$ (s)`)
	ax.SetYLabel("amplitude")
	ax.Grid(true)
	ax.Legend()
	if err := fig.SaveSVG(os.Stdout); err != nil {
		panic(err)
	}
}
3 repositories โ€” one library: go get github.com/go-plot/plot
Ask it, do not take our word

The program above, actually run.

This is the SVG it writes, unedited: two lines from the colour cycle, a dashed style, a translucent fill, a grid, a legend placed where it covers the least data, and labels set in TeX. Twelve reference figures drawn by both go-plot and matplotlib put every axes frame and every tick mark on the same pixel, and after TightLayout within 2 pixels.

Two signals, sin t and a damped cosine, with TeX labels and a legend, drawn by go-plot v0.1.0
Why go-plot

The plotting library notebooks reach for first.

A census of 339 scientific notebooks ranks plotting first among the things that keep them from moving to Go, and most of them write fig, ax = plt.subplots(); ax.plot(...). go-plot is that API, under the same names, with Go's argument style.

๐Ÿ“

matplotlib's object model

Subplots, Plot, SetXLabel, Legend, SetTitle, TightLayout, SetYLim, Axhline: every call the census ranks, named as in matplotlib. Keyword arguments become options: plot.Color("C1").

๐ŸŽฏ

Tested equal to matplotlib

Tick locations and labels, colormaps, named colours, and the layout of figures are compared with fixtures generated by matplotlib 3.11.2 itself, exactly unless stated.

โˆ‘

Real TeX in the labels

$...$ is typeset by go-tex/math with STIX Two Math: fractions, radicals, big operators, limits and matrices, as TeX lays them out.

๐Ÿงฎ

Data from go-ndarray

Every data argument takes []float64, other numeric slices, or a *ndarray.Array of any of its thirteen dtypes.

๐Ÿ–ผ๏ธ

SVG, PNG, and notebooks

SaveSVG writes vector paths, SavePNG anti-aliased pixels, and Display hands a notebook kernel both.

๐Ÿ“ฆ

Pure Go, CGO=0

No Python, no C. It builds for the six 64-bit Linux targets, 386, arm, js/wasm and wasip1/wasm.

โœ…

100% test coverage

Gated in CI on three operating systems, with six architectures.

โš–๏ธ

BSD-3-Clause

Every repository of the organization.

What equals matplotlib

6 checks, each generated by matplotlib.

The fixtures are written by scripts that call matplotlib, committed, and compared in the tests. What is not equal โ€” text rasterisation, contour vertices, image resampling โ€” is listed in the documentation, not hidden.

Ticks, bit for bit

Tick locations, labels and offset text on 408 axes of real figures (4 sizes, 37 linear and 14 log ranges): every location bit for bit, every label character for character.

Locators and formatters

45 MaxNLocator, 42 LogLocator, 72 ScalarFormatter and 25 LogFormatterSciNotation cases a default figure never reaches, exact.

Eight colormaps

viridis, plasma, inferno, magma, cividis, gray, coolwarm, RdBu (and _r): 1008 samples per map compared as floats and as bytes.

Named colours and the cycle

All 148 CSS4 colours, the 10 tab: colours, single letters, C0โ€“C9, grey levels, short and long hex: exact.

Layout, then TightLayout

15 kinds of figure at two sizes: every Axes position and view limit to 1e-9 relative, every tick label exactly. After TightLayout (6 kinds at two sizes), every Axes edge within 0.005 of the figure.

Pixels, side by side

Twelve reference figures drawn by both put every axes frame and tick mark on the same pixel, and after TightLayout within 2 pixels; two deliberately shifted figures must fail, and do.

Speed

Faster than matplotlib on every case measured.

In-process time, medians of 9 interleaved fresh-process runs per case on a shared, loaded 16-core Apple M4 Max, 2026-10-10. Python's start and import matplotlib.pyplot (about 0.5 s) are not counted.

figurego-plotmatplotlib 3.11.2ratio
1e6-point line โ†’ PNG0.055 s0.065 s1.2x
1e6-point line โ†’ SVG0.019 s0.053 s2.8x
1000ยฒ imshow โ†’ PNG0.025 s0.042 s1.7x
1000ยฒ imshow โ†’ SVG0.020 s0.042 s2.1x
Repositories

What is here.

plot

library

The library: Figure, Axes and every plot type, with ticker (tick locations and labels), colors (the cycle, eight colormaps, norms), contour (marching squares), render (raster and vector SVG back-ends) and text (DejaVu Sans, and TeX through go-tex/math).

docs

site

The documentation (Hugo + Hextra): getting started, the API and why it has this shape, every plot type with the code that drew it, what is exact against matplotlib, TeX labels, performance, and the differences. Source โ†’

brand

assets

Logos and icons for the organization, in SVG / PNG / JPG / ICO / ICNS across colour, white and black variants.

Plots for the Go scientific stack.

go-plot draws the data of go-ndarray, and a go-notebook cell shows a figure through Display. What is not in v0 yet โ€” symlog and date axes, constrained_layout, boxplot and pie, PDF, windows โ€” is listed in the documentation.

Read the source on GitHub โ†’