Skip to content

R ggplot2 Quickstart: Fast Recipes for Reliable Charts

Problem

Analysts struggle to produce consistent R charts when deadlines are tight. Switching between geoms, scales, and themes without a template leads to noisy visuals and repeated fixes.

Agitate

Misplaced aesthetics, forgotten legends, and mismatched color scales create charts that mislead stakeholders. Time is wasted tweaking defaults instead of focusing on signal.

Solution

Use a compact set of ggplot2 recipes that keep aesthetics explicit, separate mappings from fixed settings, and apply a clean theme. The patterns below cover the most requested plot types and how to facet for comparisons.

Scatter: relationships and trend lines

library(ggplot2)
 
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point(size = 3, alpha = 0.8) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 0.8) +
  labs(color = "Cylinders", x = "Weight", y = "MPG") +
  theme_minimal()

Line: time series or ordered categories

ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line(color = "#1f77b4", linewidth = 1) +
  labs(x = "Date", y = "Unemployment") +
  scale_x_date(date_breaks = "2 years", date_labels = "%Y") +
  theme_minimal()

Bar: counts or totals

ggplot(diamonds, aes(x = cut, fill = cut)) +
  geom_bar(width = 0.7, color = "white") +
  labs(x = "Cut", y = "Count") +
  theme_minimal() +
  theme(legend.position = "none")

Box and violin: distribution comparisons

ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) +
  geom_violin(alpha = 0.4, color = NA) +
  geom_boxplot(width = 0.18, outlier.shape = NA, alpha = 0.8) +
  labs(x = NULL, y = "Sepal Length") +
  theme_minimal() +
  theme(legend.position = "none")

Facets for quick comparisons

ggplot(diamonds, aes(carat, price, color = cut)) +
  geom_point(alpha = 0.4, size = 1.5) +
  facet_wrap(~ color) +
  labs(x = "Carat", y = "Price") +
  theme_light()

Geoms and best use cases

GeomData typeBest forTip
geom_point()numeric vs numericrelationships, clustersMap color/shape to categories; add geom_smooth() for trend.
geom_line()ordered x, numeric ytime series, sequencesKeep one line per group with group=; avoid sorting mistakes.
geom_bar() (count) / geom_col() (pre-agg)categoricalcounts or totalsUse position = "fill" for percentages.
geom_boxplot()categorical vs numericcomparing medians/IQRCombine with coord_flip() for long labels.
geom_violin()categorical vs numericdistribution shapePair with boxplots to show quartiles.
geom_histogram()single numericdistributionSet bins or binwidth explicitly.

Aesthetics vs. fixed settings

  • Map data inside aes(): aes(color = species).
  • Set fixed values outside aes(): geom_point(color = "steelblue").
  • Use scale_* functions to format values and control palettes.

Theme and labeling checklist

  • Start with theme_minimal() or theme_light() for clean defaults.
  • Add labs(title, subtitle, caption) for context; keep axes short.
  • Hide redundant legends with theme(legend.position = "none") when colors duplicate facets or labels.
  • For publication, adjust font sizes via theme(text = element_text(size = 12)).

Starter template

base_plot <- ggplot(data, aes(x = x_var, y = y_var)) +
  geom_point(color = "#4e79a7", alpha = 0.7) +
  labs(
    title = "Headline metric",
    x = "X axis",
    y = "Y axis",
    caption = "Source: internal data"
  ) +
  theme_minimal()

Related guides