diff --git a/doc/users/next_whats_new/boldsym_mathtext.rst b/doc/users/next_whats_new/boldsym_mathtext.rst new file mode 100644 index 000000000000..d58532d5661e --- /dev/null +++ b/doc/users/next_whats_new/boldsym_mathtext.rst @@ -0,0 +1,14 @@ +Boldsymbol mathtext command ``\boldsymbol`` +------------------------------------------- + +Supports using the ``\boldsymbol{}`` command in mathtext: + +To change symbols to bold enclose the text in a font command as +shown: + +.. code-block:: + + r'$\boldsymbol{a+2+\alpha}$' + +.. math:: + \boldsymbol{a+2+\alpha} diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py index a166f3bc21a7..b1942d0c98e4 100644 --- a/lib/matplotlib/_mathtext.py +++ b/lib/matplotlib/_mathtext.py @@ -11,6 +11,7 @@ import re import types import unicodedata +import string import numpy as np from pyparsing import ( @@ -1811,6 +1812,11 @@ class _MathStyle(enum.Enum): _right_delims = set(r") ] \} > \rfloor \rangle \rceil".split()) _delims = _left_delims | _right_delims | _ambi_delims + _small_greek = set([unicodedata.name(chr(i)).split()[-1].lower() for i in + range(ord('\N{GREEK SMALL LETTER ALPHA}'), + ord('\N{GREEK SMALL LETTER OMEGA}') + 1)]) + _latin_alphabets = set(string.ascii_letters) + def __init__(self): p = types.SimpleNamespace() @@ -1933,6 +1939,9 @@ def csnames(group, names): p.operatorname = cmd(r"\operatorname", "{" + ZeroOrMore(p.simple)("name") + "}") + p.boldsymbol = cmd( + r"\boldsymbol", "{" + ZeroOrMore(p.simple)("value") + "}") + p.placeable <<= ( p.accent # Must be before symbol as all accents are symbols | p.symbol # Must be second to catch all named symbols and single @@ -1949,6 +1958,7 @@ def csnames(group, names): | p.sqrt | p.overline | p.text + | p.boldsymbol ) p.auto_delim <<= ( @@ -2597,3 +2607,29 @@ def auto_delim(self, s, loc, toks): # if "mid" in toks ... can be removed when requiring pyparsing 3. toks["mid"].asList() if "mid" in toks else [], toks["right"]) + + def boldsymbol(self, s, loc, toks): + self.push_state() + state = self.get_state() + hlist = [] + name = toks["value"] + for c in name: + if isinstance(c, Hlist): + k = c.children[1] + if isinstance(k, Char): + k.font = "bf" + k._update_metrics() + hlist.append(c) + elif isinstance(c, Char): + c.font = "bf" + if (c.c in self._latin_alphabets or + c.c[1:] in self._small_greek): + c.font = "bfit" + c._update_metrics() + c._update_metrics() + hlist.append(c) + else: + hlist.append(c) + self.pop_state() + + return Hlist(hlist) diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_05.png new file mode 100644 index 000000000000..f7ac08149bcd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_05.png differ diff --git a/lib/matplotlib/tests/test_mathtext.py b/lib/matplotlib/tests/test_mathtext.py index 8084ffcd9179..41619c18cf91 100644 --- a/lib/matplotlib/tests/test_mathtext.py +++ b/lib/matplotlib/tests/test_mathtext.py @@ -134,7 +134,7 @@ r'$\sum x\quad\sum^nx\quad\sum_nx\quad\sum_n^nx\quad\prod x\quad\prod^nx\quad\prod_nx\quad\prod_n^nx$', # GitHub issue 18085 r'$1.$ $2.$ $19680801.$ $a.$ $b.$ $mpl.$', r'$\text{text}_{\text{sub}}^{\text{sup}} + \text{\$foo\$} + \frac{\text{num}}{\mathbf{\text{den}}}\text{with space, curly brackets \{\}, and dash -}$', - + r'$\boldsymbol{abcde} \boldsymbol{+} \boldsymbol{\Gamma + \Omega} \boldsymbol{01234} \boldsymbol{\alpha * \beta}$', ] digits = "0123456789" @@ -538,3 +538,9 @@ def test_mathtext_operators(): fig.text(0.5, (x + 0.5)/len(test_str), r'${%s}$' % i) fig.draw_without_rendering() + + +@check_figures_equal(extensions=["png"]) +def test_boldsymbol(fig_test, fig_ref): + fig_test.text(0.1, 0.2, r"$\boldsymbol{\mathrm{abc0123\alpha}}$") + fig_ref.text(0.1, 0.2, r"$\mathrm{abc0123\alpha}$")