import a11yviz
import matplotlib.pyplot as plt
import pandas as pd
from itables import show
from sklearn.datasets import load_iris
_iris = load_iris(as_frame=True)
iris = _iris.frame
iris["species"] = _iris.target_names[iris["target"]]
dt_options = dict(
buttons=["copy", "csv", "excel", "pdf"],
pageLength=10,
scrollX=True,
autoWidth=True,
classes="compact stripe hover",
)Example
with plt.rc_context({"font.size": 8}):
fig, ax = plt.subplots(figsize=(6, 4))
for sp, sub in iris.groupby("species"):
ax.scatter(sub["sepal length (cm)"], sub["sepal width (cm)"],
label=sp)
ax.legend();
Audit reveals the gaps
audit() returns one row per WCAG criterion with a status field. The table below filters to actionable rows (status = "todo" or "ok") — the items where the chart needs human attention.
| status | meaning |
|---|---|
ok |
check passes automatically |
todo |
needs user action |
applied |
handled by theme() / palette() / layout()
|
manual |
requires human review (e.g., reflow at 320 px) |
css |
covered by css() stylesheet |
doc |
document-level check; run check_headings() separately |
show(pd.DataFrame([r for r in a11yviz.audit(fig) if r["status"] in ("todo", "ok")]),
table_id="audit-example", **dt_options)| Loading ITables v2.7.3 from the internet... (need help?) |
Two actionable items come back as todo:
- WCAG 2.1: alt text missing
- WCAG 2.1: redundant group encoding (color only)
Improved
fig2, ax2 = plt.subplots(figsize=(6, 4))
cols = a11yviz.palette("dark2_8")
markers = ["o", "s", "^"]
for i, (sp, sub) in enumerate(iris.groupby("species")):
ax2.scatter(sub["sepal length (cm)"], sub["sepal width (cm)"],
label=sp, color=cols[i], marker=markers[i])
ax2.set_xlabel("Sepal length (cm)")
ax2.set_ylabel("Sepal width (cm)")
ax2.legend(title="Species")
fig2 = a11yviz.alt_text(fig2,
"Scatter of iris sepal width vs length by species; setosa forms a distinct cluster at short, wide sepals.");
Four accessibility wins from defaults plus a few extra lines: marker=markers[i] encodes group via shape (Success Criterion 1.4.1), palette("dark2_8") swaps in colors that clear 3:1 on white (Success Criterion 1.4.11; matplotlib’s default tab10 orange and green sit below), set_xlabel/set_ylabel name the axes (Success Criterion 2.4.6), and alt_text() attaches the screen-reader description (Success Criterion 1.1.1).
Audit again
show(pd.DataFrame([r for r in a11yviz.audit(fig2) if r["status"] in ("todo", "ok")]),
table_id="audit-improved", **dt_options)| Loading ITables v2.7.3 from the internet... (need help?) |
All actionable checks come back as ok.
WCAG rubric
rubric() is the per-criterion reference: name, level, threshold, and the a11yviz function that addresses each. Same criterion field as audit(), so the two join cleanly.
show(pd.DataFrame(a11yviz.rubric()), table_id="rubric", **dt_options)| Loading ITables v2.7.3 from the internet... (need help?) |
Accessible CSS
css() returns the path to a stylesheet that handles dark-mode tooltips, keyboard focus rings, table styling, and responsive layout.
import os
os.path.basename(str(a11yviz.css()))'a11yviz.css'
More features
-
Palettes —
palette_list()enumerates discrete, diverging, and sequential palettes with WCAG metadata.palette(),palette_div(),palette_seq()resolve hex codes for matplotlib / plotly. -
Plotly —
layout()applies accessible chrome, fonts, and colorway.plotly_sequences()audits plotly’s built-in discrete colorways. -
Document-level checks —
check_headings()andcheck_readability()flag heading-skip and reading-level issues in.qmd/.Rmd/.mdfiles. -
Alpha guidance —
alpha_presets()returns sensible alpha values for overlay layers; verify composited contrast withcheck_palette(alpha=...).
See the function reference for the full API.
References
- Crameri, F., Shephard, G. E., & Heron, P. J. (2020). The misuse of colour in science communication. Nature Communications, 11, 5444.
- Nuñez, J. R., Anderton, C. R., & Renslow, R. S. (2018). Optimizing colormaps with consideration for color vision deficiency to enable accurate interpretation of scientific data. PLoS ONE, 13(7), e0199239.
-
WCAG 2.1 specification — pass any
criterionvalue towcag_url()for the deep link. - ADA web guidance