Skip to main content

CI codecov Docs PyPI version conda-forge version Python versions License: MIT

memeplotlib logotype

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")

Buzz Lightyear meme: top text "memes", bottom text "memes everywhere"

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")

Drake meme in yellow text: top "writing tests", bottom "shipping to prod"

Object-oriented Meme builder, chainable:

from memeplotlib import Meme

Meme("buzz").top("python").bottom("python everywhere").save("buzz.png")

Buzz Lightyear meme: top "python", bottom "python everywhere"

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")

Line chart with the meme caption "STONKS" across the top

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

Buzz Lightyear meme in yellow Comic Sans: top "custom defaults", bottom "applied everywhere"

Forward **kwargs to Axes.text:

memes.meme("buzz", "rotated", rotation=15, alpha=0.8)

Alt text for screen readers: every render gets a description built from the template and captions, embedded in saved PNG/SVG/PDF files:

fig, ax = memes.meme("buzz", "memes", "memes everywhere", savefig="buzz.png")
memes.get_alt_text(fig)
# 'Meme using the "Buzz Lightyear" template. Top text: "memes". Bottom text: "memes everywhere".'
memes.meme("buzz", "memes", alt_text="Buzz Lightyear pointing at memes everywhere")

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 pass fontsize, a non-default outline_color / outline_width, **text_kwargs, or per-line overrides.
  • matplotlib — when **text_kwargs (e.g. rotation, alpha) are passed, since only Axes.text can apply them.
  • pillow — for custom local images / arbitrary URLs, or when any of the other client-only features above 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")

# Axes.text kwargs select the matplotlib path automatically:
memes.meme("buzz", "rotated", rotation=15, alpha=0.8)

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/hello.png  # 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

  1. Template metadata comes from the memegen API (/templates/, /templates/<id>); blank backgrounds and rendered memes alike are cached on disk.
  2. Memegen backend (default for memegen IDs): a fully-formed rendering URL (/images/<id>/<line_1>/.../<line_n>.<ext>?style=...&font=...) is built via memeplotlib.build_memegen_url. The composed image is fetched and displayed with Axes.imshow.
  3. Pillow backend (default for custom images, or when client-only features are requested): the blank is fetched once, then captions are drawn with PIL.ImageDraw using stroke-aware text rendering and a shrink-to-fit loop, and the composed RGBA array is imshown.
  4. Matplotlib backend (legacy, opt-in): captions are drawn with Axes.text plus patheffects.Stroke for the classic outlined look.
  5. The bundled Anton font (Impact-like, SIL OFL licensed) is used as a fallback for systems where Impact isn't installed.
  • matplotlib — the rendering engine.
  • memegen — the template registry and blank-image source (api.memegen.link).
  • seaborn — the API conventions for ax=None, **kwargs forwarding, and (fig, ax) returns are modeled on seaborn.

Dependencies

  • matplotlib >= 3.8
  • numpy, requests, Pillow, platformdirs

Requires Python 3.10+.

License

MIT. The bundled Anton font is licensed under the SIL Open Font License v1.1.

Metadata

Release files for memeplotlib 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for memeplotlib 0.6.0
File Size Uploaded Provenance Actions
memeplotlib-0.6.0.tar.gz 24.6 MB With provenance Details for memeplotlib-0.6.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for memeplotlib 0.6.0
File Interpreter ABI Platform Actions
memeplotlib-0.6.0-py3-none-any.whl Python 3 none any Details for memeplotlib-0.6.0-py3-none-any.whl

Total release size: 24.7 MB

Release files / memeplotlib-0.6.0.tar.gz

Download URL memeplotlib-0.6.0.tar.gz
Size 24.6 MB
Tags Source
SHA-256 checksum
How to use checksums
c6ad269105035e2c0e0a636054e4310ec6d387b5859026c55f8df3a4776d931c
BLAKE2b-256 checksum
How to use checksums
58d6e295ee409df1e1542328b7aef30f2c57075317215f5f7b17bc0b8b4429dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Release files / memeplotlib-0.6.0-py3-none-any.whl

Download URL memeplotlib-0.6.0-py3-none-any.whl
Size 136.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
23b90892924bf7fed6f2093ae3fd5abb4561e592f4746c67c1bfe6cec8bb1f27
BLAKE2b-256 checksum
How to use checksums
c39019c946072180f001421948502236a6653e9b3602098faab6e68955954a93
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

Security for memeplotlib 0.6.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for memeplotlib-0.6.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 26, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page