alt-text
Generate and improve accessible alt text for data visualizations and images in R packages and Quarto documents. Use when the user wants to add, improve, or audit alt text for figures in a pkgdown site or .qmd files. Activate for requests that mention fig-alt, fig.alt, figure desc
Install
npx skills add https://github.com/posit-dev/skills/tree/main/alt-text
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install posit-dev-skills@llmmart
git clone https://github.com/posit-dev/skills.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole posit-dev/skills collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Write Accessible Alt Text
Generate accessible alt text for data visualizations and images in this project.
ARGUMENTS
- label: (optional) specific figure label or chunk to target
- file: (optional) specific file to process
Detect project type
Before proceeding, identify the project context and read the relevant reference.
Check for a _pkgdown.yml file in the project root to detect a pkgdown site:
ls _pkgdown.yml 2>/dev/null && echo "pkgdown" || echo "not pkgdown"
- pkgdown site (
_pkgdown.ymlpresent) → readreferences/pkgdown.md - Quarto documents (no
_pkgdown.yml,.qmdfiles present) → readreferences/quarto.md
If the context is still ambiguous, ask the user which format they are working in.
Key advantage: source code access
Unlike typical alt text scenarios where you only see an image, we have access to the code that generates each chart. Use this to extract precise details:
From plotting code:
- Variable mappings → exact variable names for axes
- Color/fill mappings → what color encodes
- Plot type functions → scatter, histogram, line chart, etc.
- Trend lines or fitted curves → overlaid statistical fits
- Faceting/subplots → number of panels and what varies
- Color scales → encoding scheme (sequential, diverging, categorical)
- Axis labels and titles → customized labels
From data generation code:
- Random distributions → expected distribution shape
- Transformations → what was done to data
- Feature engineering → preprocessing applied
- Filtering/subsetting → what subset is shown
From surrounding prose:
- Text before/after the chunk explains the purpose and key insight
- Chapter context tells you what the figure is meant to teach
- This is often the best source for the "key insight" part of alt text
Three-part structure (Amy Cesal's formula)
- Chart type — first words identify the format
- Data description — axes, variables, what is shown
- Key insight — the pattern or takeaway (often found in surrounding text)
Relationship to captions
Read the caption (fig-cap, fig.cap) first. Alt text should complement, not duplicate it:
- If the caption states the insight, alt text can focus on describing the visual structure
- If the caption is generic, alt text should include the key insight
- Together they should give a complete understanding
Content rules
Include:
- Chart type as first words
- Axis labels and what they represent
- Specific values/ranges when code reveals them (e.g., "peaks between 25–50")
- Number of panels/facets
- What color/size encodes if used
- The key pattern that supports the surrounding point
Exclude:
- "Image of…" or "Chart showing…" (screen readers announce this)
- Decorative color descriptions (unless color encodes data)
- Information already in the caption
- Implementation details (package names, function internals)
Length guidelines
| Complexity | Sentences | When to use |
|---|---|---|
| Simple | 2–3 | Single geom, no facets, obvious pattern |
| Standard | 3–4 | Multiple geoms or color encoding |
| Complex | 4–5 | Faceted, multiple overlays, nuanced insight |
Quality checklist
- Starts with chart type (Scatter chart, Histogram, Faceted bar chart, etc.)
- Names the axis variables
- Includes specific values/ranges from code when informative
- States the key insight from surrounding prose
- Complements (not duplicates) the caption
- Would make sense to someone who cannot see the image
- Uses plain language (avoid jargon like "geom" or "aesthetic")
Template patterns
Scatter chart:
Scatter chart. [X var] along the x-axis, [Y var] along the y-axis.
[Shape: linear/curved/clustered]. [Specific pattern, e.g., "peaks when X is 25–50"].
[Any overlaid fits or annotations].
Histogram:
Histogram of [variable]. [Shape: right-skewed/bimodal/normal/uniform].
[If transformed: "after [transformation], the distribution [result]"].
[Notable features: outliers, gaps, multiple modes].
Bar chart:
Bar chart. [Categories] along the x-axis, [measure] along the y-axis.
[Key comparison: which is highest/lowest, relative differences].
[Pattern: increasing/decreasing/grouped].
Tile/raster chart:
Tile chart [or heatmap]. [Row variable] along the y-axis, [column variable] along the x-axis.
Color encodes [what value]. [Pattern: where values are high/low].
[If faceted: "N panels showing [what varies]"].
Faceted chart:
Faceted [chart type] with [N] panels, one per [faceting variable].
[What's constant across panels]. [What changes/varies].
[Key comparison or insight across panels].
Correlation heatmap:
Correlation [matrix/heatmap] of [what variables]. [Arrangement].
[Overall pattern: mostly positive/negative/mixed].
[Notable clusters or strong/weak pairs].
[If relevant: contrast with expected behavior].
Before/after comparison:
[N] [chart type]s arranged [vertically/in grid]. [Top/Left] shows [original].
[Bottom/Right] shows [transformed]. [Key difference/similarity].
[If overlay: "[color] curve shows [reference]"].
Line chart with overlays:
[Line/Scatter] chart with overlaid [fits/curves]. [Axes].
[Number] of [lines/fits] shown: [list what each represents].
[Which fits well vs. poorly and why].
Example
Code context:
plotting_data |>
ggplot(aes(value)) +
geom_histogram(binwidth = 0.2) +
facet_grid(name~., scales = "free_y") +
geom_line(aes(x, y), data = norm_curve, color = "green4")
Surrounding prose says: "Normalization doesn't make data more normal"
Caption: "Normalization doesn't make data more normal. The green curve indicates the density of the unit normal distribution."
Good alt text:
Faceted histogram with two panels stacked vertically. Top panel shows
original data with a bimodal distribution. Bottom panel shows the same
data after z-score normalization, retaining the bimodal shape. A green
normal distribution curve overlaid on the bottom panel clearly does not
match the data, demonstrating that normalization preserves distribution
shape rather than creating normality.
Files (skills)
-
references
-
pkgdown.md 4.7 KB
# Alt Text in pkgdown Sites This reference covers how to find images and add alt text across a pkgdown site. ## Where images appear | Location | Image type | Can have alt text? | |----------|------------|-------------------| | `vignettes/*.Rmd` or `vignettes/*.qmd` | code-generated plots | Yes — `fig.alt` chunk option | | `vignettes/*.Rmd` | static images via `knitr::include_graphics()` | Yes — `fig.alt` chunk option | | `README.Rmd` / `README.md` | code-generated plots | Yes — `fig.alt` chunk option | | `README.Rmd` / `README.md` | markdown images `` | Yes — fill in the bracket | | `README.Rmd` / `README.md` | HTML `<img src=...>` tags | Yes — add `alt="..."` attribute | | `R/*.R` `@examples` | code-generated plots | **No — pkgdown limitation** | There is currently no way to add alt text to plots generated in `@examples` blocks. Focus effort on vignettes and README. ## Step 1 — Find missing alt text ### Find chunks missing fig.alt in vignettes ```bash # Find chunks that already have fig.alt (to see what's covered) grep -rn "fig\.alt\|fig-alt" vignettes/ # Find all plot-producing chunks — each one needs a fig.alt grep -rn "ggplot\|geom_\|autoplot\|include_graphics" vignettes/ ``` Compare the two lists to identify chunks with plots but no `fig.alt`. ### Find static images missing alt text ```bash # Markdown images with empty alt:  grep -rn "!\[\](" vignettes/ README.md README.Rmd # All markdown images — review each for descriptive alt text grep -rn "!\[" vignettes/ README.md README.Rmd # HTML <img> tags — check each for a non-empty alt attribute grep -rn "<img" vignettes/ README.md README.Rmd ``` Package logos are commonly written as HTML `<img>` tags at the top of `README.Rmd`. Check that the `alt` attribute is present and descriptive: ```html <!-- Missing alt --> <img src='man/figures/logo.png' align="right" height="139" /> <!-- Fixed --> <img src='man/figures/logo.png' align="right" height="139" alt="Package hex logo: a blue hexagon with the package name." /> ``` ## Step 2 — Audit quality of existing alt text When alt text already exists, leave it alone unless it has a concrete problem. Only rewrite alt text that fails one of these checks: **Relative references** — alt text must be self-contained. Fix phrases like: - "A plot identical to the one above…" → describe the plot fully - "The same data as shown above…" → name the data explicitly **Missing key information** — fix if alt text omits chart type, axis labels, or the key pattern. **Grammar and spelling errors** — alt text is read aloud by screen readers. ## Step 3 — Add fig.alt to Rmd chunks The `fig.alt` chunk option works for both code-generated plots and static images loaded with `knitr::include_graphics()`. ### Hashpipe syntax (preferred) ```r #| fig.alt: > #| Scatter chart of bill length vs. bill depth for 344 penguins #| across three species. Gentoo penguins form a distinct cluster #| at higher bill depth. Adelie and Chinstrap overlap but separate #| along the bill length axis, with Chinstrap skewing higher. plot_code_here() ``` ### Knitr chunk option syntax ````markdown ```{r penguin-scatter, fig.alt="Scatter chart of bill length vs. bill depth..."} plot_code_here() ``` ```` ### Multiple plots in one chunk When a chunk produces multiple plots, `fig.alt` accepts a vector — one string per plot, in order: ```r #| fig.alt: #| - "Histogram of bill length. Right-skewed distribution with a peak at 45–50mm." #| - "Histogram of bill depth. Bimodal distribution with peaks at 15mm and 18mm." ``` ## Step 4 — Add alt text to static markdown images For `` images, fill in the bracket: ```markdown <!-- Before -->  <!-- After -->  ``` For purely decorative images, leave the bracket empty intentionally and add a comment: ```markdown <!-- Decorative banner, intentionally no alt text -->  ``` ## Step 5 — Verify Because pkgdown does not warn about missing alt text in vignettes, verify by re-running the same grep from Step 1 and confirming every plot-producing chunk now has a `fig.alt`: ```bash # Should list every chunk with a plot grep -rn "ggplot\|geom_\|autoplot\|include_graphics" vignettes/ # Should now match the same chunks grep -rn "fig\.alt\|fig-alt" vignettes/ ``` For the home page, `build_site()` will warn if any README images are still missing alt text. ## Quarto vignettes (`.qmd`) For vignettes using Quarto format, use `fig-alt` (hyphen) instead of `fig.alt` (dot): ```r #| fig-alt: > #| Scatter chart of bill length vs. bill depth for 344 penguins #| across three species. ``` -
quarto.md 1.8 KB
# Alt Text in Quarto Documents This reference covers how to find figures and add alt text in `.qmd` files. ## Finding figures ```bash # List all figure labels with file and line number grep -n "#| label: fig-" *.qmd # Find figures in a specific file grep -n "#| label: fig-" my-document.qmd # Find a specific figure grep -rn "#| label: fig-splines-predictor-outcome" *.qmd ``` ## For each figure 1. **Locate** — use grep to find file and line number 2. **Read context** — read ~50 lines around the chunk (prose before + code + prose after) 3. **Extract details** — note `fig-cap`, ggplot code, data generation, surrounding explanation 4. **Draft alt text** — apply the three-part structure from the main skill 5. **Verify** — check against the quality checklist ## Adding fig-alt Use the hashpipe syntax inside the code chunk: ```r #| label: fig-penguin-scatter #| fig-cap: "Bill length vs. bill depth for 344 penguins." #| fig-alt: > #| Scatter chart of bill length vs. bill depth for 344 penguins #| across three species. Gentoo penguins form a distinct cluster #| at higher bill depth. Adelie and Chinstrap overlap but separate #| along the bill length axis, with Chinstrap skewing higher. plot_code_here() ``` Note: use `fig-alt` (hyphen) in `.qmd` files. ## Auditing existing alt text When alt text already exists, leave it alone unless it fails one of these checks: **Relative references** — alt text must be self-contained. Fix phrases like: - "A plot identical to the one above…" → describe the plot fully - "Much like the first one…" → stand-alone description **Missing key information** — fix if alt text omits: - Chart type as the first words - Axis labels and what they represent - The key pattern or takeaway **Grammar and spelling errors** — alt text is read aloud by screen readers.
-
-
SKILL.md 6.7 KB
--- name: alt-text description: > Generate and improve accessible alt text for data visualizations and images in R packages and Quarto documents. Use when the user wants to add, improve, or audit alt text for figures in a pkgdown site or .qmd files. Activate for requests that mention fig-alt, fig.alt, figure descriptions, or alt text in the context of an R package or Quarto document. metadata: author: Emil Hvitfeldt (@emilhvitfeldt) version: "1.0" license: MIT --- # Write Accessible Alt Text Generate accessible alt text for data visualizations and images in this project. ARGUMENTS - label: (optional) specific figure label or chunk to target - file: (optional) specific file to process ## Detect project type Before proceeding, identify the project context and read the relevant reference. Check for a `_pkgdown.yml` file in the project root to detect a pkgdown site: ```bash ls _pkgdown.yml 2>/dev/null && echo "pkgdown" || echo "not pkgdown" ``` - **pkgdown site** (`_pkgdown.yml` present) → read `references/pkgdown.md` - **Quarto documents** (no `_pkgdown.yml`, `.qmd` files present) → read `references/quarto.md` If the context is still ambiguous, ask the user which format they are working in. ## Key advantage: source code access Unlike typical alt text scenarios where you only see an image, **we have access to the code that generates each chart**. Use this to extract precise details: **From plotting code:** - Variable mappings → exact variable names for axes - Color/fill mappings → what color encodes - Plot type functions → scatter, histogram, line chart, etc. - Trend lines or fitted curves → overlaid statistical fits - Faceting/subplots → number of panels and what varies - Color scales → encoding scheme (sequential, diverging, categorical) - Axis labels and titles → customized labels **From data generation code:** - Random distributions → expected distribution shape - Transformations → what was done to data - Feature engineering → preprocessing applied - Filtering/subsetting → what subset is shown **From surrounding prose:** - Text before/after the chunk explains the **purpose** and **key insight** - Chapter context tells you what the figure is meant to teach - This is often the best source for the "key insight" part of alt text ## Three-part structure (Amy Cesal's formula) 1. **Chart type** — first words identify the format 2. **Data description** — axes, variables, what is shown 3. **Key insight** — the pattern or takeaway (often found in surrounding text) ## Relationship to captions Read the caption (`fig-cap`, `fig.cap`) first. Alt text should **complement, not duplicate** it: - If the caption states the insight, alt text can focus on describing the visual structure - If the caption is generic, alt text should include the key insight - Together they should give a complete understanding ## Content rules **Include:** - Chart type as first words - Axis labels and what they represent - Specific values/ranges when code reveals them (e.g., "peaks between 25–50") - Number of panels/facets - What color/size encodes if used - The key pattern that supports the surrounding point **Exclude:** - "Image of…" or "Chart showing…" (screen readers announce this) - Decorative color descriptions (unless color encodes data) - Information already in the caption - Implementation details (package names, function internals) ## Length guidelines | Complexity | Sentences | When to use | |------------|-----------|----------------------------------------------| | Simple | 2–3 | Single geom, no facets, obvious pattern | | Standard | 3–4 | Multiple geoms or color encoding | | Complex | 4–5 | Faceted, multiple overlays, nuanced insight | ## Quality checklist - [ ] Starts with chart type (Scatter chart, Histogram, Faceted bar chart, etc.) - [ ] Names the axis variables - [ ] Includes specific values/ranges from code when informative - [ ] States the key insight from surrounding prose - [ ] Complements (not duplicates) the caption - [ ] Would make sense to someone who cannot see the image - [ ] Uses plain language (avoid jargon like "geom" or "aesthetic") ## Template patterns **Scatter chart:** ``` Scatter chart. [X var] along the x-axis, [Y var] along the y-axis. [Shape: linear/curved/clustered]. [Specific pattern, e.g., "peaks when X is 25–50"]. [Any overlaid fits or annotations]. ``` **Histogram:** ``` Histogram of [variable]. [Shape: right-skewed/bimodal/normal/uniform]. [If transformed: "after [transformation], the distribution [result]"]. [Notable features: outliers, gaps, multiple modes]. ``` **Bar chart:** ``` Bar chart. [Categories] along the x-axis, [measure] along the y-axis. [Key comparison: which is highest/lowest, relative differences]. [Pattern: increasing/decreasing/grouped]. ``` **Tile/raster chart:** ``` Tile chart [or heatmap]. [Row variable] along the y-axis, [column variable] along the x-axis. Color encodes [what value]. [Pattern: where values are high/low]. [If faceted: "N panels showing [what varies]"]. ``` **Faceted chart:** ``` Faceted [chart type] with [N] panels, one per [faceting variable]. [What's constant across panels]. [What changes/varies]. [Key comparison or insight across panels]. ``` **Correlation heatmap:** ``` Correlation [matrix/heatmap] of [what variables]. [Arrangement]. [Overall pattern: mostly positive/negative/mixed]. [Notable clusters or strong/weak pairs]. [If relevant: contrast with expected behavior]. ``` **Before/after comparison:** ``` [N] [chart type]s arranged [vertically/in grid]. [Top/Left] shows [original]. [Bottom/Right] shows [transformed]. [Key difference/similarity]. [If overlay: "[color] curve shows [reference]"]. ``` **Line chart with overlays:** ``` [Line/Scatter] chart with overlaid [fits/curves]. [Axes]. [Number] of [lines/fits] shown: [list what each represents]. [Which fits well vs. poorly and why]. ``` ## Example **Code context:** ```r plotting_data |> ggplot(aes(value)) + geom_histogram(binwidth = 0.2) + facet_grid(name~., scales = "free_y") + geom_line(aes(x, y), data = norm_curve, color = "green4") ``` **Surrounding prose says:** "Normalization doesn't make data more normal" **Caption:** "Normalization doesn't make data more normal. The green curve indicates the density of the unit normal distribution." **Good alt text:** ``` Faceted histogram with two panels stacked vertically. Top panel shows original data with a bimodal distribution. Bottom panel shows the same data after z-score normalization, retaining the bimodal shape. A green normal distribution curve overlaid on the bottom panel clearly does not match the data, demonstrating that normalization preserves distribution shape rather than creating normality. ```
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.