Use when working with R ggplot2 package, especially ggplot2 4.0+ features. Covers S7 migration (@ property access), theme defaults with ink/paper/accent, element_geom(), from_theme(), theme shortcuts (theme_sub_*), palette themes, labels with dictionary/attributes, discrete scale improvements (palette, continuous.limits, minor_breaks, sec.axis), position aesthetics (nudge_x/nudge_y, order), facet_wrap dir/space/layout, boxplot/violin/label styling, stat_manual(), stat_connect(), coord reversal.
Generates ggplot2 visualizations using S7 classes, theme-based defaults, and new 4.0+ features.
/plugin marketplace add jsperger/llm-r-skills/plugin install jsperger-r-skills@jsperger/llm-r-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
ggplot2 is an R package for producing visualizations using a grammar of graphics. You compose plots from data, mappings, layers, scales, facets, coordinates, and themes.
ggplot(data = mpg, mapping = aes(x = cty, y = hwy))
aes() links data columns to visual properties (x, y, colour, size, etc.)Layers display data using geometry, statistical transformation, and position adjustment:
ggplot(mpg, aes(cty, hwy)) +
geom_point() +
geom_smooth(formula = y ~ x, method = "lm")
Control how data maps to visual properties and create legends/axes:
ggplot(mpg, aes(cty, hwy, colour = class)) +
geom_point() +
scale_colour_viridis_d()
Split data into panels by variables:
ggplot(mpg, aes(cty, hwy)) +
geom_point() +
facet_grid(year ~ drv)
Interpret position aesthetics (Cartesian, polar, map projections):
ggplot(mpg, aes(cty, hwy)) +
geom_point() +
coord_fixed()
Control non-data visual elements:
ggplot(mpg, aes(cty, hwy, colour = class)) +
geom_point() +
theme_minimal() +
theme(legend.position = "top")
ggplot2 4.0.0 (September 2025) introduced S7 classes and major new features.
Access properties with @ instead of $:
# ggplot2 4.0+
ggplot()@data
# Deprecated (still works temporarily)
ggplot()$data
Stricter type validation:
element_text(hjust = "foo")
#> Error: @hjust must be <NULL>, <integer>, or <double>, not <character>
Built-in themes accept ink (foreground), paper (background), accent (highlight):
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
geom_smooth(method = "lm", formula = y ~ x) +
theme_gray(paper = "cornsilk", ink = "navy", accent = "tomato")
Set layer defaults via theme(geom):
ggplot(mpg, aes(class, displ)) +
geom_boxplot(aes(colour = from_theme(accent))) +
theme(geom = element_geom(
accent = "tomato",
paper = "cornsilk",
bordertype = "dashed",
borderwidth = 0.2,
linewidth = 2,
linetype = "solid"
))
Set default palettes in themes:
theme(
palette.colour.continuous = c("chartreuse", "forestgreen"),
palette.shape.discrete = c("triangle", "triangle open")
)
New theme_sub_*() functions reduce verbosity:
| Shortcut | Prefix replaced |
|---|---|
theme_sub_axis() | axis.* |
theme_sub_axis_x() | axis.*.x |
theme_sub_axis_bottom() | axis.*.x.bottom |
theme_sub_legend() | legend.* |
theme_sub_panel() | panel.* |
theme_sub_plot() | plot.* |
theme_sub_strip() | strip.* |
# Concise
theme_sub_axis_x(
ticks = element_line(colour = "red"),
ticks.length = unit(5, "mm")
) +
theme_sub_panel(
widths = unit(5, "cm"),
spacing.x = unit(5, "mm")
)
margin_auto(1) # all sides = 1
margin_auto(1, 2) # t/b=1, l/r=2
margin_auto(1, 2, 3) # t=1, l/r=2, b=3
margin_part(r = 20) # partial (NA inherits)
theme_sub_panel(widths = unit(c(2, 3, 4), "cm")) # per-panel
theme_sub_panel(widths = unit(9, "cm")) # total area
Variables with "label" attribute auto-populate axis labels:
attr(df$bill_dep, "label") <- "Bill depth (mm)"
ggplot(df, aes(bill_dep, bill_len)) + geom_point()
dict <- c(species = "Species", bill_dep = "Bill depth (mm)")
ggplot(penguins, aes(bill_dep, bill_len, colour = species)) +
geom_point() +
labs(dictionary = dict)
scale_colour_discrete(name = toupper)
guides(x = guide_axis(title = tools::toTitleCase))
labs(y = \(x) paste0(x, " variable"))
Label hierarchy (lowest to highest): aes() < labs(dictionary) < column attribute < labs() < scale_*(name) < guide_*(title)
scale_colour_discrete(breaks = c(
"Pygoscelis adeliae" = "Adelie",
"Pygoscelis papua" = "Gentoo"
))
# Palette for spacing
scale_x_discrete(palette = scales::pal_manual(c(1:3, 5:7)))
# Consistent limits across facets
scale_x_discrete(continuous.limits = c(1, 5))
# Minor breaks
scale_x_discrete(
minor_breaks = scales::breaks_width(1, offset = 0.5),
guide = guide_axis(minor.ticks = TRUE)
)
# Secondary axis
scale_x_discrete(sec.axis = dup_axis(
name = "Counts",
breaks = seq_len(7),
labels = paste0("n = ", table(mpg$class))
))
geom_text(aes(nudge_x = sign(value) * 3, label = value))
ggplot(data, aes(x, y, fill = group)) +
geom_boxplot(position = position_dodge(preserve = "single")) +
aes(order = group)
8 direction options for facet_wrap(dir):
| dir | Start | Fill |
|---|---|---|
"lt" | top-left | left-to-right |
"tl" | top-left | top-to-bottom |
"lb" | bottom-left | left-to-right |
"bl" | bottom-left | bottom-to-top |
"rt" | top-right | right-to-left |
"tr" | top-right | top-to-bottom |
"rb" | bottom-right | right-to-left |
"br" | bottom-right | bottom-to-top |
facet_wrap(~ island, scales = "free_x", space = "free_x")
geom_point(colour = "grey", layout = "fixed_rows") # repeat in rows
geom_point(layout = NULL) # use facet vars
annotate("text", label = "X", layout = 6) # specific panel
Options: NULL, "fixed", <integer>, "fixed_cols", "fixed_rows"
geom_boxplot(
whisker.linetype = "dashed",
box.colour = "black",
median.linewidth = 2,
staplewidth = 0.5,
staple.colour = "grey50"
)
geom_violin(
quantiles = c(0.1, 0.9),
quantile.linetype = 1,
quantile.colour = "red"
)
geom_label(
aes(linetype = factor(vs), linewidth = factor(am)),
text.colour = "black",
border.colour = "blue"
)
geom_area(aes(fill = continuous_var)) # gradient (R 4.1+)
make_centroids <- function(df) {
transform(df, xend = mean(x), yend = mean(y))
}
stat_manual(geom = "segment", fun = make_centroids)
geom_line(stat = "connect") # stairstep
geom_ribbon(stat = "connect", alpha = 0.4)
# Custom connection shape
smooth <- cbind(x = seq(0, 1, length.out = 20)[-1],
y = scales::rescale(plogis(x, 0.5, 0.1)))
stat_connect(connection = smooth)
coord_cartesian(reverse = "x") # "y", "xy", "none"
coord_sf(reverse = "y")
coord_radial(reverse = "theta") # "r", "thetar", "none"
| Old | New |
|---|---|
fatten | median.linewidth / middle.linewidth |
draw_quantiles | quantiles |
geom_errorbarh() | geom_errorbar(orientation = "y") |
coord_trans() | coord_transform() |
borders() | annotation_borders() |
facet_wrap(as.table) | facet_wrap(dir) |
theme_get/set/update/replace() | get/set/update/replace_theme() |
last_plot() | get_last_plot() |
layer_data/grob/scales() | get_layer_data/grob(), get_panel_scales() |
Activates when the user asks about AI prompts, needs prompt templates, wants to search for prompts, or mentions prompts.chat. Use for discovering, retrieving, and improving prompts.
Activates when the user asks about Agent Skills, wants to find reusable AI capabilities, needs to install skills, or mentions skills for Claude. Use for discovering, retrieving, and installing skills.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.