2D charts
Every layer takes name?, yAxis? and renderType?, and returns a handle with setData(...).
Marks
| Chart | Call |
|---|---|
| Line / step | plot.addLine({ x, y, width, step, join, dash, decimate }) |
| Scatter / bubble | plot.addScatter({ x, y, size, sizes, colors, marker, colorBy }) |
| Bar | plot.addBar({ x, y, base, width, offset, orientation, colors }) |
| Grouped / stacked bars | plot.addGroupedBars(...) · plot.addStackedBars(...) |
| Area | plot.addArea({ x, y, base }) · plot.addStackedArea(...) |
| Histogram | plot.addHistogram(values, { bins, range }) |
| Box / violin | plot.addBox({ groups, violin }) |
| Heatmap | plot.addHeatmap({ values, cols, rows, extent, colormap, domain, smooth }) |
| Contour | plot.addContour({ values, cols, rows, extent, levels }) |
| Hexbin | plot.addHexbin({ x, y, radius, colormap }) |
| Error bar | plot.addErrorBar({ x, y, yerr, xerr, band }) |
| Stem | plot.addStem({ x, y, baseline }) |
| Quiver | plot.addQuiver({ x, y, u, v, scale, colorBy }) |
| Pie / donut | plot.addPie({ values, innerRadius }) |
| Patches | plot.addPatches({ patches, colormap }) |
| Graph | plot.addGraph({ edges, nodes }) — force layout when positions are omitted |
| Image | plot.addImage({ source, extent }) |
| Spectrogram | plot.addHeatmapSpectrogram(signal, { fftSize, hop, sampleRate }) |
Fields and rasters
Builders for the gridded and vector-field half of matplotlib's gallery. Each is a free function that composes patches and lines — import it from @photonviz/core and call it on a plot.
| Chart | Call | matplotlib |
|---|---|---|
| Filled contours | addContourFilled(plot, { values, cols, rows, extent, levels, lines }) → { bands, lines? } | contourf |
| Colour mesh | addPcolormesh(plot, { values, xEdges, yEdges, curvilinear }) | pcolormesh |
| 2D histogram | addHist2d(plot, { x, y, bins, range }) | hist2d |
| Event raster | addEventPlot(plot, { positions, offsets, lineLength, orientation }) | eventplot |
| Streamlines | addStreamplot(plot, { u, v, cols, rows, extent, density, colormap }) | streamplot |
| Wind barbs | addBarbs(plot, { x, y, u, v, increment, length }) | barbs |
Filled bands are real polygons, not a quantised image: every cell is split into four triangles around its centre and clipped against the level pair, which is what removes the saddle ambiguity plain marching squares has. The cost is CPU work per cell — downsample fields much beyond ~200×200 first.
addStreamplot seeds a lattice and drops a line the moment it re-enters a cell another line already occupies, so the spacing stays even instead of bunching up along attractors. colormap colours each line by its own mean speed.
The pure halves are exported too, if you want the geometry without the drawing: isobands(field, levels), streamlines(field, opts) and hist2d(x, y, opts).
Scattered samples
When the samples are irregular rather than gridded, the tri* family triangulates them first — Delaunay by default, or pass your own triangles when the connectivity is part of the data (a finite-element result, say).
| Chart | Call | matplotlib |
|---|---|---|
| Mesh | addTriplot(plot, { x, y, triangles?, showPoints? }) | triplot |
| Flat shading | addTripcolor(plot, { x, y, z, edges? }) | tripcolor |
| Iso-lines | addTricontour(plot, { x, y, z, levels }) | tricontour |
| Filled bands | addTricontourf(plot, { x, y, z, levels, lines? }) | tricontourf |
tricontourf is simpler than its gridded cousin: a triangle is already the unit the clipper wants, so there is no cell to subdivide and no saddle to disambiguate. The triangulator itself is exported as delaunay(x, y), returning { triangles, halfedges }.
Grids of plots
PlotGrid lays several independent plots out in one container — the subplots(rows, cols) of matplotlib. Every cell keeps its own scales, toolbar and hover; linkX / linkY tie their views together.
const grid = new PlotGrid(el, { rows: 2, cols: 2, gap: 14, title: "Sensors", linkX: true });
grid.addPlot().addLine({ x, y: a }); // next free cell
grid.addPlot({ colSpan: 2 }).addLine({ x, y: total }); // straddle two
grid.addPolar({ row: 1, col: 1 }).addLine({ theta, r });Cells all draw through the one shared WebGL context the engine already keeps, so a 4×4 figure costs no more GPU contexts than a single chart. rowRatios / colRatios are matplotlib's height_ratios / width_ratios, and cell(place) hands back a bare element if you want to mount something else in a slot.
Marker glyphs
marker accepts circle (default), square, triangle, diamond, cross and plus. All are analytic SDFs, so they stay sharp at any size.
Bubble charts
sizes gives a per-point diameter in CSS pixels and colors a per-point fill; both override the uniform size / color. For a continuous scale use colorBy instead — that maps values through a colormap and gets a colorbar.
plot.addScatter({ x, y, sizes: areas, colors: hexes });
plot.addScatter({ x, y, colorBy: { values: temp, colormap: "turbo" } });Dashed lines
dash takes a Canvas-style pattern in CSS pixels — [6, 4]. Dashing turns decimation off, since a dashed line is an annotation, not a million-point series.
Categorical axes
Set scales: { x: { type: "categorical", factors: [...] } } and plot at integer indices; the band domain and one-tick-per-factor labels follow automatically.