Tutorial

Below are a series of examples of the capabilities of the Handcalcs package.

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:

Note: If you input strings instead of expressions into handcalcs, they will be enclosed in parenthesis and added to the end of the last expression line.

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

Changing the Output Settings

You can edit the layout of the returned LaTeX expression with the following kwargs:

  • cols - change the number of columns the expression returns (default = 1).
  • spa - change the vertical line spacing between expressions (default = 10).
  • color: change the color of the output (:blue, :red, etc)
  • h_env - change the environment (default = "aligned").
  • precision: formats numbers to a max precision. Given precision = 2, 2.567 will show as 2.57, while 2.5 would show as 2.5
  • 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 color=:blue

\[\color{blue} \begin{aligned} a &= 1& b &= 2& c &= 3 \\[0pt] x &= 4& y &= 5& z &= 6 \end{aligned}\]

A list of additional colors can be found here. Not all of the colors in the link work, but a good number of them do.

Below is an example of what you can do if an expression is really long.

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 calc_Is was not. As you can see, the calc_Is 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, :sum, 
    :cumsum, :max, :min, :exp, :log,
    :log10, :√]

If you want to add functions to your specific project, you can do the following:

set_handcalcs(not_funcs = [:foo :bar :baz])

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.

Options for if statements

If statements have two different formats in how they can be displayed. The default format is different than how Latexify would display the if statement. The reasoning was to show an if statement more like the way you would if you were performing a calculation by hand and to also integrate function unrolling. The default format (parse_ifs=true), only shows the branches of the if statement that pass the logic statements within the if statement. This is nice, because you only see the equations that are relevant to that specific problem. See the example below:

@handcalcs begin
x = 10
if x > 5
    Ix = calc_Ix(5, 15)
else
    Ix = calc_Ix(10, 15)
end
end

\[\begin{aligned} x &= 10 \\[10pt] \text{Since: }x > 5 &= 10 > 5 = true \\[10pt] Ix &= \frac{b \cdot h^{3}}{12} = \frac{5 \cdot 15^{3}}{12} = 1406.25 \end{aligned}\]

Nested if statements work as well. See below:

@handcalcs begin
x = 10
y = 5
if x > 5
    if y < 3
        Ix = calc_Ix(5, 15)
    else
        Ix = calc_Ix(3, 15)
    end
else
    Ix = calc_Ix(10, 15)
end
end

\[\begin{aligned} x &= 10 \\[10pt] y &= 5 \\[10pt] \text{Since: }x > 5 &= 10 > 5 = true \\[10pt] \text{Since: }y < 3 &= 5 < 3 = false \\[10pt] Ix &= \frac{b \cdot h^{3}}{12} = \frac{3 \cdot 15^{3}}{12} = 843.75 \end{aligned}\]

The other format (parse_ifs=false) looks more like the Latexify format. However, nested ifs don't always work and function unrolling does not work.

@handcalcs begin
x = 10
y = 5
if x > 5
    Ix = calc_Ix(5, 15)
else
    Ix = calc_Ix(10, 15)
end
end parse_ifs=false

\[\begin{aligned} x &= 10 \\[10pt] y &= 5 \\[10pt] \begin{cases} Ix = \mathrm{calc}_{Ix}\left( 5, 15 \right) & \text{if } x > 5\\ Ix = \mathrm{calc}_{Ix}\left( 10, 15 \right) & \text{otherwise} \end{cases} &= \begin{cases} Ix = \mathrm{calc}_{Ix}\left( 5, 15 \right) & \text{if } 10 > 5\\ Ix = \mathrm{calc}_{Ix}\left( 10, 15 \right) & \text{otherwise} \end{cases} = 1406.25 \end{aligned}\]

You can also write the if statement like so:

@handcalcs begin
x = 10
y = 5
Ix = if x > 5
    calc_Ix(5, 15)
else
    calc_Ix(10, 15)
end
end

\[\begin{aligned} x &= 10 \\[10pt] y &= 5 \\[10pt] Ix &= \begin{cases} \mathrm{calc}_{Ix}\left( 5, 15 \right) & \text{if } x > 5\\ \mathrm{calc}_{Ix}\left( 10, 15 \right) & \text{otherwise} \end{cases} = \begin{cases} \mathrm{calc}_{Ix}\left( 5, 15 \right) & \text{if } 10 > 5\\ \mathrm{calc}_{Ix}\left( 10, 15 \right) & \text{otherwise} \end{cases} = 1406.25 \end{aligned}\]

This way does not require you to write the parse_ifs=false, although that may change in future versions. If you prefer the Latexify method you can change the default settings. See next section for more info.

Changing Default Settings

You can change the default settings using the set_handcalcs function (similar to the set_default function in Latexify).

Settings

  • cols - change the number of columns the expression returns (default = 1).
  • spa - change the vertical line spacing between expressions (default = 10).
  • len: can set to :long and it will split equation to multiple lines
  • color: change the color of the output (:blue, :red, etc)
  • h_env: choose between "aligned" (default), "align" and other LaTeX options
  • precision: formats numbers to a max precision. Given precision = 2, 2.567 will show as 2.57, while 2.5 would show as 2.5
  • not_funcs: name the functions you do not want to "unroll"
  • parse_pipe: a boolean value (default=true) to remove pipe from equation. This is intended for unitful equations.
  • parse_ifs: a boolean value (default=true) to unroll if statements. Function unrolling works and it only shows the parts of the if statement that were met.
  • disable: disable handcalcs rendering to run simulations and turn it back on when needed.
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()

Set default precision

Handcalcs provides a setting to include a default precision. This setting formats a number to a max precision. See example below:

@handcalcs begin
    a = 2.567
    b = 2.5
    c = 1
    d = true
end precision = 2

\[\begin{aligned} a &= 2.57 \\[10pt] b &= 2.5 \\[10pt] c &= 1 \\[10pt] d &= true \end{aligned}\]

This setting is off by default, but you can add a default with the set_handcalcs function.

set_handcalcs(precision=4)

If other formats are preferred, then use the fmt option provided by Latexify.

@handcalcs begin
    a = 2.567
    b = 2.5
    c = 1
    d = true
end fmt = "%.2f"

\[\begin{aligned} a &= 2.57 \\[10pt] b &= 2.50 \\[10pt] c &= 1.00 \\[10pt] d &= 1.00 \end{aligned}\]

The set_default function is re-exported from the Latexify.jl package. See here for more Latexify default settings.

Using Unitful with UnitfulLatexify

The package integrates with the packages Unitful.jl and UnitfulLatexify.jl.

using Unitful, UnitfulLatexify
a = 2u"inch"
b = -5u"inch"
@handcalcs c = sqrt(a^2 + b^2)

\[\begin{aligned} c &= \sqrt{a^{2} + b^{2}} = \sqrt{\left( 2\;\mathrm{inch} \right)^{2} + \left( -5\;\mathrm{inch} \right)^{2}} = 5.385\;\mathrm{inch} \end{aligned}\]

If you want to set the units of the output, you can write it the same way you would using Unitful. The @handcalcs macro will parse the |> operator out of the output while still evaluating the result with the conversion.

b = 40u"ft"
t = 8.5u"inch"
@handcalcs begin
    b
    t
    a = b * t       |> u"inch"^2
    Ix = b*t^3/12   |> u"inch"^4
end

\[\begin{aligned} b &= 40\;\mathrm{ft} \\[10pt] t &= 8.5\;\mathrm{inch} \\[10pt] a &= b \cdot t = 40\;\mathrm{ft} \cdot 8.5\;\mathrm{inch} = 4080\;\mathrm{inch}^{2} \\[10pt] Ix &= \frac{b \cdot t^{3}}{12} = \frac{40\;\mathrm{ft} \cdot \left( 8.5\;\mathrm{inch} \right)^{3}}{12} = 2.456 \cdot 10^{4}\;\mathrm{inch}^{4} \end{aligned}\]

Pluto

Handcalcs renders in Pluto.jl. There is one function specifically for rendering in pluto.

Handcalcs.left_align_in_plutoFunction
left_align_in_pluto()

Returns html that changes mathjax settings in pluto. This results in equations that are left aligned instead of centered.

source
Use `begin` and `end`

Pluto outputs an extra variable description when using @handcalcs without begin and end.

As an example:

@handcalcs x = 2

Instead of writing the code above, write:

@handcalcs begin 
    x = 2 
end