Bokeh + Katex + jupyter

I’m trying to replicate the bokeh latex example mentioned at Creating LaTeX labels — Bokeh 2.4.2 Documentation in jupyter notebook for LabelSet. I could see the katex.min.js being loaded from web console. However when the LatexLabel renders, it states katex not defined . Katex JS doc says, it should be available globally once js is loaded.
Versions: bokeh - 1.4.0, katex - 0.11, python - 3.7

import numpy as np

from bokeh.models import LabelSet
from bokeh.plotting import figure
from bokeh.io import output_notebook, show, curdoc
from bokeh.util.compiler import TypeScript

TS_CODE = """
import * as p from "core/properties"
import {LabelSet, LabelSetView} from "models/annotations/label_set"
declare const katex: any

export class LatexLabelSetView extends LabelSetView {
  model: LatexLabelSet

  render(): void {
    const {ctx} = this.plot_view.canvas_view
    const [sx, sy] = this._map_data()

    for (let i = 0; i < this._text.length; i++) {
      try {
        this._v_css_text(ctx, i, this._text[i], sx[i] + this._x_offset[i], sy[i] - this._y_offset[i], this._angle[i])
        console.log(this._text[i])
        console.log(katex)
        katex.render(this._text[i], this.el, {displayMode: true})
      }
      catch(e) {
        console.log( 'Error: ' + e);
      }
    }
  }
}

export namespace LatexLabelSet {
  export type Attrs = p.AttrsOf<Props>

  export type Props = LabelSet.Props
}

export interface LatexLabelSet extends LatexLabelSet.Attrs {}

export class LatexLabelSet extends LabelSet {
  properties: LatexLabelSet.Props

  constructor(attrs?: Partial<LatexLabelSet.Attrs>) {
    super(attrs)
  }

  static init_LatexLabelSet() {
    this.prototype.default_view = LatexLabelSetView
  }
}
LatexLabelSet.init_LatexLabelSet()
"""


class LatexLabelSet(LabelSet):
    __javascript__ = ["https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js"]
    __css__ = ["https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css"]
    __implementation__ = TypeScript(TS_CODE)



x = np.arange(0.0, 1.0 + 0.01, 0.01)
y = np.cos(2 * 2 * np.pi * x) + 2

p = figure(title="LaTex Demonstration", plot_width=500, plot_height=500)
p.line(x, y)
latex = LatexLabelSet(text=["f = \sum_{n=1}^\infty\\frac{-e^{i\pi}}{2^n}!"],
                   x=40, y=420, x_units='screen', y_units='screen',
                   render_mode='css', text_font_size='16pt',
                   background_fill_alpha=0)

p.add_layout(latex)
output_notebook()
show(p)

Tried out output_file as html and it seems to work when I open the html. This seems like the katex js is not loaded while working with notebook. Is there a way in bokeh/jupyter to embed the js/css before starting

Can you try doing the output_notebook immediately after defining the extension, and before doing anything else? You might even try putting a sleep before the rest of the code. My best guess is that this is a race condition and that BokehJS code that uses the katex library is being executed by the notebook before the katex load is completed.

Tried adding output_notebook() time.sleep(5) after defining LatexLabelSet and also tried placing at different places before/after adding layout. Still no change.

@Revendra_Kumar So actually running this code and looking in the browser’s JS network debugging tab, I see that in fact the Katex JS file is loaded. So I wonder if there is simply some JS module format incompatibility between Katex and the notebook. If so, I am not sure there is anything we could do about it. (cc @mateusz in case you have some relevant knowledge.)

At this point I might suggest trying to do this with MathJax instead, since MathJax is definitely known to work in the notebook (and may in fact just already “be available”)

Sure. I already had something working in MathJax. However its pretty slow and the ux experience is not seamless.

@Revendra_Kumar can you elaborate? MathJax is a substantially more mature project I guess I would have assumed the contrary. I would be keen to understand what deficiencies you specifically encountered, perhaps we can take them up with the MathJax author to see if there is some better way of doing things, or if upcoming versions will improve things in anyway.

I also have this problem when using Bokeh serve, but adding

declare namespace katex {
  function render(expression: string, element: HTMLElement, options: {displayMode?: boolean}): void
}

after the typescript imports works well.

I saw the issue where MathJax displays the latext text as it eg: $R_{\phi}$ and takes a second to display the latex. This affects when I pan the plot, it rerenders and its a bad user experience.
the typesetting takes time and needs to be done before displaying the latex text. I will see if I can find my example.

I have tried this already and unfortunately it does not work in notebook.

@Revendra_Kumar I’m not sure exactly what you tried without seeing code but I would imagine rendering once to divs that get absolutely positioned as needed, but not re-rendered unless the source text changed.