Source code for panel.pane.equation

Renders objects representing equations including LaTeX strings and
SymPy objects.
from __future__ import annotations

import re
import sys

from typing import (
    TYPE_CHECKING, Any, ClassVar, Dict, List, Mapping, Type,

import param  # type: ignore

from pyviz_comms import Comm, JupyterComm  # type: ignore

from import CDN_DIST
from ..util import lazy_load
from .base import ModelPane

    from bokeh.document import Document
    from bokeh.model import Model

[docs]def is_sympy_expr(obj: Any) -> bool: """Test for sympy.Expr types without usually needing to import sympy""" if 'sympy' in sys.modules and 'sympy' in str(type(obj).__class__): import sympy # type: ignore if isinstance(obj, sympy.Expr): return True return False
[docs]class LaTeX(ModelPane): """ The `LaTeX` pane allows rendering LaTeX equations. It uses either `MathJax` or `KaTeX` depending on the defined renderer. By default it will use the renderer loaded in the extension (e.g. `pn.extension('katex')`), defaulting to `KaTeX`. Reference: :Example: >>> pn.extension('katex') >>> LaTeX( ... 'The LaTeX pane supports two delimiters: $LaTeX$ and \(LaTeX\)', ... styles={'font-size': '18pt'}, width=800 ... ) """ renderer = param.ObjectSelector(default=None, allow_None=True, objects=['katex', 'mathjax'], doc=""" The JS renderer used to render the LaTeX expression.""") # Priority is dependent on the data type priority: ClassVar[float | bool | None] = None _rename: ClassVar[Mapping[str, str | None]] = { 'renderer': None, 'object': 'text' } _updates: ClassVar[bool] = True _stylesheets: ClassVar[List[str]] = [ f'{CDN_DIST}css/katex.css' ]
[docs] @classmethod def applies(cls, obj: Any) -> float | bool | None: if is_sympy_expr(obj) or hasattr(obj, '_repr_latex_'): return 0.05 elif isinstance(obj, str): return None else: return False
def _process_param_change(self, params) -> Dict[str, Any]: if self.renderer == "mathjax": # Replace $$math$$ with \[math\] and $math$ with \(math\) msg = re.sub(r"(\$\$)(.*?)(\$\$)", r"\[\2\]", params["object"]) params["object"] = re.sub(r"(\$)(.*?)(\$)", r"\(\2\)", msg) return super()._process_param_change(params) def _get_model_type(self, root: Model, comm: Comm | None) -> Type[Model]: module = self.renderer if module is None: if 'panel.models.mathjax' in sys.modules and 'panel.models.katex' not in sys.modules: module = 'mathjax' else: module = 'katex' model = 'KaTeX' if module == 'katex' else 'MathJax' return lazy_load(f'panel.models.{module}', model, isinstance(comm, JupyterComm), root) def _get_model( self, doc: Document, root: Model | None = None, parent: Model | None = None, comm: Comm | None = None ) -> Model: self._bokeh_model = self._get_model_type(root, comm) model = self._bokeh_model(**self._get_properties(doc)) root = root or model self._models[root.ref['id']] = (model, parent) return model def _transform_object(self, obj: Any) -> Dict[str, Any]: if obj is None: obj = '' elif hasattr(obj, '_repr_latex_'): obj = obj._repr_latex_() elif is_sympy_expr(obj): import sympy obj = r'$'+sympy.latex(obj)+'$' return dict(object=obj)