Javis.jl
Javis.jl copied to clipboard
LaTeX without npm
Hello Javis developers. This is actually a tip. I've been playing around with Luxor, and I've implemented LaTeX without the need to install LaTeX in the users computer. To do so, I've used the package MathTeXEngine.jl. This awesome package is the one used by Makie to write LaTeX. Here is my implementation for a package that I'm working on
"""
latex_text_size(lstr::LaTeXString)
Returns the width and height of a latex string.
"""
function latex_text_size(lstr::LaTeXString)
sentence = generate_tex_elements(lstr)
els = filter(x -> x[1] isa TeXChar, sentence)
chars = [x[1].char for x in els]
fonts = [x[1].font for x in els]
pos_x = [x[2][1] for x in els]
pos_y = [x[2][2] for x in els]
scales = [x[3] for x in els]
extents = [get_extent(f, c) for (f, c) in zip(fonts, chars)]
textw = []
texth= []
for i in 1:length(extents)
textw = push!(textw,height_insensitive_boundingbox(extents[i], fonts[i]).widths[1]*scales[i]+pos_x[i])
texth = push!(texth,height_insensitive_boundingbox(extents[i], fonts[i]).widths[2]*scales[i]-pos_y[i])
end
return (maximum(textw), maximum(texth))
end
"""
Luxor.text(lstr::LaTeXString, valign=:baseline, halign=:left; kwargs...)
Draws LaTeX string using `MathTexEngine.jl`. Hence, uses ModernCMU as font family.
Note that `valign` is not perfect.
This function assumes that the axis are in the standard Luxor directions,
i.e. ↓→.
"""
function Luxor.text(lstr::LaTeXString, pt::Point; valign=:baseline, halign=:left, kwargs...)
# Function from MathTexEngine
sentence = generate_tex_elements(lstr)
# Get current font size.
textsize = get_fontsize()
textw, texth = latex_text_size(lstr)
if halign === :left
translate_x = 0
elseif halign === :right
translate_x = -textw * textsize
elseif halign === :center
translate_x = -textw/2 * textsize
end
if valign === :baseline
translate_y = 0
elseif valign === :top
translate_y = -textsize
elseif valign === :bottom
translate_y = texth * textsize
elseif valign === :middle
translate_y = textsize/2
end
# Writes text using ModernCMU font.
for text in sentence
if text[1] isa TeXChar
@layer begin
translate(translate_x,translate_y)
fontface(text[1].font.family_name)
fontsize(textsize*text[3])
Luxor.text(string(text[1].char), pt + Point(text[2]...)*textsize*(1,-1))
end
elseif text[1] isa HLine
@layer begin
translate(translate_x,translate_y)
pointstart = pt+Point(text[2]...)*textsize*(1,-1)
pointend = pointstart + Point(text[1].width,0)*textsize
setline(1*text[1].thickness*textsize)
line(pointstart, pointend,:stroke)
end
end
end
end
Awesome. Thanks a lot! Hopefully this will fix also our #212 issue 😅 I'll have a look at integrating this into Javis
No problem! I suggested adding the LaTeX support directly to Luxor, but since it requires adding MathTeXEngine
as a dependency, it was reject. I do understand though. So hopefully those of use who need LaTeX can add this small chunk of code and move on.
BTW, this is not a perfect implementation. There is some small issues with aligning. Feel free to improve on this code, so I can steal it back :grin:
Haha sounds good. Yeah we would have the ability to have an extra JavisLatex package otherwise but I think for us it makes sense to directly integrate it.
Out of curiosity, how does this work?
Does it use the artifact system to package it within the Julia ecosystem?
I've been looking into Tectonic
so was curious if this was used under the hood or what was.
Regardless, thanks @davibarreira and great to cross paths again!
Hope all has been well!
Hey @TheCedarPrince ! Yeah, I still owe you the answers for Chapter 2. Finished reading it, but haven't implemented. End of semester, things are chaotic again. About MathTeXEngine. Not an expert at all, but from what I understood, the package uses the CMU font and maps the LaTeX commands to the respective unicode characters. In other words, it's just a smart way to turning latex into unicode. Here is a more detailed account: MathTeXEngine parses your LaTeXString from left to right. Each latex symbol is transformed in either a unicode, a vertical line or a horizontal line, and also returns the position of the object. Take the following example:
L"\frac{\mu}{x}"
Now, MathTexEngine will recognize that the "\frac{}{}" will generate a horizontal line in a position, say (0,5), meaning that it's at the start of the string and at the middle in terms of vertical alignment. Next, it will parse to you that "\mu" is actually the unicode for \mu, at position (0,6). Finally, "x" is just "x" at position (0,-6).
This is what it returns
horizontal_line at (0,5)
\mu unicode at (0, 6)
x at (0,-6)
Now you do you :) I mean, it's your job to draw this. This is where my functions come from. I use Luxor to draw this with SVG. Hope it's clear.
LaTeX support directly to Luxor, but since it requires adding
MathTeXEngine
as a dependency, it was reject.
It's an open issue (https://github.com/JuliaGraphics/Luxor.jl/issues/124) and not rejected. 😂
Hey @Wikunia , I extensively tested @davibarreira 's suggestion and I can confirm, using his solution is completely feasible. I think the approach will actually be soon added into the issue @cormullion referenced, which, if so, only means that a user would have to install Lyx fonts onto their computer and not all of LaTeX nor fiddle with npm. A much easier solution I'd imagine!
Great thanks for testing @TheCedarPrince will it be integrated into Luxor or another package or do we have to do it in Javis directly?
It should be integrated into Luxor.jl with Requires.jl.
It should be integrated into Luxor.jl with Requires.jl.
The idea is to extend Luxor.text
to be used on LaTeXStrings
. So things should work almost out of the box. The only requirements will probably be that the user will need to install CMU font, and MathTeXEngine.jl
needs to be loaded, since the dependency will not be hard coded.
If you wish Javis users to be able to use it without loading MathTeXEngine
, you could make it a dependency in you package and load it.
Hey @Wikunia, @cormullion, and @davibarreira ! After some tinkering thanks to Davi's awesome work on this, here is so far what I have found being able to be rendered using MathTeXEngine: https://github.com/Kolaru/MathTeXEngine.jl#supported-constructions
A more visual example that I made is here:
However, it would appear that MathTeXEngine cannot yet fully subsume all parts of LaTeX just yet. One crucial aspect is the lack of rendering matrices as seen here: https://github.com/Kolaru/MathTeXEngine.jl/issues/48 That unfortunately makes it so we cannot replace the LaTeX parsing system in Javis yet as we would be unable to support morphing.
However, as you were suggesting earlier, actually, @Wikunia , I would rather advocate to create a new package in the JuliaAnimators called like JavisTeX or JavisLaTeX to move some of this code from out of core Javis to other modules. Just thinking it might make hacking on things easier (especially for new contributors) and more accessible to figure out LaTeX support in Javis. What do you think?
@TheCedarPrince , perhaps improving MathTeXEngine is a better route. It doesn't seem like supporting matrices would be hard.
Oh, I just saw that you opened an issue. Nice! I myself am thinking of contributing to MathTeXEngine. So I might try to implement the matrix notation.
I'll follow-up with you over at the issue here @davibarreira : https://github.com/Kolaru/MathTeXEngine.jl/issues/48
But, I was thinking about having a Javis TeX package for at least a staging ground for experimentation and development of Javis specific TeX handling. Plus with JSoC coming up, might be a good area for folks to contribute to potentially. :)
From #483 which I opened too soon, another alternative is to: Use an approach similar to the old one from MakieTeX.jl (latexstring/latex document -> compiled latex as pdf -> SVG through dvisvgm). There is a lightweight TeX compiler one can use which is called tectonic, which also ships as a JLL.
The reason I have used this complicated pipeline as opposed to MathJax is because it allows the user to use arbitrary LaTeX packages (like amsmath, physics, tikz, lstlistings
, et cetera. Arbitrary custom commands are also supported as a consequence, so one can paste sections of preamble from their paper and have identical LaTeX in their figures.
I have switched MakieTeX to use Poppler to render direct from PDF now, but you can see the old implementation in v0.0.4.