Skip to main content
A scatter plot draws a geom.point() per observation against two continuous axes — the tool for 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 category to color to distinguish groups of points:

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: size alone would leave every bubble in the built-in mark color, so scale.color.palette() earns its place beside scale.size.continuous().

Missing values

geom.point() has no missingValues param — an observation whose x or y is null simply isn’t drawn, and the rest of the cloud is unaffected.

Painting the markers

geom.point() takes no params at all. Everything about a marker’s appearance comes from the stylesheet, through the style.geom.point target — color, alpha, saturation, size, borderColor and borderWidth:
Markers draw at size: 8 with a 1px white border by default. Lowering alpha is the standard move for a dense cloud, where overlapping markers 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 already spoke. Put the entry in overrides to win against the mapping: