Skip to content

Instantly share code, notes, and snippets.

@patrick-kidger
Created June 25, 2025 11:29
Show Gist options
  • Save patrick-kidger/35762a31aa09349639f99b3c5966a7c3 to your computer and use it in GitHub Desktop.
Save patrick-kidger/35762a31aa09349639f99b3c5966a7c3 to your computer and use it in GitHub Desktop.
Matplotlib: using custom fonts (including emojis in colour), from a `.ttf` file

Matplotlib: using custom fonts (including emojis in colour), from a .ttf file

This is ridiculously difficult. This note is an attempt to record my findings.

There is no perfect solution (that I'm aware of), so the following demonstrates different trade-offs. I am writing this on MacOS, which I note as font behaviour can be OS-specific in subtle ways.

In this example I'm using the Twitter Color Emoji font as our external font.

Black and white, per-character

(This approach is probably the one you want if you're not using emojis and just need CJK support or something.)

The following will print without warnings, but will fail to use colour for the emojis.

import matplotlib.font_manager
import matplotlib.pyplot as plt

matplotlib.font_manager.fontManager.addfont("path/to/TwitterColorEmoji-SVGinOT-MacOS.ttf")
plt.rcParams['font.family'] = ['sans-serif', 'twitter color emoji']

plt.figtext(0.18, 0.45, "There is an emoji 🐰 in between!")
plt.show()

By way of example only, this one sets things globally.

In colour, per-region

(This approach is probably the one you want if you want emojis and don't need to mix them with regular text.)

The following will display the emojis in colour, but will fail to render the characters from outside its font family (and will spit out a warning for each one).

We use mplcairo, although who knows how that long that will be supported.

import matplotlib.font_manager
import matplotlib.pyplot as plt

matplotlib.use("module://mplcairo.macosx")
prop = matplotlib.font_manager.FontProperties(fname="path/to/TwitterColorEmoji-SVGinOT-MacOS.ttf")

plt.figtext(0.18, 0.45, "There is an emoji 🐰 in between!", fontproperties=prop)
plt.figtext(0.18, 0.65, "There is an emoji 🐰 in between!")  # use default font
plt.show()

In this case it pretty much only makes sense to set things per-call; setting things globally just results in the first font in the list being used.

What does not work

  • Per-character with colour support seem to be impossible. (If you need this then my best suggestion is to try overlaying two different figtext calls, each holding part of the text?)

  • Only some fonts will work: for example Noto Color Emoji is invisible, which I assume is something to do with it using a particular colour format that is not widely supported.

  • I tried avoiding matplotlib by using plotly.express instead (which backs out on to HTML+CSS), but it wasn't clear how to use an external font. There wasn't an obvious way to load a .ttf file directly, or a way to provide a .css file (from within which I could then set the font family). This might be enough if you don't need a custom font, and one of the built-in ones covers the range of glyphs you need.

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