• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

Data Viz with Python and R

Learn to Make Plots in Python and R

  • Home
  • Seaborn
  • Matplotlib
  • ggplot2
  • Altair
  • About
    • Privacy Policy
  • Visualizing Activation Functions in Neural Networks
  • Confusion Matrix Calculator
  • Visualizing Dropout Rate in Neural Network
  • Visualizing Loss Functions in Neural Networks
  • Show Search
Hide Search

Center Your ggplot2 Plot Titles and Subtitles in R

datavizpyr · July 30, 2025 ·

Last updated on August 26, 2025

Tired of your ggplot2 plots looking a little… off-balance? The default left-aligned title works, but for a polished, professional-looking chart, a centered title often makes all the difference.

In this step-by-step tutorial, we’ll show you the quick and easy way to perfectly center your plot titles and subtitles. You’ll not only learn the main function but also understand how to customize alignment further for complete control over your plot’s appearance.

Quick Solution (TL;DR)

To center the plot title and subtitle in ggplot2, add a theme() layer to your plot and set the hjust (horizontal justification) argument to 0.5 inside element_text().

library(ggplot2)
theme_set(theme_bw(16))
# center title and subtitle with theme() and element_text()
mtcars |>
  ggplot(aes(x = wt, y = mpg)) +
  geom_point() +
  labs(title = "My Centered Title",
       subtitle = "My Centered Subtitle") +
  theme(
    plot.title = element_text(hjust = 0.5),
    plot.subtitle = element_text(hjust = 0.5)
)
ggsave("Centered_title_and_subtitle_ggplot2.png")
Centered plot title and subtitle in ggplot2.
Centered plot title and subtitle in ggplot2.

Understanding the hjust Argument

The key to aligning text in ggplot2 is the horizontal justification argument, hjust. It controls the horizontal position of the text relative to its anchor point.

You can think of it as a scale from left to right:

  • hjust = 0: Left-justifies the text (this is the default for titles).
  • hjust = 0.5: Center-justifies the text.
  • hjust = 1: Right-justifies the text.

By setting plot.title = element_text(hjust = 0.5), you are telling ggplot2: “Take the title text element and position it so its horizontal center is aligned with the plot’s center.”

Step-by-Step Example: From Default to Centered

Now that we understand the theory, let’s walk through a complete example using the palmerpenguins dataset. First, we’ll load our libraries and create a plot with the default left-aligned title.

1. The Default Plot

Without any theme adjustments, the title appears on the left.

library(tidyverse)
library(palmerpenguins)
theme_set(theme_bw(16))

penguins |>
  drop_na() |>
  ggplot(aes(x = body_mass_g, fill = sex)) +
  geom_density(alpha = 0.5) +
  labs(title = "Body Mass Distribution",
       subtitle = "Default Left-Aligned Title and SubTitle")
Default Left Aligned Plot Title in ggplot2
Default Left Aligned Plot Title in ggplot2

2. The Centered Plot

Now, let’s add our theme() layer to center both the title and the subtitle.

penguins |>
  drop_na() |>
  ggplot(aes(x = body_mass_g, fill = sex)) +
  geom_density(alpha = 0.5) +
  labs(title = "Body Mass Distribution",
       subtitle = "Centered Title and Subtitle") +
  # Center the title and subtitle
  theme(plot.title = element_text(hjust = 0.5),
        plot.subtitle = element_text(hjust = 0.5))
ggsave("centered_plot_title_subtitle_ggplot2.png")
Plot with Centered Title and Subtitle in ggplot2
Plot with Centered Title and Subtitle in ggplot2

Pro-Tip: Set Centered Titles as the Default

If you want all your plots in a script or report to have centered titles, you don’t need to add a theme() layer every time. Instead, you can set it globally at the beginning of your R script using theme_update().

# Run this code once at the top of your script
theme_update(plot.title = element_text(hjust = 0.5))

# Now, any new plot you create will automatically have a centered title
penguins |>
  drop_na() |>
  ggplot(aes(x = flipper_length_mm)) +
  geom_histogram() +
  labs(title = "This Title is Centered by Default")
Centered Titles as the Default using theme_update()
Centered Titles as the Default using theme_update()

Useful Extras: Captions, Long Titles, Facets, Export

Center or Right-Align the Caption

Captions sit at the bottom; you can align them too. Use plot.caption with hjust.

library(patchwork)
p <- penguins |>
  drop_na() |>
  ggplot(aes(x = body_mass_g, 
             y = bill_length_mm, 
             color=sex)) +
  geom_point(alpha = 0.6) +
  labs(title = "Centered Title",
       caption = "Source: palmerpenguins")
 
# Center caption
p1 <- p + theme(plot.title = element_text(hjust = 0.5),
          plot.caption = element_text(hjust = 0.5))
 
# Or right-align
p2 <- p + theme(plot.title = element_text(hjust = 0.5),
          plot.caption = element_text(hjust = 1))
p1/p2
ggsave("ggplot2_align_caption.png", height=12, width=8)
ggplot2 caption: center or right align
ggplot2 caption: center or right align

Handle Long / Multi-Line Titles

Long titles wrap naturally. Improve readability with margins and line spacing.


library(stringr)

long_title <- str_wrap(
  "Body Mass & Bill Length in Palmer Penguins: Centered Titles Improve Readability for Presentations and Publications",
  width = 50
)

penguins |>
  drop_na() |>
  ggplot(aes(body_mass_g, 
             bill_length_mm)) +
  geom_point(alpha = 0.6) +
  labs(title = long_title,
       subtitle = "Centered subtitle with extra spacing") +
  theme(
    plot.title = element_text(
      hjust = 0.5, 
      lineheight = 1.1,     # increases spacing between wrapped lines
      margin = margin(b = 6) # adds bottom space below title
    ),
    plot.subtitle = element_text(
      hjust = 0.5, 
      margin = margin(b = 8) # creates breathing room above plot
    )
  )
ggplot2 center long multi-line title with extra spacings
ggplot2 center long multi-line title with extra spacings

In the example above

  • lineheight = 1.1 → Adds gentle vertical space between wrapped lines of the title, so the text doesn’t look squashed.
  • margin(b = 6) → Adds bottom padding below the title, separating it from the subtitle.
  • margin(b = 8) for subtitle → Pushes the subtitle down a bit, so the block of text feels balanced above the plot.

Together, these adjustments make multi-line centered titles look visually balanced, improving overall readability.

Facets & Title Positioning

In faceted plots, the main plot title still aligns with the overall plot area. If it looks off, increase figure width, adjust margins, or consider
plot.title.position (e.g., theme(plot.title.position = "plot")) to control how the title/subtitle relate to panels vs. the full plot.

Export Cleanly (No Clipping)

Prevent cropped text with tight bounding boxes and adequate size.

ggsave("centered_title.png", width = 8, height = 5, units = "in", dpi = 300)
# Vector for print
ggsave("centered_title.pdf", width = 8, height = 5, units = "in")

ggplot2 title positioning: FAQs (Advanced & Edge Cases)

  • Will a top legend or large guide shift the title’s apparent center?
    Yes—tall legends at the top can change visual balance even if the title is numerically centered. Keep the legend on the side, reduce legend rows, or add a small bottom margin to the title/subtitle so the header block reads as a single unit.
  • How do I center titles when combining plots with patchwork or cowplot?
    Center each subplot’s title with hjust = 0.5, then add a global title using patchwork’s plot_annotation(title = ...) or cowplot’s ggdraw() + draw_label(..., hjust = 0.5). Ensure the outer annotation is centered independently of panel widths.
  • Can I use rich text (bold, color, line breaks) and still keep the title centered?
    Yes, with ggtext::element_markdown() in theme(plot.title = ...). Use hjust = 0.5 and include Markdown/HTML (e.g., <span style="color:#444">...</span>). Manage line breaks with <br> or stringr::str_wrap() for predictable wrapping.
  • My theme settings keep overriding local title alignment—why?
    Theme precedence matters: theme_set() → theme_update() → plot-level + theme(). The last applied theme takes priority. If a custom theme reassigns plot.title, add your + theme(...) after the plot is built.
  • How do I center the plot tag (e.g., “A”, “B”) like the title?
    Use labs(tag = "A") and style with theme(plot.tag = element_text(hjust = 0.5)). Control vertical spacing via plot.tag.position and plot.margin for alignment with the main title block.
  • Can a logo or annotation in the header throw off perceived centering?
    Yes. Place logos using annotation_custom(), cowplot::ggdraw(), or patchwork areas, and balance them with equal padding/margins on the opposite side, or move the logo to a caption/footer bar.
  • How can I systematically insert line breaks for long titles without guessing a width?
    Use stringr::str_wrap(title, width = n) where n is derived from container width or a heuristic (e.g., 45–60 for slides, 60–75 for print). For strict control, insert \n at semantic breakpoints and keep lineheight around 1.05–1.15.
  • Can I shift only the first line of a multi-line title?
    ggplot2 aligns the entire title block. To offset the first line only, split the title into two parts (first line in title, rest in subtitle), or switch to ggtext::element_markdown() and control alignment per line with HTML spans.
  • Fonts look different after export—title seems off. What’s going on?
    Font fallback or missing glyphs can change text width. Register and embed fonts (showtext/systemfonts), export to PDF/SVG for vector text, and verify the target font supports your language and weight.
  • Does plot.title.position affect centering in all themes?
    It controls how titles/subtitles anchor to the plot vs panel area. Some custom themes alter layout enough that you may still need small manual tweaks (margins, legend placement, or container width) for perfect visual centering.

Explore the Complete ggplot2 Guide

35+ tutorials with code: scatterplots, boxplots, themes, annotations, facets, and more—tested and beginner-friendly.

Visit the ggplot2 Hub → No fluff—just code and visuals.

Related posts:

Customizing Mean mark to boxplot with ggplot2How To Show Mean Value in Boxplots with ggplot2? Scatterplot with marginal multi-histogram with ggExtraHow To Make Scatterplot with Marginal Histograms in R? ggforce geom_circle(): Annotate with a circleHow To Annotate a Plot with Circle in R Default ThumbnailHow to Make Axis Text Bold in ggplot2

Filed Under: ggplot2, R Tagged With: move subtitle to the center ggplot2, move title to the center ggplot2

Primary Sidebar

Python & R Viz Hubs

  • Seaborn Guide & Cookbook
  • ggplot2 Guide & Cookbook
  • Matplotlib Guide & Cookbook
  • Confusion Matrix Calculator
  • Visualizing Activation Functions
  • Visualizing Dropout
  • Visualizing Loss Functions

Buy Me a Coffee

Copyright © 2026 · Daily Dish Pro on Genesis Framework · WordPress · Log in

Go to mobile version