In this tutorial we are going to use the following sample plots and then customize their axes. Note that the axes can be continuous if the variable is numerical, discrete for categories or groups or date if the axis represents dates.
The following sample plot is a box plot by group has a discrete X-axis and a continuous Y-axis:
# install.packages("ggplot2")
library(ggplot2)
# Sample data
x <- droplevels(chickwts$feed[1:36])
levels(x) <- LETTERS[1:3]
y <- chickwts$weight[1:36]
df <- data.frame(x = x, y = y)
# Plot
p <- ggplot(df, aes(x = x, y = y)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot(fill = "dodgerblue1",
colour = "black",
alpha = 0.5,
outlier.colour = "tomato2")
p

The other sample plot we are going to use is a scatter plot, so both axis are continuous.
# install.packages("ggplot2")
library(ggplot2)
# Sample plot with continuous axes
ggplot(cars, aes(x = speed, y = dist)) +
geom_point()

The sample plot with the box plots has a discrete X-axis and a continuous Y-axis, so you might need to adapt some functions of the examples of this tutorial depending on your data. For instance, if the X-axis of your plot is continuous and you want to change the labels you will need to use scale_x_continuous instead of scale_x_discrete.
labs function
By default, the axis titles are the name of the variables assigned to each axis inside aes, but you can change the default axis labels with the labs function as follows.
p + labs(x = "X-axis title", y = "Y-axis title")

xlab and ylab functions
Alternatively, you can use xlab and ylab functions to set the axis titles individually.
p + xlab("X-axis title") +
ylab("Y-axis title")

The style of the axis titles can be modified through the axis.title component of the theme function. You will need to pass an element_text and customize the style with the corresponding arguments, such as size, color or face.
p + labs(x = "X-axis title", y = "Y-axis title") +
theme(axis.title = element_text(size = 15,
color = "blue",
face = "bold"))

Note that you can also customize each axis title appending .x or .y to axis.title as follows. Recall that if you don’t specify one of them it will inherit the default aesthetics.
p + labs(x = "X-axis title", y = "Y-axis title") +
theme(axis.title.x = element_text(size = 15,
color = "blue",
face = "bold"),
axis.title.y = element_text(size = 10,
color = "red",
face = "italic"))

Remove both axis titles
Setting a theme component to element_blank() will remove the corresponding element. In order to remove the axis titles you can pass the element_blank function to the axis.title component, even if you have already specified the titles, as long as you don’t add them again.
p + xlab("X-axis title") +
ylab("Y-axis title") +
theme(axis.title = element_blank())

Remove one of the axis titles
If you append .x or .y to the axis.title component you can remove only one of the axis titles. This is, you can remove the X-axis title setting axis.title.x = element_blank() and the Y axis title with axis.title.y = element_blank().
p + xlab("X-axis title") +
ylab("Y-axis title") +
theme(axis.title.x = element_blank())

Each axis will have automatic axis labels or texts. For instance, the default axis labels for the Y-axis of our example ranges from 100 to 300 with a step size of 50 and the labels of the X-axis are the names of the different groups (A, B and C). These labels can be customized with scale_(x|y)_continuous if the axis (x or y) is continuous, scale_(x|y)_discrete if the axis is discrete or other variants, such as scale_(x|y)_datetime, scale_(x|y)_date, scale_(x|y)_reverse, scale_(x|y)_log10 etc.

Custom Y-axis labels
As the Y-axis of our sample plot is continuous we can use the scale_y_continuous function to customize it. The labels argument is the one used to customize the labels, where you can input a vector with the new labels or a custom labeller function as in the example below.
# Custom Y-axis labels
labels <- function(x) {
paste(x, "grams")
}
p + scale_y_continuous(label = labels)
The length of the vector passed to labels must equal the number of breaks or ticks of the axis. See the following section for further clarification.

Custom X-axis labels
As the X-axis of our sample plot represents groups, is discrete, so we can use the scale_x_discrete function to customize the labels for the X-axis. You can pass a function or a vector with the new names to labels.
# Custom X-axis labels
labels <- c("Group 1", "Group 2", "Group 3")
p + scale_x_discrete(label = labels)

Color of the axis texts
With the axis.text component of the theme function you can control the style of the axis labels. If you pass an element_text you will be able to customize the style of the texts with its arguments, such as its color, size, angle…
p +
theme(axis.text = element_text(color = "slateblue",
size = 12))

Different color for each axis text
Recall that you can apply a different styling for each axis just appending .x or .y to the corresponding component, this is, with axis.text.x and with axis.text.y.
p +
theme(axis.text.x = element_text(color = "cyan2",
size = 12),
axis.text.y = element_text(color = "red",
size = 10,
hjust = 1))
The ticks are the marks that divide the axes. These marks are adjusted automatically by ggplot2 based on your data, but you can also customize them. It is possible to increase or decrease the number of ticks, customize its style, increase its size or remove them.
Increase the number of ticks
The number of ticks can be customized passing a vector with the desired values to the breaks argument of the scale_y_continuous function. In the following example we are passing a sequence of values that ranges from 120 to 320 with step size of 20.
p +
scale_y_continuous(breaks = seq(120, 320, by = 20))

Increase the size of the ticks
The theme function provides a component named axis.ticks.length to increase or decrease the size of the axis ticks. In order to accomplish that you will need to pass the unit function and specify the desired size in the unit you want. Recall to use axis.ticks.length.x or axis.ticks.length.y to customize only one axis ticks.
p +
theme(axis.ticks.length = unit(0.5, "cm"))

Modify the style of the ticks
You can customize the style of the ticks passing an element_line to the axis.ticks component of the theme function, specifying the desired color, size, line style, etc. Recall to append .x or .y to customize only one axis.
p +
theme(axis.ticks = element_line(color = 2,
linewidth = 2))

Remove the ticks
As with other components, passing the element_blank function to the axis.ticks component will remove the ticks from both axis. If you want to remove the ticks only for one axis pass the function to axis.ticks.x or to axis.ticks.y.
p +
theme(axis.ticks = element_blank())

The theme function also provides the axis.ticks.x.top, axis.ticks.x.bottom, axis.ticks.y.left, axis.ticks.y.right, axis.ticks.length.x, axis.ticks.length.x.top, axis.ticks.length.x.bottom, axis.ticks.length.y, axis.ticks.length.y.left and axis.ticks.length.x.right components.
The range or limits of the axes are adjusted automatically by ggplot2 based on the range of your data. Nonetheless, you can override the automatic settings and customize the limits to zoom in or zoom out or to subset the data.

coord_cartesian (zooming in)
In case you want to zoom in or zoom out the plot without removing data you will need to use the ylim and xlim arguments of the coord_cartesian function.
p +
coord_cartesian(ylim = c(100, 200))

ylim and xlim functions (subsetting)
The xlim and ylim functions subset the data to the specified range and then calculate the stats again. It is really important to understand that these functions doesn’t zoom in, they subset the data.
p +
ylim(c(100, 200))

Note that if one of your axes is discrete you can subset the data passing a vector with the names of the desired groups.
p +
xlim(c("A", "B"))

Start at the origin
You can force the plot to start at the origin with the expand_limits function, which will force the axis to include the value or values passed to the x or y arguments of the function.
p +
expand_limits(x = 0, y = 0)
The scales of the axes are automatically set by ggplot2 based on the data, but sometimes you might need to customize them. For instance, if the numbers are too big, ggplot2 will use a scientific notation format for the axis labels and you might want to remove it, or you might want to customize the decimal or thousands separator, change the format of the axis and treat them as currencies or maybe you want to transform the scale into a logarithmic scale.
Remove the scientific notation
If the numbers of the axis are too big, ggplot2 will show them by default in scientific notation. However, you can use the function from the following block of code and set the new labels without scientific notation and with marks.
# Function to set numbers with marks and without scientific notation
marks_no_sci <- function(x) format(x, big.mark = ".", decimal.mark = ",", scientific = FALSE)
ggplot(cars, aes(x = speed, y = dist * 1000000)) +
geom_point() +
scale_y_continuous(labels = marks_no_sci)

Remove the scientific notation with scales
The scales package is a package that provides automatic methods to set breaks and labels for the axes. In order to remove the scientific notation, you just need to pass the function you want to use (label_number or label_comma in this scenario) to labels.
# install.packages("scales")
library(scales)
ggplot(cars, aes(x = speed, y = dist * 1000000)) +
geom_point() +
scale_y_continuous(labels = label_number())

Other alternative is to set something like options(scipen = -10). Recall that the integer passed is based on a penalty mechanism to decide whether to print in scientific notation or not.
Dollar format
If your axis represents dollars you can use the label_dollar function to treat the axis as currency and hence a dollar sign will appear as prefix of the number.
# install.packages("scales")
library(scales)
ggplot(cars, aes(x = speed, y = dist)) +
geom_point() +
scale_y_continuous(labels = label_dollar())

Axis with other currencies (euros, pesos, yens …)
If you need other currency, such as euros, pesos or yens, you can also use the label_dollar function, but you will need to specify the desired symbol inside the suffix and prefix arguments. Note that by default, prefix = "$".
# install.packages("scales")
library(scales)
ggplot(cars, aes(x = speed, y = dist)) +
geom_point() +
scale_y_continuous(labels = label_dollar(suffix = "€", prefix = ""))

Other interesting scales provided by scales are label_bytes, label_date, label_date_short, label_math, label_percent, label_pvalue or label_scientific, among others.
Scale log 10
ggplot2 also provides some functions for scale transformations, such as scale_y_log10 or scale_x_log10 that will transform the axis into a logarithmic scale.
ggplot(cars, aes(x = speed, y = dist)) +
geom_point() +
scale_y_log10()

Square root scale
The scale_y_sqrt and scale_x_sqrt functions will transform the corresponding axis applying the square root to its values.
ggplot(cars, aes(x = speed, y = dist)) +
geom_point() +
scale_y_sqrt()

Reversed scale
The scale_y_reverse and scale_x_reverse functions will reverse the Y and X axis, respectively.
ggplot(cars, aes(x = speed, y = dist)) +
geom_point() +
scale_y_reverse()


The default ggplot2 theme doesn’t show axis lines, but if you are using other theme or you want to add lines to the axis you can pass an element_line to the axis.line component of the theme function. Then, you can set the width, color, line type, etc, or leave the default arguments.
p +
theme(axis.line = element_line(color = "red",
linewidth = 1.5,
linetype = 2))

Recall that if you want to customize or set only one axis you will need to append .x or .y to the axis.line component to customize the X-axis or Y-axis line, respectively.
p +
theme(axis.line.x = element_line(color = "blue",
linewidth = 1.5,
linetype = 3))

Adding arrows to the axis lines
Arrows can be added to the axis lines passing the arrow function to the arrow argument of the element_line function. You can customize the angle, the length, the position ("last", the default, "first" or "both") and the type of arrow ("open", the default or "closed").
p +
theme(axis.line = element_line(arrow = arrow(angle = 30,
length = unit(0.15, "inches"),
ends = "last",
type = "closed")))
It is possible to add a dual axis in ggplot2 making use of the sec.axis argument from scale_(x|y)_continuous and the sec_axis function. This function needs a formula or function of transformation and the name of the new axis.
ggplot(cars, aes(x = speed, y = dist)) +
geom_col() +
geom_smooth(data = cars, aes(x = speed, y = dist * 2)) +
scale_y_continuous(sec.axis = sec_axis(trans = ~.* 2, name = "Z-axis title"))

Secondary axis breaks
The function also provides the breaks argument to customize the default breaks or tick marks of the secondary axis. In the following example we are placing only three tick marks.
ggplot(cars, aes(x = speed, y = dist)) +
geom_col() +
geom_smooth(data = cars, aes(x = speed, y = dist * 2)) +
scale_y_continuous(sec.axis = sec_axis(~.* 2, name = "Z-axis title",
breaks = c(100, 200, 300)))

Secondary axis labels
The axis labels of the dual axis plot can be customized through the labels argument. Remember that the length of breaks must equal the length of labels.
ggplot(cars, aes(x = speed, y = dist)) +
geom_col() +
geom_smooth(data = cars, aes(x = speed, y = dist * 2)) +
scale_y_continuous(sec.axis = sec_axis(~.* 2, name = "Z-axis title",
breaks = c(100, 200, 300),
labels = c("A", "B", "C")))

Further customization of the dual axis plot
The right axis can be customized making use of the corresponding components. With axis.title.y.right you can style the axis title text, such as its color or size, with axis.text.y.right the color and size of the secondary axis labels and with axis.line.y.right you can customize the axis line.
ggplot(cars, aes(x = speed, y = dist)) +
geom_col() +
geom_smooth(data = cars, aes(x = speed, y = dist * 2)) +
scale_y_continuous(sec.axis = sec_axis(~.* 2, name = "Z-axis title")) +
theme(axis.title.y.right = element_text(color = "red",
size = 15,
face = "bold"),
axis.text.y.right = element_text(color = "blue", size = 10),
axis.line.y.right = element_line(color = "orange"))

See also