Skip to main content
A scatter plot draws a geom.point() per observation against two continuous axes. It shows correlation and distribution. Add a size mapping and it becomes a bubble chart, encoding a third variable.

Scatter

Map two numeric columns to x and y, and declare continuous scales:

Coloring by category

Map a categorical column to color to tell groups of points apart:

Bubble

Map a third numeric column to size and add a size scale. The default size scale uses a square-root transform, so bubble area is proportional to the value:
Each mapped aesthetic needs its own scale. scale.size.continuous() sizes the bubbles and scale.color.discrete() colors them; without it every bubble takes the built-in geom color.

Missing values

geom.point() has no missingValues param. An observation whose x or y is null is not drawn, and the rest of the cloud is unaffected.

Painting the markers

geom.point() takes no params. A marker’s whole appearance comes from the stylesheet, through the style.geom.point target: fill, stroke, strokeWidth, size, symbol, alpha and saturation:
Markers draw at size: 8 with a 1px white border by default. Lower alpha for a dense cloud, where overlapping markers would otherwise merge into a solid mass. One cascade rule matters here. A defaults entry applies only where no mapped aesthetic decided the value, so on a bubble chart style.geom.point({ size: 6 }) is ignored: the size mapping decides. Put the entry in overrides, which outranks the mapping: