API Conventions#

memeplotlib follows the conventions of the scientific Python stack — matplotlib, numpy, pandas, seaborn. If you write a new public function or method, match these patterns so the library feels native to anyone coming from those tools.

The ax=None pattern#

Public rendering functions accept an optional ax keyword argument. If None (the default), they create a new Figure/Axes. If provided, they render onto the supplied Axes.

import matplotlib.pyplot as plt
import memeplotlib as memes

fig, ax = plt.subplots()
memes.meme("buzz", "memes", "everywhere", ax=ax)  # renders into ax

This mirrors seaborn and pandas.DataFrame.plot().

Return (Figure, Axes), do not call plt.show#

meme() returns (fig, ax) so the caller can continue customizing or save the figure. show=False is the default — matching matplotlib’s idiom of explicit display. Pass show=True if you want auto-display in a script.

fig, ax = memes.meme("drake", "old way", "new way")
ax.set_title("annotated by the caller", fontsize=10)
fig.savefig("drake.png", dpi=200)

Forward **kwargs to Axes.text#

memify() and the backend="matplotlib" / backend="pillow" paths of meme() accept extra **kwargs that are passed through to Axes.text() for each rendered caption. This lets you tweak alpha, rotation, zorder, or any other matplotlib text parameter without library-side support:

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

Under backend="auto", passing any **text_kwargs forces the Pillow backend. memegen has no equivalent for arbitrary Axes.text arguments so they cannot be honoured by the server-side renderer.

Backends#

memeplotlib ships three rendering backends:

"memegen"

Build a memegen rendering URL via build_memegen_url() and imshow the response. Honours every memegen parameter — font, color, style, template_style, width, height, layout, background, overlays, extension.

"pillow"

Download the blank, draw captions client-side with PIL.ImageDraw.ImageDraw. Honours per-line fontsize, custom outlines, and per-line overrides via Meme.line().

"matplotlib"

Legacy: draw captions with Axes.text() plus patheffects.Stroke. Forwards **kwargs to Axes.text.

The default "auto" selects "memegen" for memegen-catalogue templates with no client-only knobs, and "pillow" otherwise. Passing any of fontsize, a non-default outline_color / outline_width, **text_kwargs, or per-line overrides forces Pillow under auto. See Constructing memegen URLs for the URL grammar.

rc_context for scoped config overrides#

The config mapping is RcParams-style. For short-lived overrides, use rc_context() — same shape as matplotlib.rc_context():

with memes.rc_context({"font": "comic", "color": "yellow"}):
    memes.meme("buzz", "scoped style")
# config is restored on block exit

Setting config["..."] = ... mutates the singleton globally; use rc_context whenever you don’t want that.

NumPy-format docstrings#

Every public function uses NumPy-format docstrings:

def meme(template, *lines, ax=None, font=None, **text_kwargs):
    """Render an image-macro meme.

    Parameters
    ----------
    template : str
        Memegen template ID, file path, or URL.
    *lines : str
        Caption lines.
    ax : matplotlib.axes.Axes, optional
        Render onto this axes. If None, a new figure is created.
    **text_kwargs
        Forwarded to :meth:`Axes.text`.

    Returns
    -------
    fig : matplotlib.figure.Figure
    ax : matplotlib.axes.Axes
    """

The docs use numpydoc (not napoleon). Run numpydoc validate to check.

Test conventions#

  • All network calls are mocked. The autouse _block_real_network fixture in tests/conftest.py disables real TCP sockets. Tests using pytest_httpserver opt out via @pytest.mark.allow_network.

  • Image-comparison tests use pytest_mpl. Baselines live in tests/baseline/. Regenerate with pytest --mpl-generate-path=tests/baseline.

  • Mocked HTTP responses use the responses library; for retry or timeout behavior that responses cannot model, use pytest_httpserver.