Position Scales
Controlling the x and y axes — limits, breaks, transformations like log scales, and why zooming with a scale is different from zooming with coordinates.
The x and y axes are position scales, and they are the scales you will adjust most often. This page covers limits, breaks, labels, and — most importantly — transformations like the log scale, plus a subtle trap about how scales filter data.
Continuous position scales
For numeric axes you use scale_x_continuous() and
scale_y_continuous(). Set breaks (tick positions), labels, and the
axis name:
Transformations: the log scale
A transformation changes the spacing of the axis, not the data. The classic case is a log scale, which turns multiplicative relationships into straight lines and tames skewed data:
Same data, same mapping, same geom. Only the scale's transformation changed — and the chart went from unreadable to clear.
Transform the scale, not the data
You could create a new column log10(size) and plot that. But then
your axis would read 0–5 instead of 1–100,000, confusing readers.
Transforming the scale keeps the axis labeled in original units
while changing only the spacing. Let the scale do the transform.
The zoom trap: scale limits remove data
Here is a subtle but important behavior. Setting limits on a position
scale does not just zoom — it drops any data outside the range
before statistics run. Watch what it does to a smoother:
The large-engine cars are gone, and the smoother never saw them. If all you wanted was to zoom — keep all the data but look at a sub-region — you must use the coordinate system instead, which we cover in the next section:
Remember this distinction
Scale limits filter the data; coordinate limits zoom the view.
Use scale_*_continuous(limits = ...) to exclude data, and
coord_cartesian(xlim = ...) to zoom while keeping all data in the
calculations.
Discrete position scales
When x is categorical, the position scale is discrete
(scale_x_discrete()), letting you reorder or relabel categories:
Why prefer scale_x_log10() over creating a log10(x) column and plotting that?
Creating a new column is impossible in R.
The two approaches give different point positions.
Transforming the scale keeps the axis labeled in the original units (1, 100, 10000) while only changing the spacing, whereas a log column would label the axis 0–5 and confuse readers.
scale_x_log10() also changes the y-axis automatically.
What is the key difference between scale_x_continuous(limits = c(1, 5)) and coord_cartesian(xlim = c(1, 5))?
They are identical in every way.
The scale version zooms; the coord version deletes data.
The scale version removes data outside the range before stats are computed (so a smoother changes), while the coord version zooms the view and keeps all data in the calculations.
Only coord_cartesian works on the x-axis.
Key takeaways
- Position scales (
scale_x/y_continuous,scale_x/y_discrete) set limits, breaks, labels, and transformations for the axes. - A log transformation belongs on the scale, so the axis keeps its original units while changing spacing.
- Scale limits remove out-of-range data before stats run;
coord_cartesian()zooms while keeping all data — choose deliberately. - Discrete position scales let you reorder and relabel categories.
What Scales Do
Scales are the translators between data values and visual values — and the source of every axis and legend in a ggplot.
Color and Fill Scales
How ggplot2 turns data into color — discrete palettes, continuous gradients, the color vs fill distinction, and choosing perceptually honest scales.