Skip to content

add documentation for reloading font cache #26453

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions galleries/users_explain/text/fonts.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,33 @@
Each glyph of the string is rendered using the first font in the list that
contains that glyph.

Loading new fonts
-----------------

All fonts that are installed in your system will become available to the
`.FontManager`, as well as the default fonts that ship with Matplotlib. The latter
fonts are located in the directory ``'matplotlib\mpl-data\fonts\ttf'``.
It is also possible to add fonts to this directory, or to `allocate a custom
directory
<https://matplotlib.org/stable/api/font_manager_api.html#matplotlib.font_manager.findSystemFonts>`_
that contains any fonts you wish to add to the `.FontManager`.

In either case, the `.FontManager` will only find the new fonts after the font cache
has been rebuilt following their addition . You may need to rebuild the cache
yourself if your new fonts cannot be found by Matplotlib.
The cache can be rebuilt by using :func:`matplotlib.font_manager.load_fontmanager`::
import matplotlib as mpl
mpl.font_manager.load_fontmanager(try_read_cache=False)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that this will actually work?

This will make a new font manager and return it to you, but it will not change the singleton that is used by the rest of the library or update the findfont and get_font_names held at the module level.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My testing procedure for this was:

  • add a new font to mpl-data\fonts\ttf
  • run a short plot with a text instance with family=new font
  • see that the text doesn't update to the new font after multiple runs
  • run the font_manager.load_fontmanager code
  • run the plot again

Now the text is now set to the new font and a new entry in the font cache is present. The findfont and get_font_names methods both return the new font.
I did notice however, that the before and after fontmanager instances were the same object with the same ID.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... ok, I do not understand why that works 🤯

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, question: are you running this all in the same process or each in its own Python process?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each in their own separate process.


Alternatively, you can expose the location of your font cache using
:func:`matplotlib.get_cachedir`::
import matplotlib as mpl
mpl.get_cachedir()
'/home/darren/.cache/matplotlib'

You can then manually delete the cache file ``'fontlist<version>.json'``. The new fonts
will be available the next time the script is run.

A majority of this work was done by Aitik Gupta supported by Google Summer of
Code 2021.
"""
11 changes: 7 additions & 4 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1456,10 +1456,10 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default,
if rebuild_if_missing:
_log.info(
'findfont: Found a missing font file. Rebuilding cache.')
new_fm = _load_fontmanager(try_read_cache=False)
new_fm = load_fontmanager(try_read_cache=False)
# Replace self by the new fontmanager, because users may have
# a reference to this specific instance.
# TODO: _load_fontmanager should really be (used by) a method
# TODO: load_fontmanager should really be (used by) a method
# modifying the instance in place.
vars(self).update(vars(new_fm))
return self.findfont(
Expand Down Expand Up @@ -1558,7 +1558,10 @@ def get_font(font_filepaths, hinting_factor=None):
)


def _load_fontmanager(*, try_read_cache=True):
def load_fontmanager(*, try_read_cache=True):
"""
Re-loads the font cache by generating a new `.FontManager` instance.
"""
fm_path = Path(
mpl.get_cachedir(), f"fontlist-v{FontManager.__version__}.json")
if try_read_cache:
Expand All @@ -1576,6 +1579,6 @@ def _load_fontmanager(*, try_read_cache=True):
return fm


fontManager = _load_fontmanager()
fontManager = load_fontmanager()
findfont = fontManager.findfont
get_font_names = fontManager.get_font_names
1 change: 1 addition & 0 deletions lib/matplotlib/font_manager.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,4 @@ def findfont(
rebuild_if_missing: bool = ...,
) -> str: ...
def get_font_names() -> list[str]: ...
def load_fontmanager(try_read_cache: bool = ...) -> FontManager: ...