# Generate PDF document showing the equations in a package

**URL:** <https://discourse.julialang.org/t/generate-pdf-document-showing-the-equations-in-a-package/91064>\
**Category:** Visualization\
**Tags:** latex, weave, literate\
**Created:** [November 30, 2022, 8:38pm UTC](https://discourse.julialang.org/t/generate-pdf-document-showing-the-equations-in-a-package/91064 "2022-11-30T20:38:59Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [November 30, 2022, 8:38pm UTC](https://discourse.julialang.org/t/generate-pdf-document-showing-the-equations-in-a-package/91064/1 "2022-11-30T20:38:59Z")

</div>

I have a small package with equations and tables copied from a book. I want to figure out a way to generate a PDF file rendering all the equations in mathy form. This will serve as a quality control that the equations being used by the package look like the ones in the book.

I had success writing a Pluto notebook for these equations which took the form below and rendered very nicely. However, I could not figure out a way to then make other packages depend on these equations, so I went back to a standard Julia file/package.

```julia
using Markdown, DataFrames, Latexify
md"Equation KM-620.5"
@latexrun A_1(σ_ys, ϵ_ys, m_1) = σ_ys * (1 + ϵ_ys) / (log(1 + ϵ_ys))^m_1

md"Equation KM-620.6"
@latexrun m_1(R, ϵ_p, ϵ_ys) = (log(R) + (ϵ_p - ϵ_ys)) / log(log(1+ϵ_p)/log(1+ϵ_ys))

md"Table KM-620"
const tableKM620 = DataFrame(...)

```

I want to avoid writing the equations twice (once for execution and once for documentation) in case they would get out of sync or be mistyped. Is there a good way to sequentially render the function definitions into a document?

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [December 5, 2022, 8:41pm UTC](https://discourse.julialang.org/t/generate-pdf-document-showing-the-equations-in-a-package/91064/2 "2022-12-05T20:41:36Z")

</div>

# Summary

I was able to achieve my goal. The resultant package is [here](https://github.com/nathanrboyer/KM620.jl). The functions and constants defined in the package are available for use by typing `using KM620`. The PDF outputs are generated by typing `]test KM620`. (You must have XeLaTeX installed.)

# Approach

## Function Definitions

Getting one-liner function definitions rendered to PDF was actually straightforward with [Weave.jl](https://github.com/JunoLab/Weave.jl) and [Latexify.jl](https://github.com/korsbo/Latexify.jl). Just write `@latexrun` in front of the function definition and mark a new weave chunk on the line above it with `#'`. Then `weave(inputfile, doctype="md2pdf", out_path=outputfile)` will do all the work for you. I put this weave command in my `test/runtests.jl` file, so I have an easy way to update the PDFs whenever I update the function definitions. (I still may look for a better way to force the PDFs to update periodically.)

## File Structure

You cannot run `weave` on the main package file because the `module` and `end #module` keywords will not work with Weave’s idea of [code chunks](https://weavejl.mpastell.com/dev/usage/#code-chunks). Instead I structured the main file as below and called `weave` on the included files.

```julia
module KM620
include("KM620_equations.jl")
include("KM620_tables.jl")
end # module KM620

```

You will also need to repeat the `using Latexify, LaTeXStrings` line at the top of each of these included files because the weaved files must be self-contained.

## Contant Definitions

If your constants have simple types, then you can use `@latexdefine` in the same manner as `@latexrun` was used for functions definitions above. Unfortunately, DataFrames cannot be rendered to PDF this way.

> The issue with `@latexdefine` is that it expects things to have a `:raw` representation (because it does something akin to `"\$x = $(latexify(x; env=:raw))\$"` ). DataFrames don’t have this, but only “latexify” as `latexify(df; env=:mdtable)`.

I also ran into [an error](https://github.com/korsbo/Latexify.jl/issues/238) when trying to use `const df = DataFrame(<stuff>)` and `latexify(df)` in the same file. The file would weave the PDF fine, but it would break on the `latexify` line when trying to `using` the package. To get around this error, I moved the `latexify` lines to their own file in the test folder and weaved that file instead of the package file. This test file will `using KM620` so the constants are defined before latexifying them.

Note that this method of latexifying after defining will **not** work for function definitions because the alphanumeric representation of the function is not saved with the function. It is only available for latexification at the time when the function definition is run. I worked around this limitation somewhat to display equations inside my DataFrame by defining [expressions](https://docs.julialang.org/en/v1/manual/metaprogramming/#Expressions-and-evaluation) which I later `eval`uated into functions.

## Markdown Notes

Markdown notes can be written and rendered to PDF anywhere using markdown syntax on the `#'` commented lines. I rendered a separate Nomenclature PDF alongside the others using this method.

# Weave vs. Literate

I originally tried using [Literate.jl](https://github.com/fredrikekre/Literate.jl), but this was a dead end. The LaTeX strings were just displayed in markdown code blocks rather than actually being rendered. [This issue](https://github.com/fredrikekre/Literate.jl/issues/192) led me to Weave. I also came across [LiterateWeave.jl](https://github.com/baggepinnen/LiterateWeave.jl) that could potentially be useful, but I did not dive into it.

# Final Thoughts

My package is in a working state now, but probably not an optimized state. I am open to suggestions on how to do this better. I just wanted to leave some lessons learned for anyone else who happens across this post and to link my package for others to use as a template for this sort of thing.

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [January 30, 2025, 6:57pm UTC](https://discourse.julialang.org/t/generate-pdf-document-showing-the-equations-in-a-package/91064/3 "2025-01-30T18:57:04Z")

</div>

I updated my package to go back to Pluto.

* * *

> [@Nathan\_Boyer](#):
>
> I had success writing a Pluto notebook for these equations which took the form below and rendered very nicely. However, I could not figure out a way to then make other packages depend on these equations

It’s actually very easy. Pluto notebooks are just `.jl` files after all, so they can be `include`-ed as `src` files in a package. Then you can export the Pluto notebook as a PDF or HTML, either manually or with PlutoSliderServer.jl.

The only [trick](https://discourse.julialang.org/t/how-to-handle-dependencies-with-pluto-notebook-as-package-source-code/122780) is to disable Pluto’s own package manager in the notebook by including a cell with the following content and then choosing “disable in file” in the cell menu options.

```julia
begin
	import Pkg
	Pkg.activate(Base.current_project(@ __DIR__ ))
	Pkg.instantiate()
	Text("Project environment is active.")
end

```

A simple package using this method is [here](https://github.com/nathanrboyer/KD232.jl). A slightly more complicated example with some additional tricks for tables of equations is [here](https://github.com/nathanrboyer/KM620.jl).
