Skip to content

The API

Figure, Subplots and Axes: matplotlib's object model with Go's argument style, and why it has that shape.

Shaped by what notebooks call

go-plot is the plotting library of a Go notebook ecosystem built on go-ndarray. Its API was chosen from a measurement, not a preference.

A census of 339 scientific notebooks (measured for this ecosystem) ranks plotting first among the things that keep them from moving to Go, and gives the share of notebooks using each call:

callnotebooksgo-plot
pyplot.subplots62 %plot.Subplots
Axes.plot56 %Axes.Plot
pyplot.show52 %Figure.Display, called by the notebook
Axes.set_xlabel47 %Axes.SetXLabel
Axes.legend46 %Axes.Legend, with matplotlib’s location names and "best"
Axes.set_ylabel45 %Axes.SetYLabel
Axes.set_title37 %Axes.SetTitle
pyplot.figure27 %plot.NewFigure
tight_layout27 %Figure.TightLayout
module-level pyplot.plot/xlabel/ylabelabout 22 %not provided (below)
Axes.set_ylim21 %Axes.SetYLim
Axes.axhline20 %Axes.Axhline

Most notebooks write fig, ax = plt.subplots(); ax.plot(...). So go-plot is the object-oriented API, and every one of those operations exists under the same name.

The module-level, state-machine functions are deliberately not provided. plt.plot and plt.xlabel act on a hidden “current” Axes. They are the minority form, and hidden global state is what a Go notebook kernel running cells concurrently should not have.

Figure, Subplots, Axes

fig, axs := plot.Subplots(2, 3)          // a 2 x 3 grid: axs is a [][]*plot.Axes
ax := axs[1][0]                          // second row, first column

fig := plot.NewFigure(plot.FigSize(6.4, 4.8), plot.DPI(100))
grid := fig.Subplots(1, 2)               // the same, on an existing figure
inset := fig.AddAxes(0.6, 0.6, 0.25, 0.25) // left, bottom, width, height, in figure fractions
  • plot.Subplots(rows, cols, ...FigOption) returns the figure and a [][]*Axes, always two-dimensional (matplotlib’s squeeze=False).
  • Plot types are Axes methods named as in matplotlib: Plot, Scatter, Bar, Barh, Hist, FillBetween, ErrorBar, Imshow, Contour, Contourf, Axhline, Axvline, Text, Annotate, Legend, SetXLim, SetYScale, TwinX… See plot types.
  • Figure.TightLayout() is matplotlib’s tight_layout, ported. It reports false, changing nothing, when the decorations cannot fit, as matplotlib then warns and does nothing.

Keyword arguments become options

matplotlib’s keyword arguments become functional options:

ax.Plot(x, y, plot.Color("C1"), plot.LineStyle("--"), plot.Label("data"))

is ax.plot(x, y, color="C1", linestyle="--", label="data"). Go has no keywords, and a struct per method would multiply types without adding safety. Each method documents the options it honours; an option a method does not use is ignored.

optionmatplotlib keyword
Color, Colors, FaceColor, EdgeColor, Alphacolor, a list of colours, facecolor, edgecolor, alpha
LineStyle, LineWidth, Marker, MarkerSize, MarkerEdgeWidthlinestyle, linewidth, marker, markersize, markeredgewidth
Label, ZOrder, Cliplabel, zorder, clip_on
Width, Bottom, Alignbar’s width, bottom, align
Bins, BinEdges, Densityhist’s bins (a count, or edges), density
XErr, YErr, CapSize, ErrorColorerrorbar’s xerr, yerr, capsize, ecolor
Wherefill_between’s where
Sizes, CValuesscatter’s s and c
Cmap, Vmin, Vmax, LogNormcmap, vmin, vmax, norm=LogNorm()
Extent, Origin, Aspectimshow’s extent, origin, aspect
Levels, NLevelscontour’s levels (a list, or a count)
FontSize, HA, VA, Rotation, Arrowfontsize, ha, va, rotation, arrowprops=dict(arrowstyle="->")
Loclegend’s loc

Data is any

Every data argument accepts []float64, []float32, []int, []int32, []int64, a scalar, or a *ndarray.Array of any of ndarray’s thirteen dtypes (converted with AsType(Float64), flattened in row-major order; 2-D arrays for Imshow and contours, 3-D (rows, cols, 3|4) arrays as RGB(A) images, uint8 taken as bytes).

A type that cannot be plotted panics, as does a length mismatch. Both are programming errors, exactly as an index out of range is, and returning an error from every Plot call would make every notebook cell three lines longer for a failure that is never handled.

Mappables and colorbars

Imshow, Scatter with CValues, Contour and Contourf return a *Mappable (a colormap and a norm). Figure.Colorbar(m, ax) draws it, taking its space from ax exactly as fig.colorbar(m, ax=ax) does, and returns the colorbar’s Axes, whose label can be set:

m := ax.Imshow(z, plot.Cmap("viridis"))
fig.Colorbar(m, ax).SetYLabel("height (m)")

Output

methodwrites
SavePNG(w io.Writer) erroran anti-aliased raster
SaveSVG(w io.Writer) errorvector SVG: paths, clip paths, images embedded as PNG, as matplotlib’s SVG backend does with svg.fonttype = "path"; text is drawn as outlines, so no font is needed to show it
Display() map[string][]bytethe notebook contract: image/svg+xml and image/png

Text is a seam

Figure.Text is a text.Renderer (Layout(s, size), LineMetrics(size)). The default sets plain text in DejaVu Sans (matplotlib’s default font, from go-opentype/fonts) and TeX between dollar signs with go-tex/math. Replacing the renderer changes the fonts of the whole figure. See TeX labels.

Packages

packagewhat it does
plotFigure, Axes and every plot type; layout, autoscaling, legend, colorbar
tickertick locations and labels: AutoLocator (MaxNLocator), ScalarFormatter, LogLocator, LogFormatterSciNotation
colorscolour parsing, the tab10 cycle, eight colormaps, Normalize and LogNorm
contourmarching squares: iso-lines and filled bands on a rectangular grid
renderthe drawing seam: a Renderer interface, a raster back-end and an SVG back-end
textstrings to glyph outlines: DejaVu Sans for text, go-tex/math for TeX

The full reference is on pkg.go.dev.

Created on by tannevaled

Modified on by tannevaled