Symbols and notation#
Recipes for making variable names, functions and operators look the way they do in your code of practice or textbook. The background is in Naming variables and Symbols and functions.
Eurocode-style subscripts#
Asked in #101.
Each further underscore adds a comma-separated subscript, and a subscript of more than one letter is set upright:
N_pl_Rd = 1250 # kN
M_c_Rd = 410 # kN m
sigma_x_Ed = 185 # MPa
$$\begin{aligned} N_{\mathrm{pl,Rd}} &= 1250 \quad\text{(kN)} \\ M_{c,\mathrm{Rd}} &= 410 \quad\text{(kN m)} \\ \sigma_{x,\mathrm{Ed}} &= 185 \quad\text{(MPa)} \end{aligned}$$
For v1-style nested subscripts (xab), use # hc: subscripts = "nested".
Greek letters joined to text#
Asked in #117.
A Greek name followed by an uppercase letter or a digit is split off, so DeltaH and
gammaM0 read as written on paper. Unicode letters work too:
DeltaH = 4.2 # kJ
gamma_M0 = 1.0
gammaM1 = 1.1
ΔT = 35 # K
$$\begin{aligned} \Delta H &= 4.2 \quad\text{(kJ)} \\ \gamma_{\mathrm{M0}} &= 1 \\ \gamma \mathrm{M1} &= 1.1 \\ \Delta T &= 35 \quad\text{(K)} \end{aligned}$$
lamb or lambda_ gives λ (lambda is a Python keyword). To turn the prefix split
off, use # hc: greek_prefixes = False.
Accents, primes and stars#
Asked in #132.
V_dot = 2.5 # m³/s
x_bar = 12.0
f_prime_c = 30 # MPa
M_star = 85 # kN m
$$\begin{aligned} \dot{V} &= 2.5 \quad\text{(m³/s)} \\ \bar{x} &= 12 \\ f'_{c} &= 30 \quad\text{(MPa)} \\ M^{*} &= 85 \quad\text{(kN m)} \end{aligned}$$
Any symbol for any name#
When a Python name can’t spell the symbol, map it to a display spec with the symbols
field. The spec syntax is the same in every renderer:
# hc: symbols = {"N_plRd": "N_{pl,Rd}", "V_flow": "dot(V)", "dH": "ΔH^{*}"}
N_plRd = 1250
V_flow = 2.5
dH = 4.2
$$\begin{aligned} N_{\mathrm{pl,Rd}} &= 1250 \\ \dot{V} &= 2.5 \\ \Delta H^{*} &= 4.2 \end{aligned}$$
Set it for a session with handcalcs.set_option("symbols", {...}).
Raw LaTeX for a symbol#
For markup the spec syntax can’t express (\tilde{u}, \mathcal{F}), register a
name:pre rule. See
Custom symbols with a rule.
Keep a name as text#
Asked in #90.
Greek names become letters. To keep some names as upright text, replace their
identifier in a name:pre rule:
class UprightMarkdownRenderer(MarkdownRenderer):
"""Names that must not become Greek letters or subscripts."""
UPRIGHT = {"psi", "ksi", "load_case_1"}
@UprightMarkdownRenderer.register("name:pre")
def keep_upright(renderer, node, base_context):
if node.identifier in renderer.UPRIGHT:
text = node.identifier.replace("_", "\\_")
node.identifier = f"\\mathrm{{{text}}}"
return node
psi = 14.7
A = 3.5
F = psi * A
beta = 0.8
$$\begin{aligned} \mathrm{psi} &= 14.7 \\ A &= 3.5 \\ F &= \mathrm{psi} \cdot A = 14.7 \cdot 3.5 = 51.45 \\ \beta &= 0.8 \end{aligned}$$
No subscripts at all#
Asked in #97.
___ (three underscores) is a literal underscore. A name:pre rule can apply that to
every name:
@NoSubscriptMarkdownRenderer.register("name:pre")
def literal_underscores(renderer, node, base_context):
# '___' is the naming convention for a literal underscore.
node.identifier = node.identifier.replace("_", "___")
return node
load_case_1 = 3
M_max = load_case_1 * 2
$$\begin{aligned} \mathrm{load\_case\_1} &= 3 \\ \mathrm{M\_max} &= \mathrm{load\_case\_1} \cdot 2 = 3 \cdot 2 = 6 \end{aligned}$$
Sigma for sum, and your own function names#
The LaTeX and Markdown renderers look function names up in MATH_FUNCS. Add entries in
a subclass. A function that isn’t in the table is shown by its name:
class SigmaMarkdownRenderer(MarkdownRenderer):
"""sum(...) as a capital sigma, and a project function shown by its textbook name."""
MATH_FUNCS = MarkdownRenderer.MATH_FUNCS | {
"sum": "\\sum",
"interp_table": "\\operatorname{interp}",
}
loads = [1.5, 2.0, 3.5]
P = sum(loads)
k = interp_table(2.5)
$$\begin{aligned} \mathrm{loads} &= [1.5, 2, 3.5] \\ P &= \sum\left(\mathrm{loads}\right) = \sum\left([1.5, 2, 3.5]\right) = 7 \\ k &= \operatorname{interp}\left(2.5\right) = 0.8 \end{aligned}$$
The same table gives ln for log: MATH_FUNCS | {"log": "\\ln"}.
Times sign for multiplication#
Asked in #163.
class TimesMarkdownRenderer(MarkdownRenderer):
"""× instead of · for multiplication."""
OPERATOR_SYMBOLS = MarkdownRenderer.OPERATOR_SYMBOLS | {"mult_op": "\\times"}
a = 2
b = 3
c = a * b
$$\begin{aligned} a &= 2 \\ b &= 3 \\ c &= a \times b = 2 \times 3 = 6 \end{aligned}$$
Each operator has a key: add_op, sub_op, mult_op, div_op, pow_op, the
comparisons and more. See Operator symbols.
Cube roots, factorials and infinity#
cbrt is typeset as a cube root, factorial as n!, and an infinite value as ∞:
V = 27.0
a = cbrt(V)
n = 4
ways = factorial(n)
more = factorial(n + 1)
limit = float('inf')
$$\begin{aligned} V &= 27 \\ a &= \sqrt[3]{V} = \sqrt[3]{27} = 3 \\ n &= 4 \\ \mathrm{ways} &= n! = 4! = 24 \\ \mathrm{more} &= \left(n + 1\right)! = \left(4 + 1\right)! = 120 \\ \mathrm{limit} &= \infty \end{aligned}$$
math.cbrt needs Python 3.11 or later. np.cbrt works too.
Functions from math and numpy#
Common functions are typeset as operators and radicals. min and max show their
arguments:
a = sqrt(16)
b = sin(pi / 6) + cos(0)
c = log(10)
d = max(a, b, c)
$$\begin{aligned} a &= \sqrt{16} = 4 \\ b &= \sin\left(\frac{\pi}{6}\right) + \cos\left(0\right) = \sin\left(\frac{3.1416}{6}\right) + \cos\left(0\right) = 1.5 \\ c &= \operatorname{log}\left(10\right) = 2.3026 \\ d &= \operatorname{max}\left(a, b, c\right) = \operatorname{max}\left(4, 1.5, 2.3026\right) = 4 \end{aligned}$$
np.sqrt, np.sin and the other numpy functions are typeset the same way.
:= (or anything else) between the steps#
handcalcs.set_option("assign", ":=") # ASCII and HTML renderers
The LaTeX and Markdown renderers also read assign, but it ends up inside math, so give
it LaTeX: handcalcs.set_option("assign", "\\coloneqq") (needs the mathtools
package in LaTeX documents).
A narrower indent in ASCII output#
handcalcs.set_option("indent", " ")
This works for the ASCII and base renderers; see the caution for LaTeX and Markdown.
Next: Units.