-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Implement Font-Fallback in Matplotlib #20740
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
Conversation
To actually trigger this workflow, I'll push similar commits similar to #20549.. Also, there's a lot of print/debug statements throughout, I'll remove them once this moves ahead.. |
9aee34b
to
9fabbc7
Compare
EDIT: I've merged the FT2Font changes together for both PRs |
0fa0625
to
e868fbc
Compare
f7ee09b
to
37c51b1
Compare
On Linux and Mac. Add a font_manager test that loads the font and uses it. This could be useful in testing the multi-font support (matplotlib#20740 etc). I couldn't get the font installed on Windows. There is a Chocolatey installer that installs all of the Noto fonts, which takes a really long time to run.
@aitikgupta Do these have a review team looking at them? |
@jklymak I don't think anybody is actively reviewing these font handling PRs at the moment.. but they're ready for review and not drafts (I'll resolve the conflicts) |
Going ahead and removing the test, since font distributions for different Linux versions across CI are different.. and thus their kerning information is different -- different visual outputs. We can test it with a self-shipped CJK font, which is guaranteed to be present across all platforms.. but that'd be another problem because their file sizes are huge. |
(Unfortunately, I will not have the bandwidth to review this in the coming days.) |
Hi @aitikgupta we were all discussing this PR yesterday - did you have an opportunity to rebase and address the review comments? |
Hey @jklymak, I'm currently out sick. Will get back to this as soon as I can, probably a week or two. Apologies! |
No rush, get better! |
Hey @QuLogic, addressed all the comments (added comments for further discussions), and brought the PR up to speed! |
3d6c81e
to
02b569a
Compare
The general design looks reasonable and a skim through the actual implementation only revealed the small issues listed above, which should be fixed, but once that's done I am happy with merging this as is and iterating over it later. |
The new code is 2-space indent instead of 4. |
30e47af
to
c62b2e5
Compare
@@ -272,7 +272,9 @@ def _prepare_font(self, font_prop): | |||
""" | |||
Get the `.FT2Font` for *font_prop*, clear its buffer, and set its size. | |||
""" | |||
font = get_font(findfont(font_prop)) | |||
fname = find_fonts_by_props(font_prop) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fname
should be renamed to filename_dict
or at least filenames
(plural) for clarity.
Given that get_font only uses .values()
, I would suggest making it clearer at this stage too (filenames = list(find_fonts_by_props(font_prop).values()); font = get_font(filenames)
) (and modify get_font to take a list instead of a dict). This would also make it easier for third-parties to directly call get_font
with a list of font paths rather having to invent keys to create a dict, if they don't already have a dict at hand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not remember why we used a dictionary instead of a list
As a meta comment, this seems like a pretty big change to squeeze in right before a 3.6 release, versus getting it in |
Talking about that: what is the time line? I sort of expected 3.5.3 to be released "soon" and then probably a few months until 3.6? (Really OT, but still...) |
Fair, however you do not pass a list of fallbacks then there should be no behavior change, we hammer these code paths in the tests, and I do not think of the core devs do enough mixed glyph work (I could be wrong about that) to meaning stress it. |
An additional point I just thought about: the actual low-level API (including passing a list of fallback FT2Font to the FT2Font constructor) should probably be marked as provisional. While I haven't actually checked, I believe that the current API may be slightly inefficient, because (if I understood it correctly) we will always immediately parse all font files (a costly operation) in the fallback list, regardless of whether we actually need them or not, whereas we could imagine an API where we only store a list of fallback paths that get parsed one at a time when needed. (This is also relevant for mplcairo, which doesn't use FT2Font at all and simply gets the paths of the fonts to do its own interfacing with freetype.) |
That will require documenting |
I wasn't actually asking for FT2Font to be documented (a blurb in the changelog without linking API entries would have worked too), but sure, that's always a good thing to add. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be good, though needs the rebase for added/removed files.
Co-authored-by: Aitik Gupta <[email protected]> Co-authored-by: Elliott Sales de Andrade <[email protected]>
14251eb
to
85bacdc
Compare
Squashed this all to 1 commit:
|
Thank you @aitikgupta ! This would not have been possible without your work. |
Super glad this finally made it! Thanks everyone for pushing this 🙇🏼♂️ |
PR Summary
This PR modifies the internal structure of
FT2Font
(the interface between fonts and Matplotlib) in favor of implementing Font Fallback for Matplotlib, and allow Agg backend to use the new codepath.It builds on the previous PR: #20549, which was the 'first-step', i.e., "parsing multiple families".. this PR implements using those families for font fallback.
This would help us in multi-language support, for example (Previous / After):
^the fonts are chosen such that the difference is visually noticeable.
A flowchart explaining the text rendering algorithm with font fallback:

Here's the script:
Fixes #18883, #15260
PR Checklist
pytest
passes).flake8
on changed files to check).flake8-docstrings
and runflake8 --docstring-convention=all
).doc/users/next_whats_new/
(follow instructions in README.rst there).doc/api/next_api_changes/
(follow instructions in README.rst there).