How can I configure matplotlib to be able to read fonts from a local path?

Question:

I would like to be able to place .ttf files in a local folder and have Matplotlib configured to look in that folder for fonts if it can’t find them in the normal system folders. This previous answer showed how to point to a specific font in any directory. Here’s the code in the answer:

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.font_manager as font_manager

path = '/usr/share/fonts/truetype/msttcorefonts/Comic_Sans_MS.ttf'
prop = font_manager.FontProperties(fname=path)
mpl.rcParams['font.family'] = prop.get_name()
fig, ax = plt.subplots()
ax.set_title('Text in a cool font', size=40)
plt.show()

The problem with this is that I would have to do this every time I want Helvetica (or in this case Comic Sans) in my plot. I believe another solution is to copy the ttf file into something like ~/anaconda/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf, but I’d prefer not to touch that stuff and place files locally so they don’t disappear when I update matplotlib, and so it’s easier to sync my configuration across different machines. I feel like there should be some way to configure matplotlib in my ~/.matplotlib/matplotlibrc file so that if I use Helvetica I don’t have to provide the path each time. How can I place a .ttf file in a custom directory (or at least one that is safe against python or matplotlib updates) and not have to retype the file path every time I plot?

Bonus points if the solution allows me to use a path relative to the directory returned by import matplotlib; matplotlib.get_configdir(), since for some of my machines that is ~/.config/matplotlib and for some it’s ~/.matplotlib.

Asked By: Ben Lindsay

||

Answers:

In case anyone cares, I decided it’s most convenient to just copy my .ttf files to the directory that looks something like ~/anaconda/lib/python2.7/site-packages/matplotlib/mpl-data/fonts/ttf. The files were still there after I updated matplotlib, so at least it will probably be a while before I will have to repeat the process, and this way I don’t need to point to a directory or call a script every time I plot. If you do this and/or change your default font list in your matplotlibrc file (both of which I did) you’ll probably have to delete your cache file located somewhere like ~/.matplotlib/fontList.cache or ~/.cache/matplotlib/fontList.cache`. Matplotlib will regenerate this next time you plot something.

Answered By: Ben Lindsay

To add to @Ben’s answer, I wrote a script that does this automatically for any python distribution. Place your .ttf files in some folder, and run this script to move them to the matplotlib fonts folder.

#!/usr/bin/env python3
# Imports
import os
import re
import shutil
from glob import glob
from matplotlib import matplotlib_fname
from matplotlib import get_cachedir

# Copy files over
dir_source = '<your-font-directory-here>'
dir_data = os.path.dirname(matplotlib_fname())
dir_dest = os.path.join(dir_data, 'fonts', 'ttf')
print(f'Transfering .ttf and .otf files from {dir_source} to {dir_dest}.')
for file in glob(os.path.join(dir_source, '*.[ot]tf')):
    if not os.path.exists(os.path.join(dir_dest, os.path.basename(file))):
        print(f'Adding font "{os.path.basename(file)}".')
        shutil.copy(file, dir_dest)

# Delete cache
dir_cache = get_cachedir()
for file in glob(os.path.join(dir_cache, '*.cache')) + glob(os.path.join(dir_cache, 'font*')):
    if not os.path.isdir(file): # don't dump the tex.cache folder... because dunno why
        os.remove(file)
        print(f'Deleted font cache {file}.')
Answered By: Luke Davis
  1. Install your font. In Windows, right-click and choose “Install.” In Linux, put your TTF file in ~/.local/share/fonts/ and run fc-cache. You can check if it worked and get the name of the font with fc-list.
  2. Run this once in your virtual environment(s): matplotlib.font_manager._rebuild()
  3. Restart your kernel if you’re using Jupyter.
  4. Add this to your code:
matplotlib.rcParams.update({
    'font.sans-serif': 'Graphik',
    'font.family': 'sans-serif',
})
  1. For some fonts matplotlib doesn’t get the weights right; you may want to specify them explicitly in rcParams:
    'font.weight': 'normal',
    'axes.labelweight': 'normal',
    'axes.titleweight': 'normal',
Answered By: Doctor J
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.