How to Use a (Random) *.Otf or *.Ttf Font in Matplotlib

How to use a (random) *.otf or *.ttf font in matplotlib?

See the example here: http://matplotlib.sourceforge.net/examples/api/font_file.html

In general, you'd do something like this if you're wanting to use a specific .ttf file. (Keep in mind that pointing to a specific font file is usually a bad idea!)

import matplotlib.font_manager as fm
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.plot(range(10))

prop = fm.FontProperties(fname='/usr/share/fonts/truetype/groovygh.ttf')
ax.set_title('This is some random font', fontproperties=prop, size=32)

plt.show()

Sample Image

Usually, you'd just point to the name of the font, and let matplotlib worry about finding the specific file. E.g.

import matplotlib.pyplot as plt

plt.plot(range(10))
plt.title('This is some random font', family='GroovyGhosties', size=32)

plt.show()

If you want to have matplotlib always use a particular font, then customize your .matplotlibrc file. (font.family is what you'd want to set. Note that you should specify the name of the font, not the path to a specific .ttf file.)

As an example of doing this dynamically (i.e. without setting up a specific .matplotlibrc file):

import matplotlib as mpl
mpl.rcParams['font.family'] = 'GroovyGhosties'

import matplotlib.pyplot as plt

plt.plot(range(10))
plt.title('Everything is crazy!!!', size=32)
plt.show()

Sample Image

Font of labels in matplotlib

You can pass a fontdict with the font parameters, specifying the 'family' with the font you want to use:

font = {'family': 'Latin Modern Roman',
'color': 'darkred',
'weight': 'normal',
'size': 16,
}
plt.ylabel('label-text', fontdict=font)

or set the family in the label:

plt.ylabel('label-text', family='Latin Modern Roman')

There's a full example in the docs using fontdict

Set matplotlib font by family name when there are multiple fonts with same name

That is a really good question. I will provide the way I found the solution to that specific problem. In order to reproduce it we first have to download the given fonts from here (I downloaded the version 10 regular and the 17 version regular to see a clearer difference). Once installed we can check if our new font is found by matplotlib:

from matplotlib import font_manager

font_manager.font_manager.findSystemFonts(fontext='otf') # Matplotlib associates with
# the .otf extension two more extensions viz. '.ttc' and '.ttf', as can be obtain over
# font_manager.get_fontext_synonyms('otf')

Once you have found your specified path to your .otf file, we can use the font_manager to make that specific version our selected font.

# This will create an object which contains your file and give it a custom name
# Here is the idea of this: https://stackoverflow.com/questions/35668219/how-to-set-up-a-custom-font-with-custom-path-to-matplotlib-global-font
fe = font_manager.FontEntry(
fname='C:\\Users\\<your_user_name>\\AppData\\Local\\Microsoft\\Windows\\Fonts\\latin-modern-roman.mroman10-regular.otf',
name='10erLatin')
font_manager.fontManager.ttflist.insert(0, fe)
mpl.rcParams['font.family'] = fe.name

Lets plot it so that we can later see whether it worked or not.

import numpy as np
from pathlib import Path

import matplotlib as mpl
# import PyQt5
# mpl.use('Qt5Agg') # I want to plot it inline ;)
import matplotlib.pyplot as plt

mpl.rcParams['font.family'] = fe.name
mpl.rcParams['font.weight'] = '400'
mpl.rcParams['font.style'] = 'normal'
mpl.rcParams['font.variant'] = 'normal'
mpl.rcParams['mathtext.fontset'] = 'custom'
mpl.rcParams['mathtext.default'] = 'it'
mpl.rcParams['mathtext.rm'] = fe.name + ':normal'
mpl.rcParams['mathtext.it'] = fe.name + ':italic'
mpl.rcParams['mathtext.bf'] = fe.name + ':bold'

mpl.rcParams['xtick.labelsize'] = 8
mpl.rcParams['ytick.labelsize'] = 8
mpl.rcParams['axes.titlesize'] = 10
mpl.rcParams['axes.labelsize'] = 10

x = np.linspace(0,2*np.pi,100)
y = np.sin(x)

fig1 = plt.figure(figsize=(3, 3*(9/16)), dpi=300)
ax1 = fig1.gca()
ax1.plot(x, y, c='r', linewidth=1.0, zorder=20)
ax1.set_xlabel(r'$x\ label$')
ax1.set_ylabel(r'$y\ label$')
fig1.tight_layout(pad=0.15)
plt.show()

Sample Image

Lets change it up to the 17 version of the regular font.

fe = font_manager.FontEntry(
fname='C:\\Users\\<your_user_name>\\AppData\\Local\\Microsoft\\Windows\\Fonts\\latin-modern-roman.mroman17-regular.otf',
name='17erLatin')
font_manager.fontManager.ttflist.insert(0, fe)
mpl.rcParams['font.family'] = fe.name

Again, lets plot it (used the exact same code as above to create that plot, just executed the given code beforehand).

Sample Image

If my hindsight is not too bad, then the text changed globally. There are some other functions which might be useful to look at, however, they are really hidden in the source code. Please let me know, if you run into problems.

Matplotlib how to set legend's font type

Pass the FontProperties object (such as font below) to ax.legend via the prop parameter:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.font_manager as font_manager

fig, ax = plt.subplots()
x = np.linspace(-10, 10, 100)
ax.plot(np.sin(x)/x, label='Mexican hat')

font = font_manager.FontProperties(family='Comic Sans MS',
weight='bold',
style='normal', size=16)
ax.legend(prop=font)
plt.show()

Sample Image

On Ubuntu, you can make new fonts available to your system by running

fc-cache -f -v /path/to/fonts/directory

I'm not sure how it is done on other OSes, or how universal fc-cache is on other flavors of Unix.


Once you've installed your font(s) so that your OS knows about them, you can cause matplotlib to regenerate its fontList by deleting the files in ~/.cache/fontconfig and ~/.cache/matplotlib.


The ~/.cache/matplotlib/fontList.json file gives you a humanly-readable list of all the fonts matplotlib knows about. There, you'll find entries that look like this:

{
"weight": "bold",
"stretch": "normal",
"fname": "/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS_Bold.ttf",
"_class": "FontEntry",
"name": "Comic Sans MS",
"style": "normal",
"size": "scalable",
"variant": "normal"
},

Notice that the fname is the path to the underlying ttf file, and that there is a name property as well. You can specify the FontProperties object by the path to the ttf file:

font = font_manager.FontProperties(fname="/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS_Bold.ttf")

or by name:

font = font_manager.FontProperties(family='Comic Sans MS',
weight='bold',
style='normal', size=16)

If you do not wish to install your font system-wide, you can specify the FontProperties object by fname path, thus by-passing the need to call fc-cache and messing with ~/.cache.

plt.show() can find font, but plt.savefig() cannot

I found this explanation this morning, which helps matplotlib find a family of fonts installed in the user profile. It's important to note that both ~/.matplotlib/fontList.py3k.cache AND ~/.matplotlip/tex.cache need to be cleared. I had only cleared ~/.matplotlib/fontList.py3k.cache during my initial tries.

I still haven't identified WHY plt.show() and plt.savefig() behaved differently when only one cache was cleared, but I am now able to save figures with the fonts that I want.

Matplotlib: set family of text

Solved it: text.usetex has to be false:

rc('text', usetex=False)

Matplotlib font families: using Arno Pro or other fonts

One can find all of the available fonts using the font manager:

import matplotlib.font_manager
print matplotlib.font_manager.findSystemFonts(fontpaths=None)

This will print a list of all fonts available, I couldn't find Arno Pro, but maybe is you can find a .ttf file for it (or something similar) then doing something like the following

import matplotlib.pylab as plt

plt.rcParams['font.family']='Sawasdee'

mpl.pylab.plot(range(10), mpl.pylab.sin(range(10)))
mpl.pylab.xlabel("Some crazy font", size=20)

produces:
Sample Image

Note I simplify picked a random file from the font manager output called Sawasdee so this may not be installed on your computer and will throw an error.

Obviously this font is also producing some errors so you'll have to watch out for those, good luck!



Related Topics



Leave a reply



Submit