Skip to content
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

Matplotlib chooses the wrong font for unrecognized weights #8550

Closed
Rufflewind opened this issue Apr 29, 2017 · 5 comments
Closed

Matplotlib chooses the wrong font for unrecognized weights #8550

Rufflewind opened this issue Apr 29, 2017 · 5 comments

Comments

@Rufflewind
Copy link
Contributor

Bug report

Bug summary

With a lot of the modern fonts containing exotic font weights like “Thin” or “Ultra bold”, matplotlib will sometimes pick the wrong font weight because it assumes that any font weight that it doesn’t recognize is either normal (400) or bold (700), even though there is a “Regular” available. Ultimately which one matplotlib picks seems to be actually kind of random, probably depending on the order in which the fonts appear in the font cache.

This is what the logic in font_manager.py looks like:

weight = next((w for w in weight_dict if sfnt4.find(w) >= 0), None)
if not weight:
    if font.style_flags & ft2font.BOLD:
        weight = 700
    else:
        weight = 400

sfnt4 appears to be a string that contains the full name of the font, including the weight. The problem with this approach is that if it doesn’t recognize the weight, it will simply assume the weight is either 400 or 700. A “Thin” font that was mistakenly labeled 400 might get picked over a “Regular” font.

Here are all the weights currently recognized:

weight_dict = {
    'ultralight' : 100,
    'light'      : 200,
    'normal'     : 400,
    'regular'    : 400,
    'book'       : 400,
    'medium'     : 500,
    'roman'      : 500,
    'semibold'   : 600,
    'demibold'   : 600,
    'demi'       : 600,
    'bold'       : 700,
    'heavy'      : 800,
    'extra bold' : 800,
    'black'      : 900}

I imagine we could add “Thin” and some others into the list, but I don’t think this solves the fundamental problem that fonts with unrecognized weights are presumed “Regular”/“Bold” and do not have lower precedence than fonts that are definitely “Regular”/“Bold”.

TL;DR: It would be nice to have a more robust way to detect font weights and handle unknown font weights.

Matplotlib version

  • Operating System: Arch Linux
  • Matplotlib Version: HEAD
  • Python Version: 3.6.0
  • Jupyter Version (if applicable): n/a
  • Other Libraries: n/a
@Rufflewind
Copy link
Contributor Author

This is a bit of "wish" but I think it would nice to have the option to specify the subfamily explicitly, in case the subfamily is really exotic. So I should be able to pass e.g. font="Fira Sans Four" and get the Four subfamily. (Either parse the subfamily from the user-provided string, or have a second attribute font_subfamily, which is arguably more principled.)

(@tacaswell)

@tacaswell
Copy link
Member

Can you even do that with the font-config tools? That seems like a difficult parsing problem as the space is used to both in the family name (which I think in 'Fire Sans') and to separate the sub-family.

There is a PR from @mdboom to replace our home-grown font selection with font-config around...

@Rufflewind
Copy link
Contributor Author

Looks like font-config uses a colon:

$ fc-match 'Fira Sans'        
FiraSans-Regular.ttf: "Fira Sans" "Regular"
$ fc-match 'Fira Sans: Italic'
FiraSans-Italic.ttf: "Fira Sans" "Italic"

(I'm actually surprised that font-config even recognizes subfamily)

@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Sep 24, 2017
@anntzer
Copy link
Contributor

anntzer commented Dec 6, 2018

https://github.com/anntzer/mplfccache should allow you to regenerate the font cache using the metadata provided by fontconfig (obviously, this depends on fontconfig utilities being available in the $PATH).

I also have a Python reimplementation of (most of) fontconfig's logic (translated from source) in https://github.com/anntzer/freetypybind/blob/master/lib/freetypybind/query_face.py#L499, just needs some packaging effort...

@anntzer
Copy link
Contributor

anntzer commented May 28, 2020

#16203 fixes most of this. I think the "direct access to subfamily request" is tracked by #4822.

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

5 participants