Library / SDK
korsbo/Latexify.jl avatar
korsbo/Latexify.jl

Latexify.jl: turning Julia expressions into LaTeX you can paste or render

Convert julia objects to LaTeX equations, arrays or other environments.

598 stars58 forksJuliaMIT

At a glance

What is it?
Latexify.jl converts Julia objects into LaTeX maths using Julia's homoiconicity, handling expressions, strings, numbers, SymEngine symbolic expressions and DifferentialEquations models, plus a recipe system for your own types. It renders in Jupyter and Pluto notebooks and can copy the source to your clipboard automatically.
Who is it for?
Latexify.jl suits a Julia researcher who wants to turn an expression or an ODE model into publication-shaped LaTeX without writing the markup by hand, and the recipe system means a domain package can support it directly rather than asking every user to write their own. It does not suit you if you need a general LaTeX document generator, since the output is maths fragments and environments rather than documents.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 66 days ago.
What is it written in?
Mainly Julia, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Homoiconicity is the trick, and the output is a LaTeXString

Latexify.jl is a package for generating LaTeX maths from julia objects, and the mechanism is specific to Julia.

The package utilises Julia's homoiconicity to convert expressions to LaTeX-formatted strings. Because a Julia expression is itself a data structure, latexify can walk it and emit the LaTeX for the same tree, which is why the output for a rational or a complex number comes out right rather than as a call to a print method.

The list of supported inputs is long. Expressions, strings, numbers including rationals and complex, symbolic expressions from SymEngine.jl, ParameterizedFunctions and ReactionNetworks from DifferentialEquations.jl, and other types for which a user recipe has been defined, as well as arrays or dicts of supported types.

The basic example is two lines:

julia
using Latexify
ex = :(x/(y+x)^2)
latexify(ex)

The result is a LaTeXString from LaTeXStrings.jl, and when printed it looks like:

LaTeX
$\frac{x}{\left( y + x \right)^{2}}$

And when that LaTeXString is displayed in an environment which supports the tex or latex MIME type, which covers Jupyter and Pluto notebooks, Jupyterlab and Hydrogen for Atom, it renders automatically. That is the practical payoff: a notebook cell displaying the result gets real typeset mathematics rather than a string of backslashes.

A plain string works too, and is parsed rather than taken literally:

julia
using Latexify
print(latexify("x+y/(b-2)^2"))

which outputs:

LaTeX
$x + \frac{y}{\left( b - 2 \right)^{2}}$

Arrays and dicts of supported types are handled as well, so a matrix of mixed symbolic and numeric entries comes out as an array environment.

Recipes are how you support your own type, and where the design decision bites

The extension mechanism is a macro named @latexrecipe, and the example is short enough to show the whole idea.

julia
using Latexify
struct Ket{T}
    x::T
end
@latexrecipe function f(x::Ket)
    return Expr(:latexifymerge, "\\left|", x.x, "\\right>")
end
latexify(:($(Ket(:a)) + $(Ket(:b))))

The recipe is a function that receives your type and returns a :latexifymerge expression, which is how pieces of LaTeX are concatenated with the rendered inner values. Because the recipe is written as a method on your type, dispatch does the work, and the same pattern applies to a package you do not own.

The maintainer is unusually direct about where these recipes belong. If you want to add support for types defined in another package, the primary suggestion is to create a PR in that package with a recipe. Latexify.jl is not intended to be a collection of recipes for different types. The exceptions are the few types which were included before the recipe system was finished.

And there is a fallback for when the other package is hesitant to pull in Latexify as a dependency: you can either use Requires.jl, or create a separate glue package.

The supported list in the README covers many base types, LaTeXStrings.jl, DifferentialEquations.jl, DiffEqBiological.jl, ParametrizedFunctions.jl, DataFrames.jl, Symbolics.jl, and Unitful.jl via UnitfulLatexify.jl, and more.

The design reasoning is sound. A recipe living with the type it describes keeps the dependency direction correct, since the domain package does not have to depend on Latexify, and the glue package pattern keeps the reverse dependency out of the domain package entirely.

DifferentialEquations models, and the arrow notation for chemistry

The reason the package exists at all, the README says, is the ability to latexify ODEs.

The DifferentialEquations.jl suite has tools for generating differential equations, and one of them is ParameterizedFunctions, which allows you to type in an ODE in something which looks very much like just plain mathematics. The ability to latexify such ODEs is described as pretty much what lured the author to create the package.

julia
using ParameterizedFunctions
using Latexify

f = @ode_def positiveFeedback begin
    dx = v*y^n/(k^n+y^n) - x
    dy = x/(k_2+x) - y
end v n k k_2

latexify(f)

That is a model written in the domain language of the modelling package, rendered as the mathematical expression it represents, which is the thing you would paste into a paper.

Catalyst.jl provides another domain-specific language, one that generates equations using a chemical arrow notation:

julia
using Catalyst
using Latexify

rn = @reaction_network begin
  (r_bind, r_unbind), A + B ↔ C
  hill(C, v, k, n), 0 --> X
  d_x, X --> 0
end

latexify(rn)

And you can output the arrow notation directly to latex:

julia
latexify(rn; env=:arrow)

So the same reaction network can be rendered either as equations or in the arrow notation, chosen with the env keyword.

Outside a notebook there is still a path to seeing the result. One can use ImageInTerminal with the Sixel backend to display rendered latexified equations in a terminal, which turns the package from a notebook-only tool into something usable over ssh.

Installation, session defaults and the clipboard

The convenience functions are about how the output behaves in a REPL session rather than about the LaTeX itself.

copy_to_clipboard with a Bool argument toggles automatic copying of the resulting LaTeX code to the clipboard, and the default is false. auto_display with a Bool argument toggles automatic display of the output, even if it is not the last command to have run, which matters because in the REPL the display is normally tied to the final result of a cell.

Then there are three functions for session defaults. set_default with keyword arguments sets your own default kwargs for your Julia session, and the documentation warns that this is not to be used within a package since the effect is global. reset_default resets the changes made with the above command, and get_default views the changes you have made to the default kwargs.

That warning is the kind of detail that matters in a package context, since a global session default set by one test would leak into the next one.

Installation is a single call, because the package is registered in the Julia registry:

julia
Pkg.add("Latexify")

The repository layout and what the release cadence says

The repository layout is a Julia package with a Project.toml, an src/ directory, a test/ directory, an ext/ directory for package extensions, a benchmark/ directory, a docs/ directory, a paper/ directory and an assets/ directory holding the images used in the README. The extension directory is the modern Julia mechanism for loading optional integrations without adding a hard dependency, which is a reasonable home for the DifferentialEquations and Symbolics integrations.

The release history shows steady work: v0.16.10 on 2025-09-04, v0.16.11 on 2026-07-17 and v0.16.12 on 2026-08-18, and the last push was on 2026-08-18. The licence is MIT, with a LICENSE file at the repository root.

The documentation is hosted at korsbo.github.io/Latexify.jl/stable with a separate latest build behind the second badge, and the README notes that the GitHub website does not really support rendering of equations, so it refers readers to the documentation for more examples. The images in the assets directory are what stand in for that rendering, and the paper/ directory suggests the package is referenced from published work.

Contributing is straightforward according to the README, which invites feedback, suggestions and help with improving the package through issues or pull requests. The one rule worth restating is the recipe placement policy: a type that lives in another package should get its recipe there, so that the dependency arrow points the right way.

Editorial conclusion

Latexify.jl suits a Julia researcher who wants to turn an expression or an ODE model into publication-shaped LaTeX without writing the markup by hand, and the recipe system means a domain package can support it directly rather than asking every user to write their own. It does not suit you if you need a general LaTeX document generator, since the output is maths fragments and environments rather than documents. Before you adopt it, read the recipe docs, and if your types live in another package, note the maintainer's guidance: create the recipe as a pull request in that package, and if that package will not depend on Latexify, use Requires.jl or a separate glue package.

Frequently asked questions

How do I install and use Latexify.jl?

The package is registered in the Julia registry, so run Pkg.add("Latexify"), then call latexify on an expression such as :(x/(y+x)^2). The result is a LaTeXString that renders automatically in Jupyter and Pluto notebooks, which support the tex and latex MIME types.

How do I add LaTeX support for my own Julia type?

Define a recipe with the @latexrecipe macro, returning an Expr(:latexifymerge, ...) that concatenates LaTeX fragments with the rendered inner values. The recipe dispatches on your type, so it can live in a separate glue package if the package that owns the type will not depend on Latexify.

Which types does Latexify.jl handle out of the box?

Expressions, strings, numbers including rationals and complex, SymEngine.jl symbolic expressions, ParameterizedFunctions and ReactionNetworks from DifferentialEquations.jl, arrays and dicts of supported types, plus LaTeXStrings.jl, DiffEqBiological.jl, DataFrames.jl, Symbolics.jl and Unitful.jl through UnitfulLatexify.jl.

Can I see Latexify.jl output in a terminal instead of a notebook?

Yes. The documentation points at using ImageInTerminal with the Sixel backend to display rendered latexified equations in a terminal, which makes the package usable outside a notebook environment.

Official sources

  1. Issues
  2. korsbo/Latexify.jl on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/korsbo-latexify-jl.svg)](https://hysenlabs.com/projects/korsbo-latexify-jl)

Was this useful?