Skip to contents
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

  • Palettespalette_list() enumerates discrete, diverging, and sequential palettes with WCAG metadata. palette(), palette_div(), palette_seq() resolve hex codes for matplotlib / plotly.
  • Plotlylayout() applies accessible chrome, fonts, and colorway. plotly_sequences() audits plotly’s built-in discrete colorways.
  • Document-level checkscheck_headings() and check_readability() flag heading-skip and reading-level issues in .qmd / .Rmd / .md files.
  • Alpha guidancealpha_presets() returns sensible alpha values for overlay layers; verify composited contrast with check_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 criterion value to wcag_url() for the deep link.
  • ADA web guidance