### Index
# handcalcs documentation v1.1.2

Covert art by Joshua Hoiberg
handcalcs:
Python calculations in Jupyter,
as though you wrote them by hand.
`handcalcs` is a library to render Python calculation code automatically in Latex, but in a manner that mimics how one might format their calculation if it were written with a pencil: write the symbolic formula, **followed by numeric substitutions**, and then the result.
Because `handcalcs` shows the numeric substitution, the calculations become significantly easier to check and verify by hand.
## Basic Demo
---
### README

Covert art by Joshua Hoiberg
handcalcs:
Python calculations in Jupyter,
as though you wrote them by hand.
`handcalcs` is a library to render Python calculation code automatically in Latex, but in a manner that mimics how one might format their calculation if it were written with a pencil: write the symbolic formula, **followed by numeric substitutions**, and then the result.
Because `handcalcs` shows the numeric substitution, the calculations become significantly easier to check and verify by hand.
## Contents
* [Basic Demo](https://github.com/connorferster/handcalcs#basic-demo)
* [Installation](https://github.com/connorferster/handcalcs#installing)
* [Basic Usage](https://github.com/connorferster/handcalcs#basic-usage-1-as-a-jupyter-cell-magic-render)
* [Enhanced Usage](https://github.com/connorferster/handcalcs#basic-usage-2-as-a-decorator-on-your-functions-handcalc)
* [Features](https://github.com/connorferster/handcalcs#features)
* [PDF Printing in Jupyter](https://github.com/connorferster/handcalcs#pdf-printing-in-jupyter)
* [Expected Behaviours](https://github.com/connorferster/handcalcs#expected-behaviours)
* [Gotchas and Disclaimer](https://github.com/connorferster/handcalcs#gotchas)
* [YouTube Tutorials](https://github.com/connorferster/handcalcs#youtube-tutorials)
* [Applications and Compatibility with Other Libraries (wiki)](https://github.com/connorferster/handcalcs/wiki)
## Basic Demo
## Installing
You can install using pip:
`pip install handcalcs`
## Basic Usage 1: As a Jupyter cell magic (`%%render`)
`handcalcs` is intended to be used with either Jupyter Notebook or Jupyter Lab as a _cell magic_.
First, import the module and run the cell:
```python
import handcalcs.render
```
> Note: This will import both `%%tex` and `%%render` magics in the Jupyter Notebook.
Then, in any cell that you want to render with `handcalcs`, just use the render cell magic at the top of your cell:
```python
%%render
```
For example:
```python
%%render
a = 2
b = 3
c = 2*a + b/3
```
**That is it!**
Once rendered, you can then export your notebook as a PDF, provided you have a Latex environment installed on your system. If you are new to working with Latex and would like to install it on your system so you can use this functionality, please see the section [Installing Tex](https://github.com/connorferster/handcalcs/wiki), in the wiki.
You can also use the `%%tex` command to convert any Python code snippet into a valid LaTex. For Example:
First import `handcalcs`. We are also importing a few properties/functions from __math__ package for the
example below.
```python
import handcalcs.render
from math import sqrt, pi
```
Now, you can use the `%%tex` magic!
```python
%%tex
a = 2 / 3 * sqrt(pi)
```
This will produce a LaTeX output as follows.
```tex
\[
\begin{aligned}
a &= \frac{ 2 }{ 3 } \cdot \sqrt{ \pi } = \frac{ 2 }{ 3 } \cdot \sqrt{ 3.142 } &= 1.182
\end{aligned}
\]
```
# Basic Usage 2: As a decorator on your functions, `@handcalc()`
_Shout-out to @eriknw for developing [innerscope](https://github.com/eriknw/innerscope) and proactively integrating it into `handcalcs`. Thank you!_
Start by importing the `@handcalc()` decorator:
```python
from handcalcs.decorator import handcalc
```
```python
@handcalc([override: str = "", precision: int = 3, left: str = "", right: str = "", jupyter_display: bool = False])
```
Returns a tuple consisting of `(latex_code: str, locals: dict)`, where `locals` is a dictionary of all variables in the scope of the function namespace.
* `override` is a str representing one of the acceptable override tags (see below)
* `precision` is an int to alter the of decimal precision displayed
* `left` and `right` are strings that can precede and follow the encoded Latex string, such as `\\[` and `\\]` or `$` and `$`
* `jupyter_display`, when True, will return only the `locals` dictionary and instead will display the encoded Latex string rendering with `display(Latex(latex_code))` from `IPython.display`. Will return an error if not used within
In your decorated function, everything between `def my_calc(...)` and a return statement (if any) is now like the code in a Jupyter cell, except it's a standard Python function.
Used in this way, you can use `@handcalc()` to dynamically generate Latex code for display in Jupyter and non-Jupypter Python environments (e.g. streamlit).
## Override tags
`handcalcs` makes certain assumptions about how you would like your calculation formatted and does not allow for a great deal of customization in this regard. However, there are currently **four** customizations you can make using `# override tags` as an argument after the `%%render` cell magic. Additionally, you can also specify the number of decimals of precision to display. You can only use __one__ override tag per cell **but** you can combine an override tag with a precision setting.
**Override tags can be used with both the Jupyter cell magic and the function decorator**. To use a override tag with the decorator, you just supply it as an argument, e.g. `@handcalc(override='params', precision=2)`
I will compare a basic rendering of the quadratic formula (below) with the change achieved with each override tag.
### Basic rendering:
___
### `params`:
`handcalcs` renders lines of code vertically, one after the other. However, when you are assigning variables, or displaying resulting variables, you may not want to waste all of that vertical space.
Using the `params` override tag, your list of parameters will instead render in three columns, thereby saving vertical space. Additionally, onsly the result will be shown, no calculations.
___
### Adjust precision:
The number of decimal places in a cell can be adjusted by providing an integer after `%%render` to indicate the decimal precision to be displayed. Can be combined with another override tag.
___
### `long` and `short`:
To save vertical space, `handcalcs` _attempts_ to figure out how long your calculation is and, if it is short enough, renders it out fully on one line.
If `handcalcs`'s internal test deems the calculation as being too long to fit onto one line, it breaks it out into multiple lines.
Use the `# long` or `# short` override tags to override the length check and display the calculation in the "Long" format or the "Short" format for all calculations in the cell. e.g.
#### `long: Spans multiple lines as though you had a long equation`
#### `short: Forced to a single line as though you had a short equation`
```python
# Format for "short" calculations (can fit on one line):
c = 2*a + b/3 = 2*(2) + (3)/3 = 5
# Format for "long" calculations (requires multi-line format)
c = 2*a + b/3
= 2*(2) + (3)/3
= 5
```
___
### `symbolic`
The primary purpose of `handcalcs` is to render the full calculation with the numeric substitution. This allows for easy traceability and verification of the calculation.
However, there may be instances when it is preferred to simply display calculations symbolically. For example, you can use the `symbolic` tag to use `handcalcs` as a fast way to render Latex equations symbolically.
Alternatively, you may prefer to render out all of input parameters in one cell, your formulae symbolically in the following cell, and then all the final values in the last cell, skipping the numeric substitution process entirely.
Keep in mind that even if you use the `symbolic` tag with your calculations, you still need to declare those variables (by assigning values to them) ahead of time in order for your calculation to be valid Python.
---
### `sympy`
This is intended to be used only with `sympy` loaded. Sympy allows for symbolic manipulation, solving, and integration of algebraic expressions. Sympy will render its own objects in Latex without handcalcs.
If you are manipulating a sympy expression or sympy equation for the purpose of calculation, you can use `handcalcs` to handle the substitution and calculation of your resulting expression.
_Note: Re-assigning your symbolic variables to numbers will clobber them as sympy variables. However, you are done with these now, right? So, it's no problem. If you need to work symbolically again, just re-run your notebook cells from the top._
---
## Units Packages Compatibility
`handcalcs` was designed to be used with the units package, [forallpeople](https://github.com/connorferster/forallpeople) (and [forallpeople](https://github.com/connorferster/forallpeople) was designed to be compatible with `handcalcs`). However, it has been recently reported that [pint](https://pint.readthedocs.org) can work to good effect, also.
**For potential compatibility with other units packages, please see [the wiki.](https://github.com/connorferster/handcalcs/wiki)**
---
## Features
### Quickly display the values of many variables
No more `print` statements needed. Just plop your variables onto a line and they will all be displayed.
### Get Just the Latex Code, without the render
If you just want to generate the rendered Latex code directly to use in your own Latex files, you can use the `%%tex` cell magic instead:
```python
%%tex
a = 2
b = 3
c = 2*a + b/3
```
Then you can just copy and paste the result into your own LaTeX document.
---
### Subscripts (and sub-subscripts, etc.)
Subscripts in variable names are automatically created when `_` is used in the variable name. Sub-subscripts are nested for each separate `_` used in series.
----
### Greek symbols
Any variable name that contains a Greek letter (e.g. "pi", "upsilon", "eta", etc.) as a string or substring will be replaced by the appropriate Latex code to represent that Greek letter.
* Using lower case letters as your variable name will make a lower case Greek letter.
* Using a Capitalized Name for your variable will render it as an upper case Greek letter.
---
### Functions, built-in or custom
If you are using Python functions in your calculation, eg. `min()` or `tan()`, they will be replaced with Latex code to represent that function in Latex.
If you are creating your own functions, then they will be rendered in Latex as a custom operator.
If you are using a function with the name `sqrt` (whether your own custom implementation or from `math.sqrt`), then it will be rendered as the radical sign.
---
### Rendered in-line Comments
Any comments placed after a line of calculation will be rendered as an inline comment in the Latex.
This makes it convenient to make notes along side your calculations to briefly explain where you may have acquired or derived a particular value.
---
### Skip the substitution
Any calculation entirely wrapped in parentheses, `()`, will be rendered as just `param = result`, without the substitution.
This can be convient when you want to calculate a parameter on the fly and not have it be the focus of the calculation.
---
### Conditional statements
Many calculations in the "real world" are dependent on context.
`handcalcs` allows for the inclusion of some simple conditional statements into its code in a way that makes it easier to understand the context of the calculation.
*Note: Multiple "lines" of calculations can be used after the conditional expression provided that they are all on the same line and separated with "`;`". See [Expected Behaviours](https://github.com/connorferster/handcalcs#expected-behaviours) for more context.*
---
### Numeric integration
You can use `scipy.quad` to perform numeric integration on a pre-defined function and have `handcalcs` perform a basic rendering of it.
This behaviour is triggered if you use a function with either `integrate` or `quad` in the name.
---
### "Prime" notation
Sometimes you need to write "prime" on your variables:
---
## PDF Printing in Jupyter
_Note: With `nbconvert` v6.0, templates are handled in a different manner that is incompatible with the below method. Be sure to use `nbconvert` v5.6.1 to allow template installation and swapping._
Jupyter Notebooks/Lab are able to print notebooks to PDF through two methods. Both can produce great results with handcalcs:
1. **Export to HTML**: Open the exported HTML page in your browser and print to PDF using your system's own PDF printer
* Pros: No additional software required, you can include images copy-pasted into your Jupyter notebook, and you can change the scale of the printed PDF in your brower's print window.
2. Cons: Page breaks can be less graceful on html output and you cannot otherwise customize the output further like you can with a .tex file
2. **Export to PDF (via Latex)**: Using your previously installed Latex distribution, Jupyter will first export your notebook to a .tex file and then render the file to PDF. This requires you to have a Latex distribution already installed on your system (Instructions: [windows](https://miktex.org/howto/install-miktex), [mac os](https://tug.org/mactex/mactex-download.html), [ubuntu](https://linuxconfig.org/how-to-install-latex-on-ubuntu-20-04-focal-fossa-linux)).
* Pros: Page breaks tend to work better and you have the ability to customize your output further using the generated .tex file
* Cons: Cannot easily rescale the PDF print (e.g. to ensure really long equations fit on the page) and you cannot include images copy/pasted into your Notebook. Images can be used but must be linked in with Markdown and the file must reside in the same directory as your Notebook.
PDF notebooks made with handcalcs tend to look better if the code input cells are suppressed. To make this convenient, handcalcs ships with two modified nbconvert template files that can be installed by running a function in Jupyter before exporting.
```python
handcalcs.install_templates.install_html(swap_in:str = "", swap_out:str = "full.tpl", restore:bool = False)
```
```python
handcalcs.install_templates.install_latex(swap_in:str = "", swap_out:str = "article.tplx", restore:bool = False)
```
**`swap_in`**: the name of the handcalcs template file you wish to install. When not provided, the function will print a list of available templates whose names are acceptable inputs for this argument.
**`swap_out`**: the name of the nbconvert template file you wish to replace (default file is nbconvert's default html or latex template, respectively)
**`restore`**: when set to `True`, the function will remove your previously installed template file and restore the default nbconvert template.
### Design rationale
While there are methods for manually changing the template that nbconvert uses, this has to be performed on the command line as a separate conversion step. This default template override approach is not available from within the Jupyter GUI interface.
I have found that the easiest and most reliable way to quickly change the default export behaviour is to swap out and replace the default template files. By using this approach, you can export your notebooks directly from the Jupyter GUI menu options and have your notebooks look how you wish without fussing with multiple configuration settings that may or may not take.
### Note
When handcalcs installs these templates, they make a semi-permanent change to your templates that will persist for all of your other notebooks that you print from with Jupyter, regardless of whether you are working with handcalcs or not. It does this because it is "physically" swapping out and replacing your nbconvert default template files for your local installation meaning it will persist past the end of your Jupyter session.
This change can be reverted at any time by using the `restore = True` argument. Additionally, the function will not let you repeatedly install the same template. If you wish to install another template, the function will prompt you to run the function with `restore = True` before attempting another installation.
In this way, handcalcs can fully manage these template installations for you. However, if you manually alter the file names of an installed handcalcs template in the nbconvert templates directory, there is no guarantee that your original template can be successfully restored.
### Example of use
You can perform the same below process using either `install_html` or `install_latex` functions.
```python
>>> from handcalcs.install_templates import install_html
>>> from handcalcs.install_templates import install_latex
>>> install_html() # Use with no arguments to discover available templates
Available templates:
['full_html_noinputs.tpl']
>>> install_html('full_html_noinputs.tpl') # Select the template you wish to install
/usr/Name/path/to/your/nbconvert/templates/dir/html/full.tpl
-is now-
/usr/Name/path/to/your/nbconvert/templates/dir/html/full_swapped.tpl
/usr/Name/path/to/your/handcalcs/templates/dir/html/full_html_noinputs.tpl
-is now-
/usr/Name/path/to/your/nbconvert/templates/dir/html/full.tpl
>>> install_html(restore = True) # To revert this change to your template files
/user/Name/path/to/your/nbconvert/templates/dir/html/full.tpl
-was restored from-
/user/Name/path/to/your/nbconvert/templates/dir/html/full_swapped.tpl
```
---
## Expected Behaviours
`handcalcs` is intended to render arithmetical calculations written in Python code. It is not intended to render arbitrary Python into Latex.
Given that, handcalcs only renders a small subset of Python and there is a lot that will not work, especially anything that happens over multiple lines (e.g. function definitions, `for` loops, `with` statements, etc.).
`handcalcs` works by parsing individual _lines_ of Python within a cell. It does not parse the cell as a whole. Therefore all statements to be rendered must be contained on a single line.
### Accepted datatypes
`handcalcs` will make an attempt to render all datatypes. However, it cannot yet render all "collection" based data types, e.g. `list` and `dict`. If you are using a collection to hold argument functions, e.g. `sum((23, 123, 45))`, use a `tuple` to ensure it is rendered properly. Alternatively, you can use one-dimensional `numpy` arrays (vectors) with handcalcs.
Objects are rendered into Latex by two main approaches:
1. If the object has a `_repr_latex_()` method defined, then that method is used.
a) If the object has some alternate method for rendering itself into Latex code, e.g. `.latex()` or `.to_latex()`, that will be attempted as well.
In order for the representation to be rendered properly, the object's Latex represention must use commands that are implemented with MathJax and/or Katex.
2. If the object does not have a Latex method, then `str()` is used.
If you are using object types which have str methods that render as ``, then that's what the Latex interpreter will see and attempt to render.
### Arithmetic operators
* `+` renders as `+`
* `-` renders as `-`
* `*` renders as the "dot operator" (Latex: \cdot)
* `/` always renders as a fraction
* `**` renders as superscripts
* `%` renders as the "mod function" (Latex: \mod)
Currently `//` is not rendered but you can easily use `math.floor` as a function instead.
### `for` loops and other iterations
Showing rendered iterations is not supported. The intention for use is that you perform your iterations in a cell that is not rendered and then, once the iteration has produced the desired resulting value, you render the result in a separate cell.
## Gotchas
Because `handcalcs` is designed for use within the Jupyter environment, and because Jupyter cells can be run out of order, there exists the possibility of having a big mess of beautifully rendered but **completely incorrect** calculations if you _re-use variable names throughout your notebook_.
`handcalcs` uses the notebook's user namespace dictionary to look up values for all variables in the namespace. If your calculations are re-using variable names throughout the notebook, then the dictionary entry for that name may not be what you think it is when you run cells out of the order originally intended.
You _can_ re-use variable names to good effect throughout a notebook, _IFF_ the cells are run in the correct order (easier if this is just top to bottom).
**On this note: if you are using `handcalcs` for any kind of reporting that may become a legal document (e.g. design engineering calculations), it is up to YOU to ensure that the results are what you expect them to be. `handcalcs` is free and open-source software and the author(s) are not responsible for incorrect calculations that result from its use.**
That being said, the very purpose for the way `handcalcs` renders its math is to make it very easy to confirm and verify calculations by hand.
## YouTube Tutorials
**Getting Started with handcalcs (assumes zero Python knowledge)**
[https://www.youtube.com/watch?v=ZNFhLCWqA_g](https://www.youtube.com/watch?v=ZNFhLCWqA_g)
**Engineering Calculations: handcalcs-on-Jupyter vs. Excel**
[https://www.youtube.com/watch?v=n9Uzy3Eb-XI](https://www.youtube.com/watch?v=n9Uzy3Eb-XI)
## Applications and Compatibility with OPP (Other People's Packages)
** Please see [the wiki](https://github.com/connorferster/handcalcs/wiki) for applications of `handcalcs` in education and engineering, in addition to examples of using `handcalcs` with other Python libraries such [streamlit](https://github.com/connorferster/handcalcs/wiki/Handcalcs-on--Streamlit) and [papermill](https://github.com/connorferster/handcalcs/wiki/Handcalcs-on-Papermill).
---
### About
## This is the about pages

Covert art by Joshua Hoiberg
---
### Cell Magic
# Jupyter cell magics (`%%render` and `%%tex`)
An easy way to use `handcalcs` is as _cell magic_ in Jupyter Notebook or Jupyter Lab.
First, import the module and run the cell:
```python
import handcalcs.render
```
This imports two cell magics:
* `%%render`
* `%%tex`
And one line magic:
* `%decimal_separator`
## Using `%%render`
In any cell that you want to render into Latex with `handcalcs`, just use the `%%render` cell magic at the top of your cell:
```python
%%render
```
For example:
```python
%%render
a = 2
b = 3
c = 2*a + b/3
```
Displays:
## Using `%%tex`
Instead of rendering the Latex code and displaying it, the `%%tex` cell magic prints the Latex code that can be copy/pasted into another Latex document.
For example:
```python
%%tex
a = 2
b = 3
c = 2*a + b/3
```
Displays:
## Using `%decimal_separator`
Instead of using `.` as the decimal separator, this line magic allows the decimal separator to be changed to another character. The change will persist for all subsequent cells that are rendered and only needs to be set once.
For example:
```python
%decimal_separator ,
```
If we re-run the above cell now, we will see:
## Magic line arguments
Both `%%render` and `%%tex` accept line arguments in the following form:
```python
%%render [override] [sympy] [precision]
```
1. `override`: a `str` as one of `params`, `long`, `short`, or `symbolic` combined with, optionally, `sympy`. See [override tags](../overrides.md) for more information.
2. `precision`: an `int` used to set the decimal precision or rendered values
For example:
See [override tags](../overrides.md) for more information.
---
### Decorator
# Function decorator: `@handcalc()`
_Shout-out to @eriknw for developing [innerscope](https://github.com/eriknw/innerscope) and proactively integrating it into `handcalcs`. Thank you!_
Start by importing the `@handcalc()` decorator:
```python
from handcalcs.decorator import handcalc
```
## Decorator arguments
All arguments are optional with defaults shown below:
```python
@handcalc([
override: str = "",
precision: int = 3,
left: str = "",
right: str = "",
dec_sep: str = ".",
jupyter_display: bool = False
])
```
A decorated function returns a 2-tuple with the following elements:
1. A `str` representing the function source as Latex code
2. The return value of the function
If a return value is not specified in the function, then the function will return a `dict` representing the function's local namespace.
## Argument descriptions
* `override`: a `str` being one of `"params"`, `"symbolic"`, `"short"`, or `"long"`. See [override tags](../overrides.md) for more information.
* `precision`: an `int` to alter the of decimal precision displayed
* `left`: a `str` to prepend to the returned Latex string. Intended to be used to define the start of a Latex math environment (e.g. `"$"` or `"\\["`)
* `right`: a `str` to append to the returned Latex string. Intended to be used to define the end of a Latex math environment (e.g. `"$"` or `"\\]"`)
* `dec_sep`: a `str` to replace `.` as the decimal separator for rendered values (e.g. `,`)
* `jupyter_display`: a `bool` that, when True, will attempt to render the Latex string with `display(Latex(latex_code))` from `IPython.display`. The decorated function will only return the function's original return value (i.e. only the second element of the tuple).
Will return an error if not used within a Jupyter environment.
In your decorated function, everything between `def my_calc(...)` and a return statement (if any) is now like the code in a Jupyter cell, except it's a standard Python function.
Used in this way, you can use `@handcalc()` to dynamically generate Latex code for display in Jupyter and non-Jupypter Python environments (e.g. streamlit).
---
### Installation
# Installing
You can install using pip:
`pip install handcalcs`
A conda-forge installation is coming soon.
## Dependencies
* pyparsing
* more-itertools
* innerscope
* nbconvert
While not a true "dependency", currently handcalcs installs nbconvert 5.6.1 to enable simple rendering of Jupyter Notebooks to PDF via the browser. In nbconvert 6.x, the templating system was changed and handcalcs does not yet support the new template system.
handcalcs intends to support nbconvert 6.x in the future.
---
### Overrides
# Override tags
In both the cell magic and decorator APIs, you can use "override tags" to alter the behaviour and display of your calculations. They work the same way in both APIs.
There are currently four + one acceptable override tags:
1. `params`
2. `symbolic`
3. `long`
4. `short`
Additionally, there is the `sympy` tag.
Override tags 1-4 are mutually exclusive, you can only use one tag at a time, e.g. `params` or `short` not `params short`.
However, you can use the `sympy` tag alongside one of the tags 1-4 to combine their behaviours.
Last, you can also include an integer
# Override tag behaviour
The following are demonstrations and examples of how each override tag works with a brief discussion on when you may use one or another.
## `params`
Use `params` when you want to display a quantity of variables.
Typically, handcalcs will display calculations vertically, one after another. By using `params`, the variables will be arranged in three columns (to save vertical space) and will be in the format of `var = value` without showing any formulas or numeric substitutions other than the final result.
**Example:**
## `symbolic`
Use `symbolic` when you want to display only the symbolic representation of your calculations, without any numeric substitution.
Using symbolic can be handy when you want to keep your document less cluttered. Final values can then displayed in a separate cell afterwards.#
**Example:**
## `long`
Use `long` when you have a calculation that's _too long_ to fit on one line and you want to break up the calculation over three lines.
handcalcs makes an attempt to figure out if your calculation is too long and, if so, it will apply the `long` style formatting to that line on it is own. However, you can use `long` to force this formatting style in all calculations in the cell.
**Example:**
## `short`
Use `short` when you have a calculation that is erroneously being interpreted by handcalcs as a "long" format line and you want to force it to render on one line, instead of over three lines.
handcalcs makes an attempt to figure out if your calculation is too long and, if so, it will apply the `long` style formatting to that line on it is own. However, sometimes it gets it wrong. The `short` tag is a way you can force your calculations into the default "short" format.
**Example:**
## `sympy`
Use `sympy` if you want to combine a sympy symbolic workflow with a handcalcs numeric substitution and rendering. The `sympy` tag can be combined with one of the other override tags to control the rendering in the cell.
There is a bit of nuanced approach to have a smooth workflow. See the [Using Sympy](sympy.md) section for more information.
**Example:**
---
### README

Covert art by Joshua Hoiberg
handcalcs:
Python calculations in Jupyter,
as though you wrote them by hand.
`handcalcs` is a library to render Python calculation code automatically in Latex, but in a manner that mimics how one might format their calculation if it were written with a pencil: write the symbolic formula, **followed by numeric substitutions**, and then the result.
Because `handcalcs` shows the numeric substitution, the calculations become significantly easier to check and verify by hand.
> ### Engineers who use handcalcs
> Did you know that you can _link_ your handcalc Jupyter notebooks together so that the result of one notebook can be available as an input for the next?
>
> [Opt-in here](https://www.structuralpython.com/handcalcs-the-chaining-technique) to see how you can use the [Chaining Technique](https://www.structuralpython.com/handcalcs-the-chaining-technique) to create entire engineering automations using your handcalcs notebooks.
## Contents
* [Basic Demo](https://github.com/connorferster/handcalcs#basic-demo)
* [Installation](https://github.com/connorferster/handcalcs#installing)
* [Basic Usage](https://github.com/connorferster/handcalcs#basic-usage-1-as-a-jupyter-cell-magic-render)
* [Enhanced Usage](https://github.com/connorferster/handcalcs#basic-usage-2-as-a-decorator-on-your-functions-handcalc)
* [Features](https://github.com/connorferster/handcalcs#features)
* [PDF Printing in Jupyter](https://github.com/connorferster/handcalcs#pdf-printing-in-jupyter)
* [Expected Behaviours](https://github.com/connorferster/handcalcs#expected-behaviours)
* [Gotchas and Disclaimer](https://github.com/connorferster/handcalcs#gotchas)
* [YouTube Tutorials](https://github.com/connorferster/handcalcs#youtube-tutorials)
* [Applications and Compatibility with Other Libraries (wiki)](https://github.com/connorferster/handcalcs/wiki)
## Basic Demo
## Installing
You can install using pip:
`pip install handcalcs`
To install the optional nbconvert "no input" exporters, use:
`pip install "handcalcs[exporters]"`
**NEW**
As of v1.9.0, handcalcs no longer installs the "no input" nbconvert exporters. This was done to lighten the installation load of handcalcs and to ensure the package has appropriate scope. The nbconvert exporters are now "out of scope" and are separately maintained at [https://github.com/connorferster/nb-hideinputs](nb-hideinputs).
## Basic Usage 1: As a Jupyter cell magic (`%%render`)
`handcalcs` is intended to be used with either Jupyter Notebook or Jupyter Lab as a _cell magic_.
First, import the module and run the cell:
```python
import handcalcs.render
```
> Note: This will import both `%%tex` and `%%render` magics in the Jupyter Notebook.
Then, in any cell that you want to render with `handcalcs`, just use the render cell magic at the top of your cell:
```python
%%render
```
For example:
```python
%%render
a = 2
b = 3
c = 2*a + b/3
```
**That is it!**
Once rendered, you can then export your notebook as a PDF, provided you have a Latex environment installed on your system. If you are new to working with Latex and would like to install it on your system so you can use this functionality, please see the section [Installing Tex](https://github.com/connorferster/handcalcs/wiki), in the wiki.
You can also use the `%%tex` command to convert any Python code snippet into a valid LaTex. For Example:
First import `handcalcs`. We are also importing a few properties/functions from __math__ package for the
example below.
```python
import handcalcs.render
from math import sqrt, pi
```
Now, you can also use the `%%tex` magic!
```python
%%tex
a = 2 / 3 * sqrt(pi)
```
This will produce a LaTeX output as follows.
```tex
\[
\begin{aligned}
a &= \frac{ 2 }{ 3 } \cdot \sqrt{ \pi } = \frac{ 2 }{ 3 } \cdot \sqrt{ 3.142 } &= 1.182
\end{aligned}
\]
```
## Basic Usage 2: As a decorator on your functions, `@handcalc()`
_Shout-out to @eriknw for developing [innerscope](https://github.com/eriknw/innerscope) and proactively integrating it into `handcalcs`. Thank you!_
Start by importing the `@handcalc()` decorator:
```python
from handcalcs.decorator import handcalc
```
```python
@handcalc([override: str = "", precision: int = 3, left: str = "", right: str = "", jupyter_display: bool = False])
```
Returns a tuple consisting of `(latex_code: str, locals: dict)`, where `locals` is a dictionary of all variables in the scope of the function namespace.
* `override` is a str representing one of the acceptable override tags (see below)
* `precision` is an int to alter the of decimal precision displayed
* `left` and `right` are strings that can precede and follow the encoded Latex string, such as `\\[` and `\\]` or `$` and `$`
* `jupyter_display`, when True, will return only the `locals` dictionary and instead will display the encoded Latex string rendering with `display(Latex(latex_code))` from `IPython.display`. Will return an error if not used within
* `record`, when True, will activate the `HandcalcsCallRecorder` to allow the function to "recall" previous outputs (see below) **New in v1.8.0**
In your decorated function, everything between `def my_calc(...)` and a return statement (if any) is now like the code in a Jupyter cell, except it's a standard Python function.
Used in this way, you can use `@handcalc()` to dynamically generate Latex code for display in Jupyter and non-Jupypter Python environments (e.g. streamlit).
### HandcalcsCallRecorder (New in v1.8.0)
The `HandcalcsCallRecorder` is a new kind of function wrapper that is available from the `@handcalc` decorator. To activate it, select `record=True` as one of the arguments in the decorator function.
The intended use case is during iterations. In engineering, it is common to compute a whole bunch of values in a table or DataFrame. The table itself contains the results of the computations but the table does not necessarily reveal the computation steps. The `HandcalcsCallRecorder` allows you to display the calculation for one of the calculation iterations that have been processed by your decorated function, as shown in the example below:
---
## Global config options (New in v1.6.0)
This is a major new release for handcalcs and introduces the global configuration feature. This allows users to have control over several options of how handcalcs works. The configuration options, with their default values, are as follow:
* `decimal_separator = "."`
* `latex_block_start = "\\["`
* `latex_block_end = "\\]"`
* `math_environment_start = "aligned"`
* `math_environment_end = "aligned"`
* `line_break = "\\\\[10pt]"`
* `use_scientific_notation = False`
* `display_precision = 3`
* `underscore_subscripts = True`
* `greek_exclusions = []`
* `param_columns = 3`
* `preferred_string_formatter = "L"`
* `custom_symbols = {}`
### Config API
```python
import handcalcs.render
handcalcs.set_option("display_precision", 4)
handcalcs.set_option("param_columns", 5)
handcalcs.set_option("line_break", "\\\\[20pt]")
handcalcs.set_option("greek_exclusions", ["psi"]) # etc...
```
These changes now affect all cells rendered in the current session. If you want to permanently update the `config.json` file with these changes (so handcalcs will always load up with these options), you can then call `handcalcs.save_config()` and the changes will be saved (and thus immediately available in the next session).
#### Custom Symbols (New in v1.7.0)
You can now add _custom symbols_ to your global config to handle ALL of the cases which handcalcs does not account for.
e.g.
```python
handcalcs.set_option("custom_symbols", {"V_dot": "\\dot{V}", "N_star": "N^{*}"})
```
This can also be used to swap substrings or individual characters within the variable name. For example, the following:
```python
handcalcs.set_option("custom_symbols", {"star": "^*", "C": ","})
```
Would render `Mstar_1C2` to $M^*_{1,2}$
This now allow this kind of rendering:
The docstring in the `handcalcs.set_option()` function demonstrates which options are available and what values they take.
---
#### Custom Brackets (New in v1.?.?)
Functioning similiar to the Custom Symbols, this allows a specified character or string of characters to be swapped for brackets. For example:
```python
handcalcs.set_option("custom_brackets", {
"parenthesis": "ˉ", # macron (ˉ) → parentheses ( )
"square_brackets": "ˍ", # low line (ˍ) → square brackets [ ]
"angle_brackets": "ˆ", # modifier letter circumflex accent (ˆ) → angle brackets ⟨ ⟩
"curly_brackets": "ǂ", # double pipe (ǂ) → curly brackets { }
"pipes": "ǀ", # vertical bar (ǀ) → pipes | |
"double_pipes": "ǁ", # double vertical bar (ǁ) → double pipes ‖ ‖
})
```
Will render the following:
`myvarˉ1ˉ` -> $myvar(1)$
`myvarˍ2ˍ` -> $myvar[2]$
`myvarˆ3ˆ` -> $myvar\langle3\rangle$
`myvarǂ4ǂ` -> $myvar\lbrace4\rbrace$
`myvarǀ5ǀ` -> $myvar|5|$
`myvarǁ6ǁ` -> $myvar\|6\|$
These can be nested as below:
`myvarˉˆ7ˆˉ_ǁ8ǁ` -> $myvar(\langle7\rangle)_{\|8\|}$
Note that the example above utilizes a range of rarely used characters for the mapping, which has the drawback of making the variable names not readily typed on the keyboard. The user could alternatively specify `"square_brackets": "SB"` for mapping to square brackets, for example, such that `myvarSB9SB` would map to $myvar[9]$, but this then makes the variable names less legible.
Note that as valid LaTeX strings require paired brackets, there will always be an equal number of opening and closing brackets, so the function works by sequentially replacing opening and closing brackets. This means you can't create `myvar(1(2))` as this would always map to `myvar(1)(2)`
## Override tags
`handcalcs` makes certain assumptions about how you would like your calculation formatted and does not allow for a great deal of customization in this regard. However, there are currently **four** customizations you can make using `# override tags` as an argument after the `%%render` cell magic. Additionally, you can also specify the number of decimals of precision to display. You can only use __one__ override tag per cell **but** you can combine an override tag with a precision setting.
**Override tags can be used with both the Jupyter cell magic and the function decorator**. To use a override tag with the decorator, you just supply it as an argument, e.g. `@handcalc(override='params', precision=2)`
I will compare a basic rendering of the quadratic formula (below) with the change achieved with each override tag.
### Basic rendering:
___
### `params`:
`handcalcs` renders lines of code vertically, one after the other. However, when you are assigning variables, or displaying resulting variables, you may not want to waste all of that vertical space.
Using the `params` override tag, your list of parameters will instead render in three columns, thereby saving vertical space. Additionally, onsly the result will be shown, no calculations.
___
### Adjust precision:
The number of decimal places in a cell can be adjusted by providing an integer after `%%render` to indicate the decimal precision to be displayed. Can be combined with another override tag.
___
### `long` and `short`:
To save vertical space, `handcalcs` _attempts_ to figure out how long your calculation is and, if it is short enough, renders it out fully on one line.
If `handcalcs`'s internal test deems the calculation as being too long to fit onto one line, it breaks it out into multiple lines.
Use the `# long` or `# short` override tags to override the length check and display the calculation in the "Long" format or the "Short" format for all calculations in the cell. e.g.
#### `long: Spans multiple lines as though you had a long equation`
#### `short: Forced to a single line as though you had a short equation`
```python
# Format for "short" calculations (can fit on one line):
c = 2*a + b/3 = 2*(2) + (3)/3 = 5
# Format for "long" calculations (requires multi-line format)
c = 2*a + b/3
= 2*(2) + (3)/3
= 5
```
___
### `symbolic`
The primary purpose of `handcalcs` is to render the full calculation with the numeric substitution. This allows for easy traceability and verification of the calculation.
However, there may be instances when it is preferred to simply display calculations symbolically. For example, you can use the `symbolic` tag to use `handcalcs` as a fast way to render Latex equations symbolically.
Alternatively, you may prefer to render out all of input parameters in one cell, your formulae symbolically in the following cell, and then all the final values in the last cell, skipping the numeric substitution process entirely.
Keep in mind that even if you use the `symbolic` tag with your calculations, you still need to declare those variables (by assigning values to them) ahead of time in order for your calculation to be valid Python.
---
### `sympy`
This is intended to be used only with `sympy` loaded. Sympy allows for symbolic manipulation, solving, and integration of algebraic expressions. Sympy will render its own objects in Latex without handcalcs.
If you are manipulating a sympy expression or sympy equation for the purpose of calculation, you can use `handcalcs` to handle the substitution and calculation of your resulting expression.
_Note: Re-assigning your symbolic variables to numbers will clobber them as sympy variables. However, you are done with these now, right? So, it's no problem. If you need to work symbolically again, just re-run your notebook cells from the top._
---
## Units Packages Compatibility
`handcalcs` was designed to be used with the units package, [forallpeople](https://github.com/connorferster/forallpeople) (and [forallpeople](https://github.com/connorferster/forallpeople) was designed to be compatible with `handcalcs`). However, it has been recently reported that [pint](https://pint.readthedocs.org) can work to good effect, also.
**For potential compatibility with other units packages, please see [the wiki.](https://github.com/connorferster/handcalcs/wiki)**
---
## Features
### Quickly display the values of many variables
No more `print` statements needed. Just plop your variables onto a line and they will all be displayed.
### Get Just the Latex Code, without the render
If you just want to generate the rendered Latex code directly to use in your own Latex files, you can use the `%%tex` cell magic instead:
```python
%%tex
a = 2
b = 3
c = 2*a + b/3
```
Then you can just copy and paste the result into your own LaTeX document.
---
### Subscripts (and sub-subscripts, etc.)
Subscripts in variable names are automatically created when `_` is used in the variable name. Sub-subscripts are nested for each separate `_` used in series.
----
### Greek symbols
Any variable name that contains a Greek letter (e.g. "pi", "upsilon", "eta", etc.) as a string or substring will be replaced by the appropriate Latex code to represent that Greek letter.
| symbol | substitution | symbol | substitution |
|-------------------------|--------------|--------|--------------|
| `alpha` | α | `Alpha` | Α |
| `beta` | β | `Beta` | Β |
| `gamma` | γ | `Gamma` | Γ |
| `delta` | δ | `Delta` | Δ |
| `epsilon`, `varepsilon` | ϵ, ε | `Epsilon` | Ε |
| `zeta` | ζ | `Zeta` | Ζ |
| `eta` | η | `Eta` | Η |
| `theta`, `vartheta` | θ, ϑ | `Theta` | Θ |
| `iota` | ι | `Iota` | Ι |
| `kappa` | κ | `Kappa` | Κ |
| `lamb` | λ | `Lamb` | Λ |
| `mu` | μ | `Mu` | Μ |
| `nu` | ν | `Nu` | N |
| `xi` | ξ | `Xi` | Ξ |
| `omicron` | ο | `Omicron` | Ο |
| `pi`, `varpi` | π, ϖ | `Pi` | Π |
| `rho`, `varrho` | ρ, ϱ | `Rho` | Ρ |
| `sigma`, `varsigma` | σ, ς | `Sigma` | Σ |
| `tau` | τ | `Tau` | Τ |
| `upsilon` | υ | `Upsilon` | Υ |
| `phi`, `varphi` | φ, ϕ | `Phi` | Φ |
| `chi` | χ | `Chi` | Χ |
| `psi` | ψ | `Psi` | Ψ |
| `omega` | ω | `Omega` | Ω |
* Using lower case letters as your variable name will make a lower case Greek letter.
* Using a Capitalized Name for your variable will render it as an upper case Greek letter.
---
### Functions, built-in or custom
If you are using Python functions in your calculation, eg. `min()` or `tan()`, they will be replaced with Latex code to represent that function in Latex.
If you are creating your own functions, then they will be rendered in Latex as a custom operator.
If you are using a function with the name `sqrt` (whether your own custom implementation or from `math.sqrt`), then it will be rendered as the radical sign.
---
### Rendered in-line Comments
Any comments placed after a line of calculation will be rendered as an inline comment in the Latex.
This makes it convenient to make notes along side your calculations to briefly explain where you may have acquired or derived a particular value.
---
### Skip the substitution
Any calculation entirely wrapped in parentheses, `()`, will be rendered as just `param = result`, without the substitution.
This can be convient when you want to calculate a parameter on the fly and not have it be the focus of the calculation.
---
### Conditional statements
Many calculations in the "real world" are dependent on context.
`handcalcs` allows for the inclusion of some simple conditional statements into its code in a way that makes it easier to understand the context of the calculation.
*Note: Multiple "lines" of calculations can be used after the conditional expression provided that they are all on the same line and separated with "`;`". See [Expected Behaviours](https://github.com/connorferster/handcalcs#expected-behaviours) for more context.*
---
### Numeric integration
You can use `scipy.quad` to perform numeric integration on a pre-defined function and have `handcalcs` perform a basic rendering of it.
This behaviour is triggered if you use a function with either `integrate` or `quad` in the name.
---
### "Prime" notation
Sometimes you need to write "prime" on your variables:
---
## PDF Printing in Jupyter
_Note:_ With `nbconvert` v6.0, installing templates (as shown in older YouTube videos) is no longer required. An `Exporter` for Jupyter Notebook/Lab is
installed when `handcalcs` is installed which gives you access to two new File -> Save and Export as options:
1. Export `HTML_NoInput`
2. Export `LaTeX_NoInput`
3. Export `PDF_NoInput`
These options suppress all input cells so you only see rendered outputs in your Jupyter notebooks.
By using these three options, you can create PDF exports either by HTML (and then PDF print from your browser) or via LaTex (whether directly or through
your own LaTeX environment).
---
## Expected Behaviours
`handcalcs` is intended to render arithmetical calculations written in Python code. It is not intended to render arbitrary Python into Latex.
Given that, handcalcs only renders a small subset of Python and there is a lot that will not work, especially anything that happens over multiple lines (e.g. function definitions, `for` loops, `with` statements, etc.).
`handcalcs` works by parsing individual _lines_ of Python within a cell. It does not parse the cell as a whole. Therefore all statements to be rendered must be contained on a single line.
### Accepted datatypes
`handcalcs` will make an attempt to render all datatypes. However, it cannot yet render all "collection" based data types, e.g. `list` and `dict`. If you are using a collection to hold argument functions, e.g. `sum((23, 123, 45))`, use a `tuple` to ensure it is rendered properly. Alternatively, you can use one-dimensional `numpy` arrays (vectors) with handcalcs.
Objects are rendered into Latex by two main approaches:
1. If the object has a `_repr_latex_()` method defined, then that method is used.
a) If the object has some alternate method for rendering itself into Latex code, e.g. `.latex()` or `.to_latex()`, that will be attempted as well.
In order for the representation to be rendered properly, the object's Latex represention must use commands that are implemented with MathJax and/or Katex.
2. If the object does not have a Latex method, then `str()` is used.
If you are using object types which have str methods that render as ``, then that's what the Latex interpreter will see and attempt to render.
### Arithmetic operators
* `+` renders as `+`
* `-` renders as `-`
* `*` renders as the "dot operator" (Latex: \cdot)
* `/` always renders as a fraction
* `**` renders as superscripts
* `%` renders as the "mod function" (Latex: \mod)
Currently `//` is not rendered but you can easily use `math.floor` as a function instead (as `floor`).
### `for` loops and other iterations
Currently, showing rendered iterations is not supported. The intention use is that you perform your iterations in a cell that is not rendered and then, once the iteration has produced the desired resulting value, you render the result in a separate cell.
## Gotchas
Because `handcalcs` is designed for use within the Jupyter environment, and because Jupyter cells can be run out of order, there exists the possibility of having a big mess of beautifully rendered but **completely incorrect** calculations if you _re-use variable names throughout your notebook_.
`handcalcs` uses the notebook's user namespace dictionary to look up values for all variables in the namespace. If your calculations are re-using variable names throughout the notebook, then the dictionary entry for that name may not be what you think it is when you run cells out of the order originally intended.
You _can_ re-use variable names to good effect throughout a notebook, _IFF_ the cells are run in the correct order (easier if this is just top to bottom).
**On this note: if you are using `handcalcs` for any kind of reporting that may become a legal document (e.g. design engineering calculations), it is up to YOU to ensure that the results are what you expect them to be. `handcalcs` is free and open-source software and the author(s) are not responsible for incorrect calculations that result from its use.**
That being said, the very purpose for the way `handcalcs` renders its math is to make it very easy to confirm and verify calculations by hand.
## YouTube Tutorials
**Getting Started with handcalcs (assumes zero Python knowledge)**
[https://www.youtube.com/watch?v=ZNFhLCWqA_g](https://www.youtube.com/watch?v=ZNFhLCWqA_g)
**Engineering Calculations: handcalcs-on-Jupyter vs. Excel**
[https://www.youtube.com/watch?v=n9Uzy3Eb-XI](https://www.youtube.com/watch?v=n9Uzy3Eb-XI)
## Applications and Compatibility with OPP (Other People's Packages)
** Please see [the wiki](https://github.com/connorferster/handcalcs/wiki) for applications of `handcalcs` in education and engineering, in addition to examples of using `handcalcs` with other Python libraries such [streamlit](https://github.com/connorferster/handcalcs/wiki/Handcalcs-on--Streamlit) and [papermill](https://github.com/connorferster/handcalcs/wiki/Handcalcs-on-Papermill).
---
### Mkdocs.Yml
site_name: handcalcs documentation
nav:
- Home: index.md
- Installation: installation.md
- API:
- Cell Magic: cell_magic.md
- Function Decorator: decorator.md
- Features: features.md
- Override tags: overrides.md
- Using Sympy: sympy.md
theme: readthedocs
---