py-maidr: Accessible Data Visualization for Python

Make matplotlib, seaborn, plotly, and altair charts accessible to blind and low-vision users with sonification, braille, text, and AI chat modalities.

A stylized MAIDR logo, with curved characters for M A, a hand pointing for an I, the D character, and R represented in braille.



maidr: Data Insight for All

Are you eager to uncover new insights from data science but frustrated by visual-only data representations? Do you want to make your data visualizations accessible to everyone, including those who are blind or low-vision? If so, maidr is for you!

maidr (pronounced as β€˜mader’) is an accessible framework for multimodal data representation. With maidr, blind and sighted users can easily augment data visualizations into touchable (Braille), readable (text), audible (sonification), and conversational (AI) formats.

To learn more about maidr framework and its scientific background, please visit the original maidr JavaScript engine repo.

The following summarizes the key features and design principles of Py maidr:

  1. Accessibility: maidr is designed to be accessible to both blind and sighted users from the ground up. Beyond the passive consumption level, blind users can also independently create, modify, and share data visualizations with others.

  2. Inclusivity: maidr does not pursue a special version for blind users. Instead, it provides a unified interface that supports both visual and non-visual data exploration. This way, blind and sighted users can work together on the same data science projects.

  3. Integration: maidr seamlessly integrates with the popular and mainstream data science environments (e.g., Python, pandas, and NumPy) as well as data visualization libraries in Python like matplotlib and seaborn.

  4. Unintrusiveness: maidr does not require changes to existing core data visualization code. Without needing to reconstruct an accessible version separately, you can just import maidr and call plt.show() as usual β€” maidr’s custom backend automatically renders your plots accessibly. Blind and sighted users can use and share the same visualization codebase in their shared data science projects.

  5. Synchronization: maidr treats visualization as one of the multimodal data representations and ensures that all representations (e.g., visual, tactile, textual, audible) cursor and braille routing key positions are synchronized across different modalities.

  6. Reactivity: maidr supports widely adopted reactive and interactive computing including Jupyter Notebooks, Jupyter Labs, Google Colab, Streamlit dashboard, and Shiny dashboard. maidr also supports interactive computing inside code editors, such as Visual Studio Code.

  7. Reproducibility: maidr supports the generation of accessible data visualizations as part of the reproducible data science workflow with Quarto scientific publishing system. You can easily create accessible data representations within your reproducible reports, website blogs, slides, e-books, dashboards, and more.

  8. Scalability: maidr supports a wide range of data visualization types, including bar plots, histograms, line plots, box plots, violin plots, heatmaps, scatter plots, and more. maidr is designed to be extensible to support new visualization types. Multi-figure and multi-layer visualizations are also supported.

Our core philosophy is to make data science accessible to everyone, regardless of their visual dis/abilities. We believe that by making data visualizations accessible, we can empower blind and sighted users to work together on data science projects, share insights, and make data-driven decisions collaboratively.

Supported Data Visualization Libraries

We currently support the following data visualization libraries in Python:, and we are working on adding support for more libraries in the future:

Matplotlib

  • One-factor bar plot having one x (categorical) and one y (numerical/count) axis.

  • Stacked bar plot having one x (categorical) and one y (numerical/count) axis with multiple data series stacked vertically.

  • Dodged (grouped) bar plot having one x (categorical) and one y (numerical/count) axis with multiple data series displayed side-by-side.

  • One distribution histogram having one x (numerical) and y (numerical/frequency) axis.

  • KDE (Kernel Density Estimation) plot having one x (numerical) and one y (density) axis showing probability density curves.

  • Single line plot having one x (numerical) and one y (numerical) axis.

  • Multi-line plot having one x (numerical) and one y (numerical) axis with multiple data series on the same axes.

  • Vertical box plot having one x (categorical) and one y (numerical) axis.

  • Horizontal box plot having one x (numerical) and one y (categorical) axis.

    • Note: For box plots, the categorical variable can be either single-class or multi-class. We support both cases.
  • Violin plot having one x (categorical) and one y (numerical) axis, combining a KDE density curve with embedded box plot statistics.

  • Heatmap having one x (categorical) and one y (categorical) and z (numerical) axis.

  • Scatter plot having one x (numerical) and one y (numerical) axis.

  • Regression plot having one x (numerical) and one y (numerical) axis with scatter points and fitted regression line.

  • Candlestick chart having one x (time/date) and four y (numerical) axes (open, high, low, close) for financial data visualization (using mplfinance).

  • Multi-layered plots combining different plot types on the same figure with shared axes.

  • Multi-panel plots (subplots) with multiple charts in a grid layout having independent axes.

  • Facet plots showing the same chart type across different data subsets with shared axis scales.

Seaborn

  • sns.barplot(): One-factor bar plot having one x (categorical) and one y (numerical/count) axis.

  • sns.countplot(): Count plot having one x (categorical) and one y (count) axis showing the frequency of categorical data.

  • sns.histplot(): One distribution histogram having one x (numerical) and y (numerical/frequency) axis.

  • sns.kdeplot(): KDE (Kernel Density Estimation) plot having one x (numerical) and one y (density) axis showing probability density curves.

  • sns.lineplot(): Single line plot having one x (numerical) and one y (numerical) axis.

  • sns.boxplot(..., orient="v"): Vertical box plot having one x (categorical) and one y (numerical) axis.

  • sns.boxplot(..., orient="h"): Horizontal box plot having one x (numerical) and one y (categorical) axis.

    • Note: For box plots, the categorical variable can be either single-class or multi-class. We support both cases.
  • sns.violinplot(): Violin plot having one x (categorical) and one y (numerical) axis, combining a KDE density curve with embedded box plot statistics. Supports vertical and horizontal orientations.

  • sns.heatmap(): Heatmap having one x (categorical) and one y (categorical) and z (numerical) axis.

  • sns.scatterplot(): Scatter plot having one x (numerical) and one y (numerical) axis.

  • sns.regplot(): Regression plot having one x (numerical) and one y (numerical) axis with scatter points and fitted regression line.

Altair

py-maidr ships an Altair adapter that compiles single-view (alt.Chart) and layered (alt.LayerChart / c1 + c2) specs to MAIDR-instrumented Vega-Lite output. Use maidr.show(chart) (or maidr.save_html(chart, ...)) to render an accessible version of any supported Altair chart.

  • One-factor bar plot (mark_bar) with one x (categorical) and one y (numerical/count) axis.

  • Dodged (grouped) bar plot using xOffset to separate series side-by-side.

  • Stacked bar plot β€” same encoding as the dodged case but without xOffset; series stack vertically.

  • Count plot (mark_bar with count() aggregate) showing the frequency of categorical data.

  • Histogram (mark_bar with bin=True) having one x (numerical/binned) and one y (count/density) axis.

  • KDE plot using transform_density, with single-series and multi-series (color-grouped) variants supported.

  • Vertical and horizontal box plots (mark_boxplot).

  • Heatmap built as a LayerChart of mark_rect + mark_text over categorical x/y with a numerical color/z encoding.

  • Single-line plot (mark_line) and multi-line plots β€” both the per-series-layer pattern and the single-mark-with-color-encoding pattern.

  • Scatter plot (mark_point / mark_circle).

  • Multi-layered plots combining mark_point + mark_line (e.g. line-with-points overlays) on a LayerChart.

  • Regression-style scatter overlaid with a transform_loess smoothing line on a LayerChart.

Note

Facet, repeat, and concat composite specs (alt.FacetChart, alt.RepeatChart, alt.ConcatChart, alt.HConcatChart, alt.VConcatChart) are not supported by the adapter; only alt.Chart and alt.LayerChart instances are accepted by maidr.show() / maidr.save_html().

Additional Libraries

  • mplfinance: Candlestick charts having one x (time/date) and four y (numerical) axes (open, high, low, close) for financial data with support for moving averages and volume data.

Installation

Python 3.x is required to use maidr. After installing Python, you can install maidr using the following commands in your terminal:

# 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

Getting Started

Making accessible data representation with maidr is easy and straightforward. If you already have data visualization code using matplotlib or seaborn, you can make your plots accessible with maidr in just a few lines of code.

Simply import maidr and call plt.show() as usual. maidr automatically activates a custom matplotlib backend, so plt.show() renders accessible HTML output (with sonification, braille, and tactile support) instead of a static image. You can then interact with the accessible plots using keyboard shortcuts (refer to Table 1).

Check more examples in the galleries.

Sample Bar Plot

import matplotlib.pyplot as plt
import seaborn as sns

# Just import maidr package 
import maidr 


# Load the penguins dataset
penguins = sns.load_dataset("penguins")

# Create a bar plot showing the average body mass of penguins by species
fig, ax = plt.subplots(figsize=(6, 6))

# Assign the plot to a variable
bar_plot = sns.barplot(
    x="species", y="body_mass_g", data=penguins, errorbar="sd", palette="Blues_d", ax=ax
)
ax.set_title("Average Body Mass of Penguins by Species")
ax.set_xlabel("Species")
ax.set_ylabel("Body Mass (g)")

# plt.show() now renders accessible maidr output 
plt.show() 

# Uncomment the following line to save and share the accessible version of your plot with others!
# maidr.save_html(bar_plot, "output.html")