Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[ENH]: Allow specifying a typeface instead of a font #29866

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

Open
thangleiter opened this issue Apr 3, 2025 · 3 comments
Open

[ENH]: Allow specifying a typeface instead of a font #29866

thangleiter opened this issue Apr 3, 2025 · 3 comments

Comments

@thangleiter
Copy link
Contributor

Problem

Matplotlib has font settings for each font family. This makes it unnecessarily cumbersome to adopt a consistent appearance when using different families.

Proposed solution

Instead of specifying a font for every family, it would be handy to simply configure matplotlib to use a certain typeface, e.g. through a rc key font.typeface. matplotlib could then try to find the font matching font.typeface and the family specified by font.family.

For example, setting font.typeface = 'DejaVu' and font.family = 'sans' would resolve to DejaVu Sans. This would arguably make it easier to switch font families and stay within a given typeface for a consistent appearance. If no match is found, one could always fall back to the fonts listed in font.{family}.

@socram-somel
Copy link

It seems like a good idea. My colleague @bruswaine and I would like to tackle this in the coming weeks—how does that sound?
At first glance, it seems that benchmarks are not required, as this change doesn’t appear to have a performance-critical impact. What’s your take on this?

@thangleiter
Copy link
Contributor Author

Sounds good, thanks!

@tacaswell
Copy link
Member

While it is true that performance is not a major concern here, this is like a major changes to the API which is significantly more impactful!

It is not clear to me that the proposed change is a standard naming convention as per https://fonts.google.com/knowledge/glossary/family_or_type_family_or_font_family the family is the typeface and the variants are weight and styles which is exactly how we are currently using it (with the extension borrowed from css of 5 "generic" names). Quoting the above link

When there are serif and sans serif (or slab serif, or monospaced, etc.) versions of a typeface, they’re often collectively referred to as a superfamily.

which is not a concept we currently express in any part of the API. This pushes me to reframe this as "how do we add super families to mpl" (https://fonts.google.com/knowledge/glossary/superfamily) then I think there is a path forward, but I think there are some significant API choices to be made.

The first constraint is: no existing user code can break by default! If someone does not opt-into using super families then things that ran on old versions of Matplotlib should still run on new versions. This includes both default values of settings and the API of any of the font / font discovery code.

If we are going to support a third meaning of font.family, what should we do in the case where the user sets font.superfamily='Roboto' and `font.family='DejaVu Serif'? We can not do both! I can think of three option (explode, use dejavu serif, use Roboto Serif) but on first pass do not see a reason to prefer any of them over the others.

How is this going to get threaded through the font search API?

How is this going to interact with the fontfallback API? Do we auto-pupulate with all of the members of the super family in some order? In the OP it suggested going with any sans font, but would it be better to go with any other member of the super family? Again, on first pass I don't see why one is clearly preferable to the other.

Any work on this needs to be done aware of the changes coming from #30000 and the work around that.

This may also need some API work done so that Matplotlib can access more than the first font in a given font file (I do not recall off the top of my head if #300000 or #29816 or the associated work is adding that yet).


If you want to work on this the first step is to write out a plan that addresses the issues above (and I expect will identify a bunch more I did not think of!). The second would be to write a prototype helper class that given superfamily can manage getting the font objects we need to render, something like

class FontSuperfamily:
    def __init__(self, name: str): ...
    # or if we want init to be something like a list of files + indexes
    @classmethod
    def get_superfamily(cls, name: str) -> Self: ...
    def get_family(self, genre: str, weight=None: int|str|None, style=None: str|None) -> Font: ...

Once the prototype manager is fully featured and working, I think it will be clearer how to thread that back through the current code base (and how to document it!).

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

No branches or pull requests

4 participants