123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- import hashlib
- from pathlib import Path
- from docutils import nodes
- from docutils.parsers.rst import Directive, directives
- import sphinx
- import matplotlib as mpl
- from matplotlib import cbook
- from matplotlib.mathtext import MathTextParser
- mathtext_parser = MathTextParser("Bitmap")
- class latex_math(nodes.General, nodes.Element):
- pass
- def fontset_choice(arg):
- return directives.choice(arg, 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')
- return [node], []
- math_role.options = {'fontset': fontset_choice}
- class MathDirective(Directive):
- has_content = True
- required_arguments = 0
- optional_arguments = 0
- final_argument_whitespace = False
- option_spec = {'fontset': fontset_choice}
- def run(self):
- latex = ''.join(self.content)
- node = latex_math(self.block_text)
- node['latex'] = latex
- node['fontset'] = self.options.get('fontset', 'cm')
- return [node]
- def latex2png(latex, filename, fontset='cm'):
- latex = "$%s$" % latex
- with mpl.rc_context({'mathtext.fontset': fontset}):
- if Path(filename).exists():
- depth = mathtext_parser.get_depth(latex, dpi=100)
- else:
- try:
- depth = mathtext_parser.to_png(filename, latex, dpi=100)
- except Exception:
- cbook._warn_external(
- f"Could not render math expression {latex}")
- depth = 0
- return depth
- def latex2html(node, source):
- inline = isinstance(node.parent, nodes.TextElement)
- latex = node['latex']
- fontset = node['fontset']
- name = 'math-{}'.format(
- hashlib.md5((latex + fontset).encode()).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)
- 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' {cls}{style}/>')
- def setup(app):
- setup.app = app
-
- 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
-
- 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
|