8000 TeX on Markup widgets Div, Paragraph by IuryPiva · Pull Request #11585 · bokeh/bokeh · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
2bcffb9
TeX working on div widgets
IuryPiva Sep 10, 2021
d6a2328
add missing inline prop to bokeh
IuryPiva Sep 11, 2021
3b073f2
baselins for tex on div
IuryPiva Sep 11, 2021
2ab38cc
check for property exist instead of getting all property values
IuryPiva Sep 11, 2021
f266a8c
restore default options
IuryPiva Sep 11, 2021
936e05f
use mathjax namespace
IuryPiva Sep 11, 2021
c7bd719
export mathjax provider
IuryPiva Sep 11, 2021
ec53f89
update div imports
IuryPiva Sep 11, 2021
277257b
remove log and unnecessary filter
IuryPiva Sep 11, 2021
678cfe1
update mathjax namespace
IuryPiva Sep 11, 2021
d5308dd
update find math function
IuryPiva Sep 11, 2021
cf6a318
unit tests find_math_parts
IuryPiva Sep 11, 2021
a24d884
update docstrings
IuryPiva Sep 11, 2021
6205be8
check for mathstrings by default; have a disable flag
IuryPiva Sep 11, 2021
22b09b2
update markups to accept tex
IuryPiva Sep 11, 2021
1f1a55b
update import order
IuryPiva Sep 11, 2021
146c6a4
update baselines
IuryPiva Sep 11, 2021
1689425
remove outdated baselines
IuryPiva Sep 11, 2021
cef673a
change is_tex_string to contains_tex_string
IuryPiva Sep 11, 2021
0f75ec5
give latex tests some threshold
IuryPiva Sep 11, 2021
b40b20d
threshold fix
IuryPiva Sep 11, 2021
f9e94c3
fix wrong style on paragraph
IuryPiva Sep 11, 2021
64eaae9
remove needless thresholds
IuryPiva Sep 11, 2021
42972b3
removed tex support from pre
IuryPiva Sep 11, 2021
88d8eb5
Merge branch 'branch-2.4' into iurypiva/mathtext-on-div-widget
IuryPiva Sep 11, 2021
d87fe63
Fix typo
IuryPiva Sep 11, 2021
c6384df
smaller sample text for pre test not latex
IuryPiva Sep 11, 2021
b71ca9b
update pre baselines
IuryPiva Sep 11, 2021
8fe2742
use doublequotes
IuryPiva Sep 11, 2021
5ffd54c
snake case
IuryPiva Sep 12, 2021
28cffab
remove random whitespace
IuryPiva Sep 12, 2021
50fee9d
update docstrings
IuryPiva Sep 12, 2021
f27068a
replace find math with regexs and mathjax implementation
IuryPiva Sep 13, 2021
227aa05
move processing of tex to views
IuryPiva Sep 13, 2021
0557249
output which tests has caused errors
IuryPiva Sep 13, 2021
9ac23e8
update contains_tex check
IuryPiva Sep 13, 2021
abcf63e
check if parts are undefined
IuryPiva Sep 13, 2021
9398619
update docstrings
IuryPiva Sep 13, 2021
4966a6a
add line between tests
IuryPiva Sep 13, 2021
d2e590f
remove test description
IuryPiva Sep 13, 2021
47f26af
rename find_math to find_tex
IuryPiva Sep 13, 2021
19099b2
remove todo warning
IuryPiva Sep 13, 2021
d440f03
remove needless regex flag
IuryPiva Sep 13, 2021
85769d5
update provider interaction
IuryPiva Sep 13, 2021
caf6540
make code consistent with other markups
IuryPiva Sep 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
TeX working on div widgets
  • Loading branch information
IuryPiva committed Sep 10, 2021
commit 2bcffb9ec6b951448f8d55dd221694000f91895e
9 changes: 8 additions & 1 deletion bokeh/embed/bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,14 @@ def _use_mathjax(objs: Sequence[Model | Document]) -> bool:
bool
'''
from ..models.text import MathText
return _any(objs, lambda obj: isinstance(obj, MathText))

def model_require_mathjax(model: Model) -> bool:
''' If any model explicit require MathJax with enable_tex option set to true
'''
properties = model._property_values
return properties.get('enable_tex', False)

return _any(objs, lambda obj: isinstance(obj, MathText) or model_require_mathjax(obj))

def _use_gl(objs: Sequence[Model | Document]) -> bool:
''' Whether a collection of Bokeh objects contains a plot requesting WebGL
Expand Down
8 changes: 8 additions & 0 deletions bokeh/models/widgets/markups.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class Div(Markup):

This Bokeh model corresponds to an HTML ``<div>`` element.

Content can be interpreted as \
`TeX and LaTeX input <https://docs.mathjax.org/en/latest/basic/mathematics.html#tex-and-latex-input/>` \
setting enable_tex to ``True``
'''

__example__ = "sphinx/source/docs/user_guide/examples/interaction_div.py"
Expand All @@ -103,6 +106,11 @@ class Div(Markup):
The default value is ``False``, meaning contents are rendered as HTML.
""")

enable_tex = Bool(False, help="""
Whether the contents should be rendered including TeX/LaTeX input.
The default value is ``False``, and only applies when rendering as HTML (that is, when render_as_text is ``False``)
""")

class PreText(Paragraph):
''' A block (paragraph) of pre-formatted text.

Expand Down
8 changes: 7 additions & 1 deletion bokehjs/src/lib/external/mathjax.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
declare namespace MathJax {
type TeXMacros = {[key: string]: string | [string, number]}
type ConvertOptions = {
display?: boolean
em?: number
ex?: number
containerWidth?: number
}

function tex2svg(input: string, macros?: TeXMacros): HTMLElement
function tex2svg(input: string, options?: ConvertOptions, macros?: TeXMacros): HTMLElement
function ascii2svg(input: string): HTMLElement
function mathml2svg(input: string): HTMLElement
}
6 changes: 4 additions & 2 deletions bokehjs/src/lib/models/text/math_text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ export class TeXView extends MathTextView {

protected _process_text(text: string): HTMLElement | undefined {
// TODO: allow plot/document level configuration of macros
return this.provider.MathJax?.tex2svg(text, this.model.macros)
return this.provider.MathJax?.tex2svg(text, undefined, this.model.macros)
}
}

Expand All @@ -423,6 +423,7 @@ export namespace TeX {

export type Props = MathText.Props & {
macros: p.Property<{[key: string]: string | [string, number]}>
inline: p.Property<boolean>
}
}

Expand All @@ -439,8 +440,9 @@ export class TeX extends MathText {
static {
this.prototype.default_view = TeXView

this.define<TeX.Props>(({Number, String, Dict, Tuple, Or}) => ({
this.define<TeX.Props>(({Boolean, Number, String, Dict, Tuple, Or}) => ({
macros: [ Dict(Or(String, Tuple(String, Number))), {} ],
inline: [ Boolean, false ],
}))
}
}
23 changes: 15 additions & 8 deletions bokehjs/src/lib/models/text/mathjax/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,26 @@ RegisterHTMLHandler(adaptor)

const svg = new SVG({fontCache: "local"})

const options = {
display: true,
em: 16,
ex: 8,
containerWidth: 80*16,
type ConvertOptions = {
display?: boolean
em?: number
ex?: number
containerWidth?: number
}

type TeXMacros = {[key: string]: string | [string, number]}

export function tex2svg(formula: string, macros: TeXMacros = {}): HTMLElement {
export function tex2svg(formula: string, options?: ConvertOptions, macros: TeXMacros = {}): HTMLElement {
const convert_options: ConvertOptions = {
display: true,
em: 16,
ex: 8,
containerWidth: 80*16,
...options,
}
const tex = new TeX({packages: AllPackages, macros})
const tex_to_svg = mathjax.document("", {InputJax: tex, OutputJax: svg})
return tex_to_svg.convert(formula, options)
return tex_to_svg.convert(formula, convert_options)
}

export function ascii2svg(_formula: string): HTMLElement {
Expand All @@ -38,5 +45,5 @@ export function ascii2svg(_formula: string): HTMLElement {
export function mathml2svg(formula: string): HTMLElement {
const mathml = new MathML({})
const mathml_to_svg = mathjax.document("", {InputJax: mathml, OutputJax: svg})
return mathml_to_svg.convert(formula, options)
return mathml_to_svg.convert(formula)
}
61 changes: 61 additions & 0 deletions bokehjs/src/lib/models/text/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {PlainText, TeX} from "../index"

export function find_math_parts(text: string): (PlainText | TeX)[] {
type Delimiter = {
start: string
end: string
inline: boolean
nextIndex?: number
}

const delimiters: Delimiter[] = [
{start: "$$", end: "$$", inline: false},
{start: "\\[", end: "\\]", inline: false},
{start: "\\(", end: "\\)", inline: true},
]

const result: (PlainText | TeX)[] = []
let remaining_text = text

const find_end = (delimiter?: Delimiter) => {
if (!delimiter) {
result.push(new PlainText({text: remaining_text}))
remaining_text = ""
return
}

if (remaining_text.includes(delimiter.start)) {
const index = remaining_text.indexOf(delimiter.start)

if (remaining_text.slice(index + 2).includes(delimiter.end)) {
result.push(new PlainText({text: remaining_text.slice(0, index)}))
remaining_text = remaining_text.slice(index + 2)

const closing_index = remaining_text.indexOf(delimiter.end)
result.push(
new TeX({
text: remaining_text.slice(0, closing_index),
inline: delimiter.inline,
})
)
remaining_text = remaining_text.slice(closing_index + 2)
}
}
}

const find_next_delimiter = () =>
delimiters
.map((delimiter) => ({
...delimiter,
nextIndex: remaining_text.indexOf(delimiter.start),
}))
.sort((a, b) => a.nextIndex - b.nextIndex)
.filter((delimiter) => delimiter.nextIndex >= 0)[0]

while (remaining_text) {
console.log(find_next_delimiter())
find_end(find_next_delimiter())
}

return result.filter(Boolean).filter(el => el.text)
}
26 changes: 25 additions & 1 deletion bokehjs/src/lib/models/widgets/div.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
import {Markup, MarkupView} from "./markup"
import * as p from "core/properties"
import {BundleProvider, MathJaxProvider} from "models/text/providers"
import {find_math_parts} from "models/text/utils"
import {TeX} from "models"

const default_provider: MathJaxProvider = new BundleProvider()
export class DivView extends MarkupView {
override model: Div

get provider(): MathJaxProvider {
return default_provider
}

override async lazy_initialize() {
await super.lazy_initialize()

if (this.provider.status == "not_started")
await this.provider.fetch()
}

override render(): void {
super.render()
if (this.model.render_as_text)
this.markup_el.textContent = this.model.text
else
else if (this.model.enable_tex) {
const html_with_svgs = find_math_parts(this.model.text).map(el => {
if (el instanceof TeX) return this.provider.MathJax?.tex2svg(el.text, {display: !el.inline}).outerHTML
else return el.text
}).join("")

this.markup_el.innerHTML = html_with_svgs
} else
this.markup_el.innerHTML = this.model.text
}
}
Expand All @@ -18,6 +40,7 @@ export namespace Div {

export type Props = Markup.Props & {
render_as_text: p.Property<boolean>
enable_tex: p.Property<boolean>
}
}

Expand All @@ -36,6 +59,7 @@ export class Div extends Markup {

this.define<Div.Props>(({Boolean}) => ({
render_as_text: [ Boolean, false ],
enable_tex: [ Boolean, false ],
}))
}
}
10 changes: 10 additions & 0 deletions bokehjs/test/integration/widgets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ describe("Widgets", () => {
foo_col.visible = false
await view.ready
})

it("should allow TeX on Divs with mathstrings and enable_tex = true", async () => {
const obj = new Div({
text: `When \\(a \\ne 0\\), there are two solutions to \\(ax^2 + bx + c = 0\\) and they are
$$x = {-b \\pm \\sqrt{b^2-4ac} \\over 2a}.$$`,
enable_tex: true,
})

await display(obj, [320, 120])
})
})

describe("Rows of widgets", () => {
Expand Down
0