Skip to content
Advertisement

matplotlib: Can I use a secondary font for missing glyphs?

The font I want to use doesn’t have all the symbols I need. Is it possible to have matplotlib use a different font if a symbol is missing?

Here is a minimal example:

JavaScript

And the output:

And the output.

Noto Sans is missing the heart symbol while Noto Sans Symbols2 is missing the letters. I’m trying to get something like the DejaVu Sans example but with letters from Noto Sans and the heart from Noto Sans Symbols2.

Advertisement

Answer

Update in 2022: As of matplotlib 3.6, font fallback is now supported.

JavaScript

Here’s my thinking:

Create a function taking x – the starting x position, y – the y position, text – the text to draw, and fallbackList – a list of fonts, ordered like font-family in CSS.

  1. When rendering the text, use fontTools.ttLib.TTFont to check if a certain character is contained within the primary font (fallbackList[0]), by parsing the font table, looping through it, and checking if the given character is inside the map (see this question).
  2. If the result of step 1 is False (i.e it’s not contained within the font pack), go through fallbackList, repeating step 1, until you find a font that does contain it. If you find a character with no font containing it, just use the first font. We’ll call this font we just found foundFont.
  3. Draw that character with textpath.TextPath((xPosNow, y) ...stuff... prop=foundFont).getextents() (matplotlib > 1.0.0). This draws that character, but also gets the bounding box of the text, from which you can extract the width (see this question). Do xPosNow += textWidth, where textWidth is extracted from getextents().

This would essentially keep a tally of the total distance from the origin (by adding together the width of each bit of text you add), and then when you need to add another bit of text in a different font, simply set the x value to be this tally + a little bit for kerning, and this way, you can just work out where you want each character to go (but do each character separately).

Here’s a code example:

JavaScript

We call it with:

JavaScript

And the output is:

image

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement