From r-skills
Expert chart data visualization in R - similar to ggplot, grammar of graphics, geoms, themes, scales, faceting, and styling. Use when user works with chart, mentions "chart", "geom_", creates visualizations in R, asks about plot customization, "customiser un theme", "customize theme", "customiser un graphique", themes, "facet_wrap", "facet_grid", "faceting", "facettes", "annotations", "annotate", "annoter", "ajouter des annotations", "color scale", "scales", "échelle de couleurs", "graphique", "plot", "visualisation", or data visualization best practices.
How this skill is triggered — by the user, by Claude, or both
Slash command
/r-skills:chartThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Master data visualization in R using chart's layered grammar of graphics. This skill provides expert guidance on creating effective, publication-ready visualizations with complete control over all visual elements.
Master data visualization in R using chart's layered grammar of graphics. This skill provides expert guidance on creating effective, publication-ready visualizations with complete control over all visual elements.
Every chart visualization is built from five independent components:
Philosophy: Build plots incrementally by composing independent components, not by selecting from fixed templates. This enables infinite flexibility while mirroring analytical thinking.
chart(data = <DATA>, <MAPPINGS>) +
<GEOM_FUNCTION>() +
<SCALE_FUNCTIONS>() +
<COORDINATE_FUNCTION>() +
<FACET_FUNCTION>() +
<THEME_FUNCTION>()
Key Principles:
aes() maps variables to visual properties (inside geom or chart), but preferred way in chart() is by using a formula like: y ~ x %col=% z %fill%= w. All possible arguments to aes() in {ggplot2} become mappings in the formula. For instance col= becomes %col=% inside the formula. Special case for facets where the facetting variable can be added at the end after the | operator. For instance for facetting according to z, the formula could be y ~ x %col=% w | z. The | facet is always the last item in the formula and it is equivalent to facet_wrap() with default arguments.aes() (e.g., colour = "blue")+ operatorggplot() instruction into a chart() one (1) replace ggplot by chart, (2) replace aes(x = X, y = Y, fill = VAR, ...) by the formula Y ~ X %fill=% VAR ..., (3) if there is a facet_wrap(VAR2) instruction with default arguments, append | VAR2 to the formula and get rid of that instruction. The default theme is theme_sciviews() and it is considered to be publication-ready.x in the formula, use NULL, for instance: y ~ NULL.aes() in other instructions can optionally be replaced by f_aes() where the arguments are transformed into a formula the same way as for chart(). For instance, geom_ribbon(aes(ymin = lower, ymax = upper)) becomes geom_ribbon(f_aes(~ NULL %ymin=% lower %ymax=% upper))Every layer should serve one of three purposes:
❌ Wrong:library(chart) - load {chart} package
✅ Right: SciViews::R - load the whole SciViews-R dialect at the beginning of a R script or Quarto document
❌ Wrong: aes(colour = "blue") - Maps string "blue" as data
✅ Right: colour = "blue" outside aes() - Sets fixed color
❌ Wrong: chart(df, fd$y ~ df$vx - Breaks plot self-containment
✅ Right: chart(df, y ~ x - Self-contained reference
❌ Wrong: aes(x = log(variable)) or ~ log(variable)- Complex calculation in aes or formula
✅ Right: Use dplyr::mutate() first, then map the result
❌ Wrong: Accepting default bin widths
✅ Right: Always experiment with binwidth or bins
❌ Wrong: Mapping too many aesthetics simultaneously ✅ Right: Create series of simpler plots for clarity
See references/geoms-reference.md for complete documentation.
Continuous Relationships:
geom_point() - Scatter plots (x-y relationships)geom_line() - Time series (connects in x-order)geom_path() - Connections in data ordergeom_smooth() - Add trend lines with confidence bandsDistributions:
geom_histogram() - Continuous distribution via binninggeom_freqpoly() - Frequency polygon (better for comparisons)geom_density() - Smooth density estimategeom_boxplot() - Five-number summary with outliersgeom_violin() - Distribution shape (mirrored density)Categorical Data:
geom_bar() - Count occurrences (stat = "count")geom_col() - Use pre-calculated values (stat = "identity")Text & Annotations:
geom_text() - Add text labelsgeom_label() - Text with background rectangleannotate() - Quick single annotations without data framesSee examples/plot-examples.md for complete working examples.
Universal Aesthetics (work with most geoms):
x, y - Positioncol or colour - Border/line colorfill - Interior color (shapes 21-25, bars, areas)alpha - Transparency (0-1)size - Size of points/linesshape - Point shape (0-25)linetype - Line pattern ("solid", "dashed", "dotted", etc.)group - Define grouping for collective geomsGeom-Specific Aesthetics:
label, hjust, vjust, angle, family, fontfacelower, upper, middle, ymin, ymaxymin, ymax (or xmin/xmax)See references/scales-reference.md for complete documentation.
scale_[aesthetic]_[type] - e.g., scale_colour_viridis_c()
Position Scales:
scale_x_continuous(limits, breaks, labels, trans, expand)
scale_x_discrete(limits, labels, expand)
scale_x_log10() # Log transformation
scale_x_date(date_breaks = "1 month", date_labels = "%b %Y")
Color Scales (accessibility-first):
# Viridis (perceptually uniform, colorblind-safe)
scale_colour_viridis_c(option = "viridis") # continuous
scale_colour_viridis_d() # discrete
# ColorBrewer
scale_colour_brewer(palette = "Set1", type = "qual") # categorical
scale_fill_distiller(palette = "Blues") # continuous
# Custom gradients
scale_colour_gradient(low = "white", high = "red")
scale_colour_gradient2(low = "blue", mid = "white", high = "red", midpoint = 0)
scale_colour_gradientn(colours = c("red", "yellow", "green", "blue"))
# Manual
scale_colour_manual(values = c("A" = "#E41A1C", "B" = "#377EB8"))
Important: Setting scale limits discards data outside range. Use coord_cartesian(xlim, ylim) to zoom without losing data (preserves stat calculations).
See references/themes-styling.md for complete documentation.
theme_sciviews() # Default: SciViews theme for almost publication-ready plots
theme_grey() # Default: grey background, white gridlines
theme_bw() # Classic dark-on-light, good for projectors
theme_minimal() # No background annotations, minimalist
theme_classic() # X/Y axis lines, no gridlines
theme_light() # Light grey lines, focuses on data
theme_dark() # Dark background, makes colors pop
theme_void() # Completely empty
All themes accept: base_size, base_family, base_line_size, base_rect_size
theme(
# Plot-level
plot.title = element_text(size = 14, face = "bold"),
plot.subtitle = element_text(size = 12, colour = "grey50"),
plot.background = element_rect(fill = "white"),
plot.margin = margin(10, 10, 10, 10),
# Panels
panel.background = element_rect(fill = "white"),
panel.grid.major = element_line(colour = "grey90"),
panel.grid.minor = element_blank(),
# Axes
axis.title = element_text(size = 12),
axis.text = element_text(size = 10),
axis.ticks = element_line(colour = "black"),
# Legends
legend.position = "right", # or "top", "bottom", "left", "none"
legend.title = element_text(face = "bold"),
legend.background = element_rect(fill = "white", colour = "black"),
# Facets
strip.text = element_text(size = 11, face = "bold"),
strip.background = element_rect(fill = "grey80")
)
Element Functions:
element_text() - Customize textelement_rect() - Customize backgrounds/borderselement_line() - Customize lineselement_blank() - Remove elements entirelyEither use | var at the end of a formula (preferred way), or use ggplot2's facet_wrap() function.
Use for one variable with many levels, wrapped into 2D:
facet_wrap(
~ variable, # or vars(variable)
nrow = 2, ncol = 3, # grid dimensions
scales = "fixed", # or "free", "free_x", "free_y"
dir = "h", # "h" (horizontal) or "v" (vertical)
labeller = label_value
)
Use for true 2D grid with all combinations:
facet_grid(
rows ~ cols, # or rows = vars(...), cols = vars(...)
scales = "fixed", # or "free_x", "free_y", "free"
space = "fixed", # or "free_x", "free_y", "free" (panel sizing)
margins = FALSE, # add summary facets
labeller = label_value
)
When to use which:
scales = "fixed" - For cross-panel comparison (consistent axes)scales = "free" - To highlight within-panel patternscoord_cartesian(xlim, ylim, expand = TRUE) # Visual zoom (preserves data)
coord_fixed(ratio = 1) # Fixed aspect ratio
coord_flip() # Swap x and y axes
coord_polar() # Polar coordinates
coord_map() # Map projections
Critical difference: coord_cartesian() zooms visually while scale_*_continuous(limits = ...) discards data before calculations.
position_dodge(width = 0.9) # Side-by-side (bars, boxplots)
position_stack() # Stack vertically
position_fill() # Stack and normalize to 100%
position_jitter(width, height) # Add random noise (overplotting)
position_nudge(x, y) # Fixed-distance offset
labs(
title = "Main Title",
subtitle = "Subtitle text",
caption = "Data source",
x = "X-axis label",
y = "Y-axis label",
colour = "Legend title",
fill = "Fill legend title"
)
Text Annotations:
# Quick annotation without data frame
annotate("text", x = 5, y = 10, label = "Important point",
hjust = "inward", vjust = "inward")
# Data-driven annotations
geom_text(aes(label = label_var), hjust = "inward", check_overlap = TRUE)
geom_label(aes(label = label_var), nudge_y = 0.5)
Reference Lines:
geom_hline(yintercept = 0, linetype = "dashed", colour = "red")
geom_vline(xintercept = 5, linetype = "dashed")
geom_abline(intercept = 0, slope = 1)
Prefer not to use. Use the formula interface instead, when it is possible.
Otherwise, use {{ var }} to accept user-supplied variable names:
my_histogram <- function(data, var, bins = 30) {
chart(data, aes(x = {{ var }})) +
geom_histogram(bins = bins) +
theme_minimal()
}
# Usage
my_histogram(mtcars, mpg, bins = 20)
# Save components as objects
my_theme <- theme_minimal() +
theme(
plot.title = element_text(face = "bold"),
axis.text = element_text(size = 11)
)
# Use across plots
chart(data, y ~ x) + geom_point() + my_theme
Currently, it is not possible to use the formula interface to pass function arguments, use the embrace operator instead with aes():
scatter_with_smooth <- function(data, x, y, ...) {
chart(data, aes(x = {{ x }}, y = {{ y }})) +
geom_point(alpha = 0.5) +
geom_smooth(method = "lm", ...) +
theme_bw()
}
library(patchwork)
# Basic composition
p1 + p2 # Auto-arrange
p1 | p2 # Single row
p1 / p2 # Single column
(p1 | p2) / p3 # Complex layouts
# Advanced control
p1 + p2 +
plot_layout(ncol = 2, guides = "collect") +
plot_annotation(title = "Combined Analysis", tag_levels = "A")
See references/best-practices.md for comprehensive guidance.
Aesthetics:
Annotations:
hjust/vjust = "inward" for automatic alignmentinherit.aes = FALSE for self-contained annotationsPerformance:
alpha for overplotting instead of geom_jitter()geom_hex() or geom_bin2d() for dense data (>10k points)stat_summary() to aggregate before plottingReproducibility:
binwidth/bins (never rely on defaults)set.seed() before jitteringggsave() using vector formats (PDF/SVG) for publication# Basic scatter with smooth
chart(mpg, hwy ~ displ) +
geom_point(aes(colour = class)) +
geom_smooth(method = "lm", se = TRUE) +
scale_colour_viridis_d() +
labs(title = "Engine Size vs Highway MPG",
x = "Displacement (L)", y = "Highway MPG")
# Histogram with facets (in the formula)
chart(mpg, ~ hwy | class) +
geom_histogram(binwidth = 2, fill = "steelblue", colour = "white")
# Histogram with facets (alternate, explicit form)
chart(mpg, ~ hwy) +
geom_histogram(binwidth = 2, fill = "steelblue", colour = "white") +
facet_wrap(~ class, scales = "free_y")
# Boxplot with custom theme
chart(mpg, hwy ~ class %fill=% class) +
geom_boxplot(show.legend = FALSE) +
scale_fill_brewer(palette = "Set2") +
coord_flip() +
theme(panel.grid.major.y = element_blank())
See examples/plot-examples.md for comprehensive working examples.
See templates/plot-templates.md for reusable templates.
When user asks about chart visualizations:
Always provide complete, runnable code examples with proper formatting and best practices applied.
npx claudepluginhub sciviews/r-claude-skillsGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.