GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Implement Font-Fallback in Matplotlib by aitikgupta · Pull Request #20740 · matplotlib/matplotlib

Conversation

@aitikgupta

@aitikgupta aitikgupta commented Jul 25, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

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:
FontFallback

Here's the script:

import matplotlib.pyplot as plt
# "Authentic" is a fancy font, whereas "SimHei" is a CJK font
plt.rcParams['font.family'] = ['Authentic', 'SimHei']
plt.rcParams['font.size'] = 30

plt.figtext(0.18, 0.45, "There are 多个汉字 in between!")
plt.show()

Fixes #18883, #15260

PR Checklist

  • Has pytest style unit tests (and pytest passes).
  • Is Flake 8 compliant (run flake8 on changed files to check).
  • New features are documented, with examples if plot related.
  • Documentation is sphinx and numpydoc compliant (the docs should build without error).
  • Conforms to Matplotlib style conventions (install flake8-docstrings and run flake8 --docstring-convention=all).
  • New features have an entry in doc/users/next_whats_new/ (follow instructions in README.rst there).
  • API changes documented in doc/api/next_api_changes/ (follow instructions in README.rst there).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

cesaryuan, lostanlen, Alalalalaki, Isuxiz, and YUCHENYUXI reacted with thumbs up emoji bmcfee, wxupjack, and YUCHENYUXI reacted with heart emoji
All reactions
  • 👍 5 reactions
  • ❤️ 3 reactions
@aitikgupta

aitikgupta commented Jul 25, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

To actually trigger this workflow, I'll push similar commits similar to #20549..
Note: this is only tested against Agg backend (since agg is pretty straightforward in terms of font usage)

Also, there's a lot of print/debug statements throughout, I'll remove them once this moves ahead..

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aitikgupta
aitikgupta marked this pull request as draft July 26, 2021 06:32
@aitikgupta
aitikgupta force-pushed the fallback-revamp branch 2 times, most recently from 9aee34b to 9fabbc7 Compare August 6, 2021 23:47
@aitikgupta aitikgupta changed the title Implement Font-Fallback in Matplotlib Implement Font-Fallback for Agg backend Aug 6, 2021
@aitikgupta aitikgupta mentioned this pull request Aug 6, 2021
Implement multi-font embedding for PDF Backend #20804
Closed
7 tasks
@aitikgupta

aitikgupta commented Aug 7, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

Note: There's some structural changes to how FT2Font is handling stuff in #20804, which builds on this PR..

EDIT: I've merged the FT2Font changes together for both PRs

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aitikgupta
aitikgupta force-pushed the fallback-revamp branch 2 times, most recently from 0fa0625 to e868fbc Compare August 7, 2021 00:08
@aitikgupta
aitikgupta marked this pull request as ready for review August 7, 2021 08:22
@aitikgupta aitikgupta changed the title Implement Font-Fallback for Agg backend Implement Font-Fallback in Matplotlib Aug 13, 2021
@aitikgupta
aitikgupta force-pushed the fallback-revamp branch from f7ee09b to 37c51b1 Compare August 18, 2021 00:14
jkseppan added a commit to jkseppan/matplotlib that referenced this pull request Aug 20, 2021
@jkseppan
Try to install the Noto Sans CJK font
bf38aa9
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.
@jkseppan jkseppan mentioned this pull request Aug 20, 2021
Try to install the Noto Sans CJK font #20851
Merged
7 tasks
@jklymak

jklymak commented Oct 4, 2021

Copy link
Copy Markdown
Member

@aitikgupta Do these have a review team looking at them?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aitikgupta

aitikgupta commented Oct 4, 2021

Copy link
Copy Markdown
Contributor Author

@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)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@story645 story645 added the topic: text/fonts label Oct 4, 2021
@aitikgupta

aitikgupta commented Oct 22, 2021 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aitikgupta
aitikgupta requested a review from anntzer October 22, 2021 21:13
@aitikgupta aitikgupta added the backend: agg label Oct 22, 2021
@anntzer

anntzer commented Oct 27, 2021

Copy link
Copy Markdown
Contributor

(Unfortunately, I will not have the bandwidth to review this in the coming days.)

aitikgupta reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bmcfee bmcfee mentioned this pull request Dec 22, 2021
Tempo(gram) display with musical notation librosa/librosa#1426
Open
@tacaswell tacaswell added this to the v3.6.0 milestone Dec 22, 2021
QuLogic
QuLogic reviewed Dec 23, 2021
View reviewed changes
Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

@QuLogic QuLogic added the status: needs rebase label Dec 23, 2021
@jklymak

jklymak commented Jan 14, 2022

Copy link
Copy Markdown
Member

Hi @aitikgupta we were all discussing this PR yesterday - did you have an opportunity to rebase and address the review comments?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aitikgupta

aitikgupta commented Jan 16, 2022

Copy link
Copy Markdown
Contributor Author

Hey @jklymak, I'm currently out sick. Will get back to this as soon as I can, probably a week or two. Apologies!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@jklymak

jklymak commented Jan 16, 2022

Copy link
Copy Markdown
Member

No rush, get better!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aitikgupta

aitikgupta commented Jan 23, 2022

Copy link
Copy Markdown
Contributor Author

Hey @QuLogic, addressed all the comments (added comments for further discussions), and brought the PR up to speed!

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tacaswell
tacaswell force-pushed the fallback-revamp branch from 3d6c81e to 02b569a Compare February 18, 2022 23:05
anntzer
anntzer reviewed Jul 7, 2022
View reviewed changes
Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

@anntzer

anntzer commented Jul 7, 2022

Copy link
Copy Markdown
Contributor

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tacaswell tacaswell mentioned this pull request Jul 7, 2022
Support TTC fonts by converting them to TTF in font cache #23293
Closed
3 of 4 tasks
@QuLogic

QuLogic commented Jul 7, 2022

Copy link
Copy Markdown
Member

The new code is 2-space indent instead of 4.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tacaswell
tacaswell force-pushed the fallback-revamp branch from 30e47af to c62b2e5 Compare July 7, 2022 22:52
QuLogic
QuLogic reviewed Jul 8, 2022
View reviewed changes
Comment thread doc/users/next_whats_new/font_fallback.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread doc/users/next_whats_new/font_fallback.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/tests/test_ft2font.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/tests/test_ft2font.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/tests/test_ft2font.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

anntzer
anntzer reviewed Jul 8, 2022
View reviewed changes
Comment thread lib/matplotlib/backends/backend_agg.py Outdated
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)

@anntzer anntzer Jul 8, 2022 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

tacaswell reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

@tacaswell tacaswell Jul 8, 2022

Copy link
Copy Markdown
Member

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

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@jklymak

jklymak commented Jul 8, 2022

Copy link
Copy Markdown
Member

As a meta comment, this seems like a pretty big change to squeeze in right before a 3.6 release, versus getting it in main and letting the devs live with it, and anyone else who is testing our dev tree, for a few months. However, maybe I am misunderstanding its potential to break existing users who don't typically need the fallback.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@oscargus

oscargus commented Jul 8, 2022

Copy link
Copy Markdown
Member

right before a 3.6 release

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...)

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tacaswell

tacaswell commented Jul 8, 2022

Copy link
Copy Markdown
Member

As a meta comment, this seems like a pretty big change to squeeze in right before a 3.6 release, ...

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.

jklymak reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

QuLogic
QuLogic reviewed Jul 9, 2022
View reviewed changes
Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@anntzer

anntzer commented Jul 9, 2022

Copy link
Copy Markdown
Contributor

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.)
I certainly don't want to hold up merging by requesting a large API design change at the last minute, but marking the low-level parts as provisional would certainly simplify possible improvements in the future.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@tacaswell

tacaswell commented Jul 9, 2022

Copy link
Copy Markdown
Member

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.

That will require documenting ft2font at all, but a reasonable request. The keyword already starts with _ so I think documenting it at provisional and/or private is consistent with the original intent.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

QuLogic
QuLogic reviewed Jul 10, 2022
View reviewed changes
Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread src/ft2font_wrapper.cpp Resolved

Uh oh!

There was an error while loading. Please reload this page.

@anntzer

anntzer commented Jul 10, 2022

Copy link
Copy Markdown
Contributor

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.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

anntzer
anntzer reviewed Jul 10, 2022
View reviewed changes
Comment thread lib/matplotlib/font_manager.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

QuLogic
QuLogic approved these changes Jul 21, 2022
View reviewed changes

@QuLogic QuLogic left a comment

Copy link
Copy Markdown
Member

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.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@aitikgupta @QuLogic @tacaswell
ENH: support font fallback for Agg renderer
85bacdc
Co-authored-by: Aitik Gupta <[email protected]>
Co-authored-by: Elliott Sales de Andrade <[email protected]>
@tacaswell
tacaswell force-pushed the fallback-revamp branch from 14251eb to 85bacdc Compare August 3, 2022 21:48
@tacaswell

tacaswell commented Aug 3, 2022

Copy link
Copy Markdown
Member

Squashed this all to 1 commit:

(dd310) ~/s/p/m/matplotlib fallback-revamp↑·1↓·63|…3⚑5
✔ 17:45:01 $ git describe
v3.5.2-2641-g85bacdccc5
(dd310) ~/s/p/m/matplotlib fallback-revamp↑·1↓·63|…3⚑5
✔ 17:45:05 $ git diff 14251eb
(dd310) ~/s/p/m/matplotlib fallback-revamp↑·1↓·63|…3⚑5

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@efiring
efiring merged commit 535c953 into matplotlib:main Aug 4, 2022
@tacaswell

tacaswell commented Aug 4, 2022

Copy link
Copy Markdown
Member

Thank you @aitikgupta ! This would not have been possible without your work.

bmcfee and aitikgupta reacted with hooray emoji
All reactions
  • 🎉 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@aitikgupta

aitikgupta commented Aug 5, 2022

Copy link
Copy Markdown
Contributor Author

Super glad this finally made it! Thanks everyone for pushing this 🙇🏼‍♂️

story645 and Hsins reacted with hooray emoji
All reactions
  • 🎉 2 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

This was referenced Aug 9, 2022
[with findfont diff] Parsing all families in font_manager #20496
Closed
[without findfont diff] Parsing all families in font_manager #20549
Closed
@tfpf tfpf mentioned this pull request Aug 20, 2022
\times in minor ticklabels not recognized due to \mathdefault #10029
Closed
@tinyboxvk tinyboxvk mentioned this pull request Sep 24, 2022
[Bug]: Font-Fallback implemented in 3.6.0 does not work for title or labels #23992
Closed
@story645 story645 mentioned this pull request Oct 16, 2023
MNT: print fontname in missing glyph warning #26989
Merged
1 task done
@StefRe StefRe mentioned this pull request Nov 23, 2023
[MNT]: pyplot.xkcd() leads to findfont errors under Windows #27350
Open
@dedebenui dedebenui mentioned this pull request Feb 29, 2024
[Bug]: Font fallback doesn't work on \mathdefault #27838
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@tacaswell tacaswell tacaswell left review comments
@anntzer anntzer anntzer left review comments
@QuLogic QuLogic QuLogic approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

backend: agg Release critical For bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. topic: text/fonts

Projects

None yet

Milestone

v3.6.0

Development

Successfully merging this pull request may close these issues.

Matplotlib would not try to apply all the font in font list to draw all characters in the given string.

Uh oh!

There was an error while loading. Please reload this page.

8 participants

@aitikgupta @jklymak @anntzer @tacaswell @QuLogic @oscargus @efiring @story645
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.