Skip to content

ENH: Allow fonts to be addressed by any of their SFNT family names#31183

Merged
ksunden merged 4 commits intomatplotlib:text-overhaulfrom
Cemonix:fix-font-alt-family-names
Mar 27, 2026
Merged

ENH: Allow fonts to be addressed by any of their SFNT family names#31183
ksunden merged 4 commits intomatplotlib:text-overhaulfrom
Cemonix:fix-font-alt-family-names

Conversation

@Cemonix
Copy link
Copy Markdown

@Cemonix Cemonix commented Feb 20, 2026

PR summary

Closes #4822

A TTF/OTF font file can advertise its family name in multiple places in the
OpenType name table. FreeType exposes one name (typically from the
Macintosh-platform Name ID 1 slot), but other entries carry equally valid names
that users reasonably expect to work:

  • Name ID 1, other platform — some fonts store different names on the Mac
    and Microsoft platforms. For example, Ubuntu Light stores "Ubuntu" in the
    Mac slot and "Ubuntu Light" in the Microsoft slot.
  • Name ID 16 — Typographic/Preferred Family: groups more than the
    traditional four styles (Regular, Bold, Italic, Bold Italic) under one name.
  • Name ID 21 — WWS Family: an even narrower grouping (weight/width/slope
    only).

Previously, only the FreeType-derived name was registered, so users had to use
an unintuitive weight-based workaround:

# Before
matplotlib.rcParams['font.family'] = 'Ubuntu'
matplotlib.rcParams['font.weight'] = 300

This PR adds _get_font_alt_names() and calls it from FontManager.addfont()
to register a separate FontEntry for each alternative name found. Each
alternate entry derives its weight from the corresponding subfamily string
(ID 2/17/22) on the same platform, so that the font's role within its named
family is reflected correctly (e.g. Ubuntu Light is weight 400/"Regular" within
the "Ubuntu Light" family, even though its absolute typographic weight is 300).

After this change:

matplotlib.rcParams['font.family'] = 'Ubuntu Light'

PR checklist

@github-actions
Copy link
Copy Markdown

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a week or so, please leave a new comment below and that should bring it to our attention. Most of our reviewers are volunteers and sometimes things fall through the cracks.

You can also join us on gitter for real-time discussion.

For details on testing, writing docs, and our review process, please see the developer guide.
Please let us know if (and how) you use AI, it will help us give you better feedback on your PR.

We strive to be a welcoming and open project. Please follow our Code of Conduct.

@Cemonix Cemonix force-pushed the fix-font-alt-family-names branch 4 times, most recently from 38ef911 to 837a43a Compare February 21, 2026 10:18
@tacaswell
Copy link
Copy Markdown
Member

This seems reasonable on a quick read to me, but @QuLogic needs to review this.

@QuLogic
Copy link
Copy Markdown
Member

QuLogic commented Feb 23, 2026

It probably makes sense to add more names where available, but I'm uncertain whether, e.g., Ubuntu Light should be regular weight, or a Light suffix should trigger a lower weight instead.

IIRC, @anntzer last looked at the algorithm here, and is probably best suited to deciding.

@anntzer
Copy link
Copy Markdown
Contributor

anntzer commented Feb 26, 2026

  • I agree that there's something not so clear about whether family = "Ubuntu Light" should match with weight = "Regular" (in that it's the "Regular" "Ubuntu Light" font). Maybe we need FontProperties attributes to have an "unset" value (differing from "Regular")? How does e.g. CSS matching (which is very well specified) work in that case?
  • How does the name detection compare with fontconfig's algorithm (at https://cgit.freedesktop.org/fontconfig/tree/src/fcfreetype.c#n1384)?
@Cemonix
Copy link
Copy Markdown
Author

Cemonix commented Feb 27, 2026

Thanks for the questions! I reviewed fontconfig's FcFreeTypeQueryFaceInternal and the CSS font matching spec to understand this better.

Re: fontconfig comparison:

The approach is very similar - both iterate over name IDs (1/16/21 for family, 2/17/22 for subfamily) on Mac and Microsoft platforms, then parse the subfamily string for weight keywords.

The main difference: fontconfig uses -1 as "unset" and defaults to FC_WEIGHT_MEDIUM if no weight is found, while my code defaults to 400 immediately when no keyword matches.

Re: "unset" vs 400:

I chose 400 to match matplotlib's existing behavior and CSS semantics. In CSS, an unspecified weight always resolves to a numeric value (typically 400/"normal") before font matching begins. So when a user requests family='Ubuntu Light' without specifying weight, they get the "Regular" variant of that family.

However, I'm open to using a sentinel value (like None) if you think that better represents these alternate families. The tradeoff is it would require changes to the scoring function to handle unset weights.

Re: CSS matching:

CSS Fonts Level 4 spec defines normal = 400, and the matching algorithm searches outward from the requested weight when exact matches aren't available. There's no concept of "unset weight" in the matching algorithm - it always works with numeric values.

Let me know if you'd prefer a different approach for handling the weights.

Copy link
Copy Markdown
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

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

Since you are changing the FontEntrys, I think you would need to bump the FontManager.__version__ to ensure the cache is regenerated.

I also think you may want to target the text-overhaul branch, as I suspect there will be some conflicts that would need resolving.

@Cemonix Cemonix force-pushed the fix-font-alt-family-names branch from 9e6bdcc to ef596a5 Compare March 20, 2026 17:35
Cemonix and others added 3 commits March 20, 2026 18:55
…latform name

A TTF/OTF file can advertise its family name in multiple places in the
SFNT name table.  FreeType exposes the primary name (usually from the
Macintosh-platform Name ID 1 slot), but other entries may carry
different (equally valid) names that users reasonably expect to work:

- Name ID 1 on the other platform (e.g. Ubuntu Light stores "Ubuntu"
  in the Mac slot and "Ubuntu Light" in the Microsoft slot)
- Name ID 16 — Typographic/Preferred Family
- Name ID 21 — WWS Family
Co-authored-by: Elliott Sales de Andrade <quantum.analyst@gmail.com>
@Cemonix Cemonix force-pushed the fix-font-alt-family-names branch from ef596a5 to c776974 Compare March 20, 2026 18:03
@Cemonix Cemonix changed the base branch from main to text-overhaul March 20, 2026 18:03
@github-actions github-actions bot added the CI: Run cibuildwheel Run wheel building tests on a PR label Mar 20, 2026
@Cemonix
Copy link
Copy Markdown
Author

Cemonix commented Mar 20, 2026

Done, also fixed the face-loop conflict in addfont and the set append in the test while rebasing onto text-overhaul.

@github-project-automation github-project-automation bot moved this to Waiting for other PR in Font and text overhaul Mar 20, 2026
@QuLogic QuLogic moved this from Waiting for other PR to Ready for Review in Font and text overhaul Mar 20, 2026
@QuLogic QuLogic added this to the v3.11.0 milestone Mar 20, 2026
@Cemonix Cemonix force-pushed the fix-font-alt-family-names branch from c776974 to b6cde63 Compare March 20, 2026 21:47
@github-actions github-actions bot removed the CI: Run cibuildwheel Run wheel building tests on a PR label Mar 20, 2026
Copy link
Copy Markdown
Member

@QuLogic QuLogic left a comment

Choose a reason for hiding this comment

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

Looking at https://learn.microsoft.com/en-us/typography/opentype/spec/name, it makes sense to me to look at IDs 1/2, 16/17, and 21/22. Maybe that'll be too many, but we'll see if people complain.

And I can see the argument that "Ubuntu Light" -> (name="Ubuntu", weight=100) with a separate entry of (name="Ubuntu Light", weight=400).

@melissawm melissawm moved this from Needs review to Needs decision in First Time Contributors Mar 26, 2026
@ksunden ksunden merged commit 4efa3c0 into matplotlib:text-overhaul Mar 27, 2026
26 of 36 checks passed
@github-project-automation github-project-automation bot moved this from Ready for Review to Done in Font and text overhaul Mar 27, 2026
@github-project-automation github-project-automation bot moved this from Needs decision to Merged in First Time Contributors Mar 27, 2026
@ksunden
Copy link
Copy Markdown
Member

ksunden commented Mar 27, 2026

Merged over known test failures that are resolved by other PRs

@QuLogic
Copy link
Copy Markdown
Member

QuLogic commented Mar 27, 2026

Thanks @Cemonix! Congratulations on your first PR to Matplotlib 🎉 We hope to hear from you again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment