Skip to content

Commit e291cdb

Browse files
authored
Merge pull request #20659 from QuLogic/mathmpl-hidpi
Add HiDPI-related config for mathmpl
2 parents 044f3d0 + 7ac178e commit e291cdb

File tree

5 files changed

+144
-10
lines changed

5 files changed

+144
-10
lines changed

doc/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ Alphabetical list of modules:
8282
rcsetup_api.rst
8383
sankey_api.rst
8484
scale_api.rst
85+
sphinxext_mathmpl_api.rst
8586
sphinxext_plot_directive_api.rst
8687
spines_api.rst
8788
style_api.rst

doc/api/sphinxext_mathmpl_api.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
================================
2+
``matplotlib.sphinxext.mathmpl``
3+
================================
4+
5+
.. automodule:: matplotlib.sphinxext.mathmpl
6+
:exclude-members: latex_math
7+
:no-undoc-members:

doc/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ def _check_dependencies():
181181
}
182182

183183
plot_gallery = 'True'
184+
mathmpl_fontsize = 11.0
185+
mathmpl_srcset = ['2x']
184186

185187
# Monkey-patching gallery signature to include search keywords
186188
gen_rst.SPHX_GLR_SIG = """\n
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
More configuration of ``mathmpl:`` sphinx extension
2+
---------------------------------------------------
3+
4+
The `matplotlib.sphinxext.mathmpl` sphinx extension supports two new
5+
configuration options that may be specified in your ``conf.py``:
6+
7+
- ``mathmpl_fontsize`` (float), which sets the font size of the math text in
8+
points;
9+
- ``mathmpl_srcset`` (list of str), which provides a list of sizes to support
10+
`responsive resolution images
11+
<https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images>`__
12+
The list should contain additional x-descriptors (``'1.5x'``, ``'2x'``, etc.)
13+
to generate (1x is the default and always included.)

lib/matplotlib/sphinxext/mathmpl.py

Lines changed: 121 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,79 @@
1+
r"""
2+
A role and directive to display mathtext in Sphinx
3+
==================================================
4+
5+
.. warning::
6+
In most cases, you will likely want to use one of `Sphinx's builtin Math
7+
extensions
8+
<https://www.sphinx-doc.org/en/master/usage/extensions/math.html>`__
9+
instead of this one.
10+
11+
Mathtext may be included in two ways:
12+
13+
1. Inline, using the role::
14+
15+
This text uses inline math: :mathmpl:`\alpha > \beta`.
16+
17+
which produces:
18+
19+
This text uses inline math: :mathmpl:`\alpha > \beta`.
20+
21+
2. Standalone, using the directive::
22+
23+
Here is some standalone math:
24+
25+
.. mathmpl::
26+
27+
\alpha > \beta
28+
29+
which produces:
30+
31+
Here is some standalone math:
32+
33+
.. mathmpl::
34+
35+
\alpha > \beta
36+
37+
Options
38+
-------
39+
40+
The ``mathmpl`` role and directive both support the following options:
41+
42+
fontset : str, default: 'cm'
43+
The font set to use when displaying math. See :rc:`mathtext.fontset`.
44+
45+
fontsize : float
46+
The font size, in points. Defaults to the value from the extension
47+
configuration option defined below.
48+
49+
Configuration options
50+
---------------------
51+
52+
The mathtext extension has the following configuration options:
53+
54+
mathmpl_fontsize : float, default: 10.0
55+
Default font size, in points.
56+
57+
mathmpl_srcset : list of str, default: []
58+
Additional image sizes to generate when embedding in HTML, to support
59+
`responsive resolution images
60+
<https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images>`__.
61+
The list should contain additional x-descriptors (``'1.5x'``, ``'2x'``,
62+
etc.) to generate (1x is the default and always included.)
63+
64+
"""
65+
166
import hashlib
267
from pathlib import Path
368

469
from docutils import nodes
570
from docutils.parsers.rst import Directive, directives
671
import sphinx
72+
from sphinx.errors import ConfigError, ExtensionError
773

874
import matplotlib as mpl
975
from matplotlib import _api, mathtext
76+
from matplotlib.rcsetup import validate_float_or_None
1077

1178

1279
# Define LaTeX math node:
@@ -25,32 +92,40 @@ def math_role(role, rawtext, text, lineno, inliner,
2592
node = latex_math(rawtext)
2693
node['latex'] = latex
2794
node['fontset'] = options.get('fontset', 'cm')
95+
node['fontsize'] = options.get('fontsize',
96+
setup.app.config.mathmpl_fontsize)
2897
return [node], []
29-
math_role.options = {'fontset': fontset_choice}
98+
math_role.options = {'fontset': fontset_choice,
99+
'fontsize': validate_float_or_None}
30100

31101

32102
class MathDirective(Directive):
103+
"""
104+
The ``.. mathmpl::`` directive, as documented in the module's docstring.
105+
"""
33106
has_content = True
34107
required_arguments = 0
35108
optional_arguments = 0
36109
final_argument_whitespace = False
37-
option_spec = {'fontset': fontset_choice}
110+
option_spec = {'fontset': fontset_choice,
111+
'fontsize': validate_float_or_None}
38112

39113
def run(self):
40114
latex = ''.join(self.content)
41115
node = latex_math(self.block_text)
42116
node['latex'] = latex
43117
node['fontset'] = self.options.get('fontset', 'cm')
118+
node['fontsize'] = self.options.get('fontsize',
119+
setup.app.config.mathmpl_fontsize)
44120
return [node]
45121

46122

47123
# This uses mathtext to render the expression
48-
def latex2png(latex, filename, fontset='cm'):
49-
latex = "$%s$" % latex
50-
with mpl.rc_context({'mathtext.fontset': fontset}):
124+
def latex2png(latex, filename, fontset='cm', fontsize=10, dpi=100):
125+
with mpl.rc_context({'mathtext.fontset': fontset, 'font.size': fontsize}):
51126
try:
52127
depth = mathtext.math_to_image(
53-
latex, filename, dpi=100, format="png")
128+
f"${latex}$", filename, dpi=dpi, format="png")
54129
except Exception:
55130
_api.warn_external(f"Could not render math expression {latex}")
56131
depth = 0
@@ -62,14 +137,26 @@ def latex2html(node, source):
62137
inline = isinstance(node.parent, nodes.TextElement)
63138
latex = node['latex']
64139
fontset = node['fontset']
140+
fontsize = node['fontsize']
65141
name = 'math-{}'.format(
66-
hashlib.md5((latex + fontset).encode()).hexdigest()[-10:])
142+
hashlib.md5(f'{latex}{fontset}{fontsize}'.encode()).hexdigest()[-10:])
67143

68144
destdir = Path(setup.app.builder.outdir, '_images', 'mathmpl')
69145
destdir.mkdir(parents=True, exist_ok=True)
70-
dest = destdir / f'{name}.png'
71146

72-
depth = latex2png(latex, dest, fontset)
147+
dest = destdir / f'{name}.png'
148+
depth = latex2png(latex, dest, fontset, fontsize=fontsize)
149+
150+
srcset = []
151+
for size in setup.app.config.mathmpl_srcset:
152+
filename = f'{name}-{size.replace(".", "_")}.png'
153+
latex2png(latex, destdir / filename, fontset, fontsize=fontsize,
154+
dpi=100 * float(size[:-1]))
155+
srcset.append(
156+
f'{setup.app.builder.imgpath}/mathmpl/{filename} {size}')
157+
if srcset:
158+
srcset = (f'srcset="{setup.app.builder.imgpath}/mathmpl/{name}.png, ' +
159+
', '.join(srcset) + '" ')
73160

74161
if inline:
75162
cls = ''
@@ -81,11 +168,35 @@ def latex2html(node, source):
81168
style = ''
82169

83170
return (f'<img src="{setup.app.builder.imgpath}/mathmpl/{name}.png"'
84-
f' {cls}{style}/>')
171+
f' {srcset}{cls}{style}/>')
172+
173+
174+
def _config_inited(app, config):
175+
# Check for srcset hidpi images
176+
for i, size in enumerate(app.config.mathmpl_srcset):
177+
if size[-1] == 'x': # "2x" = "2.0"
178+
try:
179+
float(size[:-1])
180+
except ValueError:
181+
raise ConfigError(
182+
f'Invalid value for mathmpl_srcset parameter: {size!r}. '
183+
'Must be a list of strings with the multiplicative '
184+
'factor followed by an "x". e.g. ["2.0x", "1.5x"]')
185+
else:
186+
raise ConfigError(
187+
f'Invalid value for mathmpl_srcset parameter: {size!r}. '
188+
'Must be a list of strings with the multiplicative '
189+
'factor followed by an "x". e.g. ["2.0x", "1.5x"]')
85190

86191

87192
def setup(app):
88193
setup.app = app
194+
app.add_config_value('mathmpl_fontsize', 10.0, True)
195+
app.add_config_value('mathmpl_srcset', [], True)
196+
try:
197+
app.connect('config-inited', _config_inited) # Sphinx 1.8+
198+
except ExtensionError:
199+
app.connect('env-updated', lambda app, env: _config_inited(app, None))
89200

90201
# Add visit/depart methods to HTML-Translator:
91202
def visit_latex_math_html(self, node):

0 commit comments

Comments
 (0)