up follow livre
This commit is contained in:
parent
b4b4398bb0
commit
3a7a3849ae
12242 changed files with 2564461 additions and 6914 deletions
|
|
@ -0,0 +1,242 @@
|
|||
r"""
|
||||
A role and directive to display mathtext in Sphinx
|
||||
==================================================
|
||||
|
||||
The ``mathmpl`` Sphinx extension creates a mathtext image in Matplotlib and
|
||||
shows it in html output. Thus, it is a true and faithful representation of what
|
||||
you will see if you pass a given LaTeX string to Matplotlib (see
|
||||
:ref:`mathtext`).
|
||||
|
||||
.. warning::
|
||||
In most cases, you will likely want to use one of `Sphinx's builtin Math
|
||||
extensions
|
||||
<https://www.sphinx-doc.org/en/master/usage/extensions/math.html>`__
|
||||
instead of this one. The builtin Sphinx math directive uses MathJax to
|
||||
render mathematical expressions, and addresses accessibility concerns that
|
||||
``mathmpl`` doesn't address.
|
||||
|
||||
Mathtext may be included in two ways:
|
||||
|
||||
1. Inline, using the role::
|
||||
|
||||
This text uses inline math: :mathmpl:`\alpha > \beta`.
|
||||
|
||||
which produces:
|
||||
|
||||
This text uses inline math: :mathmpl:`\alpha > \beta`.
|
||||
|
||||
2. Standalone, using the directive::
|
||||
|
||||
Here is some standalone math:
|
||||
|
||||
.. mathmpl::
|
||||
|
||||
\alpha > \beta
|
||||
|
||||
which produces:
|
||||
|
||||
Here is some standalone math:
|
||||
|
||||
.. mathmpl::
|
||||
|
||||
\alpha > \beta
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
The ``mathmpl`` role and directive both support the following options:
|
||||
|
||||
fontset : str, default: 'cm'
|
||||
The font set to use when displaying math. See :rc:`mathtext.fontset`.
|
||||
|
||||
fontsize : float
|
||||
The font size, in points. Defaults to the value from the extension
|
||||
configuration option defined below.
|
||||
|
||||
Configuration options
|
||||
---------------------
|
||||
|
||||
The mathtext extension has the following configuration options:
|
||||
|
||||
mathmpl_fontsize : float, default: 10.0
|
||||
Default font size, in points.
|
||||
|
||||
mathmpl_srcset : list of str, default: []
|
||||
Additional image sizes to generate when embedding in HTML, to support
|
||||
`responsive resolution images
|
||||
<https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images>`__.
|
||||
The list should contain additional x-descriptors (``'1.5x'``, ``'2x'``,
|
||||
etc.) to generate (1x is the default and always included.)
|
||||
|
||||
"""
|
||||
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import Directive, directives
|
||||
import sphinx
|
||||
from sphinx.errors import ConfigError, ExtensionError
|
||||
|
||||
import matplotlib as mpl
|
||||
from matplotlib import _api, mathtext
|
||||
from matplotlib.rcsetup import validate_float_or_None
|
||||
|
||||
|
||||
# Define LaTeX math node:
|
||||
class latex_math(nodes.General, nodes.Element):
|
||||
pass
|
||||
|
||||
|
||||
def fontset_choice(arg):
|
||||
return directives.choice(arg, mathtext.MathTextParser._font_type_mapping)
|
||||
|
||||
|
||||
def math_role(role, rawtext, text, lineno, inliner,
|
||||
options={}, content=[]):
|
||||
i = rawtext.find('`')
|
||||
latex = rawtext[i+1:-1]
|
||||
node = latex_math(rawtext)
|
||||
node['latex'] = latex
|
||||
node['fontset'] = options.get('fontset', 'cm')
|
||||
node['fontsize'] = options.get('fontsize',
|
||||
setup.app.config.mathmpl_fontsize)
|
||||
return [node], []
|
||||
math_role.options = {'fontset': fontset_choice,
|
||||
'fontsize': validate_float_or_None}
|
||||
|
||||
|
||||
class MathDirective(Directive):
|
||||
"""
|
||||
The ``.. mathmpl::`` directive, as documented in the module's docstring.
|
||||
"""
|
||||
has_content = True
|
||||
required_arguments = 0
|
||||
optional_arguments = 0
|
||||
final_argument_whitespace = False
|
||||
option_spec = {'fontset': fontset_choice,
|
||||
'fontsize': validate_float_or_None}
|
||||
|
||||
def run(self):
|
||||
latex = ''.join(self.content)
|
||||
node = latex_math(self.block_text)
|
||||
node['latex'] = latex
|
||||
node['fontset'] = self.options.get('fontset', 'cm')
|
||||
node['fontsize'] = self.options.get('fontsize',
|
||||
setup.app.config.mathmpl_fontsize)
|
||||
return [node]
|
||||
|
||||
|
||||
# This uses mathtext to render the expression
|
||||
def latex2png(latex, filename, fontset='cm', fontsize=10, dpi=100):
|
||||
with mpl.rc_context({'mathtext.fontset': fontset, 'font.size': fontsize}):
|
||||
try:
|
||||
depth = mathtext.math_to_image(
|
||||
f"${latex}$", filename, dpi=dpi, format="png")
|
||||
except Exception:
|
||||
_api.warn_external(f"Could not render math expression {latex}")
|
||||
depth = 0
|
||||
return depth
|
||||
|
||||
|
||||
# LaTeX to HTML translation stuff:
|
||||
def latex2html(node, source):
|
||||
inline = isinstance(node.parent, nodes.TextElement)
|
||||
latex = node['latex']
|
||||
fontset = node['fontset']
|
||||
fontsize = node['fontsize']
|
||||
name = 'math-{}'.format(
|
||||
hashlib.sha256(
|
||||
f'{latex}{fontset}{fontsize}'.encode(),
|
||||
usedforsecurity=False,
|
||||
).hexdigest()[-10:])
|
||||
|
||||
destdir = Path(setup.app.builder.outdir, '_images', 'mathmpl')
|
||||
destdir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
dest = destdir / f'{name}.png'
|
||||
depth = latex2png(latex, dest, fontset, fontsize=fontsize)
|
||||
|
||||
srcset = []
|
||||
for size in setup.app.config.mathmpl_srcset:
|
||||
filename = f'{name}-{size.replace(".", "_")}.png'
|
||||
latex2png(latex, destdir / filename, fontset, fontsize=fontsize,
|
||||
dpi=100 * float(size[:-1]))
|
||||
srcset.append(
|
||||
f'{setup.app.builder.imgpath}/mathmpl/{filename} {size}')
|
||||
if srcset:
|
||||
srcset = (f'srcset="{setup.app.builder.imgpath}/mathmpl/{name}.png, ' +
|
||||
', '.join(srcset) + '" ')
|
||||
|
||||
if inline:
|
||||
cls = ''
|
||||
else:
|
||||
cls = 'class="center" '
|
||||
if inline and depth != 0:
|
||||
style = 'style="position: relative; bottom: -%dpx"' % (depth + 1)
|
||||
else:
|
||||
style = ''
|
||||
|
||||
return (f'<img src="{setup.app.builder.imgpath}/mathmpl/{name}.png"'
|
||||
f' {srcset}{cls}{style}/>')
|
||||
|
||||
|
||||
def _config_inited(app, config):
|
||||
# Check for srcset hidpi images
|
||||
for i, size in enumerate(app.config.mathmpl_srcset):
|
||||
if size[-1] == 'x': # "2x" = "2.0"
|
||||
try:
|
||||
float(size[:-1])
|
||||
except ValueError:
|
||||
raise ConfigError(
|
||||
f'Invalid value for mathmpl_srcset parameter: {size!r}. '
|
||||
'Must be a list of strings with the multiplicative '
|
||||
'factor followed by an "x". e.g. ["2.0x", "1.5x"]')
|
||||
else:
|
||||
raise ConfigError(
|
||||
f'Invalid value for mathmpl_srcset parameter: {size!r}. '
|
||||
'Must be a list of strings with the multiplicative '
|
||||
'factor followed by an "x". e.g. ["2.0x", "1.5x"]')
|
||||
|
||||
|
||||
def setup(app):
|
||||
setup.app = app
|
||||
app.add_config_value('mathmpl_fontsize', 10.0, True)
|
||||
app.add_config_value('mathmpl_srcset', [], True)
|
||||
try:
|
||||
app.connect('config-inited', _config_inited) # Sphinx 1.8+
|
||||
except ExtensionError:
|
||||
app.connect('env-updated', lambda app, env: _config_inited(app, None))
|
||||
|
||||
# Add visit/depart methods to HTML-Translator:
|
||||
def visit_latex_math_html(self, node):
|
||||
source = self.document.attributes['source']
|
||||
self.body.append(latex2html(node, source))
|
||||
|
||||
def depart_latex_math_html(self, node):
|
||||
pass
|
||||
|
||||
# Add visit/depart methods to LaTeX-Translator:
|
||||
def visit_latex_math_latex(self, node):
|
||||
inline = isinstance(node.parent, nodes.TextElement)
|
||||
if inline:
|
||||
self.body.append('$%s$' % node['latex'])
|
||||
else:
|
||||
self.body.extend(['\\begin{equation}',
|
||||
node['latex'],
|
||||
'\\end{equation}'])
|
||||
|
||||
def depart_latex_math_latex(self, node):
|
||||
pass
|
||||
|
||||
app.add_node(latex_math,
|
||||
html=(visit_latex_math_html, depart_latex_math_html),
|
||||
latex=(visit_latex_math_latex, depart_latex_math_latex))
|
||||
app.add_role('mathmpl', math_role)
|
||||
app.add_directive('mathmpl', MathDirective)
|
||||
if sphinx.version_info < (1, 8):
|
||||
app.add_role('math', math_role)
|
||||
app.add_directive('math', MathDirective)
|
||||
|
||||
metadata = {'parallel_read_safe': True, 'parallel_write_safe': True}
|
||||
return metadata
|
||||
Loading…
Add table
Add a link
Reference in a new issue