Skip to content

Very long delay (10–20 s) on first plot in a fresh environment: Matplotlib font-cache build #235

Description

@petercorke

Symptom

In a fresh environment, the first plot (or, before #198, plain import spatialmath) can take 10–20 s. Later runs on the same machine are fast, so the delay is hard to reproduce on a long-lived development machine, but it can recur on every run in containers or CI.

Cause

This is Matplotlib behaviour, not spatialmath code. The first time Matplotlib's font manager runs with no font cache, it scans every font installed on the system to build one. That's the "Matplotlib is building the font cache; this may take a moment" message. The cache is stored in MPLCONFIGDIR, which by default is ~/.cache/matplotlib on Linux and ~/.matplotlib on macOS. If that directory doesn't persist between runs, every run pays the full cost. This commonly happens with:

  • Docker containers and CI runners started fresh each time
  • sandboxed build/test tools that don't keep the home directory's cache
  • new virtual environments or users with a different MPLCONFIGDIR

Measurements

Apple M1 (8 GB), macOS, Python 3.12. "Empty cache" means MPLCONFIGDIR pointed at an empty directory.

Empty font cache Cache already built
import matplotlib.pyplot 17.0 s —
import spatialmath, before #198 (f6a572c6^) 17.6 s 1.1 s
import spatialmath, after #198 (current master) 0.75 s 0.7 s

Before #198, import spatialmath imported matplotlib.pyplot, so every spatialmath user paid this on a cold cache, including code that never plots. Since #198 the import is lazy, so the cost appears only at the first plot, and code that never plots never pays it.

How long the scan takes depends on how many fonts are installed. A minimal Linux container will usually be faster than macOS, but several seconds is typical.

Fix

spatialmath can't avoid this without dropping Matplotlib. If you plot in a fresh environment, keep the cache between runs:

  • Docker: build the cache when building the image, so it's baked in:
    RUN python -c "import matplotlib.pyplot"
  • CI: cache the MPLCONFIGDIR directory between jobs (e.g. actions/cache on ~/.cache/matplotlib), or run the line above in a setup step.
  • Sandboxes: set MPLCONFIGDIR to a persistent, writable directory.

Proposed docs change

Add a short "Slow first plot" troubleshooting note to the docs, with the explanation and fixes above.

Related: #198 (lazy Matplotlib import), #234 (remaining import-time costs from SciPy/SymPy).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions