py-maidr
Make matplotlib, seaborn, Plotly, Bokeh, plotnine, and Altair charts accessible — MAIDR (Multimodal Access and Interactive Data Representation) for Python.
Overview
py-maidr makes data visualizations accessible to blind and low-vision readers.
import maidr and your existing plotting code renders an interactive figure that
can be navigated by keyboard, heard as sonification, read on a braille
display, and described as text — the same chart in four modalities instead
of one.
Nothing about how you plot changes. py-maidr patches matplotlib and seaborn at
import time, so plt.show() produces accessible HTML instead of a static image;
Plotly, Bokeh, plotnine and Altair figures go through the same maidr.show()
entry point (Bokeh and plotnine support are experimental; install them with
pip install "maidr[bokeh]" and pip install "maidr[plotnine]"), and so do the
charts of an Excel workbook, read without Excel by
maidr.read_excel_charts("book.xlsx") (experimental), the charts of a
PowerPoint presentation or a Word document, read by
maidr.read_powerpoint_charts("deck.pptx") and
maidr.read_word_charts("report.docx") (experimental), and the training
curves, histograms and Keras model graph of a TensorBoard log directory, read without TensorFlow
by maidr.read_tensorboard_scalars("logs"),
maidr.read_tensorboard_distributions("logs"),
maidr.read_tensorboard_histograms("logs"),
maidr.read_tensorboard_hparams("logs"),
maidr.read_tensorboard_pr_curves("logs"),
maidr.read_tensorboard_profile("logs"),
maidr.read_tensorboard_projector("logs") and
maidr.read_tensorboard_graph("logs"), or in a maidr tab of
TensorBoard itself with pip install "maidr[tensorboard]" (experimental). A Keras model's
training curves are drawn by maidr.keras.plot_history(history), or kept up
to date while it trains by maidr.keras.MaidrCallback, and its layers by
maidr.keras.plot_model(model) (experimental). The
training curves of Weights & Biases runs are read by
maidr.read_wandb_history("wandb"), from the runs' own files with no account
or network, and those of MLflow runs by maidr.read_mlflow_metrics(runs),
which maidr.log_mlflow_chart() can store back in a run for the MLflow UI to
show (both experimental). It works in a plain script, a Jupyter notebook,
Quarto, Shiny, Streamlit, and Gradio.
Quickstart
import matplotlib.pyplot as plt
import seaborn as sns
import maidr # the whole integration
penguins = sns.load_dataset("penguins")
fig, ax = plt.subplots()
sns.barplot(x="species", y="body_mass_g", data=penguins, ax=ax)
maidr.show(fig)
maidr.save_html(fig, "penguins.html") writes the same plot to a standalone HTML
file instead of displaying it. Because importing maidr also activates its
matplotlib backend, a plain plt.show() renders accessible output too.
What is supported
| Plotting libraries | matplotlib, seaborn (including seaborn.objects), Plotly, Bokeh [experimental], plotnine [experimental], Altair — plus mplfinance for financial charts (candlestick, volume, moving averages) |
| Files | the charts of an Excel workbook (.xlsx, .xlsm) [experimental]; the charts of a PowerPoint presentation (.pptx) or a Word document (.docx) [experimental]; the training curves, histograms, PR curves, hyperparameter sweeps, embeddings, profiles and the Keras model graph of a TensorBoard log directory (Keras, TensorFlow, PyTorch) [experimental] |
| Model training | the training curves of a Keras model, from model.fit or live while it trains, a classifier's confusion matrix and PR curve, and the model's layer graph [experimental]; the training curves of Weights & Biases runs, online or offline, and of MLflow runs, and an accessible chart stored in an MLflow run [experimental] |
| Environments | Python scripts, Jupyter, Quarto, Shiny for Python, Streamlit, Gradio |
| Plot types | 44 — see Plot Type Stability for which fifteen are settled and which twenty-nine are experimental; the docs mark each experimental type [experimental] after its name |
Plot types not yet supported fall back to a static image with a warning, so a plot is never lost.
Keyboard shortcuts
Press Tab (or click) to focus a rendered plot, move between data points with the arrow keys, and toggle B braille, T text, S sonification, and R review mode. Four global shortcuts open maidr's own interfaces:
| Action | Windows / Linux | macOS |
|---|---|---|
| Show or hide the keyboard shortcut help | Ctrl + / | Command + / |
| Open the command palette listing every available command | Ctrl + Shift + P | Command + Shift + P |
| Open the AI chat (requires your own API key, entered in Settings, or a local Ollama server) | Shift + / (that is, ?) | Shift + / (?) |
| Open Settings | Ctrl + , | Command + , |
The full list, including autoplay, label announcements, and layer switching, is in the maidr controls documentation.
Install and Upgrade
# install the latest release from PyPI
pip install -U maidr
# or install the development version from GitHub
pip install -U git+https://github.com/xability/py-maidr.git
User Guide
Please visit the user guide page.
Offline and Restricted-Network Use
py-maidr loads its JavaScript from a CDN by default, and resolves the current published version so browsers cannot serve a stale cached copy. That costs one bounded outbound request, the first time a plot is rendered. import maidr itself makes no request.
If you work air-gapped, behind a proxy, or in CI:
export MAIDR_CDN_VERSION=bundled # serve the version in this wheel, no lookup
export MAIDR_USE_CDN=false # or skip the CDN entirely
bundled is usually the best choice for restricted networks: it emits an immutable
CDN URL — so browser caching still works correctly — without contacting anything.
It is also the only one of the two that covers Altair charts: the Altair adapter
has no offline path and always references the CDN, so MAIDR_USE_CDN=false does not
apply to it, while MAIDR_CDN_VERSION=bundled still removes the lookup.
A DotPad tactile display needs the
vendor's SDK, which maidr.js fetches from jsDelivr the first time a device is
connected rather than bundling its 14 MB braille engine. To take that offline too,
download the pinned copy once and every use_cdn=False document carries it in
its lib/ folder:
maidr.download_dotpad_sdk() # once; ~14 MB into a per-user cache
maidr.save_html(fig, "chart.html", use_cdn=False)
The bundled maidr.js does not carry its non-English locale packs. A document that
runs it points it at the packs of the same version on jsDelivr, so a reader whose
browser asks for, say, Korean fetches that one pack when online and hears English
when not. For strictly no network, and English only, turn that off:
export MAIDR_LOCALE_BASE_URL="" # or maidr.set_locale_base_url(False)
See Offline Use and the JavaScript Bundle for the full set of options.
Example Code
We provide some example code for using py-maidr with matplotlib, seaborn, Jupyter Notebook, Quarto, Shiny, and Streamlit.
Shiny support requires the optional extra pip install "maidr[shiny]", which
provides output_maidr() and @render_maidr in maidr.widget.shiny.
Streamlit support requires pip install "maidr[streamlit]", which provides
render_maidr() and maidr_html() in maidr.widget.streamlit.
Using with AI coding agents
If an AI coding agent (Claude Code, Codex, Cursor, GitHub Copilot, and others) writes your plotting code, install the
maidr skill with npx skills add xability/maidr-skill. The agent then
routes every matplotlib, seaborn, Plotly, Bokeh, or Altair chart through py-maidr, verifies the output, and hands back an
accessible HTML file or chat artifact instead of a static image.
Contributing
Bug reports, plot types and documentation fixes are all welcome — see CONTRIBUTING.md for how to set up a development environment and shape a change, and CONDUCT.md for our code of conduct.
License
GPL-3.0-or-later. See LICENSE.
Metadata
Release files for maidr 1.27.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| maidr-1.27.0.tar.gz | 1.7 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| maidr-1.27.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 3.7 MB
Release files / maidr-1.27.0.tar.gz
| Download URL | maidr-1.27.0.tar.gz |
|---|---|
| Size | 1.7 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9c4d58fce96e4989f5b01d06843491c7aa41528423df6414709996ecd460eca7
|
|
BLAKE2b-256 checksum How to use checksums |
46f7206d7552fc275ad86aeb1f9d8e6eaf254c7177455d1607cbcff080e5a91e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / maidr-1.27.0-py3-none-any.whl
| Download URL | maidr-1.27.0-py3-none-any.whl |
|---|---|
| Size | 1.9 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8d4606316b2dde2f464b6d27d7246d3f24211497a5afd8393d3c2628b7b6f00e
|
|
BLAKE2b-256 checksum How to use checksums |
c6f3905c6c3f32bf959be7679aab2665370b36c29349dd99bd7156fc61a47f67
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|