Written and maintained by CASRAI Editorial Board
Last updated
In ggplot2 there are two ways to put an axis on a log scale, and they are not interchangeable. scale_x_log10() and scale_y_log10() transform the data before any statistics are computed; coord_transform() transforms the plot after the statistics. For most plots, use the scale. This guide shows both, the current function names (several older ones are deprecated or superseded), and how to draw log-spaced tick marks.
What it is used for in research
A log axis is used when values span several orders of magnitude, so that small and large values can be read on one plot. On a log axis, equal distances are equal ratios, not equal differences. That is why log axes are common for concentrations, counts, and fold changes. For the wider axis toolkit (limits, breaks, labels), see the guide to axes in R; this page goes deeper on the log case only.
Install or access
ggplot2 is an R package distributed through CRAN and documented at ggplot2.tidyverse.org. Install it once and load it in each session:
install.packages("ggplot2")
library(ggplot2)
The transformation objects used by scales are provided by the scales package, documented at scales.r-lib.org. For the basics of building and saving plots, see the guide to ggplot2 plots in R.
Step-by-step: put an axis on a log scale
1. Log the y axis with scale_y_log10()
Add the scale to the plot. The same call works for x with scale_x_log10().
ggplot(mtcars, aes(disp, mpg)) +
geom_point() +
scale_y_log10()
According to the ggplot2 reference, scale_x_log10() and scale_y_log10() are variants of the continuous scales that set the transform argument, and any other arguments are passed on to scale_(x|y)_continuous(). So breaks, labels, limits and name work as they do on any continuous scale.
2. Make a log-log plot
Add both scales:
ggplot(mtcars, aes(disp, mpg)) +
geom_point() +
scale_x_log10() +
scale_y_log10()
3. Use another base or transformation
The transform argument of the continuous scales accepts a transformation name. The built-in names include “log”, “log10”, “log1p” and “log2”, and the default is “identity”.
ggplot(mtcars, aes(disp, mpg)) +
geom_point() +
scale_x_continuous(transform = "log2")
The older argument name trans is deprecated in favour of transform. A custom transformation can be built with scales::new_transform().
4. Alternative: coord_transform()
The coordinate version transforms the plot space after the statistics have run:
ggplot(diamonds, aes(carat, price)) +
geom_point() +
coord_transform(x = "log10", y = "log10")
The ggplot2 reference for coord_transform() uses the same transformation of both axes. The older function coord_trans() is deprecated; use coord_transform().
5. Draw log-spaced tick marks
To replace ordinary tick marks with ticks at intervals in log10 space, use guide_axis_logticks() through the guide argument:
ggplot(diamonds, aes(carat, price)) +
geom_point() +
scale_x_log10(guide = "axis_logticks") +
scale_y_log10(guide = "axis_logticks")
The function takes long, mid and short arguments (defaults 2.25, 1.5 and 0.75) for the three tick lengths. With coord_transform(x = "log10", y = "log10") you set the guides through guides() instead.
Scale or coordinate transform: which to use
The difference is when the transformation happens. The ggplot2 reference states that coord_transform() occurs after statistical transformation, while scale transformations are applied before it. Anything computed by a stat (a fitted smoother, bin counts, a density) is therefore computed on the transformed values when you use a scale, and on the original values when you use a coordinate transform. The reference also warns that with a coordinate transform there is no guarantee that straight lines will continue to be straight.
| Setup | When the transformation happens | Log tick setting |
|---|---|---|
scale_y_log10() |
Before statistics | guide = "axis_logticks" on the scale; annotation_logticks, if you use it, needs scaled = TRUE (the default) |
coord_transform(y = "log10") |
After statistics | Set the guide through guides(); annotation_logticks needs scaled = FALSE |
Data already passed through log10() by you |
Before ggplot2 sees it | annotation_logticks with scaled = TRUE; for guide_axis_logticks() set prescale.base |
Sources for the table: the reference pages for coord_transform, guide_axis_logticks and annotation_logticks, listed under Sources.
Output and how to read it
Read a log axis as ratios. Moving the same distance along the axis always multiplies the value by the same factor. Gridlines and ticks are therefore not evenly spaced in value, and the lowest visible value is not zero. Label the axis so the reader knows it is logarithmic, and say which base you used when it is not 10.
Troubleshooting
Values of zero or below do not appear
A logarithm is not defined for zero or negative numbers, so those observations cannot be placed on a log axis. If your data contain zeros, one documented alternative is the pseudo-log transformation, which the scales documentation describes as defined for all real numbers: scale_y_continuous(transform = scales::transform_pseudo_log()). When an axis includes zero or negative limits, guide_axis_logticks() has a negative.small argument that sets the smallest absolute value that gets ticks, with mirrored ticks for negative values.
An old script uses trans = “log10” and warns
The trans argument is deprecated. Replace it with transform, for example scale_y_continuous(transform = "log10"). Likewise replace coord_trans() with coord_transform().
A fitted line looks curved after coord_transform()
This is the documented behaviour of a coordinate transform: straight lines are not guaranteed to stay straight, because the transformation is applied after the stat. If you want the fit computed on logged values, use scale_x_log10() or scale_y_log10() instead.
Log ticks are in the wrong place on pre-logged data
The documentation says to set prescale.base in guide_axis_logticks() only if the data have already been log-transformed. For data transformed with log2(), use guide_axis_logticks(prescale.base = 2); the reference notes that this axis uses log10 space for placement, not log2.
annotation_logticks() is superseded
The ggplot2 reference states that annotation_logticks() is superseded by guide_axis_logticks(). If you still use it, scaled = TRUE is for data passed through log10() or scale_y_log10(), and scaled = FALSE is for coord_transform(y = "log10"). Its base argument is described as probably sensible only for base 10, and ticks drawn outside the panel need coord_cartesian(clip = "off").
Free alternatives in base R
Base R graphics ship with R, so no package is needed. The two approaches map as follows:
| Task | Base R | ggplot2 |
|---|---|---|
| Log x axis | plot(x, y, log = "x") |
scale_x_log10() |
| Log y axis | plot(x, y, log = "y") |
scale_y_log10() |
| Both axes | plot(x, y, log = "xy") |
scale_x_log10() + scale_y_log10() |
The log argument of base R plot() takes “x”, “y” or “xy” (see the R manual page for plot.default). For the plot types this is most often applied to, see scatterplots in R and histograms in R, and for text on the plot see labels and legends in ggplot2.
FAQ
How do I make the y axis logarithmic in ggplot2?
Add scale_y_log10() to the plot. It is a variant of scale_y_continuous() with the transform argument set to log10.
What is the difference between scale_y_log10() and coord_transform(y = “log10”)?
The scale transforms the data before statistics are computed; the coordinate transform is applied after them, and straight lines may not stay straight.
Is trans still valid in scale_y_continuous()?
It is deprecated in favour of transform.
Can I use a base other than 10?
Yes. The continuous scales accept transformation names including “log2” and “log”; the dedicated shortcut is for base 10 only.
Sources
- ggplot2 reference: Position scales for continuous data (checked 2026-10-29)
- ggplot2 reference: coord_transform() (checked 2026-10-29)
- ggplot2 reference: guide_axis_logticks() (checked 2026-10-29)
- ggplot2 reference: annotation_logticks() (checked 2026-10-29)
- scales reference: transform_log() and transform_pseudo_log() (checked 2026-10-29)
- R manual: plot.default (log argument) (checked 2026-10-29)







