Dot Matrix Chart for Proportional Counts in lets-plot (Python)

The same plot in 14 other libraries — Python: Altair, Bokeh, Matplotlib, Plotly, plotnine, Pygal, Seaborn; R: ggplot2; Julia: Makie.jl; JavaScript: Chart.js, D3.js, Apache ECharts, Highcharts, MUI X Charts. Compare all 15 side by side: Dot Matrix Chart for Proportional Counts in Python, R, Julia and JavaScript.

A dot matrix chart displays proportions using a grid of equally-sized dots where filled or colored dots represent counts out of a total. Each dot corresponds to one unit, making it intuitive to read "X out of N" statistics at a glance. Unlike waffle charts that use percentage-based squares, dot matrix charts emphasize absolute counts with variable grid sizes, excelling at risk communication and survey result visualization.

Dot Matrix Chart for Proportional Counts rendered with lets-plot

Renders

Python source (lets-plot)

""" anyplot.ai
dot-matrix-proportional: Dot Matrix Chart for Proportional Counts
Library: letsplot 4.9.0 | Python 3.13.13
Quality: 88/100 | Created: 2026-05-08
"""

import os

import pandas as pd
from lets_plot import *
from lets_plot import element_blank, element_rect, element_text, theme
from lets_plot.export import ggsave as export_ggsave


LetsPlot.setup_html()

# Theme tokens
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"

IMPRINT = ["#009E73", "#C475FD", "#4467A3", "#BD8233"]

# Data — clinical trial side effect profile (n = 100 patients)
categories = ["No Side Effects", "Mild Effects", "Moderate Effects", "Severe Effects"]
counts = [72, 18, 7, 3]
total = sum(counts)  # 100
COLS = 10

dot_labels = []
for cat, cnt in zip(categories, counts, strict=True):
    dot_labels.extend([cat] * cnt)

legend_labels = [f"{cat}  (n={cnt})" for cat, cnt in zip(categories, counts, strict=True)]
legend_map = dict(zip(categories, legend_labels, strict=True))

df = pd.DataFrame(
    {"col": [i % COLS for i in range(total)], "row": [-(i // COLS) for i in range(total)], "group": dot_labels}
)
df["legend"] = pd.Categorical(df["group"].map(legend_map), categories=legend_labels, ordered=True)

# Plot
anyplot_theme = theme(
    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
    panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
    panel_border=element_blank(),
    panel_grid_major=element_blank(),
    panel_grid_minor=element_blank(),
    axis_title=element_blank(),
    axis_text=element_blank(),
    axis_line=element_blank(),
    axis_ticks=element_blank(),
    plot_title=element_text(color=INK, size=24),
    legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
    legend_text=element_text(color=INK_SOFT, size=16),
    legend_title=element_blank(),
    legend_position="right",
)

plot = (
    ggplot(df, aes(x="col", y="row", color="legend"))
    + geom_point(size=8, alpha=0.95)
    + scale_color_manual(values=IMPRINT)
    + labs(title="dot-matrix-proportional · letsplot · anyplot.ai")
    + theme_void()
    + ggsize(1200, 1200)
    + anyplot_theme
)

# Save
export_ggsave(plot, filename=f"plot-{THEME}.png", path=".", scale=3)
export_ggsave(plot, filename=f"plot-{THEME}.html", path=".")

Retrieve this implementation

Runnable source as JSON, for any HTTP client: https://api.anyplot.ai/specs/dot-matrix-proportional/letsplot/code. Any spec id and library id listed in llms-full.txt fit the same URL shape; every URL below is complete and callable.

{
  "spec_id": "dot-matrix-proportional",
  "language": "python",
  "library": "letsplot",
  "page": "https://anyplot.ai/dot-matrix-proportional/python/letsplot",
  "hub": "https://anyplot.ai/dot-matrix-proportional",
  "code_json": "https://api.anyplot.ai/specs/dot-matrix-proportional/letsplot/code",
  "spec_json": "https://api.anyplot.ai/specs/dot-matrix-proportional",
  "render_light_png": "https://storage.googleapis.com/anyplot-images/plots/dot-matrix-proportional/python/letsplot/plot-light.png",
  "render_dark_png": "https://storage.googleapis.com/anyplot-images/plots/dot-matrix-proportional/python/letsplot/plot-dark.png",
  "interactive_light_html": "https://storage.googleapis.com/anyplot-images/plots/dot-matrix-proportional/python/letsplot/plot-light.html",
  "interactive_dark_html": "https://storage.googleapis.com/anyplot-images/plots/dot-matrix-proportional/python/letsplot/plot-dark.html",
  "quality_score": 88.0,
  "license": "MIT",
  "guide": "https://anyplot.ai/llms.txt"
}

Part of Dot Matrix Chart for Proportional Counts on anyplot.ai.

Other implementations