diff options
Diffstat (limited to 'contrib/python/matplotlib/py3/matplotlib/mathtext.py')
| -rw-r--r-- | contrib/python/matplotlib/py3/matplotlib/mathtext.py | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/contrib/python/matplotlib/py3/matplotlib/mathtext.py b/contrib/python/matplotlib/py3/matplotlib/mathtext.py new file mode 100644 index 00000000000..e25b76c4037 --- /dev/null +++ b/contrib/python/matplotlib/py3/matplotlib/mathtext.py @@ -0,0 +1,140 @@ +r""" +A module for parsing a subset of the TeX math syntax and rendering it to a +Matplotlib backend. + +For a tutorial of its usage, see :ref:`mathtext`. This +document is primarily concerned with implementation details. + +The module uses pyparsing_ to parse the TeX expression. + +.. _pyparsing: https://pypi.org/project/pyparsing/ + +The Bakoma distribution of the TeX Computer Modern fonts, and STIX +fonts are supported. There is experimental support for using +arbitrary fonts, but results may vary without proper tweaking and +metrics for those fonts. +""" + +import functools +import logging + +import matplotlib as mpl +from matplotlib import _api, _mathtext +from matplotlib.ft2font import LOAD_NO_HINTING +from matplotlib.font_manager import FontProperties +from ._mathtext import ( # noqa: reexported API + RasterParse, VectorParse, get_unicode_index) + +_log = logging.getLogger(__name__) + + +get_unicode_index.__module__ = __name__ + +############################################################################## +# MAIN + + +class MathTextParser: + _parser = None + _font_type_mapping = { + 'cm': _mathtext.BakomaFonts, + 'dejavuserif': _mathtext.DejaVuSerifFonts, + 'dejavusans': _mathtext.DejaVuSansFonts, + 'stix': _mathtext.StixFonts, + 'stixsans': _mathtext.StixSansFonts, + 'custom': _mathtext.UnicodeFonts, + } + + def __init__(self, output): + """ + Create a MathTextParser for the given backend *output*. + + Parameters + ---------- + output : {"path", "agg"} + Whether to return a `VectorParse` ("path") or a + `RasterParse` ("agg", or its synonym "macosx"). + """ + self._output_type = _api.check_getitem( + {"path": "vector", "agg": "raster", "macosx": "raster"}, + output=output.lower()) + + def parse(self, s, dpi=72, prop=None, *, antialiased=None): + """ + Parse the given math expression *s* at the given *dpi*. If *prop* is + provided, it is a `.FontProperties` object specifying the "default" + font to use in the math expression, used for all non-math text. + + The results are cached, so multiple calls to `parse` + with the same expression should be fast. + + Depending on the *output* type, this returns either a `VectorParse` or + a `RasterParse`. + """ + # lru_cache can't decorate parse() directly because prop + # is mutable; key the cache using an internal copy (see + # text._get_text_metrics_with_cache for a similar case). + prop = prop.copy() if prop is not None else None + antialiased = mpl._val_or_rc(antialiased, 'text.antialiased') + return self._parse_cached(s, dpi, prop, antialiased) + + @functools.lru_cache(50) + def _parse_cached(self, s, dpi, prop, antialiased): + from matplotlib.backends import backend_agg + + if prop is None: + prop = FontProperties() + fontset_class = _api.check_getitem( + self._font_type_mapping, fontset=prop.get_math_fontfamily()) + load_glyph_flags = { + "vector": LOAD_NO_HINTING, + "raster": backend_agg.get_hinting_flag(), + }[self._output_type] + fontset = fontset_class(prop, load_glyph_flags) + + fontsize = prop.get_size_in_points() + + if self._parser is None: # Cache the parser globally. + self.__class__._parser = _mathtext.Parser() + + box = self._parser.parse(s, fontset, fontsize, dpi) + output = _mathtext.ship(box) + if self._output_type == "vector": + return output.to_vector() + elif self._output_type == "raster": + return output.to_raster(antialiased=antialiased) + + +def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None, + *, color=None): + """ + Given a math expression, renders it in a closely-clipped bounding + box to an image file. + + Parameters + ---------- + s : str + A math expression. The math portion must be enclosed in dollar signs. + filename_or_obj : str or path-like or file-like + Where to write the image data. + prop : `.FontProperties`, optional + The size and style of the text. + dpi : float, optional + The output dpi. If not set, the dpi is determined as for + `.Figure.savefig`. + format : str, optional + The output format, e.g., 'svg', 'pdf', 'ps' or 'png'. If not set, the + format is determined as for `.Figure.savefig`. + color : str, optional + Foreground color, defaults to :rc:`text.color`. + """ + from matplotlib import figure + + parser = MathTextParser('path') + width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop) + + fig = figure.Figure(figsize=(width / 72.0, height / 72.0)) + fig.text(0, depth/height, s, fontproperties=prop, color=color) + fig.savefig(filename_or_obj, dpi=dpi, format=format) + + return depth |
