Load and plot a remote font with Matplotlib#

As part of my sphinx-social-previews prototype, I wanted to be able to use the Roboto Font from Google in image previews. However, Roboto is often not loaded on your local filesystem, so it took some digging to figure out how to make it possible to load via Matplotlib’s text plotting functionality.

Here’s the solution that finally worked for me, inspired from this Tweet with a similar implementation from the dmol book.

Below I’ll use the Fira Code font from Mozilla but you could do this with any open font that you have the .ttf file for.

Create a temporary folder and download the font file#

I’ll show how to do this with a local folder, so it’ll re-download each time you run the code. Alternatively you could download the font locally and just register the path instead of downloading it:

First, download the .ttf of the font locally via urlretrieve. For example, the Fira Code font from Mozilla is located at this URL. To download it locally into a temporary folder using the tempfile.mkdtemp function, run this code:

import tempfile
from pathlib import Path
import urllib
from rich import print

# Create a temporary directory for the font file
path = Path(tempfile.mkdtemp())

# URL and downloaded path of the font
url_font = "https://github.com/google/fonts/raw/main/ofl/firacode/FiraCode%5Bwght%5D.ttf"
path_font = path / "Fira-Code.ttf"


# Download the font to our temporary directory
urllib.request.urlretrieve(url_font, path_font)
(PosixPath('/tmp/tmpirx0srfo/Fira-Code.ttf'),
 <http.client.HTTPMessage at 0x7f2039c12ef0>)

Make a plot with this font#

Now that we’ve registered the font, we can plot it with ax.text. To do so, use the plt.rc_context context manager to temporarily update our default font:

import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 3, figsize=(9, 5))

# This will now render as a `Roboto Flex` font
axs[0].text(.1, .5, "The default font!", fontdict={"fontsize": 15})
axs[1].text(.1, .5, "A Matplotlib font", fontdict={"fontsize": 15, "family": "cmmi10"})
axs[2].text(.1, .5, "The Fira Code font!", fontdict={"fontsize": 15, "family": font.name})

for ax in axs:
  ax.set_axis_off()
../../../_images/868fcd11b95a614186ca3a676d028d4548af86c0749233733e16ac5cf97f2fed.png

And that’s it!