diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 4edc581..1bbc3e1 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -52,7 +52,8 @@ "./r-lib/lifecycle", "./r-lib/r-package-development", "./r-lib/r-cli-app", - "./r-lib/mirai" + "./r-lib/mirai", + "./alt-text" ] }, { @@ -74,7 +75,8 @@ "skills": [ "./brand-yml", "./quarto/quarto-authoring", - "./quarto/quarto-alt-text" + "./quarto/quarto-alt-text", + "./alt-text" ] } ] diff --git a/README.md b/README.md index f882fac..a3c834e 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ R package development skills for working with the r-lib ecosystem and modern R p - **[lifecycle](./r-lib/lifecycle/)** - Manage R package lifecycle according to tidyverse principles using the lifecycle package, covering deprecation workflows, function/argument renaming, superseding, and experimental stages - **[r-package-development](./r-lib/r-package-development/)** - R package development with devtools, testthat, and roxygen2, covering key commands, coding conventions, testing, documentation, and NEWS.md practices - **[mirai](./r-lib/mirai/)** - Async, parallel, and distributed computing in R using mirai, covering explicit dependency passing, daemon setup, parallel mapping with `mirai_map()`, Shiny integration, remote/HPC launchers, and migration from future/parallel +- **[pkgdown-alt-text](./r-lib/pkgdown-alt-text/)** - Add accessible alt text to all images and plots in a pkgdown site, covering vignette code chunks (`fig.alt`), static markdown images, multi-plot chunks, and Quarto vignettes ### Shiny diff --git a/alt-text/SKILL.md b/alt-text/SKILL.md new file mode 100644 index 0000000..433c74a --- /dev/null +++ b/alt-text/SKILL.md @@ -0,0 +1,190 @@ +--- +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. +``` diff --git a/alt-text/references/pkgdown.md b/alt-text/references/pkgdown.md new file mode 100644 index 0000000..cf8fe85 --- /dev/null +++ b/alt-text/references/pkgdown.md @@ -0,0 +1,152 @@ +# 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 `![](path)` | Yes — fill in the bracket | +| `README.Rmd` / `README.md` | HTML `` 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: ![](path) +grep -rn "!\[\](" vignettes/ README.md README.Rmd + +# All markdown images — review each for descriptive alt text +grep -rn "!\[" vignettes/ README.md README.Rmd + +# HTML tags — check each for a non-empty alt attribute +grep -rn "` tags at the top of +`README.Rmd`. Check that the `alt` attribute is present and descriptive: + +```html + + + + +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 `![](path)` images, fill in the bracket: + +```markdown + +![](man/figures/logo.png) + + +![A hexagonal logo with a blue background and white text reading 'pkgdown'.](man/figures/logo.png) +``` + +For purely decorative images, leave the bracket empty intentionally and add a +comment: + +```markdown + +![](man/figures/decorative-banner.png) +``` + +## 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. +``` diff --git a/alt-text/references/quarto.md b/alt-text/references/quarto.md new file mode 100644 index 0000000..4ee83c0 --- /dev/null +++ b/alt-text/references/quarto.md @@ -0,0 +1,56 @@ +# 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. diff --git a/quarto/quarto-alt-text/SKILL.md b/quarto/quarto-alt-text/SKILL.md index 35e0968..67cb135 100644 --- a/quarto/quarto-alt-text/SKILL.md +++ b/quarto/quarto-alt-text/SKILL.md @@ -1,204 +1,20 @@ --- name: quarto-alt-text description: > - Generate accessible alt text for data visualizations in Quarto documents. Use - when the user wants to add, improve, or review alt text for figures in .qmd - files. Triggers for requests about accessibility, figure descriptions, fig-alt, - screen reader support, or making Quarto documents more accessible. + Generate accessible alt text for data visualizations in Quarto documents. + Use when the user wants to add, improve, or review alt text for figures in + .qmd files. metadata: author: Emil Hvitfeldt (@emilhvitfeldt) - version: "1.0" + version: "2.0" license: MIT --- -# Write Chart Alt Text +This skill has moved. Use the `alt-text` skill instead, which covers both +Quarto documents and pkgdown sites. -Generate accessible alt text for data visualizations in this project. +If you have the `quarto` plugin installed, reinstall it to get the updated skill: -ARGUMENTS -- label: (optional) specific fig- label to generate alt text for -- file: (optional) specific .qmd file to process - -## Instructions - -When invoked, analyze the figure(s) and generate alt text following these guidelines: - -### 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's shown -3. **Key insight** - The pattern or takeaway (often found in surrounding text) - -### Relationship to fig-cap - -Read the `fig-cap` first. The alt text should **complement, not duplicate** it: -- If caption states the insight, alt text can focus on describing the visual structure -- If 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 chapter's point - -**Exclude:** -- "Image of..." or "Chart showing..." (screen readers announce this) -- Decorative color descriptions (unless color encodes data) -- Information already in fig-cap -- 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 fig-cap -- [ ] 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, e.g., "unlike PCA, these are not orthogonal"]. -``` - -**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]. -``` - -## Workflow - -### Finding Figures - -To find all figure chunks in the project: -```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-" numeric-splines.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 three-part structure (type → data → insight) -5. **Verify** - Check against quality checklist - -## 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" - -**fig-cap:** "Normalization doesn't make data more normal. The green curve indicates the density of the unit normal distribution." - -**Good alt text:** ``` -#| fig-alt: | -#| 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. +/plugin install https://github.com/posit-dev/skills .claude-plugin/marketplace.json#quarto ``` diff --git a/r-lib/README.md b/r-lib/README.md index 44e1252..34e50b6 100644 --- a/r-lib/README.md +++ b/r-lib/README.md @@ -62,12 +62,20 @@ Comprehensive guidance for async, parallel, and distributed computing in R using - [mirai package documentation](https://mirai.r-lib.org/) - [mirai GitHub repository](https://github.com/r-lib/mirai) +### `pkgdown-alt-text` + +Add accessible alt text to all images and plots in a pkgdown site. Use when auditing or improving accessibility across vignettes, articles, and README files in an R package. Covers finding missing alt text (using pkgdown's built-in warnings), writing effective descriptions using the three-part formula, adding `fig.alt` to Rmd/Qmd chunks (including multi-plot chunks), and adding alt text to static markdown images. + +**Organization**: Single SKILL.md with a step-by-step workflow: find → generate → add → verify. References the `quarto-alt-text` skill for alt text writing guidelines and chart-type templates (same principles apply). + +**Resources**: This skill synthesizes guidance from: +- [pkgdown: Accessibility](https://pkgdown.r-lib.org/articles/accessibility.html) + ## Potential Skills This category could include skills for: - Package development workflows (usethis, devtools) -- Documentation with roxygen2 and pkgdown - Package structure and organization - Dependencies and NAMESPACE management - R CMD check and CRAN submission