Julia Symbolics in Jupyter - Initializing LaTeX printing

I am familiar with using python and sympy on Jupyter Notebook. When printing LaTeX expressions on Notebook I have in my printing modules the statement -

                # Affects only the plaintext printing, and makes our printing
                # tests easier to maintain

which is executed by the function Format().

I also print the following LaTeX macros so I can use them in print statements -

ip_cmds = raw"""
\newcommand{\lp}{\left (}
\newcommand{\rp}{\right )}
\newcommand{\paren}[1]{\lp {#1} \rp}
\newcommand{\llt}{\left <}
\newcommand{\rgt}{\right >}
\newcommand{\abs}[1]{\left |{#1}\right | }
\newcommand{\pdiff}[2]{\bfrac{\partial {#1}}{\partial {#2}}}
\newcommand{\npdiff}[3]{\bfrac{\partial^{#3} {#1}}{\partial {#2}^{#3}}}
\newcommand{\lbrc}{\left \{}
\newcommand{\rbrc}{\right \}}
\newcommand{\grade}[1]{\left < {#1} \right >}
\newcommand{\f}[2]{{#1}\lp {#2} \rp}
\newcommand{\eval}[2]{\left . {#1} \right |_{#2}}$

In Symbolics.jl is there an equivalent to the init_printing statement for use in Jupyter Notebook. I am doing this so I can annotate my latex strings. An example would be

print(r"\theta_{l} =",latex_string)
1 Like

Hi Alan! I’m a fellow GA nerd. On that note, I just want to make sure that you’ve seen Grassmann.jl. There are other GA julia packages, but that one’s unlike anything I’ve seen elsewhere. You and I actually interacted over galgebra a long time ago (before it went into sympy, even), and I helped move some of your unicode/latex printing stuff into sympy itself, so this feels like familiar territory!

First, I will say that your arguments to init_printing are (essentially) the default behavior of Symbolics. For no good reason that I know of, Symbolics wraps expressions in $$ rather than equation*, but I think mathjax treats those the same. So I don’t see anything you really need to adjust. Otherwise, I think the only control you have is to modify the defaults of Latexify.jl. (See why that’s relevant below.) It looks like the possible defaults to modify are listed here.

As for your ip_cmds, you basically just need to tell mathjax about them. The easiest way I know of is to just run

import LaTeXStrings


That “displays” some blank output, which nonetheless contains your commands. But then mathjax knows what to do with, e.g., $x \W y$. You can even use these manually in your markdown cells. If you’re making a package, you would call import LaTeXStrings inside your module, and then you could create your own init_printing function that just calls this display command.

Under the covers, Julia uses the show function to print out objects, kind of like python’s __str__ and __repr__ methods. Different formats are controlled by different mime arguments. Specifically, in a notebook, show is automatically called with mime=MIME("text/latex"). (And actually, it also calls it with MIME("text/plain"), but that output is just saved within the notebook, but not displayed.) So to hook into this behavior, Symbolics defines Base.show methods for the types that it creates. Those, in turn, generally rely on the latexify function from Latexify.jl.

To enable pretty latex with your own objects, you would define new methods of Base.show with your own types. At a first approximation, I’d guess that you’ll just want show to call latexify:

function Base.show(io::IO, ::MIME"text/latex", e::AbstractGAElement)
    print(io, latexify(e))

Then, your goal would be to teach latexify how to write your various elements. It looks like the recommended way to do this is to use “recipes”.

I made it work in Notebook this way -

function isJupyter()
return isdefined(Main, :IJulia) && Main.IJulia.inited

#In Jupyter Notebook you can render a LaTeX string with display.Latex(latex_str)

if isJupyter()
display = pyimport("IPython.display")
display = "" #I don't know what I want it to be if not in notebook or I just won't use it at all in that case

I know about Grassmann.jl. I am trying to make the user interface in a Julia version of galgebra look like the sympy version and clean up the internals. I also want to maintain the capability of a non-orthogonal basis. In sympy galgebra I got overly enthuses about sympy non-commutative symbols and used them internally when there was a much simpler way of doing things. By the way, for graphics I proselytize Asymptote which does have a Julia wrapper (I don’t know how good it is)


I’m not sure what you mean here. The display function is actually built in to Julia, so it should always be available — whether in the REPL or in a notebook. Relying on python to do things sounds brittle.

Attached is pdf of simple Julia Notebook to show what works and what doen’t on my computer. Am I not using display() correctly?

(Attachment Untitled3-1.pdf is missing)

Shown is simple Julia Notebook to show what works and what doesn’t on my computer. Am I not using display() correctly? The Notebook is running Julia 1.10.1

That’s correct. The problem is that you’re just asking Julia to display a literal string. It doesn’t know that you want it to be interpreted as a LaTeX string. That’s why you need the LaTeXStrings.LaTeXString function in Julia, just as you needed Display.Latex in python.

You might have to install it (one time) with

import Pkg; Pkg.add("LaTeXStrings")

But once you’ve done that, you can always do

using LaTeXStrings

Then, you need to tell Julia that you want a string to be interpreted as LaTeX. The easiest way is to just stick an L in front of the string:


Note that I don’t even have to escape the dollar signs and backslash!

So try this: install the package, open a new Jupyter notebook, and then just run these two lines:

using LaTeXStrings

It should display what you want via mathjax. (In fact, you don’t even need to call display because Julia automatically displays the last thing in a cell.) No python needed!

For programmatic use, it may make more sense to pass a normal string to LaTeXString, which produces the same kind of object:

normal_string = raw"$\theta$"