Memes with Python's matplotlib
Project description
Memes with Python's matplotlib. Create image-macro memes by either letting the memegen API render them server-side (the default) or falling back to a local Pillow renderer when the API can't express what you want — custom local images, explicit per-line font sizes, custom outlines, or per-line position overrides.
Installation
pip install memeplotlib
# or
conda install -c conda-forge memeplotlib
For the Model Context Protocol server (use memes from Claude Desktop / Claude Code / any MCP client):
pip install "memeplotlib[mcp]"
Quick start
import memeplotlib as memes
fig, ax = memes.meme("buzz", "memes", "memes everywhere")
fig.savefig("buzz.png")
The function returns (Figure, Axes) — same convention as seaborn,
pandas.plot, and other matplotlib extensions. It does not call
plt.show() implicitly. Pass show=True if you want auto-display.
Features
Memegen IDs, file paths, or URLs as templates:
memes.meme("drake", "writing tests", "shipping to prod", color="yellow")
memes.meme("/path/to/image.jpg", "top text", "bottom text")
memes.meme("https://example.com/image.png", "from a URL")
Object-oriented Meme builder, chainable:
from memeplotlib import Meme
Meme("buzz").top("python").bottom("python everywhere").save("buzz.png")
Memify existing matplotlib figures:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
memes.memify(fig, "stonks")
RcParams-style scoped configuration:
with memes.rc_context({"font": "comic", "color": "yellow"}):
memes.meme("buzz", "scoped style", "no leakage")
# defaults are auto-restored here
# Or set globally:
memes.config["fontsize"] = 96
Forward **kwargs to Axes.text:
memes.meme("buzz", "rotated", rotation=15, alpha=0.8)
Backends
memeplotlib ships three rendering backends. The default "auto" policy
picks the best fit; pass backend="..." to override.
| Backend | What it does | Honours |
|---|---|---|
memegen |
Builds a memegen rendering URL and imshows the response. No client-side text drawing. |
font, color, style, template_style, width, height, layout, background, overlays, extension (png/jpg/gif/webp) |
pillow |
Downloads the blank, draws captions client-side with PIL.ImageDraw. Used for custom local images and any feature memegen can't express. |
All caption styling including per-line fontsize, custom outline_color / outline_width, and per-line overrides via Meme.line(...). |
matplotlib |
Legacy: draws captions with Axes.text + patheffects.Stroke. Kept for backwards compatibility. |
All caption styling plus **kwargs forwarded to Axes.text (e.g. rotation, alpha). |
backend="auto" selects:
memegen— when the template comes from the memegen catalogue and the caller didn't passfontsize, a non-defaultoutline_color/outline_width,**text_kwargs, or per-line overrides.pillow— for custom local images / arbitrary URLs, or when any of the above client-only features were requested.
# Default: memegen renders this server-side.
memes.meme("buzz", "memes", "memes everywhere", template_style="default",
font="impact", width=600)
# Pillow fallback — explicit fontsize forces it.
memes.meme("/path/to/photo.jpg", "top", "bottom", fontsize=48,
outline_color="red", outline_width=4)
# Per-line overrides force the Pillow backend.
from memeplotlib import Meme
Meme("buzz").top("hi").line(1, "world", fontsize=72, color="yellow").save("out.png")
# Legacy matplotlib path (preserves old behaviour exactly):
memes.meme("buzz", "rotated", rotation=15, alpha=0.8, backend="matplotlib")
See docs/url_construction.rst for the full
memegen URL grammar — escape table, query parameters, font / style / overlay
reference — adapted from jacebrowning/memegen #993.
Use from agents
pip install "memeplotlib[mcp]"
memeplotlib-mcp # boot the MCP server (stdio)
memeplotlib meme buzz "hello" "world" -o /tmp/ # CLI render
The MCP server exposes meme, search_templates, and list_templates
tools. The CLI is useful even without MCP — agent harnesses can shell
out, and CI scripts can render directly.
Documentation
Full docs including a tutorial, user guide, conventions reference, and API reference: brianckeegan.github.io/memeplotlib.
Build locally:
pip install -e ".[docs]"
sphinx-build -W docs docs/_build
How it works
- Template metadata comes from the memegen API
(
/templates/,/templates/<id>); blank backgrounds and rendered memes alike are cached on disk. - Memegen backend (default for memegen IDs): a fully-formed rendering
URL (
/images/<id>/<line_1>/.../<line_n>.<ext>?style=...&font=...) is built viamemeplotlib.build_memegen_url. The composed image is fetched and displayed withAxes.imshow. - Pillow backend (default for custom images, or when client-only
features are requested): the blank is fetched once, then captions are
drawn with
PIL.ImageDrawusing stroke-aware text rendering and a shrink-to-fit loop, and the composed RGBA array isimshown. - Matplotlib backend (legacy, opt-in): captions are drawn with
Axes.textpluspatheffects.Strokefor the classic outlined look. - The bundled Anton font (Impact-like, SIL OFL licensed) is used as a fallback for systems where Impact isn't installed.
Related projects
- matplotlib — the rendering engine.
- memegen — the template registry and blank-image source (api.memegen.link).
- seaborn — the API conventions for
ax=None,**kwargsforwarding, and(fig, ax)returns are modeled on seaborn.
Dependencies
matplotlib >= 3.8numpy,requests,Pillow,platformdirs
Requires Python 3.10+.
License
MIT. The bundled Anton font is licensed under the SIL Open Font License v1.1.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file memeplotlib-0.5.0.tar.gz.
File metadata
- Download URL: memeplotlib-0.5.0.tar.gz
- Upload date:
- Size: 21.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7cc83cadb05d013fe96315061a1cdcd9893dd84c1e6eab9e27d3458782dc51d
|
|
| MD5 |
b60853c61554b970874fb8223b7f9751
|
|
| BLAKE2b-256 |
a0f42d372bd637752f57708cdc729c28f6855a6a4d9cd344750760b458bcb768
|
Provenance
The following attestation bundles were made for memeplotlib-0.5.0.tar.gz:
Publisher:
publish_pypi.yml on brianckeegan/memeplotlib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memeplotlib-0.5.0.tar.gz -
Subject digest:
b7cc83cadb05d013fe96315061a1cdcd9893dd84c1e6eab9e27d3458782dc51d - Sigstore transparency entry: 1397978261
- Sigstore integration time:
-
Permalink:
brianckeegan/memeplotlib@71b2675c42647c7a233a9395ee4073acb8077f81 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/brianckeegan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_pypi.yml@71b2675c42647c7a233a9395ee4073acb8077f81 -
Trigger Event:
release
-
Statement type:
File details
Details for the file memeplotlib-0.5.0-py3-none-any.whl.
File metadata
- Download URL: memeplotlib-0.5.0-py3-none-any.whl
- Upload date:
- Size: 122.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9d493a489ef268515ded23619c95ad04c4294df59007424d0b6e141f17ee908
|
|
| MD5 |
bf14c3304ac18feb30374979d8562ae1
|
|
| BLAKE2b-256 |
fba9136d6433887fc2e166a6cc0aa16fb6a1069c4dfde23144725ecefff5b2db
|
Provenance
The following attestation bundles were made for memeplotlib-0.5.0-py3-none-any.whl:
Publisher:
publish_pypi.yml on brianckeegan/memeplotlib
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
memeplotlib-0.5.0-py3-none-any.whl -
Subject digest:
e9d493a489ef268515ded23619c95ad04c4294df59007424d0b6e141f17ee908 - Sigstore transparency entry: 1397978298
- Sigstore integration time:
-
Permalink:
brianckeegan/memeplotlib@71b2675c42647c7a233a9395ee4073acb8077f81 -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/brianckeegan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish_pypi.yml@71b2675c42647c7a233a9395ee4073acb8077f81 -
Trigger Event:
release
-
Statement type: