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

Skip to content

Fix Text class bug when font argument is provided without math_fontfamily #20101

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

Merged
merged 17 commits into from
May 26, 2021
Merged

Fix Text class bug when font argument is provided without math_fontfamily #20101

merged 17 commits into from
May 26, 2021

Conversation

ain-soph
Copy link
Contributor

@ain-soph ain-soph commented Apr 28, 2021

PR Summary

Fix bug of #20099

Issue Analysis

import matplotlib.pyplot as plt
import matplotlib

plt.figure(figsize=(6, 5))
plt.plot(range(11), color="0.9")
msg = (r"Normal Text. $Text\ in\ math\ mode:\ "
       r"\int_{0}^{\infty } x^2 dx$")
plt.text(1, 7, msg, size=12, font='Arial')  # math_fontfamily='cm'
plt.show()

When you pass font='Arial' to plt.text() without math_fontfamily='cm' (Arial and cm just for example), it will raise Exception.
It is expected that the math_fontfamily will use the global default value rcParams['mathtext.fontset']. However, it is None actually.
The reason is that in

self.update(kwargs)

font='Arial' is passed in kwargs, passing to
else:
func = getattr(self, f"set_{k}", None)
if not callable(func):
raise AttributeError(f"{type(self).__name__!r} object "
f"has no property {k!r}")
ret.append(func(v))

go to Text.set_font_properties and then
Finally it calls Text(font), goes into the if condition
if isinstance(family, str):
# Treat family as a fontconfig pattern if it is the only
# parameter provided.
if (style is None and variant is None and weight is None and
stretch is None and size is None and fname is None):
self.set_fontconfig_pattern(family)
return

It returns without self.set_math_fontfamily(math_fontfamily) (since it only occurs when if condition is False), leading to math_fontfamily=None rather than the global default.

@ain-soph
Copy link
Contributor Author

@diegopetrola may take a glance of it.

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Thank you for opening your first PR into Matplotlib!

If you have not heard from us in a while, please feel free to ping @matplotlib/developers or anyone who has commented on the PR. 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

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

@ain-soph
Copy link
Contributor Author

ain-soph commented Apr 28, 2021

I notice that another issue still exists after the initial fix, since the argument order matters.

import matplotlib.pyplot as plt
import matplotlib

matplotlib.rcParams['mathtext.fontset'] = 'cm'

plt.figure(figsize=(6, 5))
plt.plot(range(11), color="0.9")
msg = (r"Normal Text. $Text\ in\ math\ mode:\ "
       r"\int_{0}^{\infty } x^2 dx$")
plt.text(1, 7, msg, size=12, math_fontfamily='dejavusans', font='Arial')
plt.show()

If we put math_fontfamily='dejavusans' before font='Arial', then the plotted mathfont will still be cm (global default value in rcParams['mathtext.fontset']).
It is caused by

else:
func = getattr(self, f"set_{k}", None)
if not callable(func):
raise AttributeError(f"{type(self).__name__!r} object "
f"has no property {k!r}")
ret.append(func(v))

where in L1048 for k, v in props.items(): the traverse order follows the passing argument orders.

Text.set_fontproperties will construct the self._fontproperties instance with self._math_fontfamily = rcParams['mathtext.fontset'] as default (None without my initial fix).

Text.set_math_fontfamily will set self._fontproperties._math_fontfamily = <desired passing value>

Therefore, we must ensure Text.set_fontproperties is called before Text.set_math_fontfamily.

@ain-soph
Copy link
Contributor Author

ain-soph commented Apr 28, 2021

This won't happen if you pass fontproperties='Arial' rather than font='Arial', because fontproperties is treated specially before any other arguments.

sentinel = object() # bbox can be None, so use another sentinel.
# Update fontproperties first, as it has lowest priority.
fontproperties = kwargs.pop("fontproperties", sentinel)
if fontproperties is not sentinel:
self.set_fontproperties(fontproperties)

But I think these 2 different names just equivalent aliases. So A possible solution is to treat font together with fontproperties as well.

@ain-soph
Copy link
Contributor Author

ain-soph commented Apr 28, 2021

A better fix might be using Text.alias_map defined in cbook.

@cbook._define_aliases({
"color": ["c"],
"fontfamily": ["family"],
"fontproperties": ["font", "font_properties"],
"horizontalalignment": ["ha"],
"multialignment": ["ma"],
"fontname": ["name"],
"fontsize": ["size"],
"fontstretch": ["stretch"],
"fontstyle": ["style"],
"fontvariant": ["variant"],
"verticalalignment": ["va"],
"fontweight": ["weight"],
})

Copy link
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.

Please give your PRs more descriptive titles.

This could also do with a test.

indent fix

Co-authored-by: Elliott Sales de Andrade <[email protected]>
@ain-soph ain-soph changed the title Fix #20099 Fix Text class when font argument is provided without math_fontfamily Apr 28, 2021
@ain-soph ain-soph changed the title Fix Text class when font argument is provided without math_fontfamily Fix Text class bug when font argument is provided without math_fontfamily Apr 28, 2021
@ain-soph
Copy link
Contributor Author

The test functions have been commited. @QuLogic

@ain-soph
Copy link
Contributor Author

ain-soph commented Apr 30, 2021

Please remove the “need tests” tag, since now it need review.
@matplotlib Hope anyone could take a review, I’d appreciate.

@jklymak jklymak requested a review from timhoffm May 13, 2021 14:14
@ain-soph
Copy link
Contributor Author

@QuLogic Have fixed. Sorry for my carelessness.

@QuLogic
Copy link
Member

QuLogic commented May 15, 2021

This will need a rebase for the conflicts, and the tests need to pass.

@jklymak jklymak marked this pull request as draft May 15, 2021 00:32
@QuLogic
Copy link
Member

QuLogic commented May 18, 2021

Downstream CI seems to think this is not mergeable, though GitHub doesn't seem to be showing any conflicts. I guess this would need a rebase to work properly.

@ain-soph
Copy link
Contributor Author

Sorry for first time dealing with co-operation workflow on GitHub. I create a pull request to merge master commits to my PR and solve the merge conflict by myself, guess it is equivalent to rebase all master commits onto my branch. Ping me if anything is wrong.

@QuLogic QuLogic marked this pull request as ready for review May 19, 2021 05:54
@QuLogic
Copy link
Member

QuLogic commented May 19, 2021

Oops, I only meant to Approve the workflows (that is very annoying to have to re-do so much), not mark the PR as ready. Is it ready?

@ain-soph
Copy link
Contributor Author

@QuLogic I think it's ready. I'm fine if it requires more reviewer.

@jklymak jklymak requested a review from QuLogic May 22, 2021 15:51
@QuLogic QuLogic merged commit c4dcf5e into matplotlib:master May 26, 2021
@QuLogic
Copy link
Member

QuLogic commented May 26, 2021

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

@QuLogic QuLogic added this to the v3.5.0 milestone May 26, 2021
jklymak pushed a commit to jklymak/matplotlib that referenced this pull request Jun 13, 2021
…ontfamily` (matplotlib#20101)

* fix mathtext.fontset issue

* fix argument order issue

* better fix using alias_map

* indent fix

* Update lib/matplotlib/text.py

indent fix

Co-authored-by: Elliott Sales de Andrade <[email protected]>

* add test

* split into 2 test methods

* fix test

* add a whitespace

* use cbook.normalize_kwargs

* no need to copy (normalize_kwargs already copy it)

Co-authored-by: Elliott Sales de Andrade <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants