Metadata-Version: 2.5
Name: maidr
Version: 1.27.0
Summary: Make matplotlib, seaborn, Plotly, Bokeh, plotnine, and Altair charts accessible through sonification, braille, and screen reader support
Project-URL: Homepage, https://py.maidr.ai/
Project-URL: Documentation, https://py.maidr.ai/
Project-URL: Repository, https://github.com/xability/py-maidr
Project-URL: Issues, https://github.com/xability/py-maidr/issues
Project-URL: Changelog, https://github.com/xability/py-maidr/blob/main/CHANGELOG.md
Author-email: JooYoung Seo <jseo1005@illinois.edu>, Saairam Venkatesh <saairam2@illinois.edu>
License-Expression: GPL-3.0-or-later
License-File: LICENSE
Keywords: a11y,accessibility,altair,blind,bokeh,braille,charts,data representation,data visualization,ggplot2,gradio,jupyter,keras,low vision,machine learning,matplotlib,mlflow,multimodal,plotly,plotnine,quarto,screen reader,seaborn,shiny,sonification,streamlit,tactile,tensorboard,visual impairments,visualization,wandb,weights and biases
Classifier: Development Status :: 5 - Production/Stable
Classifier: Framework :: Jupyter
Classifier: Framework :: Matplotlib
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: End Users/Desktop
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Adaptive Technologies
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Multimedia :: Sound/Audio
Classifier: Topic :: Scientific/Engineering :: Visualization
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Python: >=3.9
Requires-Dist: htmltools>=0.5
Requires-Dist: lxml>=5.1.0
Requires-Dist: matplotlib>=3.8
Requires-Dist: mplfinance>=0.12.10b0
Requires-Dist: numpy>=1.26
Requires-Dist: scipy>=1.11
Requires-Dist: seaborn>=0.13
Requires-Dist: wrapt<2,>=1.16.0
Provides-Extra: altair
Requires-Dist: altair>=5.0; extra == 'altair'
Provides-Extra: bokeh
Requires-Dist: bokeh>=3.1; extra == 'bokeh'
Provides-Extra: browser
Requires-Dist: playwright>=1.40; extra == 'browser'
Provides-Extra: gradio
Requires-Dist: gradio>=5.0; (python_version >= '3.10') and extra == 'gradio'
Provides-Extra: jupyter
Requires-Dist: ipykernel>=6.0.0; extra == 'jupyter'
Requires-Dist: jupyter<2,>=1.0.0; extra == 'jupyter'
Provides-Extra: mlflow
Requires-Dist: mlflow>=2.0; (python_version >= '3.10') and extra == 'mlflow'
Provides-Extra: networkx
Requires-Dist: networkx>=3.0; extra == 'networkx'
Provides-Extra: plotly
Requires-Dist: contourpy>=1.0.1; extra == 'plotly'
Requires-Dist: plotly>=5.0; extra == 'plotly'
Provides-Extra: plotnine
Requires-Dist: plotnine>=0.13; extra == 'plotnine'
Provides-Extra: shiny
Requires-Dist: shiny>=1.0; extra == 'shiny'
Provides-Extra: sklearn
Requires-Dist: scikit-learn>=1.3; extra == 'sklearn'
Provides-Extra: streamlit
Requires-Dist: streamlit>=1.30; extra == 'streamlit'
Provides-Extra: tensorboard
Requires-Dist: tensorboard>=2.12; extra == 'tensorboard'
Provides-Extra: test
Requires-Dist: altair>=5.0; extra == 'test'
Requires-Dist: bokeh>=3.1; extra == 'test'
Requires-Dist: cssselect>=1.2; extra == 'test'
Requires-Dist: flask>=3.0.0; extra == 'test'
Requires-Dist: jupyter<2,>=1.0.0; extra == 'test'
Requires-Dist: matplotlib>=3.8; extra == 'test'
Requires-Dist: plotly>=5.0; extra == 'test'
Requires-Dist: plotnine>=0.13; extra == 'test'
Requires-Dist: pytest-mock<4,>=3.12.0; extra == 'test'
Requires-Dist: pytest<8,>=7.3.2; extra == 'test'
Requires-Dist: seaborn>=0.13; extra == 'test'
Requires-Dist: shiny>=1.0; extra == 'test'
Provides-Extra: visualization
Requires-Dist: flask>=3.0.0; extra == 'visualization'
Requires-Dist: matplotlib>=3.8; extra == 'visualization'
Requires-Dist: seaborn>=0.13; extra == 'visualization'
Requires-Dist: statsmodels>=0.14.4; extra == 'visualization'
Provides-Extra: wandb
Requires-Dist: wandb>=0.16; extra == 'wandb'
Provides-Extra: wordcloud
Requires-Dist: wordcloud>=1.9; extra == 'wordcloud'
Description-Content-Type: text/markdown

<div align="center">

<img src="https://raw.githubusercontent.com/xability/maidr/refs/heads/main/docs/logo.svg" width="350px" alt="A stylized MAIDR logo, with curved characters for M A, a hand pointing for an I, the D character, and R represented in braille."/>

<hr style="color:transparent" />
<br />

[![PyPI](https://img.shields.io/pypi/v/maidr.svg)](https://pypi.org/project/maidr/)
[![Python versions](https://img.shields.io/pypi/pyversions/maidr.svg)](https://pypi.org/project/maidr/)
[![Downloads](https://img.shields.io/pepy/dt/maidr.svg)](https://pepy.tech/project/maidr)
[![CI](https://github.com/xability/py-maidr/actions/workflows/ci.yml/badge.svg)](https://github.com/xability/py-maidr/actions/workflows/ci.yml)
[![License](https://img.shields.io/pypi/l/maidr.svg)](LICENSE)
[![Docs](https://img.shields.io/badge/docs-py.maidr.ai-1f6feb.svg)](https://py.maidr.ai/)

</div>

# 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

```python
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](https://py.maidr.ai/stability.html) 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](https://maidr.ai/docs/CONTROLS.html).

## Install and Upgrade

```sh
# install the latest release from PyPI
pip install -U maidr
```

```sh
# 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](https://py.maidr.ai/) 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:

```sh
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](https://maidr.ai/docs/TACTILE_DISPLAY.html) 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:

```python
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:

```sh
export MAIDR_LOCALE_BASE_URL=""   # or maidr.set_locale_base_url(False)
```

See [Offline Use and the JavaScript Bundle](https://py.maidr.ai/#offline-use-and-the-javascript-bundle) for the full set of options.


## Example Code

We provide [some example code](https://github.com/xability/py-maidr/blob/main/example) 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](https://github.com/xability/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](CONTRIBUTING.md) for how to set up a development environment
and shape a change, and [CONDUCT.md](CONDUCT.md) for our code of conduct.

## License

GPL-3.0-or-later. See [LICENSE](LICENSE).
