Scatter
Overview
A scatter plot draws one marker per data point at its x and y position. Use it to show the relationship between two numeric variables, to spot clusters and outliers, or to plot many points at once. Every scatter trace is drawn on the GPU, so there is no separate scattergl trace for large data.
Scatter plots, line charts, and text labels all use the scatter trace type. The mode attribute picks what is drawn: 'markers', 'lines', 'text', or a combination such as 'lines+markers'.
Pick a different chart when:
- the x values are ordered (time, sequence) and the trend matters more than single points: use a line chart;
- one axis is a list of categories and you compare amounts: use a bar chart, or a dot plot (below) when the values don't start at zero.
Minimal example
import { createChart } from '@mk7s/holochart';
const chart = createChart(document.getElementById('chart')!, {
data: [{ type: 'scatter', mode: 'markers', x: [1, 2, 3, 4], y: [10, 15, 13, 17] }],
});The chart fills its container, so give the element a size. Each trace takes the next color of the colorway. The live example below has three traces with different symbols, sizes, and colors:
scatter/clustersData format
xandy: the point coordinates. Plain arrays, typed arrays (Float64Array,Float32Array, ...), numbers, dates (Dateobjects or ISO strings such as'2025-03-01'), or category strings. The axis type (linear, date, category) is inferred from the values; setxaxis.typeto override it.x0/dxandy0/dy: implicit coordinates when you leave outxory. Pointiis atx0 + i * dx.text,customdata, andids: per-point extra data for labels, hover templates, and matching points across updates.- A
nullorNaNinxoryleaves that point out (and breaks the line in'lines'mode).
See Data formats and Working with dates.
Variations
Modes and symbols
When you don't set mode, Holochart uses Plotly's rule: 'lines+markers' for fewer than 20 points, 'lines' otherwise. Set mode: 'markers' for a pure scatter plot. marker.symbol takes one symbol or one per point, and zorder raises a trace above the others.
scatter/basicColorscales and bubbles
Pass numbers to marker.color to map them through marker.colorscale (cmin, cmax, cmid, reversescale). Pass numbers to marker.size for a bubble chart; sizemode: 'area' makes the marker area, not its diameter, proportional to the value. Set marker.showscale: true to draw a colorbar; marker.colorbar takes the full axis tick API (dtick, ticksuffix, tickformat, …) plus title, orientation, thickness and len. Traces that set the same marker.coloraxis share one scale and one colorbar.
scatter/colorscaleText labels
Add 'text' to mode to label points. textposition places each label around its marker (one value or one per point), and texttemplate formats it with the same syntax as hovertemplate.
scatter/text-labelsError bars
error_y and error_x draw uncertainty per point: from data arrays (symmetric or asymmetric), as a percentage, a constant, or the square root of the value.
scatter/error-barsDot plot
A Cleveland dot plot is two or more marker traces over categories. Put the categories on the y axis so long labels stay readable.
recipes/dot-plotDumbbell
A dumbbell chart joins each pair of dots. All connectors are one mode: 'lines' trace whose points go [start, end, null] per category; the null breaks the line between categories.
recipes/dumbbellLollipop
A lollipop is a marker on a stem from zero. The stem is a capless, one-sided error bar: error_y: { symmetric: false, array: zeros, arrayminus: values, width: 0 }.
recipes/lollipopStyling
mode:'markers','lines','text', a combination such as'lines+markers', or'none'.marker.symbol: the marker shape, such as'circle','square','diamond','triangle-up', or'x', with-open,-dot, and-open-dotvariants. See Marker symbols.marker.size: size in pixels, or one per point (bubbles), withsizemode,sizeref, andsizemin.marker.color: one color, one per point, or numbers mapped throughmarker.colorscale.marker.opacity,marker.angle, andmarker.line.color/marker.line.widthfor the outline.opacityfades the whole trace;zorderchanges the drawing order.layout.colorwaysets the colors traces take in turn.
Most marker attributes accept per-point arrays. Values you don't set come from the template.
Interactivity
Hover, zoom, pan, and selection work on every scatter trace. Try them here: hover a point, drag to zoom, double-click to reset, and use the modebar (top right, on hover) to switch to pan, box select, or lasso.
scatter/interactive- Hover.
layout.hovermodeis'closest'by default.'x'and'y'show every trace at the hovered position, and'x unified'/'y unified'put them in one label. Change the label text withhovertemplate, for example'%{x:.1f}, %{y:$,.2f}<extra></extra>'(<extra></extra>hides the trace name box).hoverinfo: 'skip'turns hover off for a trace. - Zoom and pan.
layout.dragmodeis'zoom'by default; set it to'pan','select', or'lasso'. Double-click resets the axes. Wheel zoom is off for 2D plots unless you setconfig: { scrollZoom: true }. - Selection. Box and lasso selection set
selectedpointsand restyle points withselected.marker.{color, opacity, size}andunselected.marker.*(by default, unselected points fade to 20% opacity). - Events. Listen with
chart.on('hover' | 'click' | 'selected' | 'relayout', ...). Each point in the payload hascurveNumber,pointNumber,x,y, andcustomdata. See the events reference.
chart.on('selected', (event) => {
console.log(event.points.map((p) => p.pointNumber));
});3D-native options
A Holochart extension (full bundle): on a filled trace (fill), depth turns the fill into a slab with the line and markers on its front face — see Area and Extrusion & 2.5D. Traces without a fill stay flat, but layout.view3d shows any scatter plot in perspective, with hover, zoom and selection still exact.
Performance notes
- Markers are instanced on the GPU. In the M0 marker benchmark on an Apple M1 Max, 100,000 markers drew their first frame in about 25 ms, and 1,000,000 markers of 3 px panned at over 100 fps (spike A). Larger markers cost more fill time (about half that frame rate at 8 px).
- Pass typed arrays (
Float64Array) for large data. On linear and date axes they are copied with one native call, where a plain array is read and checked value by value. See Performance. - Style updates are cheap.
chart.restyle({ 'marker.color': 'crimson' })only rewrites a color buffer; changingxoryrecomputes the trace. See Updating charts. marker.maxdisplayeddraws at most that many markers, evenly strided over the data.- Text labels are typeset asynchronously, so thousands of labels take noticeably longer to appear than markers.
chart.extendTraces/prependTracesstream points in: only the new points are converted and uploaded, andmaxPointskeeps a rolling window. See Line → Performance.
Accessibility notes
- Screen readers: a chart is a single
<canvas>. The DOM mirror that describes traces and points to assistive technology is not built yet (planned for M2, see the accessibility guide). Until then, add your own text alternative: anaria-labelor visible caption on the container, and a data table for the key numbers. - Keyboard: Tab moves into the plot area; ← / → then step through the points and ↑ / ↓ move to the trace above or below, each stop showing its hover label. See the keys.
- Color: don't rely on color alone. Vary
marker.symbolbetween traces, and pick a colorscale that is readable in grayscale (such as'Viridis') for numeric colors.
Attribute reference
See the scatter attribute reference for every attribute, its type, and its default, for example marker.size and error_y. Hover and drag settings are in the layout reference.
Related charts
- Line: the same trace with
mode: 'lines', for ordered data - Bar: compare amounts across categories
- Horizontal bar: ranked categories with long labels
Plotly migration notes
scatterandscatterglare the same trace in Holochart. Renamescattergltoscatter.- The default
modefollows Plotly:'lines+markers'for fewer than 20 points,'lines'otherwise. - Attribute names and the
hovertemplate/texttemplatesyntax match Plotly. - Not supported yet:
marker.gradient,marker.angleref,marker.standoff, andline.backoff.fill,stackgroup, andhoveronare covered on the area page, and bubble sizing on the bubble page. - Draw order matches Plotly: traces with a higher
zorderdraw on top; at equalzorder, bars draw below scatter traces whatever their order indata; then trace order.