Recipes
Recipes provides a concise means of extending Latexify.jl to work with types of your own making or of other packages. The @latexrecipe
macro allows you to specify how a an argument type (or a set of types) should be pre-processed before they are passed to the standard latexify
function. Also, it allows you to define both new keyword arguments as well as to set the defaults of pre-existing ones. The main power of this macro is that is defines the necessary functions within Latexify.jl itself, as opposed to within the module where it is called.
The recipe syntax closely follow that of the Plots.jl recipes and, indeed, most of the code is copied and adapted from them (cred to the authors!).
So. The easiest way to explain it is by showing an example where we define a recipe for our type MyType
.
using Latexify
struct MyType
vector::Vector
end
@latexrecipe function f(x::MyType; reverse=false)
## we can access the input object and perform operations like in a normal function.
vec = x.vector
if reverse
vec = vec[end:-1:1]
end
## we can define defult keyword arguments to be passed along to latexify
## using an arrow notation, -->
env --> :array
transpose --> true
## These can be overridden by the keyword arguments passed to the latexify function.
## If you use the := operator to specify a value it cannot be overridden.
fmt := "%.2f"
## The return value should be something that latexify already knows how to work with.
## In this case, we have a simple vector which is fine!
return vec
end
mytype = MyType([1, 2, 3])
latexify(mytype; reverse=true)
\[\begin{equation} \left[ \begin{array}{c} 3.00 \\ 2.00 \\ 1.00 \\ \end{array} \right] \end{equation}\]
The required signature of the macro is
@latexrecipe function f(x::MyType, ...; ...)
return something
end
Here, the function name is unimportant, but the type signature is key. There must also be an explicit return
statement which returns something that base Latexify already works with (Arrays, Tuples, Numbers, Symbols, Strings, etc.). In particular, you can not rely on Julia's default to return the value of the last expression evaluated in a function body.
The special notation kwarg --> value
resets the default value of a keyword argument for your specific inputs. This will be overridden if the keyword argument in quesion is specified in a call to latexify
. To disallow this overriding, use kwarg := value
instead.
The use of @latexrecipe
to redefine how an already supported type should be interpreted is highly discouraged. There is (currently) nothing in place to forbid this but it could mess up how latexify works with other packages. Disregarding this in your own sessions is one thing, but doing it in a package could cause very difficult issues for the users of your package.
If a recipe is defined within a module, everything should just work without the need to export anything.
The special keyword argument operation
lets you specify that a type corresponds to a specific arithmetic operation. For instance, if we define a type
struct MyDifference
x
y
end
that is meant to represent the operation x - y
, we might want to create the recipe
@latexrecipe function f(m::MyDifference)
return :($(m.y) - $(m.x))
end
so that the result of latexify(MyDifference(2,3))
is $3 - 2$. But right now, latexify
does not know that this represents an operation, so for instance @latexify $(MyDifference(2,3))*4
gives $3 - 2 \cdot 4$, which is incorrect. The way around this is to edit the recipe:
@latexrecipe function f(m::MyDifference)
operation := :-
return :($(m.y) - $(m.x))
end
Now latexify
knows that MyDifference
represents a subtraction, and parenthesis rules kick in: @latexify $(MyDifference(2,3))*4
gives $\left( 3 - 2 \right) \cdot 4$.