Labels, Titles, and Annotations
Turning a correct chart into a communicative one — labs(), titles, direct annotations, and reference lines that guide the reader's eye.
A chart can be technically correct and still fail to communicate. The final layer of craft is labeling and annotation: titles that state the message, axis labels in plain language, and marks that point the reader to what matters. These are small additions with an outsized effect.
labs(): one place for all the text
labs() sets every text label on the plot — axis titles, the legend
title, the plot title, subtitle, and caption. Notice that the legend
title comes from the aesthetic name, so you label it by naming the
aesthetic:
Make the title the takeaway, not the topic
"Bigger engines are less fuel-efficient" tells the reader the conclusion. "MPG vs. displacement" only names the axes — information the axis labels already provide. A good title states what you want the reader to learn, turning a chart into an argument.
The role of each text slot:
Annotating directly on the plot
Legends cost the reader a glance back and forth. Often it is clearer to
write directly on the plot with annotate(), which adds a single
text label or shape at coordinates you choose — not tied to the data:
annotate() differs from a geom: it draws one thing from values
you supply, rather than one mark per data row. Use it for callouts,
shaded regions, and arrows that explain.
Reference lines guide the eye
Horizontal, vertical, and diagonal reference lines give the reader a baseline to compare against — an average, a target, a threshold:
geom_hline(yintercept = ...)— horizontal line (a target/average)geom_vline(xintercept = ...)— vertical line (a date, a cutoff)geom_abline(slope =, intercept =)— any diagonal (e.g.y = x)
The dashed line instantly answers "which cars are above average?" without the reader doing arithmetic.
The communication layer
Step back and see what these tools share: none of them change the analysis. They change how readily a reader extracts the message. This is the last mile of the grammar — once the components correctly encode the data, labels and annotations make the encoding legible.
In labs(), how do you set the legend title for a color legend?
With a special legend.title argument.
You cannot change a legend title.
By setting the argument named after the aesthetic, e.g. labs(color = "Drivetrain").
By editing the data column name only.
How does annotate("text", ...) differ from adding a geom_text() layer?
annotate() is just an alias for geom_text().
annotate() can only draw rectangles, not text.
annotate() draws a single element from values you supply directly, while geom_text() draws one label per row of mapped data.
geom_text() cannot use the plot's coordinate system.
What is the best practice for a plot title?
Restate the axis variables, e.g. "MPG vs. displacement."
Leave it blank so the chart speaks for itself.
State the takeaway or conclusion, e.g. "Bigger engines are less fuel-efficient," so the chart reads as an argument.
Put the data source in the title.
Key takeaways
labs()sets all plot text — title, subtitle, caption, axis titles, and legend titles (named by their aesthetic).- Make the title the takeaway, not a restatement of the axes.
annotate()adds one-off text or shapes from supplied coordinates;geom_text()labels every row.- Reference lines (
geom_hline/vline/abline) give the reader a baseline to compare against. - This layer changes legibility, not analysis — the final mile of the grammar.
Themes and Styling
Themes control everything that is not data — fonts, gridlines, backgrounds, legend placement — through a single, inheritance-based system.
Anatomy of a Complete Plot
Revisit the intimidating plot from the welcome page and decompose it, component by component, now that you know the whole grammar.