Skip to content

Conversation

saranti
Copy link
Contributor

@saranti saranti commented Aug 4, 2023

PR summary

Closes #24872. Adds documentation that describes the process of making newly added fonts available to the fontmanager.

  • Made public the load_fontmanager method which can be used in place of the deprecated matplotlib.font_manager._rebuild() method.
  • Added a new Loading new fonts section to the fonts-in-matplotlib doc with an explanation of the methods of reloading the font cache, with example code.

PR checklist

@saranti saranti marked this pull request as draft August 4, 2023 13:29
@story645 story645 added New feature Documentation: user guide files in galleries/users_explain or doc/users labels Aug 4, 2023
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.

@tacaswell
Copy link
Member

Unfortunately I do not think it is this simple because we keep a singleton of this cache and then re-expose its methods at the module level.

I think the steps here are:

  • keep the load function private
  • write top-level functions that replace find_font and get_font_names (minor API break but we need it to make sure if someone does from matplotlib.font_manager import find_font and then we update the cache the function they are holding onto is not the old one...I guess we could fake the method properties on a function but it is not worth it)
  • write a new top level function like reload_fontcache or something similar name that updates the fontManager singleton. If someone has done from matplotlib.font_manager import fontManager I think we are stuck in a world where they will still have a reference to the old one! I guess we could deprecate it as a publicly accessible

An alternate path would be to update FontManager to be able to have its internal state updated.

@tacaswell tacaswell added this to the v3.9.0 milestone Aug 4, 2023
@tacaswell
Copy link
Member

An alternate to my last comment is to explain why this does work as it looks like it creates a new FontManger that we then throw away, but some how the existing FontManager is changed?

@anntzer
Copy link
Contributor

anntzer commented Aug 8, 2023

Haven't read through the whole issue, but note that in the rebuild_if_missing branch at the end of findfont_cached, fontManager calls _load_fontmanager then replaces its __dict__ with the contents of the newly loaded instance (so the old one really becomes a copy of the new one).

See also #13810/#13852, which may be worth revisiting?

@tacaswell
Copy link
Member

That is a bit heavy handed, but makes sense (a recache method might be better).

However the way this is hidden behind a cache, we will only automatically discover the new font if it is there when we search for it. It might be worth also adding a public way to clear that cache.

@saranti saranti closed this Mar 23, 2024
@saranti saranti deleted the load_custom_font branch March 23, 2024 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation: user guide files in galleries/users_explain or doc/users New feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Doc]: Documentation should clearly describe how a user can make matplotlib load custom fonts per default
4 participants