import altair as alt
import seaborn as sns
import maidr
# Load the tips dataset and tally by day
tips = sns.load_dataset("tips")
day_counts = tips["day"].value_counts().reset_index()
day_counts.columns = ["day", "count"]
bar_plot = (
alt.Chart(day_counts)
.mark_bar(color="skyblue")
.encode(
x=alt.X("day:N", title="Day"),
y=alt.Y("count:Q", title="Count"),
)
.properties(title="The Number of Tips by Day", width=400, height=300)
)
maidr.show(bar_plot) Altair Accessible Plot Examples
Altair Examples
maidr also supports Altair charts. If you already have data visualization code using altair, you can make your charts accessible with maidr in just a few lines of code. For matplotlib / seaborn examples, see the Matplotlib / Seaborn Examples page; for Plotly examples, see the Plotly Examples page.
Simply import the maidr package and pass your Altair Chart (or layered Chart + Chart composite) to maidr.show(). maidr ships the Vega-Lite spec into an iframe that loads the upstream Vega-Lite adapter from CDN and binds the MAIDR keyboard-navigation, sonification, braille, and AI-chat UI on top of the rendered chart.
The Altair adapter currently supports single-view charts (alt.Chart) and layered composites (alt.LayerChart, including c1 + c2 and alt.layer(...)). Facet (.facet(...)), repeat (.repeat(...)), and concat (alt.hconcat / alt.vconcat / alt.concat) composite specs are not currently supported.
Bar Plot
Dodged (Grouped) Bar Plot
import altair as alt
import pandas as pd
import maidr
species = ["Adelie", "Chinstrap", "Gentoo"]
weight_counts = {
"Below": [70, 31, 58],
"Above": [82, 37, 66],
}
# Build a long-form DataFrame for Altair
rows = []
for sp_idx, sp in enumerate(species):
for category, counts in weight_counts.items():
rows.append({"species": sp, "count": counts[sp_idx], "category": category})
df = pd.DataFrame(rows)
dodged_plot = (
alt.Chart(df)
.mark_bar()
.encode(
x=alt.X("species:N", title="Species"),
y=alt.Y("count:Q", title="Count"),
color=alt.Color("category:N", title="Category"),
xOffset="category:N",
)
.properties(
title="Dodged Bar Plot: Penguin Weight Counts", width=400, height=300
)
)
maidr.show(dodged_plot) Stacked Bar Plot
import altair as alt
import seaborn as sns
import maidr
# Load the Titanic dataset
titanic = sns.load_dataset("titanic")
# Group by class and survived
grouped = (
titanic.groupby(["class", "survived"])
.size()
.reset_index(name="count")
)
grouped["survived"] = grouped["survived"].map(
{0: "Did not survive", 1: "Survived"}
)
stacked_plot = (
alt.Chart(grouped)
.mark_bar()
.encode(
x=alt.X("class:N", title="Class"),
y=alt.Y("count:Q", title="Number of Passengers", stack="zero"),
color=alt.Color("survived:N", title="Survival Status"),
)
.properties(
title="Passenger Count by Class and Survival Status on the Titanic",
width=400,
height=300,
)
)
maidr.show(stacked_plot) Count Plot
import altair as alt
import seaborn as sns
import maidr
titanic = sns.load_dataset("titanic")
count_plot = (
alt.Chart(titanic)
.mark_bar()
.encode(
x=alt.X("class:N", title="Class"),
y=alt.Y("count():Q", title="Count"),
)
.properties(
title="Passenger Class Distribution on the Titanic",
width=400,
height=300,
)
)
maidr.show(count_plot) Histogram
import altair as alt
import seaborn as sns
import maidr
iris = sns.load_dataset("iris")
hist_plot = (
alt.Chart(iris)
.mark_bar(color="steelblue")
.encode(
x=alt.X(
"petal_length:Q",
bin=alt.Bin(maxbins=20),
title="Petal Length (cm)",
),
y=alt.Y("count():Q", title="Frequency"),
)
.properties(
title="Histogram of Petal Lengths in Iris Dataset",
width=400,
height=300,
)
)
maidr.show(hist_plot) Single KDE Plot
import altair as alt
import numpy as np
import pandas as pd
import maidr
# Generate sample data
np.random.seed(42)
data = np.random.normal(loc=1, scale=2, size=300)
df = pd.DataFrame({"value": data})
# Create KDE plot using Altair's density transform
kde_plot = (
alt.Chart(df)
.transform_density("value", as_=["value", "density"])
.mark_line(color="blue", strokeWidth=2)
.encode(
x=alt.X("value:Q", title="Value"),
y=alt.Y("density:Q", title="Density"),
)
.properties(title="Single KDE Plot with Altair", width=400, height=300)
)
maidr.show(kde_plot) Multiple KDE Overlays
import altair as alt
import numpy as np
import pandas as pd
import maidr
# Generate sample data for three groups
np.random.seed(0)
data1 = np.random.normal(loc=0, scale=1, size=200)
data2 = np.random.normal(loc=2, scale=0.5, size=200)
data3 = np.random.normal(loc=-2, scale=1.5, size=200)
df = pd.DataFrame(
{
"value": np.concatenate([data1, data2, data3]),
"group": (
["Group 1"] * len(data1)
+ ["Group 2"] * len(data2)
+ ["Group 3"] * len(data3)
),
}
)
multi_kde = (
alt.Chart(df)
.transform_density("value", groupby=["group"], as_=["value", "density"])
.mark_line(strokeWidth=2)
.encode(
x=alt.X("value:Q", title="Value"),
y=alt.Y("density:Q", title="Density"),
color=alt.Color("group:N", title="Group"),
)
.properties(title="Multiple KDE Plots with Altair", width=400, height=300)
)
maidr.show(multi_kde) Box Plot (Vertical and Horizontal)
import altair as alt
import seaborn as sns
import maidr
iris = sns.load_dataset("iris")
def boxplot(orientation: str):
if orientation == "v":
return (
alt.Chart(iris)
.mark_boxplot()
.encode(
x=alt.X("species:N", title="Species"),
y=alt.Y("petal_length:Q", title="Petal Length (cm)"),
)
.properties(
title="Vertical Box Plot of Petal Length by Iris Species",
width=400,
height=300,
)
)
return (
alt.Chart(iris)
.mark_boxplot()
.encode(
x=alt.X("petal_length:Q", title="Petal Length (cm)"),
y=alt.Y("species:N", title="Species"),
)
.properties(
title="Horizontal Box Plot of Petal Length by Iris Species",
width=400,
height=300,
)
)
maidr.show(boxplot("v"))
maidr.show(boxplot("h")) Heatmap
import altair as alt
import numpy as np
import pandas as pd
import maidr
vegetables = [
"cucumber", "tomato", "lettuce", "asparagus",
"potato", "wheat", "barley",
]
farmers = [
"Farmer Joe", "Upland Bros.", "Smith Gardening", "Agrifun",
"Organiculture", "BioGoods Ltd.", "Cornylee Corp.",
]
harvest = np.array([
[0.8, 2.4, 2.5, 3.9, 0.0, 4.0, 0.0],
[2.4, 0.0, 4.0, 1.0, 2.7, 0.0, 0.0],
[1.1, 2.4, 0.8, 4.3, 1.9, 4.4, 0.0],
[0.6, 0.0, 0.3, 0.0, 3.1, 0.0, 0.0],
[0.7, 1.7, 0.6, 2.6, 2.2, 6.2, 0.0],
[1.3, 1.2, 0.0, 0.0, 0.0, 3.2, 5.1],
[0.1, 2.0, 0.0, 1.4, 0.0, 1.9, 6.3],
])
rows = []
for i, veg in enumerate(vegetables):
for j, farmer in enumerate(farmers):
rows.append(
{"Vegetable": veg, "Farmer": farmer, "Harvest": float(harvest[i, j])}
)
df = pd.DataFrame(rows)
heatmap = (
alt.Chart(df)
.mark_rect()
.encode(
x=alt.X("Farmer:N", title="Farmers"),
y=alt.Y("Vegetable:N", title="Vegetables"),
color=alt.Color("Harvest:Q", title="Harvest (tons)"),
)
.properties(
title="Harvest of local farmers (in tons/year)",
width=400,
height=300,
)
)
text = (
alt.Chart(df)
.mark_text(color="white")
.encode(
x="Farmer:N",
y="Vegetable:N",
text=alt.Text("Harvest:Q", format=".1f"),
)
)
# Layered chart: heatmap + text labels
chart = heatmap + text
maidr.show(chart) Line Plot
import altair as alt
import seaborn as sns
import maidr
flights = sns.load_dataset("flights")
flights_yearly = flights.groupby("year")["passengers"].sum().reset_index()
flights_yearly.columns = ["year", "total"]
line_plot = (
alt.Chart(flights_yearly)
.mark_line(point=True)
.encode(
x=alt.X("year:O", title="Year"),
y=alt.Y("total:Q", title="Total Passengers (Thousands)"),
)
.properties(
title="Total Passengers per Year From the Flights Dataset",
width=500,
height=300,
)
)
maidr.show(line_plot) Multi-Line Plot
import altair as alt
import numpy as np
import pandas as pd
import maidr
x = np.array([1, 2, 3, 4, 5, 6, 7, 8])
y1 = np.array([2, 4, 1, 5, 3, 7, 6, 8])
y2 = np.array([1, 3, 5, 2, 4, 6, 8, 7])
y3 = np.array([3, 1, 4, 6, 5, 2, 4, 5])
df = pd.DataFrame({
"x": np.tile(x, 3),
"y": np.concatenate([y1, y2, y3]),
"series": np.repeat(["Series 1", "Series 2", "Series 3"], len(x)),
})
multiline_plot = (
alt.Chart(df)
.mark_line(point=True)
.encode(
x=alt.X("x:Q", title="X values"),
y=alt.Y("y:Q", title="Y values"),
color=alt.Color("series:N", title="Series"),
strokeDash=alt.StrokeDash("series:N"),
)
.properties(title="Altair Multi-Line Plot", width=400, height=300)
)
maidr.show(multiline_plot) Scatter Plot
import altair as alt
import seaborn as sns
import maidr
iris = sns.load_dataset("iris")
scatter_plot = (
alt.Chart(iris)
.mark_point()
.encode(
x=alt.X("sepal_length:Q", title="Sepal Length (cm)"),
y=alt.Y("sepal_width:Q", title="Sepal Width (cm)"),
color=alt.Color("species:N", title="Species"),
)
.properties(
title="Iris Sepal Length vs Sepal Width",
width=400,
height=300,
)
)
maidr.show(scatter_plot) Multi-Layered Plot
import altair as alt
import numpy as np
import pandas as pd
import maidr
x = np.arange(5)
bar_data = np.array([3, 5, 2, 7, 3])
line_data = np.array([10, 8, 12, 14, 9])
df = pd.DataFrame({"x": x, "bar_values": bar_data, "line_values": line_data})
bar = (
alt.Chart(df)
.mark_bar(color="skyblue")
.encode(
x=alt.X("x:O", title="X values"),
y=alt.Y("bar_values:Q", title="Bar values"),
)
)
line = (
alt.Chart(df)
.mark_line(color="red", point=True, strokeWidth=2)
.encode(
x=alt.X("x:O"),
y=alt.Y("line_values:Q", title="Line values"),
)
)
# Layered chart with independent y-scales
chart = (
alt.layer(bar, line)
.resolve_scale(y="independent")
.properties(title="Multilayer Plot Example", width=400, height=300)
)
maidr.show(chart) Regression (Scatter + LOESS Smooth)
import altair as alt
import numpy as np
import pandas as pd
import maidr
np.random.seed(0)
x = np.linspace(0, 10, 100)
y = np.sin(x) + 0.3 * np.random.randn(100)
df = pd.DataFrame({"x": x, "y": y})
scatter = (
alt.Chart(df)
.mark_point(color="blue", opacity=0.6)
.encode(
x=alt.X("x:Q", title="x"),
y=alt.Y("y:Q", title="y"),
)
)
smooth = (
alt.Chart(df)
.mark_line(color="red", strokeWidth=2)
.transform_loess("x", "y")
.encode(
x="x:Q",
y="y:Q",
)
)
# Layered chart: scatter points + loess smooth
chart = (scatter + smooth).properties(
title="Altair: Scatter with LOESS Smooth Line",
width=400,
height=300,
)
maidr.show(chart) Saving an Altair Chart as a Self-Contained HTML File
If you would like to save and share the accessible chart as a standalone HTML file, use maidr.save_html():
import altair as alt
import seaborn as sns
import maidr
tips = sns.load_dataset("tips")
chart = (
alt.Chart(tips)
.mark_bar()
.encode(x="day:N", y="count():Q")
)
maidr.save_html(chart, file="tips_by_day.html")The generated HTML embeds the Vega-Lite spec and loads vega / vega-lite / vega-embed plus the upstream MAIDR Vega-Lite adapter from CDN.
Bug Report
If you encounter a bug, have usage questions, or want to share ideas to make the Altair adapter better, please file an issue.