Skip to content

Created a parameter fontset that can be used in each Text element #18145

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 2 commits into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""
===============
Math fontfamily
===============

A simple example showcasing the new *math_fontfamily* parameter that can
be used to change the family of fonts for each individual text
element in a plot.

If no parameter is set, the global value
:rc:`mathtext.fontset` will be used.
"""

import matplotlib.pyplot as plt

plt.figure(figsize=(6, 5))

# A simple plot for the background.
plt.plot(range(11), color="0.9")

# A text mixing normal text and math text.
msg = (r"Normal Text. $Text\ in\ math\ mode:\ "
r"\int_{0}^{\infty } x^2 dx$")

# Set the text in the plot.
plt.text(1, 7, msg, size=12, math_fontfamily='cm')

# Set another font for the next text.
plt.text(1, 3, msg, size=12, math_fontfamily='dejavuserif')

# *math_fontfamily* can be used in most places where there is text,
# like in the title:
plt.title(r"$Title\ in\ math\ mode:\ \int_{0}^{\infty } x^2 dx$",
math_fontfamily='stixsans', size=14)

# Note that the normal text is not changed by *math_fontfamily*.
plt.show()
58 changes: 54 additions & 4 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from matplotlib import afm, cbook, ft2font, rcParams
from matplotlib.fontconfig_pattern import (
parse_fontconfig_pattern, generate_fontconfig_pattern)
from matplotlib.rcsetup import _validators

_log = logging.getLogger(__name__)

Expand Down Expand Up @@ -624,10 +625,10 @@ class FontProperties:
"""
A class for storing and manipulating font properties.

The font properties are those described in the `W3C Cascading
Style Sheet, Level 1
The font properties are the six properties described in the
`W3C Cascading Style Sheet, Level 1
<http://www.w3.org/TR/1998/REC-CSS2-19980512/>`_ font
specification. The six properties are:
specification and *math_fontfamily* for math fonts:

- family: A list of font names in decreasing order of priority.
The items may include a generic font family name, either
Expand All @@ -653,6 +654,12 @@ class FontProperties:
'small', 'medium', 'large', 'x-large', 'xx-large' or an
absolute font size, e.g., 12.

- math_fontfamily: The family of fonts used to render math text; overrides
:rc:`mathtext.fontset`. Supported values are the same as the ones
supported by :rc:`mathtext.fontset` ::

'dejavusans', 'dejavuserif', 'cm', 'stix', 'stixsans' and 'custom'.

The default font property for TrueType fonts (as specified in the
default rcParams) is ::

Expand Down Expand Up @@ -690,6 +697,7 @@ def __init__(self,
stretch= None,
size = None,
fname = None, # if set, it's a hardcoded filename to use
math_fontfamily = None,
):
self._family = _normalize_font_family(rcParams['font.family'])
self._slant = rcParams['font.style']
Expand All @@ -698,6 +706,7 @@ def __init__(self,
self._stretch = rcParams['font.stretch']
self._size = rcParams['font.size']
self._file = None
self._math_fontfamily = None

if isinstance(family, str):
# Treat family as a fontconfig pattern if it is the only
Expand All @@ -714,6 +723,7 @@ def __init__(self,
self.set_stretch(stretch)
self.set_file(fname)
self.set_size(size)
self.set_math_fontfamily(math_fontfamily)

@classmethod
def _from_any(cls, arg):
Expand Down Expand Up @@ -745,7 +755,8 @@ def __hash__(self):
self.get_weight(),
self.get_stretch(),
self.get_size_in_points(),
self.get_file())
self.get_file(),
self.get_math_fontfamily())
return hash(l)

def __eq__(self, other):
Expand Down Expand Up @@ -934,6 +945,45 @@ def set_fontconfig_pattern(self, pattern):
else:
getattr(self, "set_" + key)(val)

def get_math_fontfamily(self):
"""
Return the name of the font family used for math text.

The default font is :rc:`mathtext.fontset`.
"""
if self._math_fontfamily is None:
return rcParams['mathtext.fontset']
return self._math_fontfamily

def set_math_fontfamily(self, fontfamily):
"""
Set the font family for text in math mode.

If not set explicitly, :rc:`mathtext.fontset` will be used.

Parameters
----------
fontfamily : str
The name of the font family.

Available font families are defined in the
matplotlibrc.template file
:ref:`here <customizing-with-matplotlibrc-files>`

See Also
--------
.text.Text.get_math_fontfamily
"""
if fontfamily is None:
self._math_fontfamily = None
return

valid_fonts = _validators['mathtext.fontset'].valid.values()
# _check_in_list() Validates the parameter math_fontfamily as
# if it were passed to rcParams['mathtext.fontset']
cbook._check_in_list(valid_fonts, math_fontfamily=fontfamily)
self._math_fontfamily = fontfamily

def copy(self):
"""Return a copy of self."""
new = type(self)()
Expand Down
9 changes: 4 additions & 5 deletions lib/matplotlib/mathtext.py
Original file line number Diff line number Diff line change
Expand Up @@ -3351,12 +3351,10 @@ def parse(self, s, dpi=72, prop=None, *, _force_standard_ps_fonts=False):
# lru_cache can't decorate parse() directly because the ps.useafm and
# mathtext.fontset rcParams also affect the parse (e.g. by affecting
# the glyph metrics).
return self._parse_cached(s, dpi, prop, _force_standard_ps_fonts,
rcParams['mathtext.fontset'])
return self._parse_cached(s, dpi, prop, _force_standard_ps_fonts)

@functools.lru_cache(50)
def _parse_cached(self, s, dpi, prop, force_standard_ps_fonts, fontset):

def _parse_cached(self, s, dpi, prop, force_standard_ps_fonts):
if prop is None:
prop = FontProperties()

Expand All @@ -3365,7 +3363,8 @@ def _parse_cached(self, s, dpi, prop, force_standard_ps_fonts, fontset):
else:
backend = self._backend_mapping[self._output]()
fontset_class = cbook._check_getitem(
self._font_type_mapping, fontset=fontset)
self._font_type_mapping,
fontset=prop.get_math_fontfamily())
font_output = fontset_class(prop, backend)

fontsize = prop.get_size_in_points()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions lib/matplotlib/tests/test_mathtext.py
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,13 @@ def test_mathtext_to_png(tmpdir):
mt = mathtext.MathTextParser('bitmap')
mt.to_png(str(tmpdir.join('example.png')), '$x^2$')
mt.to_png(io.BytesIO(), '$x^2$')


@image_comparison(baseline_images=['math_fontfamily_image.png'],
savefig_kwarg={'dpi': 40})
def test_math_fontfamily():
fig = plt.figure(figsize=(10, 3))
fig.text(0.2, 0.7, r"$This\ text\ should\ have\ one\ font$",
size=24, math_fontfamily='dejavusans')
fig.text(0.2, 0.3, r"$This\ text\ should\ have\ another$",
size=24, math_fontfamily='stix')
34 changes: 34 additions & 0 deletions lib/matplotlib/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -1061,6 +1061,40 @@ def set_fontsize(self, fontsize):
self._fontproperties.set_size(fontsize)
self.stale = True

def get_math_fontfamily(self):
"""
Return the font family name for math text rendered by Matplotlib.

The default value is :rc:`mathtext.fontset`.

See Also
--------
set_math_fontfamily
"""
return self._fontproperties.get_math_fontfamily()

def set_math_fontfamily(self, fontfamily):
"""
Set the font family for math text rendered by Matplotlib.

This does only affect Matplotlib's own math renderer. It has no effect
when rendering with TeX (``usetex=True``).

Parameters
----------
fontfamily : str
The name of the font family.

Available font families are defined in the
:ref:`matplotlibrc.template file
<customizing-with-matplotlibrc-files>`.

See Also
--------
get_math_fontfamily
"""
self._fontproperties.set_math_fontfamily(fontfamily)

def set_fontweight(self, weight):
"""
Set the font weight.
Expand Down