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}.
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?
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
classFontSuperfamily:
def__init__(self, name: str): ...
# or if we want init to be something like a list of files + indexes@classmethoddefget_superfamily(cls, name: str) ->Self: ...
defget_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!).
Activity
socram-somel commented on May 9, 2025
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 commented on May 9, 2025
Sounds good, thanks!
tacaswell commented on May 9, 2025
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
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
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!).
Add font.superfamily support with genre-aware resolution