The FontProperties family parameter can be a generic family such as sans-serif and the actual font should be looked up in rcParams according to the documentation.
Code for reproduction
>>>importmatplotlibasmpl>>>importmatplotlib.font_managerasfm>>>mpl.rcParams["font.family"]
['sans-serif']
>>>mpl.rcParams["font.sans-serif"]
['DejaVu Sans',
'Bitstream Vera Sans',
'Computer Modern Sans Serif',
'Lucida Grande',
'Verdana',
'Geneva',
'Lucid',
'Arial',
'Helvetica',
'Avant Garde',
'sans-serif']
>>>fp=fm.FontProperties()
<matplotlib.font_manager.FontPropertiesat ...>>>>fp.get_family()
['sans-serif']
Actual outcome
>>>fp.get_family()
['sans-serif']
Expected outcome
>>>fp.get_family()
['DejaVu Sans',
'Bitstream Vera Sans',
'Computer Modern Sans Serif',
'Lucida Grande',
'Verdana',
'Geneva',
'Lucid',
'Arial',
'Helvetica',
'Avant Garde',
'sans-serif']
Why is the result correct? Where, other than the documentation is the public API specified? If it's just documentation that is out of date, then the FontProperties docstring needs updating also.
Yes, I appreciate what the docs say. However, our usual pattern for setter/getters is for them to be reversible, so it would be unusual for get_family to return something other than what set_family was given.
that sounds like this is a bug in Matplotlib where the intended behavior is what's stated in the docs and somehow didn't get implemented or got reverted years ago. thanks for catching that
eta: I think this might be a consistency issue attn: @timhoffm
To start with, I want to note that fonts are confusing. I do not think there are any major bugs or documentation errors here, however the documentation is ambiguous and should be clearer.
First FontProperties are not actually fonts, they are the input to
(which is a wrapper around _findfont_cached defined right below) that takes in the props and gives back the file path of the closest font to the one requested. Internally we will eventually open what ever file that is and use it to render the text.
Because the "family" on the FontProperties is a list (rather than a single name) this means you can list several fonts in preference order and we will use the first one that is actually installed. This behavior dates back to 2007-2008 and is consistent with css https://developer.mozilla.org/en-US/docs/Web/CSS/font-family . The ambiguity of using "family" to refer to the list, the things in the list, and the generic things seems to be an ambiguity that we inherited. I think the docstring on get_family should be clearer on which "family" it is referring too.
The other question is when do we resolve the generic font families ("sans", "serif", ...). @l-johnston has the expectation that we resolve it eagerly when the family is set on the FontProperties, however we actually do it lazily when we are actually looking the font up at
. I think either behavior is defendable, however we have been doing it late from 2008.
On net, I think doing it late is a preferable. If the rcparam for the generic families changes between when the FontProperties object is created and when the Figure is saved it is ambiguous which state should be used. "do what it says at draw time" seems easier to understand as if we resolved it early you could have N FontProperties than were created identically (but would at least not be equal) that all render differently!
If we did go to eager evaluation, I would not expect the generic family to survive in the list.
We do some light normalization in set_family to ensure that we always get a list back from get_family which wile it does not round trip, I think is reasonable behavior.
Activity
jklymak commented on Jul 26, 2022
On the face of it, the result looks correct to me, so it seems the documentation is out of date? https://matplotlib.org/stable/api/font_manager_api.html#matplotlib.font_manager.FontProperties.get_family
l-johnston commented on Jul 26, 2022
Why is the result correct? Where, other than the documentation is the public API specified? If it's just documentation that is out of date, then the FontProperties docstring needs updating also.
jklymak commented on Jul 26, 2022
If you ask for the font_family, it seems reasonable to return the font_family?
l-johnston commented on Jul 26, 2022
but according to the docstring, get_family():
Return a list of font names that comprise the font family.
meaning get all the family members, as opposed to simply the family name.
story645 commented on Jul 26, 2022
this seems more useful - do you have a guess of how hard it'd be to implement?
l-johnston commented on Jul 26, 2022
here's another place in the documentation stating that a generic family name maps to a set of actual fonts
jklymak commented on Jul 26, 2022
Yes, I appreciate what the docs say. However, our usual pattern for setter/getters is for them to be reversible, so it would be unusual for get_family to return something other than what set_family was given.
jklymak commented on Jul 26, 2022
If this ever behaved differently, it was more than 8 years ago according to git blame. I'll stand by my assertion that this is a documentation error.
l-johnston commented on Jul 26, 2022
For a documentation error, this is massive wide scale errors where all the errors are consistent. set_family accepts a list of real fonts.
story645 commented on Jul 26, 2022
that sounds like this is a bug in Matplotlib where the intended behavior is what's stated in the docs and somehow didn't get implemented or got reverted years ago. thanks for catching that
eta: I think this might be a consistency issue attn: @timhoffm
l-johnston commented on Jul 27, 2022
workaround is to set rcParams["font.family"] = 'list of real fonts'
tacaswell commented on Jul 30, 2022
To start with, I want to note that fonts are confusing. I do not think there are any major bugs or documentation errors here, however the documentation is ambiguous and should be clearer.
First FontProperties are not actually fonts, they are the input to
matplotlib/lib/matplotlib/font_manager.py
Lines 1290 to 1291 in cd66bfd
Because the "family" on the FontProperties is a list (rather than a single name) this means you can list several fonts in preference order and we will use the first one that is actually installed. This behavior dates back to 2007-2008 and is consistent with css https://developer.mozilla.org/en-US/docs/Web/CSS/font-family . The ambiguity of using "family" to refer to the list, the things in the list, and the generic things seems to be an ambiguity that we inherited. I think the docstring on get_family should be clearer on which "family" it is referring too.
The other question is when do we resolve the generic font families ("sans", "serif", ...). @l-johnston has the expectation that we resolve it eagerly when the family is set on the FontProperties, however we actually do it lazily when we are actually looking the font up at
matplotlib/lib/matplotlib/font_manager.py
Lines 1191 to 1192 in cd66bfd
On net, I think doing it late is a preferable. If the rcparam for the generic families changes between when the FontProperties object is created and when the Figure is saved it is ambiguous which state should be used. "do what it says at draw time" seems easier to understand as if we resolved it early you could have N FontProperties than were created identically (but would at least not be equal) that all render differently!
If we did go to eager evaluation, I would not expect the generic family to survive in the list.
We do some light normalization in set_family to ensure that we always get a list back from get_family which wile it does not round trip, I think is reasonable behavior.
14 remaining items
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
FIX: correctly handle generic font families in svg text-as-text mode
DOC: make "family" less ambiguous in FontProperties docs