Handcalcs
Introduction
This is the documentation for Handcalcs.jl. This package supplies macros to generate $\LaTeX$ formatted strings from mathmatical formulas. This package takes inspiration from handcalcs.py which is a python package that works best in jupyter notebooks. The goal is to get the functionalities of that package and bring them to Julia. The current version of Handcalcs.jl is working for typical algebraic formulas. Future plans are to integrate the package with Unitful.jl, be able to render the algebraic expressions within a function, and many other things. This package is an extension of Latexify.jl. The @latexdefine
macro is similar to the main @handcalcs
macro, but instead of only a symbolic rendering it also renders the numeric substitution.
Note: This package now renders properly in Quarto/Weave!! You can change the default settings to your liking. See examples below.
Expression Examples
A single expression example:
using Handcalcs
a = 2
b = -5
c = 2
@handcalcs x = (-b + sqrt(b^2 - 4*a*c))/ (2*a)
\[\begin{aligned} x &= \frac{ - b + \sqrt{b^{2} - 4 \cdot a \cdot c}}{2 \cdot a} = \frac{ + 5 + \sqrt{\left( -5 \right)^{2} - 4 \cdot 2 \cdot 2}}{2 \cdot 2} = 2.0 \end{aligned}\]
The variable x is still evaluated:
x
2.0
An example of multiple expressions:
b = 5 # width
h = 15 # height
@handcalcs begin
I_x = (b*h^3)/12; "moment of inertia about x";
I_y = (h*b^3)/12; "moment of inertia about y";
end
\[\begin{aligned} I_{x} &= \frac{b \cdot h^{3}}{12} = \frac{5 \cdot 15^{3}}{12} = 1406.25\;\text{ }(\text{moment of inertia about x}) \\[10pt] I_{y} &= \frac{h \cdot b^{3}}{12} = \frac{15 \cdot 5^{3}}{12} = 156.25\;\text{ }(\text{moment of inertia about y}) \end{aligned}\]
The I_x
and I_y
variables are still evaluated:
println("The moment of inertia about the x direction is: $I_x\n
The moment of inertia about the y direction is: $I_y\n")
The moment of inertia about the x direction is: 1406.25
The moment of inertia about the y direction is: 156.25
You can edit the layout of the returned LaTeX expression with cols
and spa
:
- cols - change the number of columns the expression returns (default = 1).
- spa - change the vertical line spacing between expressions (default = 10).
- h_env - change the environment (default = "aligned").
- len - change expression to write to multiple lines using
len=:long
(default = :short).
Note: @handcalcs
macro can also take symbols of defined variables. See below.
a, b, c = 1, 2, 3
@handcalcs begin
a # see note above
b
c
x = 4
y = 5
z = 6
end cols=3 spa=0
\[\begin{aligned} a &= 1& b &= 2& c &= 3 \\[0pt] x &= 4& y &= 5& z &= 6 \end{aligned}\]
a, b, c = 2, -5, 2
@handcalcs begin
x1 = (-b + sqrt(b^2 - 4*a*c))/(2*a)
x2 = (-b - sqrt(b^2 - 4*a*c))/(2*a)
end len = :long # using len argument forces cols=1
\[\begin{aligned} x1 &= \frac{ - b + \sqrt{b^{2} - 4 \cdot a \cdot c}}{2 \cdot a} \\[10pt] &= \frac{ + 5 + \sqrt{\left( -5 \right)^{2} - 4 \cdot 2 \cdot 2}}{2 \cdot 2} \\[10pt] &= 2.0 \\[10pt] x2 &= \frac{ - b - \sqrt{b^{2} - 4 \cdot a \cdot c}}{2 \cdot a} \\[10pt] &= \frac{ + 5 - \sqrt{\left( -5 \right)^{2} - 4 \cdot 2 \cdot 2}}{2 \cdot 2} \\[10pt] &= 0.5 \end{aligned}\]
Function Examples
The @handcalcs
macro will now automatically try to "unroll" the expressions within a function when the expression has the following pattern: variable = function_name(args...; kwargs...)
. Note that this is recursive, so if you have a function that calls other functions where the expressions that call the function are of the format mentioned, it will continue to step into each function to "unroll" all expressions.
One issue that can arise are for the functions that you do not want to unroll. Consider the expression: y = sin(x)
or y = x + 5
. Both of these expressions match the format: variable = function_name(args...; kwargs...)
and would be unrolled. This would result in an error since these functions don't have generic math expressions that can be latexified defining the function. You will need to use the not_funcs
keyword to manually tell the @handcalcs macro to pass over these functions. Some of the common math functions that you will not want to unroll are automatically passed over. See examples below.
An example for rendering expressions within a function:
function calc_Ix(b, h) # function defined in TestHandcalcFunctions
Ix = b*h^3/12
return Ix
end;
calc_Ix (generic function with 1 method)
using TestHandcalcFunctions
b = 5 # width
h = 15 # height
@handcalcs Ix = calc_Ix(b, h) # function is defined in TestHandcalcFunctions package
\[\begin{aligned} Ix &= \frac{b \cdot h^{3}}{12} = \frac{5 \cdot 15^{3}}{12} = 1406.25 \end{aligned}\]
The Ix
variable is evaluated. Ix being the variable assigned in the @handcalcs part (variables within function are not defined in the global name space). If you assign it to a different variable then that will be the variable defined (although you will still see it as Ix in the latex portion). Also note that return statements are filtered out of the function body, so keep relevant parts separate from return statements.
function calc_Is(b, h) # function defined in TestHandcalcFunctions
Ix = calc_Ix(b, h)
Iy = calc_Iy(h, b)
return Ix, Iy
end;
calc_Is (generic function with 1 method)
using TestHandcalcFunctions
x = 0
@handcalcs begin
y = sin(x)
z = cos(x)
I_x, I_y = TestHandcalcFunctions.calc_Is(5, 15)
end not_funcs = [sin cos]
\[\begin{aligned} y &= \sin\left( x \right) = \sin\left( 0 \right) = 0.0 \\[10pt] z &= \cos\left( x \right) = \cos\left( 0 \right) = 1.0 \\[10pt] Ix &= \frac{b \cdot h^{3}}{12} = \frac{5 \cdot 15^{3}}{12} = 1406.25 \\[10pt] Iy &= \frac{h \cdot b^{expo}}{denominator} = \frac{15 \cdot 5^{3}}{12} = 156.25 \end{aligned}\]
In the above example sin
and cos
were passed over and calcIs was not. As you can see, the calcIs function was a function that called other functions, and the @handcalcs macro continued to step into each function to unroll all expressions. Please see below for a list of the current functions that are passed over automatically. Please submit a pull request if you would like to add more generic math functions that I have left out.
const math_syms = [
:*, :/, :^, :+, :-, :%,
:.*, :./, :.^, :.+, :.-, :.%,
:<, :>, Symbol(==), :<=, :>=,
:.<, :.>, :.==, :.<=, :.>=,
:sqrt, :sin, :cos, :tan]
Current Limitations for @handcalcs
- I believe the function needs to be defined in another package. The @code_expr macro from CodeTracking.jl does not see functions in Main for some reason.
- If the function has other function calls within it's body that are not available in Main, then the macro will error.
An example of changing default settings:
You can change the default settings using the set_handcalcs
function (similar to the set_default
function in Latexify).
set_handcalcs(cols=3)
Note that this changes Handcalcs.jl from within and should therefore only be used in your own Julia sessions (do not call this from within your packages).
The calls are additive so that a new call with
set_handcalcs(spa = 5)
will not cancel out the changes we just made to cols
.
To view your changes, use
get_handcalcs()
and to reset your changes, use
reset_handcalcs()
Using Unitful with UnitfulLatexify
The package has plans to work with the packages Unitful.jl and UnitfulLatexify.jl. The only issue known is the rendering of units under exponents. Parenthesis need to wrap the numerical value and the unit for it to display correctly. See example below.
using Unitful, UnitfulLatexify
a = 2u"inch"
b = -5u"inch"
@handcalc c = sqrt(a^2 + b^2)
\[c = \sqrt{a^{2} + b^{2}} = \sqrt{2\;\mathrm{inch}^{2} -5\;\mathrm{inch}^{2}} = 5.385\;\mathrm{inch}\]
You can see that it looks as though only the unit is being squared. This should be an easy fix. See pull request made in Latexify.jl here. The pull request has been up for a while, so not sure if it will get updated soon. You can always dev Latexify
and add the one line change for now.
Future Plans
There are a number of things that I would like to implement to the package. See handcalcs.py for potential features. Here is a list of features I hope to add:
- Get recursion working for @handfunc macro
- A way to break down a $\LaTeX$ equation that is too long to multiple lines
References
Handcalcs.Handcalcs
Handcalcs.get_handcalcs
Handcalcs.reset_handcalcs
Handcalcs.set_handcalcs
Handcalcs.@handcalc
Handcalcs.@handcalcs
Handcalcs.@handfunc
Handcalcs.Handcalcs
— ModuleModule for better calc documentation.
Handcalcs.get_handcalcs
— Functionget_handcalcs
Get a Dict with the user-specified default kwargs for handcalcs, set by set_handcalcs
.
Handcalcs.reset_handcalcs
— Methodreset_handcalcs()
Reset user-specified default kwargs for handcalcs, set by set_handcalcs
.
Handcalcs.set_handcalcs
— Methodset_default(; kwargs...)
Set default kwarg values for handcalcs.
This works for all keyword arguments. It is additive such that if you call it multiple times, defaults will be added or replaced, but not reset.
Example:
set_handcalcs(cols = 2, spa = 5)
To reset the defaults that you have set, use reset_handcalcs
. To see your specified defaults, use get_handcalcs
.
Handcalcs.@handcalc
— Macro@handcalc expression
Create LaTeXString
representing expression
. The expression being a vaiable followed by an equals sign and an algebraic equation. Any side effects of the expression, like assignments, are evaluated as well. The RHS can be formatted or otherwise transformed by supplying a function as kwarg post
.
Examples
julia> a = 2
2
julia> b = 5
5
julia> @handcalc c = a + b
L"$c = a + b = 2 + 5 = 7$"
julia> c
7
Handcalcs.@handcalcs
— Macro@handcalcs expressions
Create LaTeXString
representing expressions
. The expressions representing a number of expressions. A single expression being a vaiable followed by an equals sign and an algebraic equation. Any side effects of the expression, like assignments, are evaluated as well. The RHS can be formatted or otherwise transformed by supplying a function as kwarg post
. Can also add comments to the end of equations. See example below.
Examples
julia> a = 2
2
julia> b = 5
5
julia> e = 7
7
julia> @handcalcs begin
c = a + b; "eq 1";
d = a - c
e
end
L"$\begin{aligned}
c &= a + b = 2 + 5 = 7\;\text{ }(\text{eq 1})
\\[10pt]
d &= a - c = 2 - 7 = -5
\\[10pt]
e &= 7
\end{aligned}$"
julia> c
7
julia> d
-5
Handcalcs.@handfunc
— Macro@handfunc expression
Create LaTeXString
representing expressions
. These expressions represent a number of expressions that exist within the function that was called. A single expression being a variable followed by an equals sign and the function being called. The expression is evaluated as well (not the expressions within the function). The RHS can be formatted or otherwise transformed by supplying a function as kwarg post
.
Examples
julia> @handfunc Iy = calc_Ix(5, 15)
L"$\begin{aligned}
Ix &= \frac{b \cdot h^{3}}{12} = \frac{5 \cdot 15^{3}}{12} = 1406.25
\end{aligned}$"
julia> Iy
1406.25
Note how Iy is evaluated but Ix is not.