The font properties in matplotlib's plot styles are managed by a FontManager class and are specified with a FontProperties class.
To fetch these font properties, matplotlib internally uses an instance of the FontManager class to call a findfont()
function that searches for fonts and returns the best TrueType (TTF) font file in the local or system font path that matches the font specifications in the FontProperties instance. The default fallback font in the specification is DejaVu Sans. The font family can be set to either of the following parameters: 'serif', 'sans-serif', 'cursive', 'fantasy', or 'monospace'. It is possible to find out the TTF file location for any of the font families like this:
In [1]: from matplotlib.font_manager import findfont, FontProperties
In [2]: font = findfont(FontProperties(family=['sans-serif']))
In [3]: font
Out[3]: 'C:\\Users\\xxxxxx\\Anaconda3\\envs\\py3.7.4\\lib\\site-packages\\matplotlib\\mpl-data\\fonts\\ttf\\DejaVuSans.ttf'
Another example for the 'monospace' family:
In [7]: font = findfont(FontProperties(family=['monospace']))
In [8]: font
Out[8]: 'C:\\Users\\xxxxxx\\Anaconda3\\envs\\py3.7.4\\lib\\site-packages\\matplotlib\\mpl-data\\fonts\\ttf\\DejaVuSansMono.ttf'
As you can see, the sans-serif family above is pointing to the default DejaVuSans TTF file because I haven't yet set the FONTNAME
to something else like the 'Lato' font which also belongs to the sans-serif family.
Before, I change the FONTNAME
, it is important to understand first how the font search happens.
Now font search is an expensive task and to make this efficient for subsequent requests, the font info is cached in a JSON file. You can find the evidence in the source code for the FontManager
class. For Windows, this file is found at: %userprofile%\.matplotlib. For more details, refer to the Notes section of the FontManager
class docs:
This performs a nearest neighbor search. Each font is given a
similarity score to the target font properties. The first font with
the highest score is returned. If no matches below a certain threshold
are found, the default font (usually DejaVu Sans) is returned.
The result is cached, so subsequent lookups don't have to perform the
O(n) nearest neighbor search.
On my computer(Windows 10), I had two cache files: fontlist-v300 & fontlist-v310. If you examine the contents of any of these files, it shows a list of fonts and their properties such as TTF file location, style, weight etc. Observe the default family key:
"defaultFamily": {
"ttf": "DejaVu Sans",
"afm": "Helvetica"
}
At this point, we understand that the font will display in DejaVu Sans. This is most noticeable in the title of the plot:
In [1]: import matplotlib as mpl
...: mpl.rcParams['font.family'] = 'sans-serif'
...: import matplotlib.pyplot as plt
...: plt.plot(range(0,50,10))
...: plt.title('Font test', size=32)
...: plt.show()
Plot(default font):

The findfont()
function will always look for the cache file(and create one if it doesn't exist) and if I install a new font on my computer, it is important that this cache file is updated otherwise it would continue to display the fallback font(which is same as default). Before proceeding to next steps, make sure the Lato font is installed correctly. The font should be available under Fonts in the Control Panel.
Now with the Lato font properly installed, delete the cache file(s) and set the sans-serif font to Lato:
In [4]: import matplotlib as mpl^M
...: mpl.rcParams['font.family'] = 'sans-serif'
...: mpl.rcParams['font.sans-serif'] = 'Lato'
...: import matplotlib.pyplot as plt
...: plt.plot(range(0,50,10))
...: plt.title('Font test', size=32)
...: plt.show()
Plot(Lato sans-serif font):

You will also observe a new cache file has been created. The above snippet has re-build the cache file, which now also has Lato fonts' info. Again, you can open this cache file in a text editor to verify its presence. Let's verify the TTF file path for the sans-serif family now:
In [4]: from matplotlib.font_manager import findfont, FontProperties
In [5]: font = findfont(FontProperties(family=['sans-serif']))
In [6]: font
Out[6]: 'C:\\Users\\xxxxx\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Lato-Thin.ttf'
As you can see that the sans-serif family is now pointing to the Lato-Thin TTF file.
Changing the font style to italic also requires that the cache file is deleted first:
In [3]: In [4]: import matplotlib as mpl
...: ...: mpl.rcParams['font.family'] = 'sans-serif'
...: ...: mpl.rcParams['font.sans-serif'] = 'Lato'
...: ...: mpl.rcParams['font.style'] = 'italic'
...: ...: import matplotlib.pyplot as plt
...: ...: plt.plot(range(0,50,10))
...: ...: plt.title('Font test', size=32)
...: ...: plt.show()
In [4]: from matplotlib.font_manager import findfont, FontProperties
In [5]: font = findfont(FontProperties(family=['sans-serif']))
In [6]: font
Out[6]: 'C:\\Users\\xxxxxx\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Lato-HairlineItalic.ttf'
Plot:

Note: All the steps were performed on IPython console, it may be required to restart the IPython session in order for the changes to take effect.