Written and maintained by CASRAI Editorial Board
Last updated
To label a legend in ggplot2, change the labels on the scale that draws that legend: pass a character vector to the labels argument of the scale for the aesthetic you mapped (for example scale_colour_discrete(labels = ...) for colour). Changing the legend text any other way, such as editing the plot title or the axis, leaves the legend untouched. This guide covers the safe way to relabel legend keys so the right text stays attached to the right colour, how to fix labels in the data itself, and how to reorder, hide and lay out the keys. The legend title is a separate topic, covered in ggplot titles.
What it is used for in research
Raw data columns often hold codes such as 4, 6 and 8, or group names such as ctrl and trt1. A figure submitted to a journal or shared with collaborators needs readable legend keys (“four cylinders”, “Control”, “Treatment 1”) without altering the underlying dataset. Legend labels are also where silent mistakes happen: a label vector in the wrong order attaches the wrong text to a colour and the figure still renders with no error. The sections below are arranged to prevent that.
Install or access (official source only)
ggplot2 is an R package distributed through CRAN and documented at the tidyverse reference site, ggplot2.tidyverse.org/reference. From the R console:
install.packages("ggplot2")
library(ggplot2)
It is also installed as part of the tidyverse collection. The examples below use the mtcars data set that ships with R, so they run without any extra files.
Step-by-step: change legend labels with a scale
The legend for an aesthetic is produced by that aesthetic’s scale, so labels belong on the scale. The ggplot2 reference for scale_manual defines the labels argument as: NULL for no labels, waiver() for the default labels, a character vector giving labels that must be the same length as breaks, or a function that takes the breaks as input and returns labels as output.
- Build the plot and map the aesthetic.
p <- ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) + geom_point() - Add the scale for that aesthetic and pass
labels. Becausecolouris mapped, use acolourscale:p + scale_colour_discrete(labels = c("four", "six", "eight")) - Set
breakstogether withlabelswhen you can. The scale reference states that it is highly recommended to also set thebreaksargument as a vector. With a manual scale, the official example pairs all three arguments:cols <- c("4" = "#1b9e77", "6" = "#d95f02", "8" = "#7570b3") p + scale_colour_manual(values = cols, breaks = c("4", "6", "8"), labels = c("four", "six", "eight")) - Use a function when the label is a rule, not a list.
p + scale_colour_discrete(labels = function(x) paste(x, "cylinders"))
Which scale to target
The scale must match the aesthetic you mapped. Adding a fill scale to a plot whose legend comes from colour changes nothing, and no error is raised.
| You mapped | Relabel with | Typical geoms |
|---|---|---|
colour |
scale_colour_discrete() or scale_colour_manual() |
points, lines, box outlines |
fill |
scale_fill_discrete() or scale_fill_manual() |
bars, boxplots, areas |
shape |
scale_shape_discrete() or scale_shape_manual() |
points |
| Several aesthetics at once | scale_discrete_manual(aesthetics = c("colour", "fill"), ...) |
any |
The reference shows the general form as scale_discrete_manual(aesthetics, ..., values, breaks = waiver()). For colour choices themselves, see ggplot colour.
Keep labels attached to the right colours
With a manual scale, values can be a named vector. The reference states that when it is named, the values are matched on the names instead of on position. Naming the values (as cols does above) means a later change in the order of the data cannot move a colour onto the wrong group. Labels given as a plain character vector are still matched by position to breaks, which is why setting breaks explicitly matters.
Change labels by editing the factor levels
Scale labels fix one plot. If the same group names appear in several figures, relabel the data once and every legend, facet strip and axis follows:
mtcars$cyl_f <- factor(mtcars$cyl,
levels = c(4, 6, 8),
labels = c("four", "six", "eight"))
ggplot(mtcars, aes(wt, mpg, colour = cyl_f)) + geom_point()
The scale reference also describes limits as a character vector that defines the possible values of the scale and their order, so limits is the scale-level tool for ordering, while levels is the data-level tool.
Reorder, hide or lay out the legend keys
Guide settings
The signature in the ggplot2 reference is guide_legend(title = waiver(), theme = NULL, position = NULL, direction = NULL, override.aes = list(), nrow = NULL, ncol = NULL, reverse = FALSE, order = 0, ...). Useful arguments:
reverse = TRUEreverses the order; the reference describes it as a logical that, whenTRUE, reverses the order of legends.nrowandncolset the number of rows and columns of keys.override.aestakes a list of aesthetic parameters for the legend keys, for examplelist(size = 4)to enlarge small points in the legend only.
p + guides(colour = guide_legend(nrow = 1, reverse = TRUE,
override.aes = list(size = 4)))
Remove a legend
The guides reference notes that guides can be set scale by scale with the guide argument or all together with guides(), and removes one with guides(colour = "none"). To keep the legend but drop its title, the scale name can be set to NULL.
Text size and position through the theme
The theme reference lists legend.text as the legend item labels (an element_text()), legend.key.size as the size of the keys (a unit), and legend.position as one of “none”, “left”, “right”, “bottom”, “top” or “inside”. For “inside”, legend.position.inside takes a numeric vector of length two.
p + theme(legend.position = "inside",
legend.position.inside = c(0.9, 0.85),
legend.text = element_text(size = 12))
Broader theme choices are in ggplot themes. Legend keys describe a mapped aesthetic; axis tick labels are a different set of labels and are changed on the axis scale, as covered in axis labels in R.
Output and how to read it
After a change, check three things on the rendered figure: each label sits beside the colour or shape it should (compare against a few points you can identify in the data), the number of keys equals the number of groups, and no second legend has appeared. If a second legend appears, check that every aesthetic mapped to the same variable has the same scale name and labels. For a wider overview of building figures, see ggplots in R.
Troubleshooting
Legend labels did not change
The scale probably targets a different aesthetic than the one mapped. If the plot maps fill, use scale_fill_*; if it maps colour, use scale_colour_*. Check the aes() call first.
Labels attached to the wrong colours
The label vector is matched by position. Set breaks explicitly alongside labels, use named values in manual scales, or relabel the factor levels in the data.
Error about label length
The reference requires a character vector of labels to be the same length as breaks. Count your groups, including any you removed with limits.
The labels changed but the axis text did not
Legend labels and axis labels belong to different scales. Use scale_x_discrete(labels = ...) for a discrete x axis.
Free alternatives
| Tool | Where legend labels are set |
|---|---|
| ggplot2 (R) | labels argument of the aesthetic’s scale, as above |
| Base R graphics | the legend argument of legend(), a character vector of the text to show |
| Matplotlib (Python) | the legend text is set from the plot labels; see legend in Matplotlib |
FAQ
How do I change ggplot legend labels?
Pass a character vector to labels in the scale for the mapped aesthetic, for example scale_colour_discrete(labels = c("four", "six", "eight")), and set breaks as well so the order cannot drift.
How do I label a legend in ggplot without editing my data?
Use the scale labels argument. It changes only the displayed text; the data frame is not modified.
How do I remove the legend entirely?
Use guides(colour = "none") for one aesthetic, or theme(legend.position = "none") for all legends.
Sources (official docs)
- ggplot2 reference, scale_manual: https://ggplot2.tidyverse.org/reference/scale_manual.html (checked 2026-10-29)
- ggplot2 reference, guide_legend: https://ggplot2.tidyverse.org/reference/guide_legend.html (checked 2026-10-29)
- ggplot2 reference, guides: https://ggplot2.tidyverse.org/reference/guides.html (checked 2026-10-29)
- ggplot2 reference, theme: https://ggplot2.tidyverse.org/reference/theme.html (checked 2026-10-29)
- R graphics, legend(): https://stat.ethz.ch/R-manual/R-devel/library/graphics/html/legend.html (checked 2026-10-29)







