Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

CivilKit Calcs is an engineering calculation sheet that runs in your browser. You write a calculation as readable text, with quantities, units, formulas and notes, and the page works it out and shows a formatted report. You can plot the results, export the report to Word, Excel or PDF, and keep working with no network connection.

Everything is calculated on your own computer. The engine is compiled to WebAssembly and runs inside the page, so a calculation is never sent to a server.

Try it. Open CivilKit Calcs in a new tab and start typing, or begin from a worked example in Calculators and guides: a beam, a retaining wall, a pad footing, a pipe or a pump, each of which opens as a form. The product page gives the short overview.

What you get

  • Real units. 6 m, 12 kN/m, 300 MPa. The engine multiplies, divides and converts them, and it refuses to add a length to a time. A moment comes out in kilonewton metres because the units said so, not because you typed a label.
  • Two ways to write. The sheet format is Markdown prose with name: value lines. The Calcpad worksheet language (.cpd) is the full language of CalcpadCE, with macros, input forms and every directive. Both run on the same engine, and a sheet can show you the Calcpad it becomes.
  • Vectors, matrices and a large function library. Linear solves, eigenvalues, interpolation, numerical integration, root finding and more.
  • Plots. A one-line plot command, the Calcpad $Plot and $Map commands, and a Python block that draws with a matplotlib-style or Plotly-style interface, including 3D charts.
  • Python blocks. Small Python programs inside a sheet, run in the page, with results handed back to the sheet as ordinary quantities.
  • Templates with inputs. Put a ? in front of a value (L: ? 6 m) and it becomes a box, a drop-down, radio buttons or a checkbox in a fill-in form. A template is one file.
  • Symbolic maths. Rearrange a formula, differentiate, integrate or solve exactly.
  • A worksheet importer. Bring in worksheets from another calculation tool.
  • Export. Word with real equations, Excel with native charts, and PDF through the print dialog.
  • Free and open source. The source is on GitHub under the MIT licence.

Where to start

If you have never used it, open Your first sheet and follow it through once. It takes about five minutes. After that, read The sheet format, which describes everything you can write on a sheet line. The later chapters are independent: read the ones you need.

Each chapter that matches a short how-to video carries a line starting with “Video:”. The videos are recorded from the scripts in the book/videos folder of the source.

The videos

Each video has an Enlarge button in its top right corner that opens it large over the page; Esc closes it again.

VideoLengthChapter
1. Your first calculation in five minutes85 secondsYour first sheet in five minutes
2. Units and results85 secondsUnits
3. Plots in the sheet format80 secondsPlots
4. Plots from Python (Plotly style and matplotlib style)90 secondsPython blocks
5. Templates with inputs85 secondsTemplates with inputs
6. Import an existing worksheet90 secondsImporting worksheets
7. Symbolic maths for a beam deflection90 secondsSymbolic maths
8. Export a report to Word, Excel and PDF85 secondsExporting

The lengths are the planned ones in the storyboards.

Credit

CivilKit Calcs is built on CalcpadCE, the continuation of Calcpad by Nedelcho Ganchovski (Proektsoft) and contributors. The worksheet language, the editor support and the sample worksheets all come from that work. See Credits and licences.

A note on the examples

Every sheet and cpd example in this guide was run through the real engine when the guide was built (book/check-examples.sh). The results shown beside them are what the engine printed, with the default setting of two decimals. The seven template sheets quoted in Templates with inputs are checked to be identical to the samples the app ships. The Python examples and the input forms need the browser: they are run in the built app (book/check-python.mjs), which also counts the controls each form draws.

Your first sheet in five minutes

Video: Your first calculation in 5 minutes

This walk-through builds a bending check for a simply supported beam. You will type a few lines, see units work, add a pass or fail message and change a number.

1. Open a new sheet

Open https://civilkit.io/calcs/ . The first tab is a short welcome sheet. To start your own, use File > New sheet, or the New button at the top left. A sheet opens with a few lines of example text. Select all of it and delete it. The editor is on the left and the result is on the right.

A sheet is a plain text file. Its first line is <!--sheet-->, which the editor adds for you.

2. Type the inputs

Type these lines. Each one is a quantity line: a name, a colon, a value with a unit, and after a bar | a note.

# Beam check

A simply supported beam under a uniform load.

L: 6 m | span
w: 12 kN/m | design load

The result pane shows the heading, the sentence, and two lines like these:

L = 6 m    span
w = 12 kN/m    design load

The result updates as you type. If it does not, press Calculate on the Calculation tab, or Ctrl+Alt+X.

3. Calculate with units

Add a line below the inputs:

L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment

The result shows the formula, the numbers put in, and the answer:

M⋆ = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m    maximum bending moment

Three things happened:

  • Mstar was written as M with a subscript “star”. A name that ends in star after a capital letter becomes a subscript. Greek names work the same way: phi is φ, sigma_c is σ with a subscript c.
  • ^ is a power. L^2 is L squared.
  • -> kN*m asked for the answer in kilonewton metres. Without it the engine picks a unit itself, which here is also kN·m. Write -> when you want to be sure which unit you get, or a different one (-> N*mm).

4. Add a capacity and a check

Now add the section capacity and a utilisation ratio. This is the complete sheet:

# Beam check

A simply supported beam under a uniform load. The moment **comes out in kN·m** because the
engine tracks the units.

L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment
fy: 300 MPa | yield stress
Ze: 1230000 mm³ | section modulus
Ms: fy * Ze -> kN*m | moment capacity
utilisation: Mstar / (0.9 * Ms)
if utilisation <= 1: "OK" else: "Fails"

The result ends with:

Ms = fy·Ze = 300 MPa · 1230000 mm³ = 369 kN·m    moment capacity
utilisation = M⋆ / (0.9·Ms) = 54 kN·m / (0.9 · 369 kN·m) = 0.163
OK

Look at the Ms line. A stress in megapascals times a volume in cubic millimetres came out as a moment in kilonewton metres. You did not convert anything. The utilisation line divides a moment by a moment, so the units cancel and it is a plain number.

The last line is a one-line condition. It prints the text OK when the ratio is at most 1 and Fails otherwise.

5. Change a number

Change w: 12 kN/m to w: 80 kN/m. The moment becomes 360 kN·m, the ratio 1.08, and the last line reads Fails. Everything after the changed line recalculates as you type.

6. See what the sheet compiles to

A sheet is turned into the Calcpad worksheet language, and the engine runs that. To see the translation, open the Resources tab and choose Show compiled. For the sheet above it is:

'<h1>Beam check</h1>

#markdown
A simply supported beam under a uniform load. The moment **comes out in kN·m** because the
engine tracks the units.
#end markdown

L = 6 m
w = 12 kN/m
M_star = w * L^2 / 8|kN*m
fy = 300 MPa
Ze = 1230000 mm^3
Ms = fy * Ze|kN*m
utilisation = M_star / (0.9 * Ms)
#if utilisation ≤ 1
'OK
#else
'Fails
#end if

(In the compiled view each note is kept as a comment at the end of its line.) You can read it as a short lesson in the Calcpad language: |kN*m is the conversion, #if … #end if is the condition. The language is covered in The Calcpad language. Convert to Calcpad, next to Show compiled, replaces the sheet with that text, for when you want to leave the sheet format for good.

7. Save it

Press Ctrl+S (Cmd+S on a Mac). In browsers that can write files, you choose a place and the sheet is saved as a .sheet file. In other browsers the file downloads. See Saving, opening and working offline.

Where next

Related calculators: Simply supported beam, Cantilever beam. More pages are in Calculators and guides.

The screen

The window has five parts.

+-------------------------------------------------------------+
| (suite bar, wide browser windows only)                      |
| File  New Open Save Undo Redo                               |
| Math | Input/Output | Functions | ... | Resources           |   ribbon
|  [groups of buttons for the selected tab]                   |
+----------------------------+-----------------------+--------+
| tab: Beam check            |  Results              |Sidebar |
|                            |  Preview Unwrapped    | Insert |
|  editor                    |  Input Report         |  ...   |
|                            |                       |        |
+----------------------------+-----------------------+--------+

The ribbon

A quick-access strip at the top holds New, Open, Save, Undo and Redo. Under it are ten tabs. In a sheet the buttons insert the sheet form of each item, and a button that has no sheet form inserts Calcpad text as >> lines and carries a small >> mark.

TabWhat is on it
MathRegions (math line, text, heading, image, plot, table), operators, Greek letters and symbols, programming (conditions, loops, macros), constants, numerical methods, units, clipboard.
Input/OutputInput fields: entry, slider, dropdown, radio, checkbox (the ? form in a sheet, #UI in a worksheet), data grid; reading and writing files; breakpoints; the Input form view.
FunctionsTrigonometric, hyperbolic, logarithmic, rounding, statistical, logical, complex and other functions; define a function; the Symbolic dialog.
Matrices/TablesVector and matrix literals, vector and matrix functions, determinant, inverse and transpose, tables.
CalculationCalculate, auto-calculate, the four result views, settings, and the Variables and Errors lists.
Plots & DiagramsFunction, parametric, multiple and colour-map plots; plot settings; the Figures group: the Diagrams menu of starter diagrams (see Diagrams) and Image.
Math FormattingRounding, number format, angle units, output control (#hide, #val, #nosub and so on).
Text FormattingHeadings, bold, italic, colours, links, lists, rules, page break. In a sheet these write Markdown.
DocumentImport worksheet, the tidy tools, header and footer, page break, the report, contents, metadata, and Save as, Print PDF, Word, Excel and Export.
ResourcesSamples, library, New sheet, New Calcpad, Show compiled, Convert to Calcpad, themes, zoom, the sidebar and Settings, help.

The tabs follow the work: write (Math to Matrices/Tables), calculate, plot, format, then the document. Hover over a button for what it inserts or does; where it teaches syntax the tooltip shows the typed form.

The editor

The editor is on the left, one tab per open file. It colours the text, completes names, Greek spellings and function names, and underlines mistakes. Hover over a name to see where it is defined; F12 jumps to the definition. Format Document (Shift+Alt+F) tidies a sheet. See Editing.

The results

The right-hand pane shows the calculated worksheet. The Calculation tab chooses between four views:

  • Preview: the document as written, with every #pre and #post part. This is the usual view while you work.
  • Unwrapped: the source listing with macros and includes resolved. Useful for finding errors in macros.
  • Input: the fill-in form of a sheet or worksheet that has inputs (L: ? 6 m in a sheet, #UI in a worksheet). See Templates with inputs.
  • Report: the print layout, as it will come out in a PDF or Word file.

Results update as you type; Auto-calculate can be turned off on the Calculation tab, and then Calculate (Ctrl+Alt+X, and F5 in the desktop app) runs the sheet on demand.

Under a plot there is a row of small buttons (log axes, 1:1, copy data, save as PNG or SVG). These are in the preview only and are not part of a printout or export.

The sidebar

The sidebar holds the Insert tab, a searchable library of every symbol, function, unit and snippet (a click inserts it at the cursor), and tabs for the table of Contents and the Variables of the worksheet. Settings, Export, Errors and Prettify open as dialogs over the page. Hide the sidebar with the button at its top right, or Resources > Sidebar (Ctrl+Shift+B in the desktop app).

Settings

The gear at the right end of the top strip opens Settings (so do Calculation > Calculation settings and Resources > Settings). It has five tabs:

TabWhat is on it
GeneralLanguage, number format, and the appearance (colour theme, preview theme).
CalculationDecimals, angle units, complex numbers and the other math settings, plot defaults, US or UK units.
EditorQuick typing, comment format, formatting keys, auto-run, cursor sync, the linter.
ExportThe PDF page: paper size (A4 or Letter by the browser’s region until you choose one), orientation, margins, header and footer.
AdvancedScript libraries, logging and limits, the server address, saved configurations.

The search box above the tabs looks through all of them and lists each match under its tab’s name; clear it to get the tabs back. Settings opens on the tab you last used, until the browser tab is closed. Calculation settings opens it on Calculation, and Document > Header and footer on Export. On the tab strip, the arrow keys, Home and End move between the tabs.

On a phone

At 760 pixels wide or less, one pane shows at a time, switched from a bar along the bottom: Edit, Results and Insert. The ribbon starts folded; tap an open tab to fold it. See Editing for touch editing.

Saving, opening and working offline

The File menu

The File button at the top left of the ribbon opens a menu:

ItemWhat it does
New sheetA new sheet in a new tab.
New Calcpad worksheetA new .cpd worksheet, the advanced syntax.
Open…Opens a .sheet, .cpd or .txt file. Data files and pictures you pick join the library.
Import worksheet…Converts a worksheet from another tool. See Importing worksheets.
Samples…The sample browser. See Samples tour.
Save, Save as…Saves the active tab.
Print PDF…, Export…, Export Excel…See Exporting.

Below the commands are the Recent worksheets and the Library. The library holds the files that #include and #read use: data files, pictures, shared definitions. Everything you open or drop on the page goes into it. It is stored in your browser.

You can also drag a file onto the page. A .cpd or .sheet file opens in a tab, and any other file joins the library.

Saving

Press Ctrl+S (Cmd+S on a Mac), or use Save in the quick-access strip. Ctrl+Shift+S is Save as.

  • In a browser that can write files in place (Chrome and Edge on a computer), you choose a file once and later saves write to it.
  • In other browsers the file downloads each time you save.

A sheet is saved with the extension .sheet and a Calcpad worksheet as .cpd. Both are plain text. You can open them in any text editor and keep them in version control.

Saving is manual. Nothing you type is uploaded anywhere, and the browser keeps no copy of unsaved text, so save before you leave.

Knowing what is unsaved

A document has unsaved changes when its text differs from what Save or Save As last wrote.

  • Its tab shows a dot (●) after the name, and the browser tab’s title starts with ● while that document is the active one.
  • Undoing back to the saved text clears the dot again.
  • Closing a tab with unsaved changes asks Save, Don’t Save or cancel (click outside the box).
  • Closing or reloading the browser tab while any document has unsaved changes makes the browser ask whether to leave. The wording of that box is the browser’s own.

Print PDF, Word and Excel exports are copies of the report. They do not save the document, so the dot stays until you save it.

Working offline

CivilKit Calcs is a progressive web app. After one visit the whole app (about 22 MB) is cached by the browser, and it opens and calculates with no connection. To make it behave like an installed program, use your browser’s Install or Add to home screen command.

The page’s own files include the calculation engine, the Word and Excel writers, the importer, the Python runtime and the Symbolic dialog, so all of them work offline after the first visit. The one exception is the Plotly chart script: interactive Plotly charts from Python blocks load the Plotly script from its CDN the first time a chart is shown, and cache it after that. Without it the chart’s place shows a note instead of a blank. See Python blocks. The first visit itself needs a connection, and so does installing the app.

When a new build is available the app tells you with a small box (Reload and Later). It never reloads by itself, so unsaved work is safe.

Themes

The Resources tab has Light and Dark. Adding ?theme=dark or ?theme=light to the address forces the theme for that visit.

The sheet format

A sheet is a calculation written the way you would explain it to a colleague: Markdown prose, plain name: value lines, and LaTeX where you want a typeset formula. The sheet compiler turns it into the Calcpad worksheet language and the engine runs that. There is no second engine: units, vectors, matrices, plots, and the Word and Excel exports all work because the engine sees an ordinary Calcpad worksheet.

A file is a sheet when its first non-blank line is <!--sheet-->, or when its name ends in .sheet. The editor adds the marker line for you.

A whole sheet

# Beam bending check

A simply supported beam. The moment **comes out in kN·m**.

L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment
Ms: 300 MPa * 1230000 mm³ -> kN*m
utilisation: Mstar / (0.9 * Ms)
if utilisation <= 1: "OK" else: "Fails"

The result:

Beam bending check
A simply supported beam. The moment comes out in kN·m.

L = 6 m    span
w = 12 kN/m    design load
M_star = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m    maximum bending moment
Ms = 300 MPa · 1230000 mm³ = 369 kN·m
utilisation = M_star / (0.9·Ms) = 54 kN·m / (0.9 · 369 kN·m) = 0.163
OK

The line kinds

Every line of a sheet is one of these.

LineLooks likeChapter
ProseA simply supported beam. or ## HeadingProse, LaTeX and tables
QuantityL: 6 m | spanQuantities and notes
InputL: ? 6 m | spanTemplates with inputs
Section marker## Workings {collapse}, M: ... {key}, {key results}Folding sections and key results
Functionf(x): x^2 + 1Functions
Conditionif u <= 1: "OK" else: "Fails"Conditions and loops
Blockfor i in 1..5: with an indented bodyConditions and loops
Plotplot M(x) for x in 0..LPlots
Pythona fenced python blockPython blocks
Diagrama fenced mermaid blockDiagrams
Calcpada line starting with >>, or a calcpad fenceMixing in Calcpad

A line that looks like a quantity but is really prose (Note: see the drawing) is prose, because its right-hand side is not an expression. To force prose, start the line with a backslash.

A page to keep open

The quick reference puts the sheet language on one page that prints: every line kind and input, the functions, constants, operators and units of the engine. It has a Print button, and it is also what to hand to a colleague who has not used a sheet before.

What a sheet cannot do

  • There is no symbolic algebra in the sheet itself. The engine is numeric. Use the Symbolic dialog to derive a formula and paste it in.
  • A vector or matrix literal cannot carry a unit after the bracket ([1, 2] kN). Put the unit on the elements.
  • A formula is typeset in the page, but in Word and Excel it appears as its TeX source in italics.
  • Convert to Calcpad works one way. Calcpad text is not turned back into a sheet.

Everything else in the Calcpad language is reachable by passing lines through. See Mixing in Calcpad.

Quantities, units and notes

A quantity line defines a name:

name: expression [-> unit] [| note]
name = expression
a: 1; b: 2 | note for b

The colon and the equals sign both work. The result shows what an equation line shows in Calcpad: the name, the formula, the numbers put in, and the answer with its unit.

Names

A name is made of letters, digits, _ and primes. Greek spellings become Greek letters:

phi: 0.9
sigma_c: 25 MPa
Delta_T: 40 K
phiMs: phi * 369 kN*m
Mstar: 54 kN*m
φ = 0.9
σ_c = 25 MPa
Δ_T = 40 K
φMs = φ · 369 kN·m = 0.9 · 369 kN·m = 332.1 kN·m
M_star = 54 kN·m
  • phi is φ, sigma_c is σ with a subscript c, Delta_T is Δ with a subscript T.
  • A Greek spelling followed by a capital or a digit (phiMs, sigma2) is the letter and the rest.
  • Capital Greek letters are written only where they differ from a Latin capital: Gamma, Delta, Theta, Lambda, Xi, Pi, Sigma, Upsilon, Phi, Psi, Omega.
  • A name that ends in star after a capital or a digit (Mstar) is that name with the subscript star.
  • The first _ in a name starts the subscript: my_long_name_2 is shown as my with the subscript long_name_2, as Calcpad writes it. Names with digits and several underscores calculate normally; only the way they are typeset changes.

The same rule renames every use of a name, so you spell it one way throughout the sheet. Inside >> lines and calcpad fences the sheet’s spelling is used too: phi in a raw line is φ.

Units

Write a unit after a number. The engine checks and combines them:

a: 2 m; b: 350 mm
A: a * b -> m^2
v: 90 km/h -> m/s
t: 2 h + 30 min -> min
F: 10 N * 3 m -> J
a = 2 m
b = 350 mm
A = a·b = 2 m · 350 mm = 0.7 m²
v = 90 km/h = 25 m/s
t = 2 h + 30 min = 150 min
F = 10 N · 3 m = 30 J
  • ² and ³ after a name or unit are ^2 and ^3. mm³ and mm^3 are the same.
  • A unit written after a number is never renamed, so 3 psi is a pressure and psi alone would be the Greek letter ψ.
  • Adding a length to a time is an error. Multiplying and dividing them is fine.
  • Several units in a sum convert to the first: 5 m + 30 cm is 5.3 m.

The whole subject, with the unit list and custom units, is in Units.

Converting the answer: ->

-> unit converts the result. It must come last, before the note:

Mstar: 12 kN/m * (6 m)^2 / 8 -> kN*m | maximum bending moment
Mnmm: Mstar -> N*mm
M_star = 12 kN/m · (6 m)² / 8 = 54 kN·m    maximum bending moment
Mnmm = M_star = 54 kN·m = 54000000 N·mm

Without -> the engine chooses the unit itself, from the units in the formula. Use -> when you want a particular unit in the result, and always when the result goes into a report.

Notes

The first | outside brackets starts a note, a short comment shown beside the result in a muted style. || is the logical or, not a note. A note can contain LaTeX (| load at stage $i$).

Several per line

Separate quantities with ;. A note belongs to the last one:

a: 3; b: 4 | note for b
c: sqrt(a^2 + b^2)
a = 3
b = 4    note for b
c = √(a² + b²) = √(3² + 4²) = 5

Numbers and operators

  • You can write 1.23e6 or 2.5e-3. The engine has no exponent notation, so the compiler writes the plain number (1230000, 0.0025) and that is what the result shows.
  • Operators are + - * / ^ % and the comparisons < > <= >= == !=, with and and or. The Unicode forms ≤ ≥ ≠ ≡ ∧ ∨ × · ÷ − work too. In a condition a single = also means equal.
  • Calls take commas: max(a, b). The compiler writes the semicolon the engine wants.
  • Use abs(x) for an absolute value, not bars.
  • π (or pi) and e are built in. The other constants in the Insert tab (gravity, the speed of light, unit weights and so on) are snippets that insert a definition line such as g = 9.80665m/s^2; until you insert one, g is the unit gram. See the reference.

Vectors and matrices

v: [1, 2, 3]
A: [2, -1; -1, 2]

[1, 2, 3] is a vector; [1, 2; 3, 4] is a matrix with columns separated by commas and rows by semicolons. See Vectors and matrices.

Inputs: a quantity the reader can change

Put a ? in front of the value and the quantity becomes an input, with that value as its default:

L: ? 6 m | span
w: ? 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum moment

In Input mode L and w are boxes. Everywhere else the lines read as the quantities they are. A list of options ([Steel = 200 GPa, Timber = 11 GPa], or round brackets for radio buttons) and on or off (a checkbox) are inputs too. See Templates with inputs.

Prose, LaTeX and tables

Anything that is not one of the line kinds is Markdown prose. Use it to say what is being checked, to state assumptions and to explain results.

Markdown

Supported Markdown: headings (# to ######), paragraphs, **bold**, *italic*, bulleted (-) and numbered lists, pipe tables, links, ![alt](file) images from the library, `code` and fenced code blocks. Blank lines between sections are kept.

A plain paragraph, even over several lines, becomes one text line. Only prose that really contains Markdown (lists, tables, quotes, emphasis, links, code) is passed to the engine’s Markdown renderer.

LaTeX

$...$ is an inline formula and $$...$$ a display formula, in prose, in notes and in the text of an if line. A $$ alone on a line opens and closes a multi-line formula. \$ is a dollar sign, and a $ before a digit (“$5”) is one too.

A pipe of diameter $d$ carries a flow $Q$. The mean velocity is

$$v = \frac{4 Q}{\pi d^2}$$

d: 0.2 m
Q: 0.05 m^3/s
v: 4 * Q / (π * d^2) -> m/s
A pipe of diameter d carries a flow Q. The mean velocity is

        4Q
   v = ----
        πd²

d = 0.2 m
Q = 0.05 m³/s
v = 4·Q / (π·d²) = 4 · 0.05 m³/s / (3.14 · (0.2 m)²) = 1.59 m/s

The page typesets formulas with KaTeX, which is bundled with the app and loaded the first time a sheet has a formula, so formulas work offline. A formula that cannot be typeset is shown as its TeX source. In the LaTeX of a sheet, variable names take the same blue as in an equation. In Word and Excel a formula appears as its TeX source in italics, not as Office Math.

Tables

A pipe table is prose, with the engine’s table styling:

| Action     | Symbol | Value |
|------------|--------|-------|
| Permanent  | G      | 4.5 kPa |
| Imposed    | Q      | 3 kPa |

G: 4.5 kPa
Q: 3 kPa
w_uls: 1.2 * G + 1.5 * Q -> kPa | strength combination
Action      Symbol   Value
Permanent   G        4.5 kPa
Imposed     Q        3 kPa

G = 4.5 kPa
Q = 3 kPa
w_uls = 1.2·G + 1.5·Q = 1.2 · 4.5 kPa + 1.5 · 3 kPa = 9.9 kPa    strength combination

The table is text. It does not feed the calculation, so type the numbers again in quantity lines, or define the quantities first and mention them in the table text.

In the preview, click a column heading to sort the rows by it (again for descending, a third time for the source order). It is a view only: the sheet, the printout and the exports keep the order you wrote. See Sorting a table.

Diagrams

A fenced block tagged mermaid is drawn as a diagram in the results: boxes and arrows, a flow chart, a sequence or a timeline, written as text in Mermaid’s syntax.

# Load path

```mermaid
graph TD
  Slab --> Beam
  Beam --> Column
  Column --> Footing
```

G: 4.5 kPa

The drawing comes from the text, so editing the fence redraws it. Diagrams starts from three small examples (a flow chart, a sequence and a state diagram) and gives tips, what prints and what exports.

Forcing prose

A line starts with a backslash when it must not be read as a quantity:

\L: 5 is shown as text
Note: see the drawing

Note: see the drawing is already prose, because “see the drawing” is not an expression.

Diagrams

A diagram is written as text in a fenced block tagged mermaid, and the results draw it. Type the steps, the app draws the boxes and arrows. Edit the text and the drawing follows. The language of the fence is Mermaid’s, and the app bundles Mermaid 12.1.0, which draws more than thirty kinds of diagram and chart: flow charts, sequence and state diagrams, Gantt charts, pie and XY charts, Sankey diagrams, mind maps and more.

This chapter is a gallery: one small example of each kind, grouped by what it is for. Copy one into a sheet to see it drawn, then change it. A kind whose first word ends in -beta is new in the diagram library, and its syntax may still change in a later version. The kinds that are not available are listed at the end, and the samples show diagrams next to the calculations they describe.

Starting from the ribbon

The Diagrams menu in the Figures group of the Plots & Diagrams tab of the ribbon inserts a short starter diagram, so there is no syntax to learn before the first one. Put the caret where the diagram should go and pick a kind: flowchart, sequence, state, block, architecture, entity relationship, requirement, tree view, mind map, fishbone, Gantt, timeline, pie, XY chart, quadrant, radar, Sankey or treemap. In a sheet the starter goes in as a block of its own after the paragraph or block the caret is in; in a Calcpad worksheet it goes in a #markdown block after the caret’s line. Its text is left selected, ready to edit, and Undo takes it out in one step. The menu offers the kinds engineers use most; the other kinds can be typed by hand, and the gallery below shows them all.

A diagram does not read the sheet’s numbers. Work a value out with a quantity line and type it into the diagram, as the samples do.

Processes and behaviour

Flow chart

flowchart TD draws from top to bottom (LR draws from left to right). A box is a name and its label in square brackets, a decision is in braces, and --> is an arrow. Text between -- and --> labels the arrow.

# Design check

```mermaid
flowchart TD
  A[Design moment M*] --> B{M* <= phi Ms?}
  B -- yes --> C[Section passes]
  B -- no --> D[Choose a deeper section]
  D --> A
```

Mstar: 54 kN*m | design moment
phiMs: 332 kN*m | design capacity
if Mstar <= phiMs: "OK: the section passes." else: "Fails: choose a deeper section."

Sequence diagram

sequenceDiagram draws people or parts side by side and the messages between them, in order from the top. ->> is a solid arrow and -->> a dashed one.

# Review of the calculation

```mermaid
sequenceDiagram
  participant D as Designer
  participant C as Checker
  D->>C: Calculation for review
  C-->>D: Comments
  D->>C: Revised calculation
  C-->>D: Approved
```

State diagram

stateDiagram-v2 draws the states something passes through. [*] is the start or the end, and the text after a colon labels the change.

# Status of the calculation

```mermaid
stateDiagram-v2
  [*] --> Draft
  Draft --> Checked: checker signs
  Checked --> Draft: comments
  Checked --> Issued: approved
  Issued --> [*]
```

User journey

journey scores each step of a task from 1 (bad) to 5 (good) for the people who take part.

# Inspection of a slab pour

```mermaid
journey
  title Site inspection of a slab pour
  section Before the pour
    Check reinforcement: 4: Engineer
    Check cover and chairs: 3: Engineer, Builder
  section The pour
    Slump test: 5: Tester
    Take cylinders: 4: Tester
```

Use case diagram

usecase-beta draws actors and the things they do. actor names the actors, and name(label) is a use case.

# Who does what

```mermaid
usecase-beta
  actor Designer, Checker
  Designer --> design(Design a member)
  Designer --> report(Print the report)
  Checker --> review(Review the calculation)
```

Event model

eventmodeling draws a process as frames in time order: tf is a time frame with a number, a kind (ui, cmd, evt, rmo) and a name, and ->> points to the frame it follows.

# A check from input to report

```mermaid
eventmodeling
  tf 01 ui InputForm
  tf 02 cmd RunCheck ->> 01
  tf 03 evt CheckPassed ->> 02
  tf 04 rmo DesignReport ->> 03
```

Structure and data

Class diagram

classDiagram draws classes with their fields and methods. <|-- is inheritance.

# Section shapes

```mermaid
classDiagram
  class Section {
    +area() A
    +inertia() I
  }
  class Rectangle {
    +b
    +h
  }
  class Circle {
    +d
  }
  Section <|-- Rectangle
  Section <|-- Circle
```

Entity relationship diagram

erDiagram draws a data model. }o--|| reads “many to exactly one”, and the braces list the attributes of an entity.

# Member data model

```mermaid
erDiagram
  MEMBER }o--|| SECTION : uses
  SECTION }o--|| MATERIAL : "made of"
  MEMBER {
    string mark
    float length_m
  }
  SECTION {
    string name
    float area_mm2
  }
  MATERIAL {
    string grade
    float fy_MPa
  }
```

Requirement diagram

requirementDiagram ties requirements to the elements that satisfy or verify them.

# Traceability

```mermaid
requirementDiagram
  requirement deflection {
    id: R1
    text: Deflection under span over 250
    risk: medium
    verifymethod: analysis
  }
  element beam_check {
    type: sheet
  }
  beam_check - satisfies -> deflection
```

Block diagram

block-beta lays blocks out on a grid. columns 3 sets the grid, :3 makes a block span three columns and space leaves a gap.

# A portal frame in blocks

```mermaid
block-beta
  columns 3
  Roof:3
  Beam1["Beam"] space Beam2["Beam"]
  Col1["Column"] space Col2["Column"]
  Footing:3
```

Architecture diagram

architecture-beta draws services with icons (cloud, database, disk, internet, server) in groups. sensors:R -- L:logger joins the right side of one to the left side of the other.

# Monitoring a bridge

```mermaid
architecture-beta
  group site(cloud)[Bridge site]
  service sensors(disk)[Strain gauges] in site
  service logger(server)[Data logger] in site
  service store(database)[Database]
  sensors:R -- L:logger
  logger:R -- L:store
```

C4 diagram

C4Context draws a system in its setting, in the C4 model’s notation: people, systems and the relations between them.

# Context of a calculation system

```mermaid
C4Context
  title Calculation system
  Person(eng, "Engineer", "Writes the calculation")
  System(app, "Calculation app", "Runs the sheet")
  System_Ext(lib, "Section library", "Section properties")
  Rel(eng, app, "Uses")
  Rel(app, lib, "Reads")
```

Packet diagram

packet-beta draws the fields of a data record by bit position.

# A logger record

```mermaid
packet-beta
  0-15: "Sensor id"
  16-31: "Strain, microstrain"
  32-47: "Temperature"
  48-63: "Checksum"
```

Plans and time

Gantt chart

gantt draws tasks against dates. dateFormat sets how dates are written, after a1 starts a task when another ends, and a duration such as 10d is in days.

# Design programme

```mermaid
gantt
  title Design programme
  dateFormat YYYY-MM-DD
  section Design
  Concept       :a1, 2026-11-02, 10d
  Detailed      :a2, after a1, 15d
  section Review
  Check         :b1, after a2, 5d
  Issue         :milestone, after b1, 0d
```

Timeline

timeline lists events by period, one line each: period : event.

# Strength gain

```mermaid
timeline
  title Concrete strength gain
  Day 3 : 15 MPa
  Day 7 : 22 MPa
  Day 28 : 32 MPa
```

Kanban board

kanban draws columns of cards. A line indented under a column is a card in it.

# Design tasks

```mermaid
kanban
  todo[To do]
    t1[Wind loads]
    t2[Connection design]
  doing[In progress]
    t3[Column check]
  done[Done]
    t4[Gravity loads]
```

Git graph

gitGraph draws commits on branches, here the revisions of a calculation and a checker’s branch.

# Revisions

```mermaid
gitGraph
  commit id: "Rev A"
  branch checker
  commit id: "Comments"
  checkout main
  commit id: "Rev B"
  merge checker
  commit id: "Rev C issued"
```

Charts of numbers

Pie chart

pie draws each value as a slice; showData adds the values to the legend.

# Dead load share

```mermaid
pie showData
  title Dead load, kPa
  "Slab" : 4.8
  "Screed" : 1.1
  "Services" : 0.5
  "Partitions" : 1.0
```

XY chart

xychart-beta draws bars and lines over an x axis of categories or numbers.

# Moment along a beam

```mermaid
xychart-beta
  title "Bending moment, kN.m"
  x-axis "x, m" [0, 1, 2, 3, 4, 5, 6]
  y-axis "M" 0 --> 60
  bar [0, 30, 48, 54, 48, 30, 0]
  line [0, 30, 48, 54, 48, 30, 0]
```

Quadrant chart

quadrantChart places points with coordinates from 0 to 1 in four labelled quadrants.

# Risk matrix

```mermaid
quadrantChart
  title Site risks
  x-axis Unlikely --> Likely
  y-axis Minor --> Severe
  quadrant-1 Control first
  quadrant-2 Plan for it
  quadrant-3 Accept
  quadrant-4 Monitor
  Trench collapse: [0.3, 0.9]
  Wet weather: [0.9, 0.5]
```

Radar chart

radar-beta compares options over several axes. max sets the outer ring.

# Floor systems

```mermaid
radar-beta
  title Floor systems
  axis cost["Cost"], speed["Speed"], depth["Shallow depth"], span["Span"]
  curve flat["Flat plate"]{4, 3, 5, 2}
  curve steel["Steel and deck"]{3, 5, 3, 4}
  max 5
```

Sankey diagram

sankey-beta draws flows as bands whose width is the value. Each line is from,to,value.

# Energy through a pump

```mermaid
sankey-beta
Input,Motor,43.3
Motor,Motor losses,3.0
Motor,Pump,40.3
Pump,Pump losses,8.9
Pump,Water,31.4
```

Treemap

treemap draws nested rectangles with an area in proportion to the value. Indentation nests an item in its group.

# Cost plan

```mermaid
treemap
"Cost plan"
    "Structure"
        "Frame": 310
        "Floors": 260
    "Envelope"
        "Facade": 280
        "Roof": 90
```

Ideas and analysis

Mind map

mindmap draws a tree from its root; indentation gives the branches. ((text)) draws a circle.

# Footbridge brief

```mermaid
mindmap
  root((Footbridge))
    Geometry
      Span 24 m
      Width 2.5 m
    Loads
      Crowd 5 kPa
    Limits
      Deflection L/360
```

Ishikawa (fishbone) diagram

ishikawa-beta draws an effect at the head and its causes on the bones. Indentation gives the categories and the causes in each.

# Causes of cracking

```mermaid
ishikawa-beta
  Cracked slab
    Materials
      High water content
    Method
      Late curing
    Design
      Joints too far apart
```

Venn diagram

venn-beta draws sets as circles. set adds a set, and union labels where sets overlap.

# Kinds of check

```mermaid
venn-beta
  title Checks
  set S["Strength"]
  set V["Serviceability"]
  union S, V["Both"]
```

Cynefin framework

cynefin-beta places items in the five domains (complex, complicated, clear, chaotic, confusion). An item is a quoted text, and --> shows a move from one domain to another.

# Kinds of design problem

```mermaid
cynefin-beta
  complex
    "Novel bracing system"
  complicated
    "Long-span roof"
  clear
    "Standard lintel"
  chaotic
    "Collapse on site"
  chaotic --> complex : "Make safe, then probe"
```

Wardley map

wardley-beta maps components by visibility (up) and evolution (across). The coordinates are [visibility, evolution], from 0 to 1, and -> joins a component to one it depends on.

# Design office

```mermaid
wardley-beta
  title Design office
  anchor Client [0.95, 0.6]
  component Calculation [0.7, 0.5]
  component Section tables [0.4, 0.85]
  Client -> Calculation
  Calculation -> Section tables
```

Tree view

treeView-beta draws an indented list as a tree, such as the folders of a project.

# Project folders

```mermaid
treeView-beta
  project
    calcs
      beams.sheet
      columns.sheet
    drawings
      general.pdf
```

Grammars: railroad diagrams

A railroad diagram draws the grammar of a language: follow the track from left to right. Each rule ends with ;. The same drawing comes from four notations.

EBNF

railroad-ebnf-beta: , joins in sequence and [ ] is optional. This is the grammar of a quantity line.

# A quantity line

```mermaid
railroad-ebnf-beta
  quantity = name , ":" , expression , [ "->" , unit ] , [ "|" , note ] ;
```

ABNF

railroad-abnf-beta: 1*DIGIT is one or more digits and [ ] is optional.

# A number

```mermaid
railroad-abnf-beta
  number = 1*DIGIT [ "." 1*DIGIT ] ;
```

PEG

railroad-peg-beta: <- defines a rule, + is one or more and ? is optional.

# A number

```mermaid
railroad-peg-beta
  Number <- Digit+ ("." Digit+)? ;
```

Railroad functions

railroad-beta builds a diagram from functions: sequence, choice, optional, oneOrMore, zeroOrMore, terminal and nonterminal.

# A quantity line

```mermaid
railroad-beta
  quantity = sequence(nonterminal("name"), terminal(":"), nonterminal("expression"), optional(sequence(terminal("|"), nonterminal("note")))) ;
```

Kinds that are not available

Every kind above was drawn in the app with the bundled Mermaid 12.1.0. These are not available:

KindWhy
ZenUML (zenuml)A separate plugin of the diagram library, not part of the app. The fence shows “No diagram type detected”. Use a sequence diagram instead.
The elk layout (layout: elk)Not shipped; diagrams use the standard layout.

Samples

The Plots and diagrams group of the Samples dialog (Resources > Samples) has sheets with a diagram next to the calculation it describes:

  • Design check as a flow diagram and Load path and tributary loads (flow charts)
  • Design states of a steel beam (state diagram) and Review and sign-off (sequence diagram)
  • Construction programme (Gantt chart), with durations worked out from quantities and rates
  • Dead load share (pie chart) and Cost plan (treemap), with the shares worked out
  • Site risk matrix (quadrant chart) and Bending moment along a beam (XY chart)
  • Energy flow through a pump (Sankey), from the hydraulic power back to the electrical input
  • Footbridge design brief (mind map) and Requirements traceability (requirement diagram)
  • Concrete strength gain (timeline) and Section shapes (class diagram)

For plots drawn from a function, see Plots.

Learning more

Every diagram type and option is described in the Mermaid project’s own documentation; what it shows there can be pasted into a fence here, as long as the kind is in the gallery above.

Tips

  • Keep the text in a box short. A long label wraps onto several lines and makes the box tall.
  • A diagram is part of the page, not of the calculation. Names in it are only text: changing w in a box does not change the load, and a quantity line is still needed for every number.
  • In the dark theme a diagram is drawn on a white panel, so it reads the same as on paper.
  • A fence that cannot be read shows its text with the reason under it. The usual cause is a character the diagram language treats as syntax, such as a bracket or a quote inside a label.

Printing and exports

Diagrams print and save with the HTML and PDF report as drawings; in Word they appear as their text. The same fence works inside a #markdown block of a Calcpad worksheet. The diagram library is part of the app and is only loaded when a page has a diagram, so it works offline and costs nothing on a page without one.

Folding sections and key results

A long calculation has a few numbers the reader came for and a lot of working that leads to them. Two markers let the sheet say which is which, without changing a single result.

A section that folds

End a heading with {collapse} and the section under it is folded away until the reader opens it:

# Beam moment

L: 6 m | span
w: 12 kN/m | design load

## Workings {collapse}
The moment at mid-span of a simply supported beam under a uniform load is $w L^2 / 8$.
M: w * L^2 / 8 -> kN*m | maximum bending moment
Ms: 180 kN*m | moment capacity

## Result
utilisation: M / Ms | bending utilisation

In the preview and the report the heading shows with a small arrow in front of it. Click the heading to open the section and click it again to fold it. The lines under a folded heading are still calculated, so M is there for the line after it. The section runs to the next heading of the same level or a higher one, so a ### under a ## is part of it, and it ends at the end of the sheet if no such heading follows.

{collapse open} starts the section open. Use it for a section the reader should see at first and may fold away.

Only a heading at the top level of the sheet can fold. A {collapse} heading inside an if, for, while or repeat block is ignored, with a warning.

The preview also has a fold arrow beside every other heading (see Editing). That fold is only a view and is not saved in the sheet; a {collapse} heading folds by its marker and has no arrow of its own, and “Collapse all” leaves it as the sheet wrote it.

When you print, or save as PDF, every folded section is opened, so the printed report is complete. The Word and Excel exports include them too. There is no option to leave a folded section out of an export.

Key lines

End a quantity or an input line with {key} to mark it as one of the numbers that matter:

L: ? 6 m | span {key}
w: 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum bending moment {key}
Ms: 180 kN*m
utilisation: M / Ms | bending utilisation {key}

A key line carries a star after it and is highlighted in the preview, the report and the printed page. In Word and Excel the star is in the line, though the highlight is not. The marker goes last, after the note.

A list of the key lines

A line that is just {key results} becomes a list of the key lines above it, with the values the engine worked out and their notes:

L: ? 6 m | span {key}
w: 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum bending moment {key}
Ms: 180 kN*m
utilisation: M / Ms | bending utilisation {key}

## Key results
{key results}

Put it after the lines it lists: a sheet is calculated from the top, so a key line written below the list has no value yet and is not in it. A line inside an if or for block, and a function definition, can be marked but are not listed.

In the editor, Text formatting > Fold inserts a folding heading, Key results inserts the heading and the list, and the + between blocks of the preview offers both. Format Document writes the markers as one space and the marker.

Conditions and loops

One-line conditions

utilisation: 0.82
if utilisation <= 1: "OK" else: "Fails"

The branches are a quoted text or quantities. The text may contain LaTeX. A one-line condition can also define a quantity: if a == 2: b: 1.

Blocks

A line ending in : that starts with if, else if, else, for, while or repeat opens a block. The body is the lines indented more than the header. A tab counts as four spaces. Blank lines inside are fine. A line indented no deeper than the header closes the block. A body can hold anything: quantities, prose, formulas, >> lines, and nested blocks.

n: 5
if n > 3:
    Large.
else if n > 1:
    Medium.
else:
    Small.
n = 5
Large.

Loops

for i in 1..3:
    P: 10 kN * i | load at stage $i$
P = 10 kN · i = 10 kN · 1 = 10 kN    load at stage 1
P = 10 kN · i = 10 kN · 2 = 20 kN    load at stage 2
P = 10 kN · i = 10 kN · 3 = 30 kN    load at stage 3
SheetMeaning
for i in a..b:i takes a, a+1, … b.
for i in a..b step s:A stepped range. The step may be negative.
for x in v:Each element of the vector v (a name or a literal).
while c:Repeat while the condition holds.
repeat n:Repeat n times.
break, continueLeave the loop, or skip to the next pass. if c: break works on one line.
for i in 0..10 step 5:
    s: i
for x in [2, 4, 6]:
    y: x^2
n: 3
while n > 0:
    n: n - 1
total: 0
for i in 1..5:
    total: total + i
    if total > 5: break

The last example stops once the total passes 5; it prints the passes with total 1, 3 and 6.

A quantity line in a loop prints on every pass, exactly like a Calcpad loop. Use the loop to build a vector or to accumulate; if you only need the final value, put the quantity line after the loop.

Limits

  • repeat needs a count; for anything else use >> lines.
  • A loop over a vector cannot have a step.
  • A header whose condition is not an expression (If the load is large:) is prose. The compiler warns if it starts with a keyword.
  • An else with no matching if at the same indentation is read as text, with a warning.

Functions

Your own functions

A line with an argument list defines a function:

f(x, y): sqrt(x^2 + y^2)
g(t): 2 * t
r: f(3, 4) + g(1)
f(x; y) = √(x² + y²)
g(t) = 2·t
r = f(3; 4) + g(1) = 7

Calls take commas in a sheet; the compiler writes the engine’s ;. Calcpad’s own ; works too, in a definition and in a call (f(x; y): x + y, max(3; 7)): inside brackets it means the same as a comma. Functions can use any quantity defined above them, and may be used in plots (plot g(t) for t in 0..5).

Keeping functions for reuse

A function defined in a sheet belongs to that sheet. To use it in other sheets, put its definition in a .cpd file and add the file to the library (File > Library > Add files to the library, or drop it on the page). Any sheet then pulls it in with an include line:

>> #include beam_functions.cpd

The file holds Calcpad text, so its arguments are separated by ;:

delta(w; L; E; I) = 5*w*L^4/(384*E*I)

Two things to watch in definitions that integrate over time or space:

  • The limits of $Area, $Sum and the other numerical commands must have the same unit. $Area{F(t) @ t = 0ms : 2s} is fine; a bare 0 against 2s is an error.
  • An angular frequency is a number per second. Write 20 / 1 s, not 20 rad/s.

Copying the definition lines into each sheet also works, and keeps the sheet self-contained when you send it to someone who does not have your library.

Built-in functions

The engine has more than 200 functions: trigonometric, hyperbolic, logarithmic, rounding, statistical, interpolation, complex numbers, and a large set for vectors and matrices. The function reference lists them all, with the argument forms, and the Insert tab in the sidebar finds them as you type.

A few that are used constantly:

a: sqrt(2)
b: round(3.14159)
c: max(3, 7, 5)
d: sum([1, 2, 3])
e: interp(2.5, [1, 2, 3], [10, 20, 30])

There is no hypot in a sheet. For the hypotenuse, or the resultant of any number of components, use srss (square root of the sum of squares), which keeps the unit:

a: 3 m
b: 4 m
c: srss(a, b)

The result is 5 m, and srss(3 m, 4 m, 12 m) is 13 m. (In a Python block math.hypot exists.)

A function whose name is also a variable name needs the Calcpad spelling (a name like gamma or beta used as a variable only keeps working if you write it the Calcpad way). Function calls are not renamed unless the sheet defines the function.

Solving, integrating and slopes

Three numerical operations have a sheet form of their own, written like a plot line:

f(x): x^2
x0: solve f(x) = 2 for x in 0..2 | the positive root
A: integral of f(x) for x in 0..3
k: slope of f(x) at x = 3
  • solve f(x) = c for x in a..b finds the x between a and b where both sides are equal (Calcpad’s $Root{f(x) = c @ x = a : b}). Without = c it solves f(x) = 0. Both sides may use the variable (solve f(x) = g(x) for x in 0..5 finds where two curves cross). The difference of the sides must change sign once across the range.
  • integral of f(x) for x in a..b is the numerical integral ($Integral).
  • slope of f(x) at x = a is the derivative at a point ($Slope).

root(27, 3) is something else: the cube root of 27. The bounds may carry units, and a bare 0 takes the unit of the other bound, so solve x^2 = 4 m^2 for x in 0..5 m -> mm gives 2000 mm. A line that starts like one of these but is malformed (for 2 in 0..5, two = signs) is an error on its line.

Numerical commands

The $Root, $Area, $Sum, $Find and similar commands are Calcpad commands. Apart from the three above, in a sheet they go through >>:

>> f(x) = x^2 - 2
>> x_0 = $Root{f(x) @ x = 0 : 2}
>> I = $Area{x^2 @ x = 0 : 3}

The result of the first is 1.41, of the second 9. See The Calcpad language.

Mixing in Calcpad, Show compiled and errors

Every feature of the Calcpad language stays reachable from a sheet.

>> lines and calcpad fences

A line that starts with >> is handed to the engine as written. So is everything between a calcpad fence:

n: 3 | number of bays
bay: 2.5 m | bay width
>> total = 0 m
```calcpad
#for i = 1 : n
    total = total + bay
#loop
```
len: total * 1 -> m
n = 3    number of bays
bay = 2.5 m    bay width
total = 0 m
total = total + bay = 0 m + 2.5 m = 2.5 m
total = total + bay = 2.5 m + 2.5 m = 5 m
total = total + bay = 5 m + 2.5 m = 7.5 m
len = total · 1 = 7.5 m · 1 = 7.5 m

Sheet lines and raw lines share one worksheet, so they alternate freely: a raw block reads the variables defined by sheet lines above it and defines variables that sheet lines below it use. Prose, quantities, formulas and raw Calcpad can come in any order. To make that work without remembering renames, an identifier in a raw line that the sheet defines is spelled the way the sheet spells it (phi in a raw line is φ). That includes the name that a >> #UI line assigns. Text after a ' or " in a raw line is left alone.

A raw block inside a sheet block keeps the block’s indentation rules like any other line.

The ribbon uses >> for anything with no sheet form: the data grid and the other #UI input forms (an entry, drop-down, radio or checkbox has a sheet form, L: ? 6 m), $Map colour maps, directives and macros. Those buttons carry a small >> mark and a tooltip saying so. See The Calcpad language.

Python

A fenced block with the language python is a Python block. It is explained in Python blocks.

Show compiled and Convert to Calcpad

On the Resources tab:

  • Show compiled opens a panel beside the editor with the Calcpad text the sheet becomes. Its line numbers are the sheet’s lines.
  • Convert to Calcpad replaces the sheet with that text. It is one way: there is no conversion back to a sheet.

A worked example is in Your first sheet. Both views give Calcpad as a person would write it, so the sheet is also a way to learn the Calcpad language.

Errors

The engine’s errors, the report’s “on line [n]” links, the error banner, the scroll anchors and the editor’s lint markers all report the sheet line, whatever kind of line it was. An undefined name, for example:

bad: foo + 1

Error in "bad = foo + 1" on line [1]: Undefined variable or units: "foo".

The text of an engine message still quotes the compiled Calcpad line (bad = foo + 1), which is what Show compiled displays. The compiler’s own problems, such as mixed tab and space indentation, an else with no if, an empty block, an unclosed $$ or a bad plot line, are markers on their lines too. “Unused variable” hints are not shown for sheets, since every quantity is shown.

Format Document

Format Document (Shift+Alt+F) prettifies a sheet: one space around :, | and -> and after ;, a blank line before each heading, runs of blank lines collapsed, and the colons of a run of quantity lines aligned. Expressions, prose, >> lines, fences and formulas are not touched, and formatting twice changes nothing.

Other editor help works on the names a sheet defines: Go to definition (F12), find references, hover (shows the defining line and the Calcpad spelling), and colouring by role.

The Calcpad language

The sheet format is a front end. Underneath, every sheet becomes a Calcpad worksheet, the language of CalcpadCE, and the engine runs that. You can also write Calcpad directly: choose File > New Calcpad worksheet (the second item of the File menu, also on the Resources tab), or open a .cpd file.

Use the Calcpad language when you need something a sheet does not offer on its own: macros that repeat a block with different arguments, input forms with drop-downs and grids, output control (hide a block, show only results), the numerical commands, reading and writing data files, or when you are working with worksheets from the CalcpadCE community.

How a Calcpad worksheet reads

A worksheet is a list of lines. Each line is one of these.

First characterKindExample
"Heading, a comment shown as a heading"Beam check
'Text, a comment shown as written (HTML allowed)'Span -'L = 6m
#A directive#if, #for, #def, #hide
$A command$Plot{x^2 @ x = 0 : 5}
anything elseA calculationM = w*L^2/8|kN*m

A single quote also switches between text and calculation inside a line, which is how labels sit in front of an equation: 'Span -'L = 6m shows the text “Span -” and then the equation.

"Beam check
'Span -'L = 6m
'Load -'w = 12kN/m
'Moment -'M = w*L^2/8|kN*m
#if M < 100kN*m
    'OK
#else
    'Too large
#end if
Beam check
Span - L = 6 m
Load - w = 12 kN/m
Moment - M = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m
OK

Sheet and Calcpad side by side

SheetCalcpad
L: 6 m | spanL = 6m 'span
M: w*L^2/8 -> kN*mM = w*L^2/8|kN*m
# Heading'<h1>Heading</h1>
Plain paragraph'Plain paragraph
if u <= 1: "OK" else: "Fails"#if u ≤ 1 … #else … #end if
for i in 1..5: + indented body#for i = 1 : 5 … #loop
f(x, y): x + yf(x; y) = x + y
[1, 2; 3, 4][1; 2 | 3; 4]
plot f(x) for x in 0..5$Plot{f(x) @ x = 0 : 5}
phi, Mstarφ, M_star

Function arguments are separated with ; in Calcpad, matrix rows with |, and a unit conversion is a vertical bar. A sheet writes commas, -> and brackets, and the compiler does the translation. To see it for any sheet, use Show compiled.

Operators

^ power, * multiplication, / division, \ integer division, ⦼ modulo (type %%), ! factorial, + - , comparisons ≡ ≠ < > ≤ ≥ (type == != <= >=), logical ∧ ∨ ⊕ (type && || ), = assignment, ← assignment to an outer scope. The editor converts the typed forms when you open a file. The complete table is in the reference.

Angles

Angles are in degrees unless you say otherwise. #rad switches the rest of the worksheet to radians, #gra to gradians and #deg back. This matters whenever you pass π or a plain number to a trigonometric function. See Troubleshooting.

Output control

Directives shape what the report shows without changing the calculation.

#hide
k = 3
#show
a = k*2
#val
b = k*3
#equ
#nosub
c = k*4
#varsub
a = k·2 = 3 · 2 = 6
9
c = k·4 = 12

#hide … #show calculates but does not print, #val prints only the value, #nosub prints the formula without the numbers put in, #noc the formula without the result and #novar only the substituted numbers. #pre and #post split a document into the part that is filled in on screen and the part that appears in the report. The complete list is in Directives.

What the next pages cover

Related pages: Calcpad worksheets in the browser. More pages are in Calculators and guides.

Directives and commands

A directive starts with # and controls the flow of the worksheet. A command starts with $ and takes arguments in braces. In a sheet, both are written on >> lines (or inside a calcpad fence), except the ones the sheet has its own form for (if, for, while, repeat, plot).

Conditions

M = 150kN*m
#if M < 100kN*m
    'OK
#else if M < 200kN*m
    'Check again
#else
    'Too large
#end if

The condition can be any expression that gives a number: zero is false. A condition that cannot be evaluated (an undefined name, say) is an error, and the block is left unresolved: no branch runs. CalcpadCE would silently take the #else branch; see Deviations from CalcpadCE.

Loops

#repeat 3
    y = 2
#loop
#for i = 1 : 4
    #if i ≡ 3
        #continue
    #end if
    s = i
#loop
s = i = 1
s = i = 2
s = i = 4

Pass 3 is skipped by #continue.

n = 0
#while n < 3
    n = n + 1
#loop

#break leaves the loop and #continue skips to the next pass. Every line in the loop prints on every pass, so use #hide around the body when you only want the final value. The commands $Sum, $Product, $Repeat and $While do the same without printing each pass.

Macros and string variables

Macros are text substituted before the worksheet is calculated. A name ends with $.

#def twice$(a$) = 2*a$
r = twice$(7)
r = 2·7 = 14

A multi-line macro repeats a whole block with different values:

#def beam$(span$; load$)
    M = load$*span$^2/8
    V = load$*span$/2
#end def
beam$(6m; 12kN/m)
M = 12 kN/m · (6 m)² / 8 = 9 kN·m
V = 12 kN/m · 6 m / 2 = 36 kN

The macro text does not have to be valid Calcpad by itself. It is substituted first and parsed after. Unwrapped in the results views shows the text after substitution, which is the place to look when a macro misbehaves. A macro cannot contain another definition; it can use an earlier one.

Modules

#include name.cpd pulls in a file from the library (see Saving). Put shared definitions in a file with a #global section and keep the worksheet-specific part in #local: only the global part is included when the file is imported.

Constants

#const g_n = 9.81m/s^2
F = 70kg*g_n|N

A #const cannot be changed later.

Number format

#round n rounds output to n digits, #round default goes back; #format spec sets a custom format string (for example #format 0.00). The Decimals setting sets the default. #settings {"decimals": 4} overrides engine settings for the lines that follow.

Text modes

#md on and #md off turn Markdown on and off in comment lines. #markdown … #end markdown and #html … #end html switch to a block of Markdown or raw HTML, and #cpd goes back to calculation inside one.

#markdown
## Section

* one
* two
#end markdown

Reading and writing data

#read M from file.csv, #write M to file.csv and #append M to file.csv move a matrix between the worksheet and a text, CSV or Excel file in the library. Options choose the cell range (@R1C1:R2C2 for text, @Sheet1!A1:B2 for Excel), the matrix type and the separator. The full forms are in the reference.

A worksheet that writes files saves them into the library and downloads them when their content changes.

Numerical commands

#rad
f(x) = x^3 - 2*x - 5
r = $Root{f(x) @ x = 2 : 3}
A = $Area{sin(x) @ x = 0 : π}
m = $Slope{x^3 @ x = 2}
hi = $Sup{sin(x) @ x = 0 : 3}
S = $Sum{1/k^2 @ k = 1 : 100}
P = $Product{k @ k = 1 : 5}
r = $Root{f(x) = 0; x ∈ [2; 3]} = 2.09
A = ∫ sin(x) dx from 0 to π = 2
m = d/dx x³ at x = 2 = 12
hi = $Sup{sin(x); x ∈ [0; 3]} = 1
S = Σ 1/k² for k = 1 to 100 = 1.63
P = Π k for k = 1 to 5 = 120
CommandMeaning
$Root{f(x) @ x = a : b}A root of f in the interval. $Root{f(x) = c @ ...} solves f(x) = c.
$Find{f(x) @ x = a : b}An approximate solution, when the exact value is not needed.
$Sup, $InfLocal maximum or minimum.
$AreaNumerical integral (adaptive Gauss-Lobatto).
$IntegralNumerical integral (tanh-sinh).
$Slope{f(x) @ x = a}Derivative at a point.
$Sum, $ProductIterative sum and product.
$Repeat, $While, $Block, $InlineIterative expression blocks.
$Plot, $MapPlots; see Plots.

The relative precision of the numerical methods is the Precision setting (default 1e-12).

Python

#python … #end python is a Python block. In a sheet it is a fenced python block. See Python blocks.

Input forms

#UI turns an assignment into an input control. See Input forms with #UI. In a sheet, most inputs are written as L: ? 6 m lines instead; see Templates with inputs.

Not available in the browser

#pause and #input (step-by-step execution) are not supported in the web version, and neither are raster (PNG) plots or compiled .cpdz worksheets. See Deviations from CalcpadCE.

Input forms with #UI

#UI is the Calcpad language’s own input directive. It turns the assignment that follows it into an input control in Input mode: a text box, a drop-down, radio buttons, a checkbox or an editable grid.

In a sheet, most inputs do not need it. A line such as L: ? 6 m | span is an input, and the sheet compiler writes the #UI line for you. See Templates with inputs, which also covers the Input mode, saving values and sharing a template. Write #UI yourself when:

  • you work in a Calcpad worksheet (.cpd);
  • you need a data grid, a vector or matrix input, or one of the entry options below, which the ? form has no way to say.

In a sheet, a #UI line is a Calcpad line, so it starts with >>.

The input line

>> #UI 'Span, 'L = 6m
  • >> hands the line to the engine as written (leave it out in a .cpd worksheet).
  • #UI says “show the next assignment as an input control in Input mode”.
  • 'Span, 'L = 6m: an optional label ('Span, is text) and then the assignment. L = 6m is the name and the default value, with its unit.

In Preview and in a report this line shows as a plain line (Span, L = 6 m). In Input mode the 6 becomes a text box with m beside it.

What may be on the right of the =

Right-hand sideAllowedExample
A number, with or without a unitYes#UI L = 10m, #UI n = 4, #UI q = 3kN/m
A vector or matrix literalYes#UI v = [1; 2; 3], #UI M = [1; 2 | 3; 4]
vector(n) or matrix(r; c)Yes#UI Z = vector(5)
An expressionOnly with allowExpression#UI {"allowExpression": true} h = L/2
TextNo

A sheet with #UI lines

The beam check as a sheet whose inputs are #UI lines. Names such as phi or Delta_T work in a #UI line as in any other line (the first is shown as φ). A dotted name does not: a dot is the index operator.

# Beam bending check

Fill in the inputs, then read the check below.

## Inputs
>> #UI 'Span, 'L = 6m
>> #UI 'Design load, 'w = 12kN/m
>> #UI 'Yield stress, 'f_y = 300MPa
>> #UI 'Section modulus, 'Z_e = 1230000mm^3
>> #UI 'Capacity factor, 'cf = 0.9

## Check
Mstar: w * L^2 / 8 -> kN*m | maximum moment
Mcap: cf * f_y * Z_e -> kN*m | design capacity
ratio: Mstar / Mcap | utilisation
if ratio <= 1: "OK: the section passes." else: "Fails: increase the section."

Change the span to 10 and the load to 20 in the form: the moment is 250 kN·m, the ratio 0.753 and the message still reads OK.

Controls

The type property picks the control. When it is left out, the engine picks one from the right-hand side.

>> #UI {"type": "dropdown", "keys": ["Soft clay", "Stiff clay", "Dense sand"], "values": ["75kPa", "150kPa", "300kPa"]} 'Soil allowable bearing, 'q_a = 150kPa
>> #UI {"type": "radio", "keys": ["Concrete", "Steel"], "values": ["25", "78.5"]} 'Column unit weight in kN/m3, 'unit_weight = 25
>> #UI {"type": "checkbox"} 'Include footing weight (1 = yes), 'add_weight = 1
  • A drop-down or radio group shows the keys and works by the matching values entry. A value can carry its own unit, so a menu can switch units as well as magnitudes ("values": ["1m", "3.281ft"]).
  • A checkbox is 1 when ticked and 0 when not.
  • Use the ? form of a sheet for these when you can: E: ? [Steel = 200 GPa, *Timber = 11 GPa] writes this JSON for you.

A grid and a radio group together

# Column load take-down

A column carries the tributary area of each level. Choose the column material, set the sizes and fill in the floor loads, one row per level.

## Inputs
>> #UI 'Tributary area per level, 'A_t = 36m^2
>> #UI 'Column section area, 'A_c = 0.09m^2
>> #UI 'Storey height, 'H = 3.5m
>> #UI {"type": "radio", "keys": ["Concrete", "Steel"], "values": ["25", "78.5"]} 'Column unit weight in kN/m3, 'unit_weight = 25
>> #UI {"type": "datagrid", "columnHeaders": ["Dead", "Live"], "rowHeaders": ["Roof", "Level 2", "Level 1"]} loads = [20; 5 | 35; 15 | 35; 15]

## Loads at the base of the column
levels: n_rows(loads)
G_floors: sum(col(loads, 1)) * 1 kPa * A_t -> kN | dead load from the floors
Q_floors: sum(col(loads, 2)) * 1 kPa * A_t -> kN | live load from the floors
G_column: unit_weight * 1 kN/m^3 * A_c * H * levels -> kN | weight of the column
Nstar: 1.2 * (G_floors + G_column) + 1.5 * Q_floors -> kN | factored axial load

The grid is a small spreadsheet of three rows and two columns with its own headers. Its default ([20; 5 | 35; 15 | 35; 15], with | between rows) fills the cells. Click a cell, type a number and press Enter, and every line that uses loads follows. At the defaults:

levels = n_rows(loads) = 3
G_floors = sum(col(loads; 1)) · 1 kPa · A_t = ... = 3240 kN    dead load from the floors
Q_floors = sum(col(loads; 2)) · 1 kPa · A_t = ... = 1260 kN    live load from the floors
G_column = unit_weight · 1 kN/m³ · A_c · H · levels = 25 · 1 kN/m³ · 0.09 m² · 3.5 m · 3 = 23.62 kN
N_star = 1.2·(G_floors + G_column) + 1.5·Q_floors = 1.2 · (3240 kN + 23.62 kN) + 1.5 · 1260 kN = 5806.35 kN

Choose Steel: unit_weight becomes 78.5, G_column 74.18 kN and N_star 5867.02 kN.

  • A grid holds numbers only. To give them units, multiply in the sheet (* 1 kPa above) or write the units in the headers ("Dead (kPa)").
  • The grid size comes from the default value (or the rows and columns properties). Rows and columns cannot be added in the form.
  • One #UI line per name is the stable arrangement. Rename an input and a value saved under the old name is not used any more.

Entry options

A JSON object between #UI and the label sets properties:

>> #UI {"forceUnits": false} 'Line load, 'q = 3kN/m
>> #UI {"allowExpression": true} 'Half span, 'h = L/2
  • forceUnits: false puts the unit inside the box (3kN/m), so the user can type another unit.
  • allowExpression: true accepts a formula as typed, and keeps it a formula across edits. Nothing is validated as you type: an entry the engine cannot read leaves the control in place and shows the error on the line.

Both were run in the form: the first box held 3kN/m and 5kN/m gave a moment of 22.5 kN·m; the second held L/2.

All the properties

PropertyApplies toMeaning
typeallentry, datagrid, dropdown, radio, checkbox. Found from the right-hand side when omitted.
forceUnitsentry, gridDefault true: the unit stays in the document and only the number is editable.
allowExpressionentry, gridDefault false. Accepts any expression. Implies forceUnits: false.
keys, valuesdropdown, radioThe labels shown and the values used. Both are required and must be the same length.
rows, columnsgridThe grid size. A literal is cut or padded with zeros to fit.
rowHeaders, columnHeadersgridHeader labels.
width, rowHeaderWidth, columnWidthsgridSizes in pixels, or a percentage for width.
style, reportStyleallA CSS class for the control, or for its line in the report.

The ribbon’s Input/Output tab inserts a starting line for each control. In a sheet, Entry, Dropdown, Radio and Checkbox insert the ? form. Data grid and More input forms (the labelled, vector, matrix and formula forms) insert >> #UI lines.

The views, #pre and #post

#pre and #post let one file serve two audiences: an instruction (“fill in the values below”) that only the person at the form sees, and a note (“values used in this report”) that only the report carries. See the table of views in Templates with inputs. In a sheet they go in a calcpad fence:

```calcpad
#pre
'<p>Fill in the values below, then press Report.</p>
#end pre
```

In a Calcpad worksheet

A worksheet takes the lines as they are and has no renaming issue. The beam check as a .cpd:

"Beam bending check
#UI 'Span, 'L = 6m
#UI 'Design load, 'w = 12kN/m
#UI 'Yield stress, 'f_y = 300MPa
#UI 'Section modulus, 'Z_e = 1230000mm^3
#UI 'Capacity factor, 'φ = 0.9
M_star = w*L^2/8|kN*m
M_cap = φ*f_y*Z_e|kN*m
ratio = M_star/M_cap
#if ratio ≤ 1
    'OK
#else
    'Fails
#end if

In a worksheet, Save values writes the entered values into a comment on the first line, and the browser opens the form only when you press Input. The Excel export has an Inputs sheet listing the variables set by input fields.

Known limits

Workarounds for behaviour that is to be fixed. This is the only list of them on this page.

  • Superscript units and exponent notation in a #UI line. The engine’s own #UI line takes only the ^ and * spellings. 1230000mm³ is an error there (Error parsing "mm³" as units), and so is 1.23e6. Write 1230000mm^3. A ? line has no such limit: it takes mm³, kN·m, N/mm², ° and %, and writes the engine’s spelling for you.
  • A default should be one of the options. In a raw line the default of a drop-down or radio group should be one of its values. A default that matches none still shows the first label while the calculation keeps using the default, so the control and the numbers disagree. (The ? form cannot do this: its default is always one of the options.) A match is by value, so a default such as 25kN/m finds the option written 25 kN/m.
  • Two options cannot have the same value in a ? line. It is an error on that line.

Units

Video: Units and results

Units are part of the value. The engine carries them through every operation, converts between them, and stops with an error when a formula does not add up dimensionally.

Attaching units

Write the unit after a number, with or without a space: 15 kg, 12kN/m, 1230000 mm³.

a: 1.23 m + 35 cm + 12 mm -> cm
v: 10 m/s -> km/h
P: 2.5 kN / (50 mm * 200 mm) -> MPa
g0: 9.81 m/s²
m: 70 kg
W: m * g0 -> N
a = 1.23 m + 35 cm + 12 mm = 159.2 cm
v = 10 m/s = 36 km/h
P = 2.5 kN / (50 mm · 200 mm) = 0.25 MPa
g0 = 9.81 m/s²
m = 70 kg
W = m·g0 = 70 kg · 9.81 m/s² = 686.7 N

Without ->, a sum comes out in the first unit it meets. With -> unit the result is converted to the unit you choose. In the Calcpad language the same conversion is a vertical bar: a = 1.23m + 35cm + 12mm | cm.

SI base units

-> base shows a result in the SI base units of its dimensions, so you do not have to spell them out:

F: 5 kN
L: 2 m
M: F * L -> base
P: 3 MPa -> base

The moment comes out as 10000 kg·m²/s² and the pressure as 3000000 kg·m⁻¹·s⁻². The units used are kg, m, s, A, mol and cd. A value with no unit is left as it is, and so is one with a temperature or an angle in it. In the Calcpad language the same thing is M = F*L | base.

Prefixes work on every unit that takes them: kN is 10³ N, MPa is 10⁶ Pa, mm is 10⁻³ m. See “Prefixes” below for the full list.

Prefixes

Any SI prefix goes in front of any SI unit that takes one, so 3 mN, 2 GPa, 5 µm, 40 nF and 1.2 kΩ all work.

PrefixSymbolFactorPrefixSymbolFactor
yottaY10²⁴decid10⁻¹
zettaZ10²¹centic10⁻²
exaE10¹⁸millim10⁻³
petaP10¹⁵microμ, µ or u10⁻⁶
teraT10¹²nanon10⁻⁹
gigaG10⁹picop10⁻¹²
megaM10⁶femtof10⁻¹⁵
kilok10³attoa10⁻¹⁸
hectoh10²zeptoz10⁻²¹
decada10¹yoctoy10⁻²⁴

Micro can be typed as the Greek mu μ, the micro sign µ (what a keyboard gives) or a plain u; the result shows μ. The units that take a prefix are g, m, s, A, mol, cd, rad, L, N, Nm, Pa, bar, J, W, Wh, VA, VAR, Hz, V, C, F, Ω, S, Wb, T, H, Bq, Gy, Sv, lm, lx, kat, eV, Ah and Da. Everything else stays as it was: min, h, d, ft, in, lb, psi, °C and the other non-SI units take no prefix (kft and mmin are errors), the kilogram is kg (Mg is a megagram, not kkg), and kelvin K takes none either.

A name the unit list already had keeps its meaning, and the list is read first. So min is the minute (not a milli-inch), mm is the millimetre, Pa the pascal, cd the candela, ft the foot, h the hour, d the day, T the tesla and u the atomic mass unit; da alone is not a unit, and dam is the decametre. The prefix spellings that read as another unit are told apart by their case: fT is a femtotesla and ft a foot, mS is a millisiemens and ms a millisecond. One name is shadowed: ks has always been the metric horsepower, so a kilosecond is written 1000 s. A variable you define always wins over a unit of the same name, so a sheet that has a variable called mN still works.

F: 3 mN
F_n: F -> N
E: 2 GPa
E_m: E -> MPa
t: 5 µm
t_n: t -> nm
F_n = F = 3 mN = 0.003 N
E_m = E = 2 GPa = 2000 MPa
t_n = t = 5 μm = 5000 nm

Errors you want

x: 6 m
t: 2 s
speed: x / t
speed = x/t = 6 m / 2 s = 3 m/s

Dividing a length by a time is fine. Adding them is not:

x: 6 m
t: 2 s
speed: x / t
len: x + t

Error in "len = x + t" on line [4]: Inconsistent units: "m + s".

That is the engine doing its job. A unit slip is the most common mistake in hand calculations, and here it stops the sheet and names the line.

Which units exist

The built-in list is long. The groups are:

GroupExamples
Dimensionless%, ‰, ppm, angles °, rad, grad, rev
Massg, kg, t, mg, lb, oz, slug
Lengthm, km, mm, μm, in, ft, yd, mi, nmi
Time and frequencys, ms, min, h, d, Hz, rpm
ForceN, kN, MN, kgf, lbf, kip
PressurePa, kPa, MPa, bar, atm, psi, ksi
Energy and powerJ, kJ, Wh, kWh, cal, BTU, W, kW, hp
Area and volumea, ha, ac, L, mL, gal, bbl
TemperatureK, °C, °F, °R
ElectricalA, V, Ω, F, H, C, S, T, Wb
Othermol, cd, lm, lx, Bq, Gy, Sv, kat

The Insert tab in the sidebar lists all 400 or so, grouped, and a click inserts one. The Math tab has a Units palette organised by dimension.

Angles

Angle units are accepted by trigonometric functions and override every other setting. sin(30 deg) is 0.5 whatever the angle setting is. A bare number follows the setting: degrees by default, changed on the Math Formatting tab (#deg, #rad, #gra in Calcpad). Inverse trigonometric functions return a plain number unless you define ReturnAngleUnits = 1 (Calcpad line) first:

a = asin(0.5)
ReturnAngleUnits = 1
b = asin(0.5)
a = asin(0.5) = 30
ReturnAngleUnits = 1
b = asin(0.5) = 30°

Temperatures

20 °C is a temperature; 300 K is another, and the difference of two temperatures is a difference:

T1: 20 °C
T2: 300 K
d: T2 - T1
d = T2 − T1 = 300 K − 20 °C = 280 K

US and UK names

A few bare names mean different things in the US and UK systems (gal, ton, pt, qt, bbl, cwt, therm). The setting Non-metric units picks one. Write the explicit suffix (gal_US, gal_UK) when a sheet must not depend on the setting.

Percentages

A ratio has no unit, so it comes out as a plain number. Convert it with -> % to show it as a percentage, and write % after a number to enter one. ‰ (per mille) works the same way.

Ed: 245.25 kN
Rd: 355.1 kN
ratio: Ed / Rd
util: ratio -> %
r: 4%
f: Ed * r
slope: 1 / 40 -> ‰
ratio = Ed / Rd = 245.25 kN / 355.1 kN = 0.691
util = ratio = 0.691 = 69.07 %
r = 4 %
f = Ed · r = 245.25 kN · 4 % = 9.81 kN
slope = 1 / 40 = 25 ‰

The value itself does not change, only the way it is shown: util is the same number as ratio, and r is 0.04 in every formula. A result in percent is rounded to the decimals set on the Math Formatting tab like any other result, and the rounded figure typed back in (69.07%) is the same ratio to that many digits. An input works the same way: rate: ? 12.5 % shows a box holding 12.5 with % after it, and the name is 0.125 in the formulas.

A percentage times a plain number is a plain number (4 % · 2 is 0.08); add -> % to the line to keep it as a percentage.

Your own units

A sheet defines a unit of its own with a #unit line: the name, =, and its value in units the engine knows or in units defined above it. Later lines use it after a number and after ->, like any other unit.

#unit bag = 25 kg | cement bag
#unit pallet = 40 bag
load: 3 pallet -> t
n: 1000 kg -> bag
rate: 6 bag / 1 m³ -> kg/m³
bag = 25 kg   cement bag
pallet = 40 bag
load = 3 pallet = 3 t
n = 1000 kg = 40 bag
rate = 6 bag / 1 m³ = 150 kg/m³

A unit name is letters and _ only (bag, ton_short), with no digits; a name with a digit is an error on its line. The value can use the usual spellings (m², kN·m) and can have a note after |. A built-in unit cannot be redefined: #unit slug = 14.6 kg is an error, because slug is already a unit. In the Calcpad language, and in a >> line of a sheet, the same unit is a line with a dot in front of the name: .bag = 25kg.

Currency and information units are defined as dimensionless units, the first as 1 and the others as multiples:

#unit USD = 1
#unit AUD = 0.65 USD
price: 200 AUD -> USD
USD = 1
AUD = 0.65 USD
price = 200 AUD = 130 USD

Two families of dimensionless custom units in one sheet share a dimension, so do not mix them.

Units and names

A word that follows a number immediately is a unit (2 m). A standalone word is a variable if you defined one with that name, and a unit otherwise. Put a dot in front to force a unit even when a variable has the same name. In a sheet this rarely matters, but it explains one surprise: if you name a variable m and later write 5 m, the m after the number is still the unit.

Removing and reading units

The functions getunits(x), clrunits(x) and setunits(x, u) read, strip and attach units. They are in the function reference.

q: setunits(5, kN)
F: 5 kN
n: F / 1 kN
q = setunits(5; kN) = 5 kN
F = 5 kN
n = F / 1 kN = 5 kN / 1 kN = 5

Use clrunits sparingly. A value without a unit is a value the engine can no longer check.

Units in vectors and matrices

A vector or matrix whose elements all carry the same unit shows the unit once after the bracket. See Vectors and matrices.

Related pages: Calculations with units, Simply supported beam, Pipe flow, Darcy-Weisbach. More pages are in Calculators and guides.

Vectors and matrices

Writing them

In a sheet, a bracket makes a vector or a matrix. Elements are separated by commas or semicolons and rows by semicolons:

You writeYou get
[1, 2, 3] or [1; 2; 3]a vector with three elements
[1, 2; 3, 4]a 2 by 2 matrix: columns separated by commas, rows by semicolons

Rows must have equal length and elements can be expressions. (In the Calcpad language the same matrix is [1; 2 | 3; 4], with | between rows.)

v: [1, 2, 3]
A: [2, -1; -1, 2]
b: [1; 0]
x: lsolve(A, b)
d: det(A)
e: v.2
f: A.(1, 2)
v = [1; 2; 3] = [1 2 3]
A = [2; -1 | -1; 2] = | 2 -1 |
                      | -1 2 |
b = [1; 0] = [1 0]
x = lsolve(A; b) = [0.667 0.333]
d = det(A) = 3
e = v.2 = 2
f = A.(1; 2) = -1

An element is reached with a dot: v.2 is the second element of the vector v, and A.(1, 2) is row 1, column 2 of A. Indexes start at 1.

Vector and matrix names show an arrow over a vector in the report.

Arithmetic

A: [1, 2; 3, 4]
B: A * A
C: A + 2
D: A - [1, 1; 1, 1]
At: transp(A)
v: [1; 2]
Av: A * v
r: rank(A)
tr: trace(A)
B = A·A = | 7 10 |
          | 15 22 |
C = A + 2 = | 3 4 |
            | 5 6 |
Av = A·v = [5 11]
rank(A) = 2     trace(A) = 5

A matrix times a matrix is the matrix product. A matrix plus or minus a number applies to every element. A power applies to every element of a vector (x^2 above squares each element), and hprod(A, B) is the element-by-element product of two matrices.

Solving and decomposing

K: [4, -2; -2, 3]
F: [10; 0]
u: lsolve(K, F)
u = lsolve(K; F) = [3.75 2.5]

lsolve(A, b) solves A x = b with an LDLᵀ factorisation for a symmetric matrix and an LU factorisation otherwise. clsolve uses Cholesky and slsolve an iterative method for large sparse systems. msolve solves for several right-hand sides at once. inverse, det, rank, cond, lu, qr, svd, cholesky, eigenvals, eigenvecs and eigen are there too.

Eigenvalues and eigenvectors

K: [4, -2; -2, 3]
lam: eigenvals(K)
V: eigenvecs(K)
E: eigen(K)
lam = eigenvals(K) = [1.44 5.56]
V = eigenvecs(K) = | -0.615 -0.788 |
                   | -0.788  0.615 |
E = eigen(K) = | 1.44 -0.615 -0.788 |
               | 5.56 -0.788  0.615 |

eigenvals(M) returns the eigenvalues of a square matrix in ascending order. eigenvecs(M) returns one unit eigenvector per row, in the same order, and eigen(M) gives both at once with the eigenvalue in the first column. A second argument keeps only some of them: eigenvals(M, 2) is the two smallest and eigenvals(M, -1) the largest. Units carry over, so a stress tensor in MPa has principal stresses in MPa.

The matrix does not have to be symmetric:

A: [4, 1; 2, 3]
lam: eigenvals(A)
V: eigenvecs(A)
lmax: eigenvals(A, -1)
lam = eigenvals(A) = [2 5]
V = eigenvecs(A) = | -0.447 0.894 |
                   |  0.707 0.707 |
lmax = eigenvals(A; -1) = [5]

A symmetric matrix uses the symmetric solver. Any other square matrix is reduced to Hessenberg form and solved with the shifted QR iteration; each eigenvector is scaled to unit length with its largest component positive.

Complex eigenvalues

A real matrix that is not symmetric can have complex eigenvalues, which a vector cannot hold. eigenvals then stops with The matrix has complex eigenvalues. Use ceigenvals and ceigenvecs, which write each complex number as a real part and an imaginary part, the same layout fft uses:

R: [1, -2; 2, 1]
C: ceigenvals(R)
W: ceigenvecs(R)
C = ceigenvals(R) = |  1 1 |
                    | -2 2 |
W = ceigenvecs(R) = | 0.707     0 |
                    |     0 0.707 |
                    | 0.707     0 |
                    |     0 -0.707 |

Column k of ceigenvals is eigenvalue k: row 1 is the real part and row 2 the imaginary part, so the eigenvalues above are 1 - 2i and 1 + 2i. In ceigenvecs eigenvector k is row 2k - 1 (real parts) plus row 2k (imaginary parts): the first one is [0.707, 0.707i]. They are sorted by real part, then imaginary part.

For the polar form, magnitude and angle, use the two rows:

R: [1, -2; 2, 1]
C: ceigenvals(R)
mag: sqrt(row(C, 1)^2 + row(C, 2)^2)
ang: atan2(row(C, 1), row(C, 2))
mag = [2.24 2.24]
ang = atan2(row(C; 1); row(C; 2)) = [-63.43 63.43]

In a Calcpad document with complex numbers switched on in Settings, #phasor shows every complex result as magnitude∠angle, and #complex switches back to a + bi.

Natural frequencies: K x = λ M x

Give eigenvals, eigenvecs or eigen a second matrix and they solve the generalized problem K x = λ M x. With a stiffness matrix K and a mass matrix M, each λ is ω², the square of a natural circular frequency:

k: 20000 kN/m
m: 10 t
K: [2*k, -k; -k, k]
M: [2*m, 0 t; 0 t, m]
λ: eigenvals(K, M)
f_1: sqrt(λ.1)/(2*π) -> Hz
Phi: eigenvecs(K, M)
m_1: dot(row(Phi, 1), M*row(Phi, 1))
λ = eigenvals(K; M) = [585.79 3414.21] s⁻²
f_1 = 3.85 Hz
Φ = eigenvecs(K; M) = |  0.158 0.224 | t^-0.5
                      | -0.158 0.224 |
m_1 = 1

K must be symmetric and M symmetric positive definite, both square and the same size; anything else stops with a message that says which matrix is wrong. The eigenvalues come in ascending order with the units of K/M (kN/m over t is s⁻²). Each mode shape is a row of eigenvecs(K, M), scaled so that xᵀ M x = 1 and turned so that its largest component is positive; its units are those of M^-0.5, so the modal mass m_1 above is exactly 1. Divide a row by one of its components to scale it to 1 at that point instead. Internally M is factored by Cholesky (M = L Lᵀ), the problem is turned into the symmetric one of L⁻¹ K L⁻ᵀ, solved with the symmetric solver, and transformed back. To keep only the lowest modes, take them from the result: first(eigenvals(K, M), 3).

The samples Principal stresses (a plane and a 3D stress tensor, checked with Mohr’s circle) and Shear frame natural frequencies (the frequencies and mode shapes of a two storey frame from eigenvals(K, M)) use these functions.

Building vectors and matrices

x: range(0, 10, 2.5)
y: x^2
s: sum(y)
mx: max(y)
w: linspace(0, 1, 5)
x = range(0; 10; 2.5) = [0 2.5 5 7.5 10]
y = x ^ 2 = [0 6.25 25 56.25 100]
s = sum(y) = 187.5
mx = max(y) = 100
w = linspace(0; 1; 5) = [0 0.25 0.5 0.75 1]

Constructors: vector(n), matrix(m, n), identity(n), diagonal(n, d), column(m, c), utriang(n), ltriang(n), symmetric(n), join_cols, join_rows, augment, stack. Pieces: row, col, submatrix, slice, first, last, extract, diag2vec. Sorting and searching: sort, rsort, order, find, lookup, hlookup, vlookup. Statistics and interpolation: average, median, stdev, var, take, line, spline, interp, linterp, polyfit.

A2: [1, 2, 3; 4, 5, 6]
r1: row(A2, 1)
c2: col(A2, 2)
sm: submatrix(A2, 1, 2, 2, 3)
r1 = row(A2; 1) = [1 2 3]
c2 = col(A2; 2) = [2 5]
sm = submatrix(A2; 1; 2; 2; 3) = | 2 3 |
                                 | 5 6 |

The whole list is in the function reference. The large high-performance variants (matrix_hp and so on) are for big numerical models: they store the numbers more compactly and are faster, and they behave like the ordinary ones in a calculation.

Units in vectors and matrices

A vector or matrix whose elements all have the same unit shows the unit once, after the closing bracket:

P: [16 ft; 12 ft]
Q: [3 m; 40 cm]
P = [16; 12] ft = [16 12] ft
Q = [3 m; 40 cm] = [3 0.4] m

Elements in another unit of the same dimension are converted to the first element’s unit in the result. An element that is an expression, has no unit, or has another dimension keeps its own unit. To write the unit on every element, put a >> line in the sheet:

>> #settings {"unitPerElement": true}
P: [16 ft; 12 ft]

You cannot write a unit after a bracket ([1, 2] kN). Put it on the elements.

Reading and writing files

#read brings a matrix in from a text, CSV or Excel file in the library, and #write and #append save one. They are Calcpad directives, so in a sheet they are >> lines:

>> #read M from loads.csv
>> #write M to results.csv

Add the files to the library first (File > Open, or drag them onto the page). The options for cell ranges and separators are in the directive list.

Related calculators: Principal stresses, Principal axes of a section, Shear frame frequencies. More pages are in Calculators and guides.

Function and command reference

This page is generated from the editor’s own snippet library (book/gen-reference.py), so it lists what the Insert tab and the ribbon offer. In the Calcpad language, arguments are separated with ;, as shown here. In a sheet, write commas: max(a, b).

Names are case sensitive. Greek letters, subscripts (x_1) and primes can be part of a name.

Constants

π (also pi) and e are built in. The others are snippets that insert a definition line; until the line is in the worksheet the name means whatever it meant before (g is the unit gram).

FormMeaning
πPi - ratio of circumference to diameter
piPi - ratio of circumference to diameter (spelled out)
eEuler’s number - base of natural logarithm
φ = 1.618033988749894Golden ratio
γ = 0.5772156649015328Euler-Mascheroni constant
g = 9.80665m/s^2Standard gravitational acceleration
G = 6.67430*10^-11*(m^3/(kg*s^2))Gravitational constant
M_E = 5.9722*10^24*kgEarth mass
M_S = 1.98847*10^30*kgSolar mass
c = 299792458m/sSpeed of light in vacuum
h = 6.62607015*10^-34*J/HzPlanck constant
μ_0 = 1.25663706212*10^-6*N/A^2Vacuum permeability
ε_0 = 8.8541878128*10^-12*F/mVacuum permittivity
k_e = 8.9875517923*10^9*N*m^2/C^2Coulomb constant
e = 1.602176634*10^-19*CElementary charge
m_e = 9.1093837015*10^-31*kgElectron mass
m_p = 1.67262192369*10^-27*kgProton mass
m_n = 1.67492749804*10^-27*kgNeutron mass
N_A = 6.02214076*10^23*mol^-1Avogadro constant
σ = 5.670374419*10^-8*W*m^-2*K^-4Stefan-Boltzmann constant
k_B = 1.380649*10^-23*J/KBoltzmann constant
R = 8.31446261815324*(J/(mol*K))Molar gas constant
F = 96485.33212331C/molFaraday constant
γ_c = 25kN/m^3Unit weight of concrete
γ_s = 78.5kN/m^3Unit weight of steel
γ_a = 27kN/m^3Unit weight of aluminium
γ_g = 25kN/m^3Unit weight of glass
γ_w = 10kN/m^3Unit weight of water

Operators

Where a typed alternative exists it is given; the editor converts it when a file is opened.

FormMeaning
!Factorial
^Exponent (power)
/Division
÷Division bar (inline) / slash (pro mode)
\Integer division
⦼Modulo (remainder) (type %%)
*Multiplication
-Subtraction / Negation
+Addition
≡Equal to (type ==)
≠Not equal to (type !=)
<Less than
>Greater than
≤Less than or equal (type <=)
≥Greater than or equal (type >=)
∧Logical AND (type &&)
∨Logical OR (type ||)
⊕Logical XOR
∠Phasor angle operator A∠φ (type <<)
=Assignment
←Outer scope assignment (type <*)

Functions

Trigonometric

FormMeaning
sin(x)Sine
cos(x)Cosine
tan(x)Tangent
csc(x)Cosecant
sec(x)Secant
cot(x)Cotangent

Inverse Trigonometric

FormMeaning
asin(x)Inverse sine (arc sine)
acos(x)Inverse cosine (arc cosine)
atan(x)Inverse tangent (arc tangent)
atan2(a; b)Two-argument arc tangent
acsc(x)Inverse cosecant
asec(x)Inverse secant
acot(x)Inverse cotangent

Hyperbolic

FormMeaning
sinh(x)Hyperbolic sine
cosh(x)Hyperbolic cosine
tanh(x)Hyperbolic tangent
csch(x)Hyperbolic cosecant
sech(x)Hyperbolic secant
coth(x)Hyperbolic cotangent

Inverse Hyperbolic

FormMeaning
asinh(x)Inverse hyperbolic sine
acosh(x)Inverse hyperbolic cosine
atanh(x)Inverse hyperbolic tangent
acsch(x)Inverse hyperbolic cosecant
asech(x)Inverse hyperbolic secant
acoth(x)Inverse hyperbolic cotangent

Logarithmic, Exponential and Roots

FormMeaning
log(x)Decimal (base-10) logarithm
ln(x)Natural logarithm
log_2(x)Binary (base-2) logarithm
exp(x)Exponential function (e^x)
sqr(x)Square root
sqrt(x)Square root
cbrt(x)Cubic root
root(a; b)N-th root

Rounding

FormMeaning
round(x)Round to the nearest integer
floor(x)Round down (towards -∞)
ceiling(x)Round up (towards +∞)
trunc(x)Truncate towards zero

Integer

FormMeaning
mod(a; b)Remainder of integer division
gcd(a; b)Greatest common divisor
lcm(a; b)Least common multiple
fact(x)Factorial

Complex

FormMeaning
re(x)Real part of a complex number
im(x)Imaginary part of a complex number
abs(x)Absolute value / magnitude
phase(x)Phase angle of a complex number
conj(x)Complex conjugate

Aggregate and Interpolation

FormMeaning
min(v₁; v₂; ...)Minimum of multiple values (scalars, vectors, or matrices)
min(x)Minimum element of a vector
min(x)Minimum element of a matrix
max(v₁; v₂; ...)Maximum of multiple values (scalars, vectors, or matrices)
max(x)Maximum element of a vector
max(x)Maximum element of a matrix
sum(v₁; v₂; ...)Sum of multiple values (scalars, vectors, or matrices)
sum(x)Sum of all elements in a vector
sum(x)Sum of all elements in a matrix
sumsq(v₁; v₂; ...)Sum of squares of multiple values (scalars, vectors, or matrices)
sumsq(x)Sum of squares of all elements in a vector
sumsq(x)Sum of squares of all elements in a matrix
srss(v₁; v₂; ...)Square root of sum of squares of multiple values (scalars, vectors, or matrices)
srss(x)Square root of sum of squares of all elements in a vector
srss(x)Square root of sum of squares of all elements in a matrix
average(v₁; v₂; ...)Arithmetic mean of multiple values (scalars, vectors, or matrices)
average(x)Arithmetic mean of all elements in a vector
average(x)Arithmetic mean of all elements in a matrix
product(v₁; v₂; ...)Product of multiple values (scalars, vectors, or matrices)
product(x)Product of all elements in a vector
product(x)Product of all elements in a matrix
mean(v₁; v₂; ...)Geometric mean of multiple values (scalars, vectors, or matrices)
mean(x)Geometric mean of all elements in a vector
mean(x)Geometric mean of all elements in a matrix
median(v₁; v₂; ...)Median of multiple values (scalars, vectors, or matrices)
stdev(v₁; v₂; ...)Sample standard deviation (n - 1) of multiple values
stdevp(v₁; v₂; ...)Population standard deviation (n) of multiple values
var(v₁; v₂; ...)Sample variance (n - 1) of multiple values
varp(v₁; v₂; ...)Population variance (n) of multiple values
take(a; b)Returns the n-th element from a list of scalars
take(a; b)Returns the n-th element from a vector
take(a; b)Returns the n-th element from a matrix
line(a; b)Linear interpolation with scalar data pairs
line(a; b; c)Linear interpolation with x and y vectors
line(a; b)Linear interpolation over a linearized matrix
spline(a; b)Hermite spline interpolation with scalar data pairs
spline(a; b; c)Hermite spline interpolation with x and y vectors
spline(a; b)Hermite spline interpolation over a linearized matrix

Conditional and Logical

FormMeaning
if(a; b; c)Conditional evaluation
switch(c₁; v₁; c₂; v₂; …; def)Selective evaluation (multiple conditions)
not(x)Logical NOT
and(a; b)Logical AND of multiple boolean values
or(a; b)Logical OR of multiple boolean values
xor(a; b)Logical XOR of multiple boolean values

Other

FormMeaning
sign(x)Sign of a number (-1, 0, or 1)
random(x)Random number between 0 and x
getunits(x)Gets the units of x (returns 1 if unitless)
setunits(a; b)Sets the units to a scalar, vector, or matrix
clrunits(x)Clears the units from a scalar, vector, or matrix
hp(x)Converts to high-performance type
ishp(x)Checks if the type is high-performance
timer(x)Elapsed time in seconds
mandelbrot(a; b)Mandelbrot set escape value

Vector functions

Creational

FormMeaning
vector(x)Creates an empty vector with length n
vector_hp(x)Creates an empty high-performance vector with length n
range(a; b; c)Creates a vector with values from x1 to xn with step s
range_hp(a; b; c)Creates a high-performance vector from a range
linspace(a; b; c)Vector of n equally spaced values from a to b

Structural

FormMeaning
len(x)Returns the length of the vector
size(x)Returns the actual size (index of last non-zero element)
resize(a; b)Sets a new length for the vector
fill(a; b)Fills the vector with a value
join(x)Creates a vector by joining matrices, vectors, and scalars
slice(a; b; c)Returns part of vector bounded by indexes i1 and i2
first(a; b)Returns the first n elements of the vector
last(a; b)Returns the last n elements of the vector
extract(a; b)Extracts elements from v whose indexes are in i

Data

FormMeaning
sort(x)Sorts the vector in ascending order
rsort(x)Sorts the vector in descending order
order(x)Returns indexes in ascending order by element values
revorder(x)Returns indexes in descending order by element values
reverse(x)Returns vector with elements in reverse order
count(a; b; c)Counts elements equal to x starting from index i
search(a; b; c)Returns index of first element equal to x starting from i
find(a; b; c)Returns indexes of elements equal to x after index i
find_eq(a; b; c)Returns indexes of elements = x after index i
find_ne(a; b; c)Returns indexes of elements != x after index i
find_lt(a; b; c)Returns indexes of elements < x after index i
find_le(a; b; c)Returns indexes of elements <= x after index i
find_gt(a; b; c)Returns indexes of elements > x after index i
find_ge(a; b; c)Returns indexes of elements >= x after index i
lookup(a; b; c)Elements of a where corresponding elements of b equal x
lookup_eq(a; b; c)Elements of a where b elements = x
lookup_ne(a; b; c)Elements of a where b elements != x
lookup_lt(a; b; c)Elements of a where b elements < x
lookup_le(a; b; c)Elements of a where b elements <= x
lookup_gt(a; b; c)Elements of a where b elements > x
lookup_ge(a; b; c)Elements of a where b elements >= x
polyfit(a; b; c)Least-squares polynomial fit
interp(a; b; c)Linear interpolation in a table
linterp(a; b; c)Linear interpolation in a table, continued outside it

Math

FormMeaning
norm(x)L2 (Euclidean) norm of vector
norm_1(x)L1 (Manhattan) norm of vector
norm_2(x)L2 (Euclidean) norm of vector
norm_e(x)L2 (Euclidean) norm of vector
norm_p(a; b)Lp norm of vector
norm_i(x)L-infinity norm of vector
unit(x)Normalized vector (with L2 norm = 1)
cumsum(x)Running sum of a vector
convolve(a; b)Discrete convolution of two vectors
dot(a; b)Scalar (dot) product of two vectors
cross(a; b)Cross product of two vectors (length 2 or 3)

Matrix functions

Functions marked _hp use the high-performance storage; they behave like the ordinary ones.

Creational

FormMeaning
matrix(a; b)Creates an empty matrix with dimensions m x n
identity(x)Creates an identity matrix with dimensions n x n
diagonal(a; b)Creates a diagonal matrix n x n filled with value d
column(a; b)Creates a column matrix m x 1 filled with value c
utriang(x)Creates an upper triangular matrix n x n
ltriang(x)Creates a lower triangular matrix n x n
symmetric(x)Creates a symmetric matrix n x n
matrix_hp(a; b)Creates a high-performance matrix m x n
identity_hp(x)Creates a high-performance identity matrix n x n
diagonal_hp(a; b)Creates a high-performance diagonal matrix n x n
column_hp(a; b)Creates a high-performance column matrix m x 1
utriang_hp(x)Creates a high-performance upper triangular matrix
ltriang_hp(x)Creates a high-performance lower triangular matrix
symmetric_hp(x)Creates a high-performance symmetric matrix
vec2diag(x)Creates a diagonal matrix from vector elements
vec2row(x)Creates a row matrix from vector elements
vec2col(x)Creates a column matrix from vector elements
join_cols(a; b)Creates a matrix by joining column vectors
join_rows(a; b)Creates a matrix by joining row vectors
augment(a; b)Creates a matrix by appending matrices side by side
stack(a; b)Creates a matrix by stacking matrices vertically

Structural

FormMeaning
n_rows(x)Number of rows in matrix M
n_cols(x)Number of columns in matrix M
mresize(a; b; c)Sets new dimensions m and n for matrix M
mfill(a; b)Fills the matrix M with value x
fill_row(a; b; c)Fills the i-th row of matrix M with value x
fill_col(a; b; c)Fills the j-th column of matrix M with value x
copy(a; b; c; d)Copies all elements from A to B starting at indexes i, j
add(a; b; c; d)Adds elements from A to B starting at indexes i, j
row(a; b)Extracts the i-th row of matrix M as a vector
col(a; b)Extracts the j-th column of matrix M as a vector
extract_rows(a; b)Extracts rows from M whose indexes are in vector i
extract_cols(a; b)Extracts columns from M whose indexes are in vector j
diag2vec(x)Extracts diagonal elements of matrix M to a vector
submatrix(a; b; c; d; e)Extracts submatrix bounded by rows i1-i2 and columns j1-j2

Data

FormMeaning
sort_cols(a; b)Sorts columns based on values in row i (ascending)
rsort_cols(a; b)Sorts columns based on values in row i (descending)
sort_rows(a; b)Sorts rows based on values in column j (ascending)
rsort_rows(a; b)Sorts rows based on values in column j (descending)
order_cols(a; b)Column indexes in ascending order by row i values
revorder_cols(a; b)Column indexes in descending order by row i values
order_rows(a; b)Row indexes in ascending order by column j values
revorder_rows(a; b)Row indexes in descending order by column j values
mcount(a; b)Number of occurrences of value x in matrix M
msearch(a; b; c; d)Vector with indexes of first occurrence of x starting from i, j
mfind(a; b)Indexes of all elements in M equal to x
mfind_eq(a; b)Indexes of elements = x
mfind_ne(a; b)Indexes of elements != x
mfind_lt(a; b)Indexes of elements < x
mfind_le(a; b)Indexes of elements <= x
mfind_gt(a; b)Indexes of elements > x
mfind_ge(a; b)Indexes of elements >= x
hlookup(a; b; c; d)Values from row i2 where row i1 elements = x
hlookup_eq(a; b; c; d)Values from row i2 where row i1 = x
hlookup_ne(a; b; c; d)Values from row i2 where row i1 != x
hlookup_lt(a; b; c; d)Values from row i2 where row i1 < x
hlookup_le(a; b; c; d)Values from row i2 where row i1 <= x
hlookup_gt(a; b; c; d)Values from row i2 where row i1 > x
hlookup_ge(a; b; c; d)Values from row i2 where row i1 >= x
vlookup(a; b; c; d)Values from column j2 where column j1 = x
vlookup_eq(a; b; c; d)Values from column j2 where column j1 = x
vlookup_ne(a; b; c; d)Values from column j2 where column j1 != x
vlookup_lt(a; b; c; d)Values from column j2 where column j1 < x
vlookup_le(a; b; c; d)Values from column j2 where column j1 <= x
vlookup_gt(a; b; c; d)Values from column j2 where column j1 > x
vlookup_ge(a; b; c; d)Values from column j2 where column j1 >= x

Math

FormMeaning
hprod(a; b)Hadamard (element-wise) product of matrices A and B
fprod(a; b)Frobenius product of matrices A and B
kprod(a; b)Kronecker product of matrices A and B
mnorm(x)L2 norm of matrix M
mnorm_1(x)L1 norm of matrix M
mnorm_2(x)L2 norm of matrix M
mnorm_e(x)Frobenius norm of matrix M
mnorm_i(x)L-infinity norm of matrix M
cond(x)Condition number based on L2 norm
cond_1(x)Condition number based on L1 norm
cond_2(x)Condition number based on L2 norm
cond_e(x)Condition number based on Frobenius norm
cond_i(x)Condition number based on L-infinity norm
det(x)Determinant of matrix M
rank(x)Rank of matrix M
trace(x)Trace of matrix M (sum of diagonal elements)
transp(x)Transpose of matrix M
adj(x)Adjugate of matrix M
cofactor(x)Cofactor matrix of M
polyroots(x)Real roots of a polynomial
eigenvals(a; b)First ne eigenvalues of matrix M (or all if omitted), or of K x = λ M x
eigenvecs(a; b)First ne eigenvectors of matrix M (or all if omitted), or of K x = λ M x
eigen(a; b)First ne eigenvalues and eigenvectors (or all if omitted)
ceigenvals(x)Complex eigenvalues of matrix M
ceigenvecs(x)Complex eigenvectors of matrix M
cholesky(x)Cholesky decomposition of symmetric positive-definite matrix
lu(x)LU decomposition of matrix M
qr(x)QR decomposition of matrix M
svd(x)Singular value decomposition of M
inverse(x)Inverse of matrix M
lsolve(a; b)Solves Ax = b using LDLT (symmetric) or LU decomposition
clsolve(a; b)Solves Ax = b using Cholesky decomposition
slsolve(a; b)Solves Ax = b using preconditioned conjugate gradient
msolve(a; b)Solves AX = B using LDLT or LU decomposition
cmsolve(a; b)Solves AX = B using Cholesky decomposition
smsolve(a; b)Solves AX = B using preconditioned conjugate gradient
fft(x)Fast Fourier transform (1 row for real, 2 for complex)
ift(x)Inverse Fourier transform (1 row for real, 2 for complex)
take(a; b; c)Returns element of matrix M at indexes x and y
line(a; b; c)Double linear interpolation from matrix M
spline(a; b; c)Double Hermite spline interpolation from matrix M

Commands

Commands start with $ and take their arguments in braces. @ separates the expression from the variable and its interval a : b. In a sheet, write them on a >> line, except plots, which have the plot line.

FormMeaning
$Root{a @ b = c : d}Root finding for f(x) = 0
$Root{a = b @ c = d : e}Root finding for f(x) = const
$Find{a @ b = c : d}Find approximate solution (x not required to be precise)
$Sup{a @ b = c : d}Find local maximum of a function
$Inf{a @ b = c : d}Find local minimum of a function
$Area{a @ b = c : d}Numerical integration (adaptive Gauss-Lobatto)
$Integral{a @ b = c : d}Numerical integration (Tanh-Sinh)
$Slope{a @ b = c}Numerical differentiation (slope at point)
$Sum{a @ b = c : d}Iterative sum
$Product{a @ b = c : d}Iterative product
$Repeat{a @ b = c : d}Iterative expression block with counter
$While{a; b}Iterative expression block with condition
$Block{x}Multiline expression block
$Inline{x}Inline expression block
$Plot{a @ b = c : d}Simple function plot
$Plot{a | b @ c = d : e}Parametric plot
$Plot{a & b @ c = d : e}Multiple function plot
$Map{a @ b = c : d & e = f : g}2D color map of a 3D surface

Directives

Directives start with #. The block forms (#if … #end if) are listed once, by their opening word.

Program Flow Control

FormMeaning
#ifIf condition
#else if conditionElse If clause
#elseElse clause

Iteration Blocks

FormMeaning
#repeatRepeat loop start
#forFor loop start
#whileWhile loop start
#loopEnd of loop block
#breakBreak out of current loop
#continueContinue to next iteration

Modules and Macros

FormMeaning
#include filenameInclude external file (module). Path is relative to the current file or the library path.
#ProjectPath pathDeclares the folder {project} stands for in #include, #read, #write and image paths below this line.
#LibraryPath pathDeclares the folder {library} stands for in #include, #read, #write and image paths below this line.
#localStart local section (not included when file is imported)
#globalStart global section (included when file is imported)
#defDefine macro or string variable
#def name$ = expressionInline string variable definition
#def name$(param$) = expressionInline macro with parameters

External Data

FormMeaning
#read M from filenameRead matrix from text/CSV or Excel file
#read M from filename.csv@R1C1:R2C2 TYPE=R SEP=','Read matrix from a CSV/text file with all options. @R1C1:R2C2 = cell range (row, column). TYPE: R=Raw (default), D=Diagonal, C=Column, L=Lower triangular, U=Upper triangular, S=Symmetric, V=Vector. SEP: column separator character (default ‘,’).
#read M from filename.xlsx@Sheet1!A1:B2 TYPE=RRead matrix from an Excel file (.xlsx/.xlsm) with all options. @Sheet!A1:B2 = sheet name and cell range. TYPE: R=Raw (default), D=Diagonal, C=Column, L=Lower triangular, U=Upper triangular, S=Symmetric, V=Vector.
#write M to filenameWrite matrix to text/CSV or Excel file
#write M to filename.csv@R1C1:R2C2 TYPE=N SEP=','Write matrix to a CSV/text file with all options. @R1C1:R2C2 = cell range (row, column). TYPE: Y=Compact (transpose special matrix types), N=Normal (default). SEP: column separator character (default ‘,’).
#write M to filename.xlsx@Sheet1!A1:B2 TYPE=NWrite matrix to an Excel file (.xlsx/.xlsm) with all options. @Sheet!A1:B2 = sheet name and cell range. TYPE: Y=Compact (transpose special matrix types), N=Normal (default).
#append M to filenameAppend matrix to text/CSV or Excel file
#append M to filename.csv@R1C1:R2C2 TYPE=N SEP=','Append matrix to a CSV/text file with all options. @R1C1:R2C2 = cell range (row, column). TYPE: Y=Compact (transpose special matrix types), N=Normal (default). SEP: column separator character (default ‘,’).
#append M to filename.xlsx@Sheet1!A1:B2 TYPE=NAppend matrix to an Excel file (.xlsx/.xlsm) with all options. @Sheet!A1:B2 = sheet name and cell range. TYPE: Y=Compact (transpose special matrix types), N=Normal (default).

Read Only

FormMeaning
#constDefine a constant (readonly) variable or function
#const name = valueDefine a constant variable
#const f(x) = expressionDefine a constant function

Output Control

FormMeaning
#showShow the output contents (default). Optionally takes a condition, e.g. ‘#show x == 5’. Applies to the rest of the document, or up to a matching #end show.
#hideHide the output contents. Optionally takes a condition, e.g. ‘#hide x == 5’. Applies to the rest of the document, or up to a matching #end hide.
#preShow contents on screen only - hidden when printing/exporting to PDF. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end pre.
#postShow contents in the preview and when printing/exporting to PDF - hidden in UI mode. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end post.
#valShow only the result, without the equation. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end val.
#equShow complete equations and results (default). Optionally takes a condition. Applies to the rest of the document, or up to a matching #end equ.
#nocShow equations without results (no calculations). Optionally takes a condition. Applies to the rest of the document, or up to a matching #end noc.
#varsubShow equations with both variable names and their substituted values (default). Optionally takes a condition. Applies to the rest of the document, or up to a matching #end varsub.
#nosubShow equations with variable names only, without substituted values. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end nosub.
#novarShow equations with substituted values only, without variable names. Optionally takes a condition. Applies to the rest of the document, or up to a matching #end novar.
#splitSplit long equations after the “=” symbol onto a new indented line. Applies to the rest of the document; takes no condition and has no #end form - switch back with #wrap.
#wrapWrap long equations at the end of the line (default). Applies to the rest of the document; takes no condition and has no #end form - switch back with #split.
#format specSpecify custom format string
#format defaultRestore default formatting
#phasorSet complex number output to polar phasor (A angle phi)
#complexSet complex number output to cartesian algebraic (a + ib)
#md onEnable markdown in comments
#md offDisable markdown in comments
#htmlOutput the following lines as raw HTML. Only #cpd, #markdown and the #end forms are allowed inside; macros still expand. Optionally takes a condition, e.g. ‘#html x > 3’, that skips the block when false. Applies up to a matching #end html, or until the next mode directive.
#markdownRender the following lines as Markdown, including tables, lists and code blocks. Only #cpd, #html and the #end forms are allowed inside; macros still expand. Optionally takes a condition, e.g. ‘#markdown x > 3’, that skips the block when false. Applies up to a matching #end markdown, or until the next mode directive.
#cpdParse the following lines as Calcpad (the default mode), e.g. to calculate inside an #html block. Optionally takes a condition, e.g. ‘#cpd x > 3’, that skips the block when false. Applies up to a matching #end cpd, or until the next mode directive.

UI Inputs

FormMeaning
#UI L = 10mExpose the following assignment as an input control in UI mode. Ignored when rendering a report.
#UI {"type": "datagrid", "rows": 2, "columns": 3, "columnHeaders": ["a", "b", "c"]} M = [1; 2; 3 | 4; 5; 6]Editable grid for a vector or matrix. Rows and columns are auto-detected from the right hand side when omitted.
#UI v = [1; 2; 3]Editable grid whose size is auto-detected from the vector or matrix assigned to it.
#UI {"type": "datagrid", "width": "100%", "rowHeaderWidth": 120, "columnWidths": [2, 1, 1]} M = matrix(2; 3)Sized grid. ‘width’ is the total in pixels or “100%” to fill the line; ‘columnWidths’ are shared out in proportion.
#UI {"forceUnits": false} q = 3kN/mPut the unit in the input box, so the whole value - number and unit - is editable.
#UI {"allowExpression": true} k = 2*LAccept any expression, written to the document as typed. The line’s own errors report what it cannot read.
#UI {"type": "dropdown", "keys": ["Low", "High"], "values": ["1", "2"]} x = 1Drop-down list. ‘keys’ are the labels shown, ‘values’ are substituted into the calculation.
#UI {"type": "radio", "keys": ["Steel", "Concrete"], "values": ["200GPa", "25GPa"]} E = 200GPaRadio button group. ‘keys’ are the labels shown, ‘values’ are substituted into the calculation.
#UI {"type": "checkbox"} b = 1Checkbox toggling the value between 1 and 0.

Settings/Rounding

FormMeaning
#round digitsRound output to n digits after decimal point
#round defaultRestore rounding to default settings

Settings/Overrides

FormMeaning
#settings {"decimals": 4, "substitute": false}Override engine settings for subsequent lines via JSON. Use the Properties panel to see the available settings and edit them.

Breakpoints

FormMeaning
#pausePause calculation and wait for user to resume. Not supported in Calcpad.Web.
#inputRender input form and wait for user input. Not supported in Calcpad.Web.

Settings/Angle Units

FormMeaning
#degSet angle units to degrees
#radSet angle units to radians
#graSet angle units to gradians

Worksheet settings

Written as an assignment on a line of their own. In a sheet, use a >> line.

FormMeaning
PlotHeight = 400Height of plot area in pixels
PlotWidth = 800Width of plot area in pixels
PlotSVG = 1Draw plots in SVG (1) or PNG (0) format
PlotAdaptive = 1Use adaptive mesh (1) or uniform (0)
PlotStep = 0Mesh size for map plotting
PlotPalette = 0Color palette number (0-9) for surface plots
PlotShadows = 1Draw surface plots with shadows
PlotSmooth = 1Smooth gradient (1) or isobands (0) for surface plots
PlotLightDir = 0Direction to light source (0-7) clockwise
Precision = 1e-12Relative precision for numerical methods (10^-2 to 10^-16)
Tol = 1e-8Target tolerance for iterative PCG solver

Number format strings

Used after #format, or at the end of an equation to format one result.

FormMeaning
:eExponential notation, default precision
:e3Exponential notation with 3 mantissa digits
:fFixed-point notation, default precision
:f3Fixed-point notation with 3 decimal digits
:gGeneral notation, default precision
:g3General notation with 3 significant digits
:nNumber with digit grouping, default precision
:n3Number with digit grouping and 3 decimal digits
:cCurrency notation, default precision
:c3Currency notation with 3 decimal digits
:0.000Custom format - fixed decimal places, zero-padded
:#,#.00Custom format - digit grouping with optional leading digits
:0.00e+00Custom format - explicit exponential notation

Units

The predefined units by group. Prefixes (k, M, G, m, μ and so on) are listed where they apply. The names, not the descriptions, are what you type.

  • Dimensionless: %, ‰, ‱, pcm, ppm, ppb, ppt, ppq
  • Angles: °, ′, ″, deg, rad, grad, rev
  • Metric/Mass: g, dag, hg, kg, t, kt, Mt, Gt, dg, cg, mg, μg, ng, pg, Da, u
  • Metric/Length: m, km, dm, cm, mm, μm, nm, pm, AU, ly
  • Metric/Area: a, daa, ha
  • Metric/Volume: L, daL, hL, dL, cL, mL, μL, nL, pL
  • Time: s, ms, μs, ns, ps, min, h, d, w, y
  • Frequency: Hz, kHz, MHz, GHz, THz, mHz, μHz, nHz, pHz, rpm
  • Speed: kmh
  • Temperature: °C, Δ°C, K
  • Metric/Force: N, daN, hN, kN, MN, GN, TN, gf, kgf, tf, dyn
  • Metric/Moment: Nm, kNm
  • Metric/Pressure: Pa, daPa, hPa, kPa, MPa, GPa, TPa, dPa, cPa, mPa, μPa, nPa, pPa, bar, mbar, μbar, atm, at, Torr, mmHg
  • Metric/Viscosity: P, cP, St, cSt
  • Metric/Energy: J, kJ, MJ, GJ, TJ, mJ, μJ, nJ, pJ, Wh, kWh, MWh, GWh, TWh, mWh, μWh, nWh, pWh, VAh, kVAh, MVAh, GVAh, VARh, kVARh, MVARh, GVARh, eV, keV, MeV, GeV, TeV, PeV, EeV, cal, kcal, erg
  • Metric/Power: W, kW, MW, GW, TW, mW, μW, nW, pW, VA, kVA, MVA, GVA, TVA, mVA, μVA, nVA, pVA, VAR, kVAR, MVAR, GVAR, TVAR, mVAR, μVAR, nVAR, pVAR
  • Electrical/Current: A, kA, MA, GA, TA, mA, μA, nA, pA
  • Electrical/Charge: C, kC, MC, GC, TC, mC, μC, nC, pC, Ah, mAh
  • Electrical/Potential: V, kV, MV, GV, TV, mV, μV, nV, pV
  • Electrical/Capacitance: F, kF, MF, GF, TF, mF, μF, nF, pF
  • Electrical/Resistance: Ω, kΩ, MΩ, GΩ, TΩ, mΩ, μΩ, nΩ, pΩ
  • Electrical/Conductance: S, kS, MS, GS, TS, mS, μS, nS, pS, ℧, k℧, M℧, G℧, T℧, m℧, μ℧, n℧, p℧
  • Electrical/Magnetic Flux: Wb, kWb, MWb, GWb, TWb, mWb, μWb, nWb, pWb
  • Electrical/Magnetic Flux Density: T, kT, MT, GT, TT, mT, μT, nT, pT
  • Electrical/Inductance: H, kH, MH, GH, TH, mH, μH, nH, pH
  • Luminous: cd, lm, lx
  • Radioactivity: Bq, kBq, MBq, GBq, TBq, mBq, μBq, nBq, pBq, Ci, Rd
  • Dose/Absorbed: Gy, kGy, MGy, GGy, TGy, mGy, μGy, nGy, pGy
  • Dose/Equivalent: Sv, kSv, MSv, GSv, TSv, mSv, μSv, nSv, pSv
  • Catalytic Activity: kat
  • Amount of Substance: mol
  • Imperial/Mass: gr, dr, oz, lb, lbm, lb_m, kipm, kip_m, klb, st, qr, cwt, cwt_US, cwt_UK, ton, ton_US, ton_UK, slug
  • Imperial/Length: th, in, ft, yd, ch, fur, mi, ftm, ftm_UK, ftm_US, cable, cable_UK, cable_US, nmi, li, rod, pole, perch, lea
  • Imperial/Speed: mph, knot
  • Imperial/Temperature: °F, Δ°F, °R
  • Imperial/Area: rood, ac
  • Imperial/Volume: fl_dr_UK, fl_dr_US, fl_oz, fl_oz_UK, fl_oz_US, gi, gi_UK, gi_US, pt, pt_UK, pt_US, pt_dry, qt, qt_UK, qt_US, qt_dry, gal, gal_UK, gal_US, gal_dry, bbl, bbl_UK, bbl_US, bbl_dry, pk_UK, pk_US, bu_UK, bu_US
  • Imperial/Force: ozf, oz_f, lbf, lb_f, kip, kipf, kip_f, tonf, tonf_US, tonf_UK, pdl
  • Imperial/Pressure: osi, osf, psi, psf, ksi, ksf, tsi, tsf, inHg
  • Imperial/Energy: BTU, therm, therm_US, therm_UK, quad
  • Imperial/Power: hp, hp_E, hp_S, hp_M, ks

Plots

Video: Plots in the sheet format

There are three ways to draw: the plot line of the sheet format, the Calcpad $Plot and $Map commands, and Python blocks, which are covered in Python blocks. All three can sit in the same sheet.

Charts that are not drawn from a function, such as a pie chart, a Gantt chart, a Sankey diagram or a bar chart of values you type, are diagrams written as text. See Diagrams for a gallery of every kind, and the Plots and diagrams group of the samples.

The plot line

L: 6
w: 12
M(x): w * x * (L - x) / 2
plot M(x) for x in 0..L

The line is plot expression for variable in from..to. It becomes $Plot{ M(x) @ x = 0 : L }. The expression can be a function you defined, or any expression of the variable:

>> #rad
plot sin(x), cos(x) for x in 0..2*π

Several expressions, separated by commas, are drawn together, each in its own colour. An optional y = before the expressions is dropped (plot y = f(x) for x in 0..10). A malformed plot line is reported on its line in the report and in the editor.

A legend

Give a curve a name with as "name" after its expression, and the plot gets a legend in its top right corner: a colour swatch and the name of each curve.

>> #rad
plot sin(x) as "sine", cos(x) as "cosine" for x in 0..2*π

A curve without a name is listed by its expression, and a plot where no curve has a name has no legend, as before. A name cannot contain quotes, &, |, @ or braces. The legend is part of the SVG, so it is in the printout and the PDF and in the Word picture; in Excel the names are the series names of the chart. In Calcpad text the name follows the expression in double quotes, $Plot{sin(x) "sine" & cos(x) "cosine" @ x = 0 : 2*π} (this is not in CalcpadCE).

The plot is an SVG drawing. It is sharp at any zoom, it prints well, and its data is exported to Excel as a native chart.

Radians, not degrees

Angles are in degrees by default. sin(x) over 0..2*π is then the sine of the first six degrees, which is a nearly flat line. Put >> #rad in the sheet before the plot, as above, or plot over degrees (0..360).

Plotting a function with units

The plotted variable must be a plain number. If L is 6 m, then for x in 0..L stops with Inconsistent units. Give the variable the unit inside the expression instead:

L: 6 m
w: 12 kN/m
M(x): w * x * (L - x) / 2
plot M(x * 1 m) for x in 0..6

The axes are labelled with the variable names, and the end points of the curve are marked with their values.

Other kinds of plot: $Plot and $Map

A sheet reaches the rest of the plotting commands through >> lines.

>> #rad
>> $Plot{cos(t) | sin(t) @ t = 0 : 2*π}
>> $Plot{cos(t) | sin(t) & 2*cos(t) | 2*sin(t) @ t = 0 : 2*π}
>> $Map{x*y @ x = -1 : 1 & y = -1 : 1}
FormDraws
$Plot{y(x) @ x = a : b}A function of one variable.
$Plot{y1(x) & y2(x) @ x = a : b}Several functions on one plot.
$Plot{y1(x) "name 1" & y2(x) "name 2" @ x = a : b}The same, with a legend.
$Plot{x(t) | y(t) @ t = a : b}A parametric curve.
$Plot{x1(t) | y1(t) & x2(t) | y2(t) @ t = a : b}Several parametric curves.
$Map{f(x; y) @ x = a : b & y = c : d}A colour map of a surface.

$Plot must be the first thing on its line. Anything after the closing brace is ignored. Plotting supports real numbers only.

Size and style

Set these by assigning them on a line of their own (in a sheet, a >> line), before the plot:

L: 6
w: 12
M(x): w * x * (L - x) / 2
>> PlotWidth = 600
>> PlotHeight = 300
plot M(x) for x in 0..L
SettingMeaning
PlotWidth, PlotHeightSize of the plot area in pixels.
PlotSVG1 for vector (SVG), 0 for raster. The web version draws SVG only.
PlotAdaptive1 to concentrate sample points where the curve bends (the default). Turn it off for rapidly oscillating functions, which can lose peaks.
PlotStepMesh size for colour maps.
PlotPaletteColour palette 0 to 9 for colour maps.
PlotSmooth1 for a smooth gradient, 0 for isobands.
PlotShadows1 to shade colour maps.
PlotLightDirDirection of the light, 0 to 7 clockwise from north.

The same settings are on the Calculation tab of the Settings dialog, which sets the defaults for every worksheet. The Plots & Diagrams tab of the ribbon has buttons for each form and for these lines.

The buttons under a plot

In the preview, a plot has a row of small buttons. They are not part of a printout or an export.

Plot made byButtons
A plot line or $PlotCopy data, PNG, SVG
Python (matplotlib style)Log x, Log y, 1:1, Copy data, PNG, SVG
Python (3D scene)Copy data, PNG

Copy data puts the plotted points on the clipboard. For a plot line the data is read back from the drawing, through the axis labels, so it is correct to about four figures. PNG and SVG save the picture.

Plots in exports

  • Word: plots are pictures. The SVG is rasterised for Word and kept beside the picture.
  • Excel: a $Plot or plot becomes a native, editable XY chart with its data on a “Plot data” sheet. A colour map becomes a picture.
  • PDF: the printed page has the plot as drawn.

See Exporting.

Python plots

For interactive charts, subplots, 3D surfaces and plots of computed arrays, use a Python block. See Python blocks. For a chart that redraws while you drag a slider, see Interactive panels.

Related calculators: Moment and shear diagrams, Pump operating point, Concrete strength gain. More pages are in Calculators and guides.

Python blocks

Video: Plots from Python, Plotly and matplotlib style

A sheet can hold small Python programs. They run in the page, in a sandbox, on a compact Python interpreter (MicroPython) with small stand-ins for numpy, matplotlib and Plotly. What a block prints, draws and exports becomes part of the sheet, and the numbers it exports can be used by the quantity lines that follow.

Nothing is downloaded for a sheet without Python. The first time a sheet with a Python block is calculated, the page asks “This worksheet runs Python code” (Run Python or Not now). The answer is remembered for that tab. About 0.6 MB is fetched the first time and cached afterwards.

The block

A Python block is a fenced code block with the language python:

# Moment diagram with matplotlib

L: 6 m | span
w: 12 kN/m | design load

```python
import numpy as np
import matplotlib.pyplot as plt

L_m, w_k = 6.0, 12.0
x = np.linspace(0, L_m, 61)
M = w_k * x * (L_m - x) / 2

print("Maximum moment", round(float(M.max()), 2), "kN.m at", round(float(x[np.argmax(M)]), 2), "m")

plt.figure(figsize=(7, 3))
plt.plot(x, M, "b-", label="M(x)")
plt.fill_between(x, M, alpha=0.2)
plt.xlabel("x (m)")
plt.ylabel("M (kN.m)")
plt.title("Simply supported beam")
plt.grid(True)
plt.legend()
plt.show()

export(M_peak=float(M.max()))
```

Mmax: M_peak * 1 kN*m
Mcheck: w * L^2 / 8 -> kN*m

The result shows the printed line, the figure where plt.show() was called, and then the two quantity lines:

Maximum moment 54.0 kN.m at 3.0 m
[figure: the parabolic moment diagram]
M_peak = 54
Mmax = M_peak · 1 kN·m = 54 · 1 kN·m = 54 kN·m
Mcheck = w·L²/8 = 12 kN/m · (6 m)² / 8 = 54 kN·m

The two numbers agree, which is the point of mixing: Python draws and explores, the sheet carries the units and the check.

In the blockIn the sheet
print(...)A monospace paragraph.
plt.show() or plt.savefig(...)An inline SVG figure at that point.
fig.show() on a Plotly figureAn interactive chart at that point.
export(name=value, ...)A definition name = value, a vector for a list or 1-D array, a matrix for a list of lists.
export_data(name=value, ...)Like export but nothing is printed; for large arrays.
An exceptionOne red error line naming the Python line and the exception type. The rest of the sheet still calculates.

Rules worth knowing:

  • All blocks of a sheet run in order in one interpreter, before the engine. A later block sees the earlier blocks’ variables.
  • Variables are exported explicitly, so a loop variable never collides with a unit name such as m or s. Exported numbers are unitless; attach the unit in the sheet, as Mmax does above.
  • Names in export are written the way the sheet spells them: export(sigma_c=2) is σ_c below the block.
  • Python cannot read the sheet’s quantities. Pass numbers in by writing them in the block.
  • Several names in one export call arrive in no promised order. Use separate calls where order matters.

Which numpy and matplotlib

The stand-ins are small subsets that mimic those packages. What works:

  • numpy: array, linspace, arange, zeros, ones, full, arithmetic and **, @, dot, sum, mean, max, argmax, cumsum, abs, clip, maximum, where, sqrt, exp, sin, cos, diff, trapz, eye, boolean masks, and for plotting hypot, arctan2, meshgrid (indexing="xy" or "ij"), outer, interp, polyfit, polyval.
  • math: everything in MicroPython’s math, plus hypot, dist, prod, fsum, isqrt, comb, perm, gcd and lcm, which the page adds.
  • numpy.linalg and scipy.linalg: solve, inv, det, cholesky, eigh, svd, matrix_rank, cond, pinv, norm. The numbers come from the same engine as the sheet’s lsolve, inverse and det.
  • matplotlib: plot, scatter, bar, fill_between, axhline, axvline, text, xlabel, ylabel, title, legend, grid, xlim, ylim, figure(figsize), subplots, tight_layout, suptitle, axis("equal"), log axes, show, savefig.

Missing functions raise a named error rather than a wrong answer. Not available: vstack, hstack, reshape, sort, random, poly1d, roots in numpy; hist, pie, errorbar, step, annotate, imshow, contour, twinx in matplotlib; non-symmetric eig and lstsq in linalg.

NotImplementedError: numpy.linalg.lstsq is not available in the light Python stand-in

A singular matrix raises LinAlgError: Matrix is singular. on the Python line that made the call. A list written out in the source can hold up to 16,000 numbers; a longer one is refused with an error that says what to do instead. For thousands of values, build the list in a loop or parse a text string ([float(v) for v in "1.5 2.5 3.5".split()]), which is also much faster.

# Linear algebra in a block

```python
import numpy as np

K = np.array([[4.0, -2.0], [-2.0, 3.0]])
u = np.linalg.solve(K, np.array([10.0, 0.0]))
print("u =", [round(float(v), 4) for v in u])
export(u1=float(u[0]), u2=float(u[1]))
```

total: u1 + u2
u = [3.75, 2.5]
u1 = 3.75
u2 = 2.5
total = u1 + u2 = 3.75 + 2.5 = 6.25

Plotly-style charts

import plotly.graph_objects as go gives a small copy of the Plotly interface. A figure shown with fig.show() becomes an interactive chart in the page: hover to read values, drag to zoom, use the toolbar to save a picture.

# Shear and moment with Plotly

```python
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots

L_m, w_k = 6.0, 12.0
x = np.linspace(0, L_m, 61)
V = w_k * (L_m / 2 - x)
M = w_k * x * (L_m - x) / 2

fig = make_subplots(rows=2, cols=1, shared_xaxes=True, subplot_titles=["Shear V (kN)", "Moment M (kN.m)"])
fig.add_trace(go.Scatter(x=x, y=V, name="V", line_color="#1f77b4"), row=1, col=1)
fig.add_trace(go.Scatter(x=x, y=M, name="M", fill="tozeroy"), row=2, col=1)
fig.add_vline(x=L_m / 2, line_dash="dot")
fig.update_layout(title="Simply supported beam", height=480, xaxis2_title="x (m)")
fig.show()
```

This is a pass-through, not a second copy of Plotly. Every keyword argument is written into the figure as given, and Plotly.js in the page checks it. Supported pieces:

SupportedNotes
go.Figure(data=, layout=, frames=)data takes traces or dicts.
Traces Scatter, Scattergl, Bar, Histogram, Box, Violin, Pie, Heatmap, Contour, Surface, Scatter3d, Mesh3d, Scatterpolar, Waterfall, Indicator, Table, CandlestickThe class only sets the type. All other keywords are the trace’s own.
fig.add_trace, add_traces, add_scatter, add_barrow and col on a figure from make_subplots.
fig.update_layout, update_xaxes, update_yaxes, update_tracesRecursive merge.
add_shape, add_annotation, add_vline, add_hline, add_vrect, add_hrectWith row and col, the lines use that subplot’s axes.
make_subplots(rows, cols, shared_xaxes, shared_yaxes, subplot_titles, row_heights, column_widths, vertical_spacing, horizontal_spacing)
updatemenus and sliders with precomputed stepsDropdowns, buttons, sliders; frames for animation.

“Magic underscores” work when they are keyword arguments of a call: line_color="red" is line=dict(color="red") and xaxis_title="x" is xaxis=dict(title="x"). Inside a dict they are not expanded, and the shim refuses them by name rather than letting Plotly drop them silently.

Things that fail with a named error: trace types not in the table, write_html, write_image, fig.data, fig.show(renderer=...), make_subplots(specs=...), plotly.express, plotly.io, named templates (template="plotly_white"; the page applies a light or dark theme itself).

NotImplementedError: go.Figure.write_html is not available in the light plotly shim

Controls are Plotly’s own, and they are independent. A dropdown or slider step is a fixed update that Plotly applies; it cannot read another control or run Python. For controls that combine, precompute one step per combination or give each control its own traces. The “Beam explorer” sample shows both.

Sliders that run the Python again

For a control that runs Python again on every move, use an interactive panel: a function decorated with @ui.panel(ui.slider("L", 6, 2, 12, unit="m")) that returns a Plotly figure is called again each time the slider moves, and only its chart is redrawn.

Plotly offline, printing and exports

Plotly.js is not bundled. It is fetched once from its CDN when the first chart is shown, and cached. Without a connection the chart’s place shows a note: “Interactive charts need a connection to load Plotly…”. The Python solve and the rest of the sheet still run. The charts follow the page’s light or dark theme.

Print, PDF, Word and Excel cannot run Plotly.js, so they carry a still picture of the chart instead: the page makes it when the chart is drawn (light colours, without menus and sliders, at the view you left it in). A chart that was never drawn in this session (no connection) has no picture, and a paragraph stands in its place (“Interactive chart: TITLE. It is drawn in the browser and is not carried by print or export.”). Let the chart draw before you print or export.

3D plots

A Plotly Surface, Scatter3d, Mesh3d or a 3D line figure is a 3D scene you can rotate and zoom. The contour lines can be projected onto the floor.

# A 3D surface

```python
import plotly.graph_objects as go

xs = [i * 0.25 for i in range(25)]
ys = [j * 0.25 for j in range(17)]
z = [[((x - 3) ** 2 + (y - 2) ** 2) ** 0.5 for x in xs] for y in ys]

fig = go.Figure(go.Surface(x=xs, y=ys, z=z, colorscale="Viridis"))
fig.update_layout(height=420, scene=dict(zaxis=dict(title=dict(text="distance"))))
fig.show()
```

The samples under 3D plots show a plate deflection surface, a column interaction surface, a space frame drawn in 3D lines, a mode-shape explorer with a dropdown, and a 3D bar chart of footing reactions. The walls of the 3D axes follow the light or dark theme. The buttons under a 3D scene are Copy data and PNG.

The Plot gallery sample (group “Plots and diagrams”) is a gallery of four plots on a grid in the style of a plotting demo: implicit curves (f(x, y) = 0 drawn as a contour at level zero), functions, parametric curves, noise, and polylines with markers, a legend and a second y axis. It is drawn in a Python block with the Plotly API, so it can be zoomed and read by hovering.

Limits

LimitValue
Time per block10 seconds. The worker is stopped and restarted.
Time per calculation30 seconds.
Print output100,000 characters
Figures20 per sheet, 3 MB of SVG
Chart size4 MB of figure data, 20 figures and drawings together
Exported names500
Interpreter memory32 MB

The longer time limit. When a block runs out of its ten seconds, the page asks whether to run the sheet again with a longer limit: 60 seconds per block and 180 seconds per calculation. This is for a slow device such as a phone, which can need several times what a laptop needs. The answer is kept for the tab.

The sandbox

A block runs in a Web Worker: no page access, no cookies, no stored data. The worker’s network functions are removed after loading, so a script cannot send data anywhere, and the interpreter’s host-access modules are refused. A runaway loop or allocation is stopped by the time and memory limits.

This is a practical guard and not a security boundary against a determined attacker. Calculating a sheet executes its blocks, which is why the page asks before the first run. The Samples browser never runs a sample’s Python; its preview shows the source, and opening the sample asks.

Errors

A Python exception shows as one red line naming the sheet line and the exception type, and appears in the error list on that line. The rest of the sheet still calculates, so a failed block leaves the names it never exported undefined, and the lines that use them report their own errors.

Python error on line 5: ZeroDivisionError ...

Typical causes: a name that is not in the stand-in (a NotImplementedError naming it), a Plotly keyword written in a dict with an underscore, an exported value that is nan or inf, or a block that ran past its time limit.

Calcpad #python blocks

In the Calcpad language the block is #python … #end python on lines of their own, and a sheet accepts that pair too.

Interactive panels

An interactive panel is a set of controls drawn above a chart, a table or a line of text, all made by one Python block. Move a slider and one Python function runs again with the new value, and its chart or table is redrawn in place. The rest of the sheet is not recalculated, so a panel stays quick even when the sheet is long.

The samples in the Panels group show three of them: a beam deflection explorer, a pump operating point with a play button, and a column buckling player.

Prompt-friendly summary

A complete sheet with a slider that redraws a chart:

# Moment explorer

```python
import ui
import plotly.graph_objects as go
L = ui.slider("L", 6, 2, 12, step=0.5, unit="m", label="Span")
@ui.panel(L)
def moment(L):
    x = [L * i / 40 for i in range(41)]
    return go.Figure(go.Scatter(x=x, y=[12 * v * (L - v) / 2 for v in x]))
```

The five rules:

  1. Write it in a ```python fence of a sheet, import ui, make the widgets with ui.slider, ui.select, ui.checkbox or ui.player, and decorate one function with @ui.panel(widget, ...). The function takes one argument per widget, in the same order, and receives plain values.
  2. Return a Plotly figure (do not call fig.show()), a string, ui.table(rows, header=[...]), or a list of these. Return the chart from the very first call too: Plotly is loaded only when the first result holds a chart.
  3. The panel cannot read the sheet’s quantities, and the sheet cannot read the panel’s values. Put every number the panel needs in the block itself.
  4. The Python is a small stand-in for numpy: reshape, vstack, hstack and sort are not there (meshgrid and math.hypot are). Build large lists with a loop or a comprehension: a list literal of more than 16,000 numbers in the code is refused.
  5. Do the heavy work once in the block body and keep the panel function light: it runs on every move of a control.

A panel, a sheet slider or an input form

There are three ways to put a slider in front of a reader. Choose by what has to change.

You wantUseWhat a move does
A chart, table or text redrawn live while draggingAn interactive panelRuns one Python function again. Nothing else is recalculated.
A sheet input with a slider, L: ? 6 m [2 .. 12 step 0.5]Templates with inputsRecalculates the whole sheet with the new value, a moment after you stop.
A fill-in form of several inputsInput mode, see Templates with inputsRecalculates the whole sheet; every quantity line follows.

A sheet slider changes a quantity that the lines below use, with its unit, and the report shows the working. A panel is for exploring: the chart follows your finger, but its numbers stay inside the panel.

The first run

A panel is part of a Python block, so the first calculation of the sheet in a tab asks “This worksheet runs Python code” with Run Python and Not now. The block runs in a sandbox in the page, see Python blocks. The first run takes several seconds while Python starts and, for a chart, while Plotly loads from its CDN; after that a move of a control usually redraws in a fraction of a second.

A chart: the beam moment

# Beam moment explorer

```python
import ui
import plotly.graph_objects as go

L = ui.slider("L", 6, 2, 12, step=0.5, unit="m", label="Span")
w = ui.slider("w", 12, 1, 40, unit="kN/m", label="Load")

@ui.panel(L, w)
def moment(L, w):
    x = [L * i / 60 for i in range(61)]
    M = [w * v * (L - v) / 2 for v in x]
    fig = go.Figure(go.Scatter(x=x, y=M, mode="lines", fill="tozeroy", name="M"))
    fig.update_layout(height=320, xaxis_title="x (m)", yaxis_title="M (kN.m)")
    return [fig, "Maximum moment %.1f kN.m at midspan" % (w * L * L / 8)]
```

The page shows two sliders, Span and Load, each with its value and unit beside it, then the chart and the line of text. At the start it reads Maximum moment 54.0 kN.m at midspan. Drag Span to 10 m and the curve and the text follow: Maximum moment 150.0 kN.m at midspan.

What happens, in order:

  1. The block runs once, top to bottom, like any Python block.
  2. At @ui.panel(L, w) the function moment is called with the starting values, 6 and 12, and its result is drawn under the controls.
  3. Each move of a control calls moment again with the new values, in the same Python session, and only the panel is redrawn. The function’s name, moment, is the panel’s name.

A 3D surface

A 3D trace works the same way. Here one slider sets the amplitude of a surface:

# Surface explorer

```python
import ui
import math
import plotly.graph_objects as go

a = ui.slider("a", 1.0, 0.2, 3.0, step=0.1, label="Amplitude")
xs = [-3 + 0.2 * i for i in range(31)]

@ui.panel(a)
def surface(a):
    Z = [[a * math.sin(x) * math.cos(y) for x in xs] for y in xs]
    fig = go.Figure(go.Surface(x=xs, y=xs, z=Z))
    fig.update_layout(height=420, scene=dict(zaxis=dict(range=[-3, 3])))
    return fig
```

The grid xs is made once, in the block body. The fixed zaxis range keeps the box the same size while the surface grows and shrinks; without it, Plotly rescales the axis on every move. A rotated view is kept when the surface is redrawn.

A table, a drop-down and a checkbox

A panel does not need a chart. This one returns only a table:

# Timber joist spans

```python
import ui

d = ui.select("d", [("200 mm", 0.2), ("300 mm", 0.3), ("400 mm", 0.4)], default="300 mm", label="Depth")
b = ui.slider("b", 90, 45, 200, step=5, unit="mm", label="Width")
sw = ui.checkbox("sw", True, label="Include own weight")

@ui.panel(d, b, sw)
def spans(d, b, sw):
    Z = b / 1000 * d * d / 6
    g = 5.0 * b / 1000 * d if sw else 0.0
    rows = []
    for L in [3, 4, 5, 6]:
        M = (2.0 + g) * L * L / 8
        rows.append([L, "%.2f" % M, "%.1f" % (M / Z / 1000)])
    return ui.table(rows, header=["Span (m)", "M (kN.m)", "Stress (MPa)"])
```

The drop-down shows the labels (200 mm, …) and the function receives the value paired with the chosen label (0.3). The checkbox gives True or False. A table without a chart never loads Plotly, so it also works offline once the page has been visited.

A player

ui.player is a frame number with a Play and Pause button. Each frame is one call of the function, and the next frame is asked for only after the last one is drawn, so a slow function plays slower rather than piling up.

# Travelling wave

```python
import ui
import math
import plotly.graph_objects as go

t = ui.player("t", 0, 39, fps=8, label="Frame")
xs = [i * 0.1 for i in range(101)]

@ui.panel(t)
def wave(t):
    y = [math.sin(x - t * 0.3) for x in xs]
    fig = go.Figure(go.Scatter(x=xs, y=y, mode="lines"))
    fig.update_layout(height=260, yaxis_range=[-1.2, 1.2])
    return fig
```

A player never starts by itself, and it pauses when the browser tab is hidden. With loop=False it stops at the last frame.

The ui reference

CallDrawsThe function receives
ui.slider(name, default, min, max, step=None, unit="", label=None)A slider with its value and unit beside itA number between min and max, on a step. An int when default, min, max and step are all whole numbers, otherwise a float.
ui.select(name, options, default=None, label=None)A drop-downThe value of the chosen option
ui.checkbox(name, default=False, label=None)A checkboxTrue or False
ui.player(name, start, stop, fps=5, loop=True, label=None)A slider with Play and PauseA whole frame number from start to stop
@ui.panel(widget, ...)The controls, then the function’s result(a decorator)
ui.table(rows, header=None)A table(a return value)
ui.text(s)A line of plain text(a return value)

Details that matter:

  • name is the first argument of every widget. It must be unique within a panel. label is what the reader sees; it defaults to the name.
  • step: without one, a slider of whole numbers moves by 1, and any other slider takes a round step that gives 100 to 200 steps across its range. A value is always kept between min and max and snapped to a step.
  • unit is only shown beside the value. The function receives a plain number, so write the conversions yourself (w * 1000 for kN/m to N/m).
  • options of ui.select is a list of labels (["Steel", "Timber"], the value is the label itself) or of (label, value) pairs. A dict works, but its order is not promised. default is a label or a value; without it the first option is chosen. A select needs two options or more.
  • fps of a player is at most 30. A frame waits for the last one, so the real rate can be lower.
  • Return values: a Plotly figure from plotly.graph_objects, a str or ui.text(...) (always shown as text, never as HTML), a number, ui.table(...), or a list of these in the order they are drawn. None draws nothing. Anything else is a TypeError that names the type.
  • Numbers in a ui.table are written with six significant digits. Format them yourself ("%.2f" % M) to fix the decimals.

Several outputs, several panels

To drive two charts with the same slider, return both from one function: return [fig1, fig2].

A block can hold several panels, each with its own @ui.panel and its own controls. A widget given to two panels is drawn in each of them, and the two copies do not move together. Moving one control reruns only its own panel’s function.

Errors

  • An error during the first call is a normal Python error: one red line naming the sheet line.
  • An error after a move (a division by zero at one end of a slider, say) is shown in the panel, with its type. The panel recovers at the next value that works.
  • A function that runs for more than 10 seconds is stopped. The panel says so, and it stays out of date until the sheet is calculated again (edit any line, or press calculate).
  • print() inside the panel function shows only on the first call. Return a string to show text that follows the controls.

Printing and exports

Print, PDF, Word and Excel cannot run Python. They show the panel at the values the controls were left at, without the controls, and a note under it, for example: “Interactive panel moment: Span = 10 m, Load = 12 kN/m. It is drawn in the browser; print and export show it at these values.” Text and tables are carried as they are. A chart is carried as a note naming it, as for any Plotly chart.

The values the controls were left at are kept while the tab is open, so a recalculation (an edit elsewhere in the sheet) starts the panel where you left it. They are not saved in the file: opening the file again starts from the defaults.

Limits

A panel cannot read the sheet, and the sheet cannot read the panel. Python runs before the sheet’s quantity lines and cannot see them, and a slider’s value never reaches a quantity line. A panel therefore holds its own data and inputs: write the section properties, loads and lengths in the block. An export() from the block body works as in any block, but it is done once, before any control moves; do not call export() in a panel function. When a value has to drive the sheet’s calculation, use a sheet input instead (L: ? 6 m [2 .. 12 step 0.5]).

The numpy stand-in is small. The block runs on MicroPython with a light stand-in for numpy, not on full Python. The list of what works is in Which numpy and matplotlib. Things that surprise people:

  • numpy.reshape, vstack, hstack and sort raise NotImplementedError. numpy.meshgrid, hypot, arctan2, outer, interp, polyfit and polyval work, as does math.hypot.
  • A list literal of more than 16,000 numbers written out in the code is refused before it runs, with a hint to build the list in a loop or parse a text string. Shorter ones, even several thousand numbers, work.
  • np.linspace and array arithmetic work, but plain lists and comprehensions are just as quick for the sizes a chart needs.

It runs only in the browser. The MCP server does not run Python blocks, so it cannot evaluate a sheet with a panel. Word and Excel get the snapshot described above.

Plotly comes from its CDN. A chart needs a connection the first time (the controls, tables and text work without one). Plotly is loaded only when the first result of a panel holds a chart, so a panel that returns a chart only after some move shows a note instead of the chart. Return a chart on the first call too.

The usual Python limits apply: 10 seconds per call, and an answer of at most 2 MB (a figure and its data) per move. See Python blocks.

Keeping it fast

The function runs on every move of a control, so keep in it only what depends on the controls. Work that does not, such as a grid, a stiffness matrix or a solved model, belongs in the block body, which runs once. The function can read the variables the block made before it.

# Precomputed surface

```python
import ui
import math
import plotly.graph_objects as go

xs = [-3 + 0.1 * i for i in range(61)]
base = [[math.sin(x) * math.cos(y) for x in xs] for y in xs]

k = ui.slider("k", 1.0, 0.1, 2.0, step=0.1, label="Scale")

@ui.panel(k)
def scaled(k):
    Z = [[k * v for v in row] for row in base]
    fig = go.Figure(go.Surface(x=xs, y=xs, z=Z))
    fig.update_layout(height=420, scene=dict(zaxis=dict(range=[-2, 2])))
    return fig
```

The sines and cosines of the 61 by 61 grid are worked out once; each move only multiplies.

  • Keep charts to a few thousand points. The whole figure is sent on every move.
  • Do not change globals in the function. A function that depends only on its arguments and on what the block computed before it gives the same picture for the same control values, whatever order the reader moved them in.
  • Fix axis ranges (yaxis_range, scene=dict(zaxis=dict(range=...))) so the chart does not jump while dragging.

Templates with inputs

Video: Templates with inputs

A template is a calculation that you fill in rather than edit. A few lines of the sheet are inputs: a number with its unit, a choice from a list, a group of radio buttons, a checkbox. Choose Input in the results bar and those lines become boxes, lists, buttons and ticks. Change one and the whole sheet recalculates. The same file is still an ordinary sheet: in Preview and in the report an input line reads like any other line.

A template is one .sheet file. There is nothing to install and nothing to configure: the inputs are lines of text in the sheet.

An input is a line with a question mark

A quantity line gives a name a value: L: 6 m | span. Put a ? in front of the value and the same line becomes an input, with that value as its default:

# Beam moment

L: ? 6 m | span
w: ? 12 kN/m | design load
M: w * L^2 / 8 -> kN*m | maximum moment

Everything else about the line is as for a quantity: the name is a plain name (Greek spellings work as usual), the unit is written after the number, and the text after | is a note. Later lines use L and w like any other quantity. In Preview the sheet reads L = 6 m span, with the defaults. In Input mode 6 is a yellow box with m beside it and span after it. Change the box to 8, press Enter, and the moment follows.

The default is a number with an optional unit (6 m, 12 kN/m, 0.9, 1230000 mm³). It is not an expression: 2*3 m is an error on its line, and the message says what to write. Units may be written with the superscript signs (mm³) as everywhere else in a sheet. The name can be written either way too: phi: ? 0.9 is the input φ.

name = ? 6 m works as well as name: ? 6 m.

The kinds of input

You writeYou getThe name is
L: ? 6 m | spanA box with the unit after itThe number typed, with the unit
E: ? [Steel = 200 GPa, *Timber = 11 GPa] | materialA drop-down listThe value of the chosen option
k: ? (Low = 1, High = 2) | load classRadio buttonsThe value of the chosen option
ribs: ? on | stiffeners fittedA checkbox1 when ticked, 0 when not
L: ? 6 m [2 .. 12 step 0.5] | spanA slider with the box beside itThe number, kept between the bounds

Sliders

Put bounds after the default and the box gets a slider:

# Beam moment

L: ? 6 m [2 .. 12 step 0.5] | span
w: ? 12 kN/m [2 .. 40 step 1] | design load
M: w * L^2 / 8 -> kN*m | maximum moment

[2 .. 12 step 0.5] is the smallest value, the largest value and, if you give one, the step the slider moves in. The numbers are in the unit of the default (metres for 6 m). The default must lie between the bounds. In Input mode the slider sits next to the box: drag it, use the arrow keys, or type a number, and the sheet recalculates a moment after you stop moving. A number typed outside the bounds is not used; the box turns red and says must be from 2 to 12. Without step the slider takes about a hundred steps across its range; a typed number does not have to land on a step. Preview, Report, PDF and the Word and Excel exports show the number, as they do for a plain input, so a sheet with sliders reads the same when it is printed. Two of the sample templates, the beam check and the cantilever, use sliders for their span, length and loads.

Docked inputs

A slider is most use when you can see what it moves. In Input mode the Dock inputs button (a pin) in the results bar gathers every input of the sheet into one panel that stays put while the results scroll: at the left of the results when the pane is wide, in a strip above them when it is narrow or on a phone. Scroll the results to the plot, drag a slider in the panel, and the plot is drawn again as you drag. The panel holds the same values as the input lines (they are hidden while it is docked), with the same checks: a number typed outside the bounds is refused, with the message beside the box. The arrow in the panel’s header folds it to one line of values.

The panel is docked when a sheet has a slider, and not otherwise; your choice is kept until the browser tab is closed. A sheet without inputs has no panel. Nothing printed or exported shows it.

A choice is a list of label = value entries between square brackets (a drop-down) or round brackets (radio buttons). The label is what the reader sees. The value is a number with an optional unit, and it is what the name becomes when that option is chosen.

  • The option marked with * is the one selected when the sheet opens. With no *, the first option is.
  • A label that contains a comma, an equals sign or a bracket goes in double quotes: "Beam (A), long" = 1.
  • A choice needs at least two options, and each option needs a value.
  • A drop-down, radio buttons and a checkbox show no name. Their note (the text after |) becomes the label in front of the control. With no note the name is used.

Checkboxes

on or off (true and false also work) sets the starting state, and the name is 1 or 0. That makes it a multiplier (sw * rho * A) or a test (if ribs == 1:).

A choice that picks several things at once

A choice gives one number. When a material has a modulus, a strength and a density, let the choice give an index and look the rest up in tables written after it. The template below does this with E_tab.mat, the entry of E_tab that mat points at:

mat: ? [Structural steel = 1, *Aluminium = 2, Timber = 3] | material
E_tab: [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
E: E_tab.mat -> GPa
if mat == 2: "The material is aluminium."

A new material is then one more option and one more entry in each table. The report shows the number a choice stands for (mat = 3), so a line such as if mat == 3: "The material is timber." tells the reader what it means. Most of the sample templates do this.

Grouping the inputs as a form

A run of input lines is drawn as one form: a block with a bar down its left edge. Put the inputs together under a heading, so that the heading titles the form. The run ends at the first line that is not an input (a line of prose, a calculation). A blank line inside the run does not end it.

## Inputs
L:    ? 6 m | span
w:    ? 12 kN/m | applied uniform load
mat:  ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
sw:   ? on | include the own weight of the beam

Preview and the report show the same block without the bar, and Show compiled shows plain Calcpad (the bar is not written). Format Document (Shift+Alt+F) lines the colons up.

Using the form

In the browser a template opens as Preview. Choose Input in the results bar (Preview, Unwrapped, Input, Report), or Input form on the Input/Output tab. Then:

  • Each input line is a control. A box holds the number only; the unit stays beside it, so a number cannot be typed in the wrong unit. A box accepts digits, a decimal point and a sign.
  • Consecutive input lines are drawn as one block, so the names, the boxes, the sliders, the units and the notes start at the same place on every row. The names are right aligned so the equals signs meet, a very long name is held to 40% of the width and wraps, and a text line, a heading or a blank line starts a new block. This is how the form looks only; the report, print and the exports are unchanged. (The docked panel, described above, is laid out on its own.)
  • Type a value and press Enter, or leave the box, and the sheet recalculates. Lists, buttons and the checkbox act at once.
  • The Insert panel says “Unavailable in input mode”: it acts on the source, which the form does not edit. Choose Preview to edit again.
  • The bar has Report and Print PDF, which use the values you entered, Update defaults and Reset (they appear once you have entered a value), Save values (it appears once you have changed a value) and Exit input mode.
  • Leaving input mode with values you did not save asks “Unsaved input values: save the values entered in the input form before exiting?” with Save, Don’t Save and Cancel.
ViewEntered values applied#pre shown#post shown
PreviewNo (the defaults), unless Apply #UI Values in Preview is on in SettingsYesYes
InputYesYesNo
ReportYesNoYes

The Word and Excel exports and Print PDF use the entered values. The Excel file lists the input variables on its Inputs sheet. The form itself has no Word export; the report is the document. See Exporting.

Saving the values

The values you type are held in the page, so typing never changes the file. Choose Save values to keep them. It writes one comment line directly under the <!--sheet--> line:

<!--sheet-->
'<!--{"uiOverrides":{"L:1":"8"}}-->

The file is still a sheet. The next time it is opened and put in Input mode, or opened as a report, the saved values are applied again. Preview still shows the defaults written in the sheet. To change a default for good, edit the number in the sheet line.

A saved value belongs to the input’s name. Rename an input and the value saved under the old name is not used any more. Delete the comment line to go back to the defaults.

Keeping the source and the form the same

A value held in the form and the default written in the sheet can differ, and then the report uses one number while the source shows another. Three things deal with that:

  • A mark at the end of the line. An input line whose entered value is not its default shows a faint ← form: 8 after it in the editor, with the explanation when you point at it. It appears for held values and for saved ones, in Preview and in the editor too.
  • Update defaults (in the results bar) writes every entered value into the default of its line and forgets the value: L: ? 6 m | span becomes L: ? 8 m | span, a drop-down or a group of radio buttons moves its * to the chosen option, a checkbox becomes on or off, and a slider keeps its bounds. A saved comment line is rewritten without the values that were written, and removed when none is left. The edit is one step of undo in the editor. A value that has no line to go to, such as one entered for a later pass of a #for loop, stays as entered.
  • Reset drops the entered values, held and saved, and the form shows the defaults in the source again.

To have the source always show what the calculation uses, turn on Keep Input Form Values in the Source in Settings (Editor tab). A value you enter is then written into its line at once instead of being held: there is nothing to save and no mark to see. A slider writes when you let go of it. The setting is off by default, because a sheet kept as a template with defaults for others to fill in is easier to hand over when the form never changes it.

What an input cannot do

  • Numbers only. An input holds a number. There is no text box: a choice of names is a drop-down. There is no minimum or maximum either, so check a range in the sheet: if L > 30 m: "Span out of range".
  • No expression as a default. 2*3 m is an error. Write the number, or compute the value in a line after the input.

Known limits

Workarounds for behaviour that is to be fixed. This is the only list of them on this page.

  • No two options may have the same value. (Low = 1 m, High = 1 m) is an error on its line, because the form could not tell which option is chosen. Give each option its own value.
  • A name cannot contain a dot. A dot is the index operator (E_tab.mat), so a.b: ? 5 is not an input.

Worked template 1: a simply supported beam

Inputs: the span, the load, a section depth (drop-down), a material (drop-down), a deflection limit (radio buttons) and whether the beam’s own weight counts (checkbox). The beam is a doubly symmetric I-beam described by one depth, so the section is a drop-down of three depths. This is the sample Template: simply supported beam check in the Templates group of the Samples browser, and the text below is the file as shipped.

The inputs, six lines:

## Inputs
L:     ? 6 m | span
w:     ? 12 kN/m | applied uniform load
h:     ? [200 mm deep = 200 mm, *300 mm deep = 300 mm, 400 mm deep = 400 mm] | I-beam section
mat:   ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
limit: ? (L/250 = 250, L/360 = 360, L/500 = 500) | deflection limit
sw:    ? on | include the own weight of the beam

Note that h is a drop-down whose values are lengths: the choice sets the section depth directly. The deflection limit is a number, 250, 360 or 500, and a later line divides the span by it (L / limit).

The whole sheet
<!--sheet-->
# Simply supported beam check

A template with inputs. Choose **Input** in the results bar to fill in the form; every change
recalculates the page. The beam is a doubly symmetric I-beam, so one depth $h$ describes it:
flange width $b = h/2$, flange thickness $t_f = h/20$ and web thickness $t_w = h/40$. The check
compares the bending stress $\sigma = M/Z$ with an allowable stress and the mid-span deflection
$\delta = 5 w L^4 / (384 E I)$ with a limit.

## Inputs
L:     ? 6 m [2 .. 12 step 0.5] | span
w:     ? 12 kN/m [2 .. 40 step 1] | applied uniform load
h:     ? [200 mm deep = 200 mm, *300 mm deep = 300 mm, 400 mm deep = 400 mm] | I-beam section
mat:   ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
limit: ? (L/250 = 250, L/360 = 360, L/500 = 500) | deflection limit
sw:    ? on | include the own weight of the beam

## Material properties
The input above picks one entry of each table, so a new material is one more entry in each.

E_tab:   [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
fa_tab:  [165 MPa, 100 MPa, 12 MPa] | allowable bending stress
rho_tab: [7850 kg/m^3, 2700 kg/m^3, 500 kg/m^3] | density
E:   E_tab.mat -> GPa
f_a: fa_tab.mat -> MPa
rho: rho_tab.mat -> kg/m^3

if mat == 1: "The material is structural steel."
if mat == 2: "The material is aluminium."
if mat == 3: "The material is timber."

## Section
b:   h / 2 | flange width
t_f: h / 20 | flange thickness
t_w: h / 40 | web thickness
A:   2 * b * t_f + (h - 2 * t_f) * t_w -> cm^2 | area
I:   (b * h^3 - (b - t_w) * (h - 2 * t_f)^3) / 12 -> cm^4 | second moment of area
Z:   2 * I / h -> cm^3 | elastic section modulus

## Load
g_acc: 9.81 m/s^2 | gravitational acceleration
w_sw:  sw * rho * A * g_acc -> kN/m | own weight, when included
w_tot: w + w_sw | total uniform load

## Results
M_max: w_tot * L^2 / 8 -> kN*m | maximum bending moment, at mid-span
V_max: w_tot * L / 2 -> kN | maximum shear force, at the supports
sigma: M_max / Z -> MPa | maximum bending stress
delta: 5 * w_tot * L^4 / (384 * E * I) -> mm | mid-span deflection
delta_lim: L / limit -> mm | deflection limit
util_b: sigma / f_a | bending utilisation
util_d: delta / delta_lim | deflection utilisation

if util_b <= 1: "Bending: OK, the stress is within the allowable stress." else: "Bending: the stress exceeds the allowable stress, choose a deeper section or a stronger material."
if util_d <= 1: "Deflection: OK, within the limit." else: "Deflection: over the limit, choose a deeper section or a stiffer material."

## Moment diagram
M(x): w_tot * x * (L - x) / 2 -> kN*m | bending moment along the span

plot M(x * 1 m) / (1 kN*m) for x in 0..L / (1 m)

At the defaults (6 m, 12 kN/m, 300 mm deep, steel, L/250, own weight on):

QuantityResult
Own weight w_sw and total load w_tot0.502 kN/m and 12.5 kN/m
Section A, I, Z65.25 cm², 10376.4 cm⁴, 691.76 cm³
Moment M_max, shear V_max56.26 kN·m, 37.51 kN
Stress σ against f_a81.33 MPa against 165 MPa, utilisation 0.493
Deflection δ against δ_lim10.17 mm against 24 mm, utilisation 0.424
MessagesBending: OK. Deflection: OK.

What changing each input does (one change at a time from the defaults, unless the row says otherwise):

ChangeResult
Span 8 mMoment 100.02 kN·m, stress 144.59 MPa (0.876), deflection 32.13 mm against a 32 mm limit. Bending: OK. Deflection: over the limit.
Span 8 m and 400 mm deepTotal load 12.89 kN/m, moment 103.15 kN·m, stress 62.9 MPa (0.381), deflection 10.48 mm (0.328). Both OK.
TimberMoment 54.14 kN·m, stress 78.27 MPa against 12 MPa (6.52), deflection 177.89 mm (7.41). Both fail.
Limit L/500 and own weight offMoment 54 kN·m, stress 78.06 MPa (0.473), deflection 9.76 mm against 12 mm (0.813). Both OK.

The first row shows a deflection utilisation of 1 next to the message “over the limit”. The value is 1.004, and two decimals show it as 1. The message tests the full number, not the rounded one. For a closer look, raise the decimals in Settings.

The own-weight checkbox is a multiplier: w_sw: sw * rho * A * g_acc. With the box ticked it is 0.502 kN/m, unticked it is 0 and the total load is the applied load alone.

Worked template 2: a pad footing under a load and a moment

Eight inputs: the column load and moment, the footing’s width, length and thickness, the depth of its base, a soil (a drop-down of allowable bearing pressures) and a checkbox for the weight of the footing and the soil above it. This is Template: pad footing bearing pressure.

The whole sheet
<!--sheet-->
# Pad footing: bearing pressure check

A template with inputs. Choose **Input** in the results bar to fill in the form. A rectangular
pad footing $B \times L$ carries a vertical column load $N$ and a moment $M$ about the axis
parallel to $B$. The total vertical load $P$ adds the weight of the footing and of the soil above
it, the eccentricity is $e = M/P$ and, while $e \le L/6$ (no uplift), the largest bearing pressure is
$q_{max} = \frac{P}{B L}\left(1 + \frac{6e}{L}\right)$. Beyond that the pressure acts on part of the
base only, $q_{max} = \frac{2P}{3B(L/2 - e)}$. It is compared with an allowable bearing pressure.

## Inputs
N:    ? 600 kN | vertical column load
M:    ? 60 kN*m | column moment, in the direction of L
B:    ? 2 m | footing width
L:    ? 2.4 m | footing length, in the direction of the moment
t:    ? 0.5 m | footing thickness
D_f:  ? 1 m | depth of the base below the ground
q_a:  ? [Soft clay = 80 kPa, Firm clay = 150 kPa, *Medium dense sand = 200 kPa, Dense gravel = 300 kPa] | soil, allowable bearing pressure
wts:  ? on | include the weight of the footing and of the soil above it

## Constants
gamma_c: 24 kN/m^3 | unit weight of concrete
gamma_s: 18 kN/m^3 | unit weight of the soil above the footing

## Vertical load
W_f: wts * gamma_c * B * L * t -> kN | weight of the footing
W_s: wts * gamma_s * B * L * (D_f - t) -> kN | weight of the soil above the footing
P:   N + W_f + W_s -> kN | total vertical load on the soil

## Bearing pressure
e:   M / P -> m | eccentricity of the load
e_lim: L / 6 | the load stays inside the middle third while e is below this
q_avg: P / (B * L) -> kPa | average pressure

if e <= e_lim:
    q_max: q_avg * (1 + 6 * e / L) -> kPa | largest pressure
    q_min: q_avg * (1 - 6 * e / L) -> kPa | smallest pressure
    The whole base stays in contact with the soil.
else:
    q_max: 2 * P / (3 * B * (L / 2 - e)) -> kPa | largest pressure, partial contact
    q_min: 0 kPa | smallest pressure
    Part of the base lifts off the soil.

util: q_max / q_a | utilisation of the allowable bearing pressure
if util <= 1: "OK: the largest pressure is within the allowable bearing pressure." else: "Fails: the largest pressure exceeds the allowable bearing pressure. Enlarge the footing."

Two things in this sheet are new. The soil drop-down has an option marked *:

q_a: ? [Soft clay = 80 kPa, Firm clay = 150 kPa, *Medium dense sand = 200 kPa, Dense gravel = 300 kPa] | soil, allowable bearing pressure

so it opens on Medium dense sand, the third option. And the check has two branches. An if block may hold quantity lines and prose, and the branch that applies is the one shown:

if e <= e_lim:
    q_max: q_avg * (1 + 6 * e / L) -> kPa | largest pressure
    ...
    The whole base stays in contact with the soil.
else:
    q_max: 2 * P / (3 * B * (L / 2 - e)) -> kPa | largest pressure, partial contact
    ...
    Part of the base lifts off the soil.

At the defaults (600 kN, 60 kN·m, 2 m by 2.4 m, 0.5 m thick, base 1 m down, medium dense sand, weights on):

QuantityResult
Footing weight W_f, soil weight W_s57.6 kN, 43.2 kN
Total vertical load P700.8 kN
Eccentricity e against e_lim0.0856 m against 0.4 m, so the whole base is in contact
Average, largest, smallest pressure146 kPa, 177.25 kPa, 114.75 kPa
Utilisation0.886. OK.
ChangeResult
Soft clayLargest pressure unchanged, 177.25 kPa against 80 kPa: utilisation 2.22. Fails.
Moment 200 kN·me 0.285 m, largest 250.17 kPa, smallest 41.83 kPa, utilisation 1.25. Fails.
Moment 400 kN·me 0.571 m is beyond 0.4 m: “Part of the base lifts off the soil.” Largest 371.25 kPa, smallest 0 kPa, utilisation 1.86. Fails.
Weights off (checkbox)P is 600 kN, e 0.1 m, largest 156.25 kPa, utilisation 0.781. OK.

Worked template 3: a rectangular column

Seven inputs: the section, the length, the end conditions (a drop-down whose values are the effective length factors), a material (drop-down), the axial load and a factor of safety. This is Template: rectangular column slenderness. The sheet picks the buckling formula by slenderness: a short column crushes, an intermediate one uses the parabolic formula, a slender one the Euler formula.

Here one choice is the number the sheet needs, with no table in between:

k:    ? [Pinned at both ends = 1, Fixed and pinned = 0.7, Fixed at both ends = 0.5, Fixed and free = 2] | end conditions
The whole sheet
<!--sheet-->
# Rectangular column: slenderness and buckling

A template with inputs. Choose **Input** in the results bar to fill in the form. A solid
rectangular column of length $L$ with an effective length factor $k$ has a slenderness
$\lambda = k L / r$, where $r = b_{min}/\sqrt{12}$ is the smallest radius of gyration. Above the
transition slenderness $\lambda_c = \pi \sqrt{2E/f_y}$ the column buckles elastically (Euler),
$\sigma_{cr} = \pi^2 E / \lambda^2$. Below it the parabolic (Johnson) formula applies,
$\sigma_{cr} = f_y \left(1 - f_y \lambda^2 / (4 \pi^2 E)\right)$. The load that is allowed is
$\sigma_{cr} A$ divided by a factor of safety.

## Inputs
b:    ? 60 mm | section width
d:    ? 100 mm | section depth
L:    ? 2.4 m | column length
k:    ? [Pinned at both ends = 1, Fixed and pinned = 0.7, Fixed at both ends = 0.5, Fixed and free = 2] | end conditions
mat:  ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
N:    ? 100 kN | axial load
FS:   ? 2 | factor of safety

## Material properties
E_tab:  [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
fy_tab: [250 MPa, 160 MPa, 24 MPa] | yield strength, or crushing strength for timber
E:  E_tab.mat -> GPa
f_y: fy_tab.mat -> MPa

if mat == 1: "The material is structural steel."
if mat == 2: "The material is aluminium."
if mat == 3: "The material is timber."

## Section
A:   b * d -> cm^2 | area
b_min: min(b, d) | smaller side
I_min: max(b, d) * b_min^3 / 12 -> cm^4 | smaller second moment of area
r:   b_min / sqrt(12) -> mm | smallest radius of gyration

## Slenderness
L_e:      k * L -> m | effective length
lambda:   L_e / r | slenderness ratio
lambda_c: π * sqrt(2 * E / f_y) | transition slenderness

if lambda <= 50:
    The column is short: crushing is likely to govern rather than buckling.
else if lambda <= lambda_c:
    The column is intermediate: it buckles inelastically and the parabolic formula applies.
else:
    The column is slender: it buckles elastically and the Euler formula applies.

## Buckling resistance
sigma_E: π^2 * E / lambda^2 -> MPa | elastic (Euler) buckling stress
P_E:     π^2 * E * I_min / L_e^2 -> kN | elastic (Euler) buckling load

if lambda <= lambda_c:
    sigma_cr: f_y * (1 - f_y * lambda^2 / (4 * π^2 * E)) -> MPa | critical stress, parabolic formula
else:
    sigma_cr: sigma_E | critical stress, Euler formula

P_cr:    sigma_cr * A -> kN | critical load
P_allow: P_cr / FS -> kN | allowed load
util:    N / P_allow | utilisation

if util <= 1: "OK: the applied load is within the allowed load." else: "Fails: the applied load exceeds the allowed load. Enlarge the section, shorten the column or fix its ends."

At the defaults (60 mm by 100 mm, 2.4 m, pinned at both ends, steel, 100 kN, factor of safety 2):

QuantityResult
Area, smaller second moment, radius of gyration60 cm², 180 cm⁴, 17.32 mm
Effective length L_e2.4 m
Slenderness λ against λ_c138.56 against 125.66: “The column is slender”
Critical stress (Euler) and load102.81 MPa, 616.85 kN
Allowed load308.43 kN
Utilisation0.324. OK.
ChangeResult
Fixed at both endsL_e 1.2 m, λ 69.28: “The column is intermediate”, parabolic formula, critical stress 212 MPa, allowed load 636.01 kN, utilisation 0.157.
Fixed at both ends and 300 kNUtilisation 0.472. OK.
Timberλ_c drops to 95.12, still slender, critical stress 5.65 MPa, allowed load 16.96 kN, utilisation 5.9. Fails.

Worked template 4: pipe flow

Eight inputs, with a flow rate in L/s, a pipe diameter and length, a rise in level, a sum of loss coefficients, a pipe material (a drop-down of roughnesses in mm), a water temperature (radio buttons that pick table entries) and a checkbox for the fittings. This is Template: pipe flow, Darcy-Weisbach. The flow is laminar or turbulent by its Reynolds number, and the sheet uses the matching friction factor.

The whole sheet
<!--sheet-->
# Pipe flow: friction loss and pump head

A template with inputs. Choose **Input** in the results bar to fill in the form. Water flows
through a full circular pipe of diameter $D$ and length $L_p$. The Darcy-Weisbach equation gives the
friction head loss $h_f = f \frac{L_p}{D}\frac{V^2}{2g}$. The friction factor is $f = 64/Re$ in laminar
flow and, in turbulent flow, the explicit Swamee-Jain formula
$f = 0.25 / \left[\log_{10}\left(\frac{\varepsilon}{3.7 D} + \frac{5.74}{Re^{0.9}}\right)\right]^2$.
Fittings add $h_m = K V^2 / 2g$.

## Inputs
Q:    ? 25 L/s | flow rate
D:    ? 150 mm | inside diameter of the pipe
L_p:  ? 300 m | pipe length
dz:   ? 5 m | rise in level from the inlet to the outlet
K_m:  ? 2.5 | sum of the loss coefficients of the fittings
eps:  ? [Drawn plastic = 0.0015 mm, *Commercial steel = 0.045 mm, Cast iron = 0.26 mm, Concrete = 1 mm] | pipe material, roughness
temp: ? (5 degrees C = 1, 20 degrees C = 2, 40 degrees C = 3) | water temperature
minor: ? on | include the fittings

## Water properties
rho_tab: [1000 kg/m^3, 998 kg/m^3, 992 kg/m^3] | density at 5, 20 and 40 degrees C
nu_tab:  [0.00000152 m^2/s, 0.00000100 m^2/s, 0.00000066 m^2/s] | kinematic viscosity at 5, 20 and 40 degrees C
rho: rho_tab.temp -> kg/m^3
nu:  nu_tab.temp -> m^2/s
g_acc: 9.81 m/s^2 | gravitational acceleration

if temp == 1: "The water is at 5 degrees C."
if temp == 2: "The water is at 20 degrees C."
if temp == 3: "The water is at 40 degrees C."

## Flow
A:  π * D^2 / 4 -> cm^2 | flow area
V:  Q / A -> m/s | mean velocity
Re: V * D / nu | Reynolds number
rr: eps / D | relative roughness

if Re < 2300:
    The flow is laminar.
    f: 64 / Re | friction factor, laminar
else:
    The flow is turbulent.
    f: 0.25 / (log(rr / 3.7 + 5.74 / Re^0.9))^2 | friction factor, Swamee-Jain

## Head loss
h_f: f * (L_p / D) * V^2 / (2 * g_acc) -> m | friction head loss
h_m: minor * K_m * V^2 / (2 * g_acc) -> m | head loss in the fittings, when included
h_L: h_f + h_m -> m | total head loss
H:   dz + h_L -> m | head the pump must supply
dp:  rho * g_acc * h_L -> kPa | pressure drop from losses
P_h: rho * g_acc * Q * H -> kW | hydraulic power

if V <= 3 m/s: "OK: the velocity is within the usual limit of 3 m/s." else: "High velocity: more than 3 m/s, consider a larger pipe."

Because the first radio option is selected when none is marked, the water starts at 5 degrees C. At the defaults (25 L/s, 150 mm, 300 m, 5 m rise, K 2.5, commercial steel, 5 degrees C, fittings on):

QuantityResult
Velocity, Reynolds number1.41 m/s, 139610: “The flow is turbulent.”
Friction factor0.0186
Friction loss, fittings loss, total3.79 m, 0.255 m, 4.05 m
Pump head H9.05 m
Pressure drop, hydraulic power39.72 kPa, 2.22 kW
MessageOK: the velocity is within the usual limit
ChangeResult
Water at 20 degrees C (second radio button)Total loss 3.86 m, H 8.86 m, pressure drop 37.8 kPa, power 2.17 kW.
Fittings offTotal loss 3.79 m, H 8.79 m, power 2.16 kW.
Diameter 200 mmVelocity 0.796 m/s, total loss 1 m, H 6 m, power 1.47 kW.
Flow 60 L/sVelocity 3.4 m/s: “High velocity: more than 3 m/s, consider a larger pipe.”
Flow 0.2 L/sReynolds number 1116.88: “The flow is laminar”, friction factor 0.0573.

Worked template 5: a cantilever with a tip load

The fifth sample, Template: cantilever with a tip load, is the beam template’s close relative: length, tip load, a rectangular section, a material and a deflection limit, with the own-weight checkbox. It ends with a moment diagram.

The whole sheet
<!--sheet-->
# Cantilever with a load at the tip

A template with inputs. Choose **Input** in the results bar to fill in the form. A cantilever of
length $L$ with a solid rectangular section $b \times d$ carries a point load $P$ at the free end
and, if wanted, its own weight $w$. At the fixed end $M = P L + w L^2 / 2$ and
$V = P + w L$, and the tip deflection is $\delta = P L^3 / (3 E I) + w L^4 / (8 E I)$.

## Inputs
L:     ? 2.5 m [0.5 .. 6 step 0.1] | length
P:     ? 8 kN [1 .. 100 step 1] | point load at the free end
b:     ? 100 mm | section width
d:     ? 200 mm | section depth
mat:   ? [Structural steel = 1, Aluminium = 2, Timber = 3] | material
limit: ? (L/90 = 90, L/180 = 180, L/360 = 360) | tip deflection limit
sw:    ? on | include the own weight of the beam

## Material properties
E_tab:   [200 GPa, 70 GPa, 11 GPa] | modulus of elasticity
fa_tab:  [165 MPa, 100 MPa, 12 MPa] | allowable bending stress
rho_tab: [7850 kg/m^3, 2700 kg/m^3, 500 kg/m^3] | density
E:   E_tab.mat -> GPa
f_a: fa_tab.mat -> MPa
rho: rho_tab.mat -> kg/m^3

if mat == 1: "The material is structural steel."
if mat == 2: "The material is aluminium."
if mat == 3: "The material is timber."

## Section
A: b * d -> cm^2 | area
I: b * d^3 / 12 -> cm^4 | second moment of area
Z: b * d^2 / 6 -> cm^3 | elastic section modulus

## Load
g_acc: 9.81 m/s^2 | gravitational acceleration
w:     sw * rho * A * g_acc -> kN/m | own weight, when included

## Results at the fixed end and at the tip
M_max: P * L + w * L^2 / 2 -> kN*m | maximum bending moment, at the fixed end
V_max: P + w * L -> kN | maximum shear force, at the fixed end
sigma: M_max / Z -> MPa | maximum bending stress
delta: P * L^3 / (3 * E * I) + w * L^4 / (8 * E * I) -> mm | tip deflection
theta: P * L^2 / (2 * E * I) + w * L^3 / (6 * E * I) | tip rotation, in radians
delta_lim: L / limit -> mm | tip deflection limit
util_b: sigma / f_a | bending utilisation
util_d: delta / delta_lim | deflection utilisation

if util_b <= 1: "Bending: OK, the stress is within the allowable stress." else: "Bending: the stress exceeds the allowable stress, enlarge the section or change the material."
if util_d <= 1: "Deflection: OK, within the limit." else: "Deflection: over the limit, enlarge the section or change the material."

## Bending moment diagram
M(x): P * (L - x) + w * (L - x)^2 / 2 -> kN*m | bending moment at a distance x from the fixed end

plot M(x * 1 m) / (1 kN*m) for x in 0..L / (1 m)

At the defaults (2.5 m, 8 kN, 100 mm by 200 mm, steel, L/90, own weight on) the moment at the fixed end is 24.81 kN·m, the shear 11.85 kN, the bending stress 37.22 MPa (0.226) and the tip deflection 3.69 mm against a 27.78 mm limit (0.133). Both checks pass. Choose timber and the stress is 30.46 MPa against 12 MPa (2.54) and the tip deflection 57.47 mm (2.07): both fail.

Worked template 6: a retaining wall

The sixth sample, Template: retaining wall stability, checks a cantilever retaining wall (a stem on a base slab, one metre of wall) for overturning, sliding and bearing pressure under the base. Its inputs are the geometry, a surcharge on the fill, and the backfill:

## Inputs
H_s:   ? 3 m | height of the stem above the base slab
B:     ? 2.4 m | width of the base slab
t_b:   ? 0.4 m | thickness of the base slab
t_s:   ? 0.4 m | thickness of the stem
L_t:   ? 0.6 m | length of the toe, in front of the stem
soil:  ? (Loose sand = 28 °, *Medium sand = 32 °, Dense sand = 36 °) | backfill, friction angle
q_s:   ? 10 kPa | surcharge on the fill, when it is on
sur:   ? off | surcharge on the fill

Two things are new here. The radio group soil chooses a friction angle directly: its values are angles (28 °), and a later line uses the chosen angle as a quantity (phi: soil). The values carry the degree sign, which an input accepts like any other unit. The checkbox sur is used as a multiplier, q: sur * q_s: ticked it is 1 and the surcharge counts, unticked it is 0.

The whole sheet
<!--sheet-->
# Retaining wall: sliding and overturning

A template with inputs. Choose **Input** in the results bar to fill in the form. A cantilever
retaining wall of concrete (a stem on a base slab) holds back a level fill; the sheet takes a strip of wall one metre long.
The active earth pressure is $K_a = \tan^2(45^\circ - \phi/2)$, acting on the vertical plane through
the heel, so the thrust is $P_a = \tfrac12 K_a \gamma H^2$ at $H/3$ above the underside of the base. A
surcharge $q$ on the fill adds $K_a q H$ at $H/2$ and its weight on the heel. The wall slides on a
base friction of $\tan(2\phi/3)$, and overturns about the toe. The soil in front of the toe is ignored.

## Inputs
H_s:   ? 3 m | height of the stem above the base slab
B:     ? 2.4 m | width of the base slab
t_b:   ? 0.4 m | thickness of the base slab
t_s:   ? 0.4 m | thickness of the stem
L_t:   ? 0.6 m | length of the toe, in front of the stem
soil:  ? (Loose sand = 28 °, *Medium sand = 32 °, Dense sand = 36 °) | backfill, friction angle
q_s:   ? 10 kPa | surcharge on the fill, when it is on
sur:   ? off | surcharge on the fill

## Constants
gamma_c: 24 kN/m^3 | unit weight of concrete
gamma_s: 18 kN/m^3 | unit weight of the fill
b_w:     1 m | length of wall in the strip
FS_min:  1.5 | required factor of safety, for sliding and for overturning

## Geometry
phi: soil | friction angle of the fill
H:   H_s + t_b -> m | height of the thrust plane, above the underside of the base
L_h: B - L_t - t_s -> m | length of the heel, behind the stem
q:   sur * q_s -> kPa | surcharge in use

## Earth pressure
K_a: tan(45 ° - phi / 2)^2 | active pressure coefficient
P_s: K_a * gamma_s * H^2 / 2 * b_w -> kN | thrust of the fill
P_q: K_a * q * H * b_w -> kN | thrust of the surcharge
P_h: P_s + P_q -> kN | total horizontal thrust

## Weights and their lever arms about the toe
W_stem: gamma_c * t_s * H_s * b_w -> kN | stem
x_stem: L_t + t_s / 2 -> m | its lever arm
W_base: gamma_c * B * t_b * b_w -> kN | base slab
x_base: B / 2 -> m | its lever arm
W_fill: gamma_s * L_h * H_s * b_w -> kN | fill on the heel
W_sur:  q * L_h * b_w -> kN | surcharge on the heel
x_heel: B - L_h / 2 -> m | lever arm of the fill and the surcharge
W: W_stem + W_base + W_fill + W_sur -> kN | total vertical load

## Overturning
M_o: P_s * H / 3 + P_q * H / 2 -> kN*m | overturning moment about the toe
M_r: W_stem * x_stem + W_base * x_base + (W_fill + W_sur) * x_heel -> kN*m | resisting moment about the toe
FS_o: M_r / M_o | factor of safety against overturning
if FS_o >= FS_min: "Overturning: OK." else: "Overturning: the factor of safety is too low, widen the base."

## Sliding
mu:   tan(2 * phi / 3) | friction coefficient of the base on the ground
R_h:  mu * W -> kN | sliding resistance
FS_s: R_h / P_h | factor of safety against sliding
if FS_s >= FS_min: "Sliding: OK." else: "Sliding: the factor of safety is too low, widen the base or make it thicker."

## Bearing pressure under the base
x_r: (M_r - M_o) / W -> m | where the resultant crosses the base, from the toe
e:   B / 2 - x_r -> m | eccentricity from the middle of the base
q_max: W / (B * b_w) * (1 + 6 * e / B) -> kPa | pressure at the toe
q_min: W / (B * b_w) * (1 - 6 * e / B) -> kPa | pressure at the heel
if abs(e) <= B / 6: "The resultant is inside the middle third: the whole base is in compression." else: "The resultant is outside the middle third: part of the base lifts off, and the pressures above no longer apply."

At the defaults (medium sand, no surcharge) the horizontal thrust is 31.97 kN and the vertical load 127.44 kN:

QuantityResult
Active pressure coefficient K_a0.307
Overturning moment, resisting moment36.23 kN·m, 179.21 kN·m
Factor of safety against overturning FS_o4.95: “Overturning: OK.”
Sliding resistance, friction coefficient mu49.77 kN, 0.391
Factor of safety against sliding FS_s1.56: “Sliding: OK.”
Pressure at the toe, at the heel63.46 kPa, 42.74 kPa
MessageThe resultant is inside the middle third.
ChangeResult
Surcharge tickedFS_o 3.76, FS_s 1.3: “Sliding: the factor of safety is too low, widen the base or make it thicker.”
Loose sandFS_o 4.21, FS_s 1.15: sliding fails.
Dense sandFS_o 5.85, FS_s 2.1. Both pass.
Base 3 m wideFS_o 7.79, FS_s 2.02. Both pass.

Worked template 7: a pump and pipeline operating point

The seventh sample, Template: pump operating point, finds where a pump works. A pump lifts water through a pipeline to a higher tank. The pump gives less head as the flow grows, the pipeline needs more, and the pump runs where the two curves cross. The inputs are a choice of three pumps (radio buttons), the pipe diameter (a drop-down whose values are lengths), the pipe length, the static lift, and a checkbox for an aged, rougher pipe:

## Inputs
pump: ? (Small = 1, *Medium = 2, Large = 3) | pump
D:    ? [100 mm = 100 mm, *150 mm = 150 mm, 200 mm = 200 mm] | pipe inside diameter
L_p:  ? 400 m | pipe length
H_st: ? 15 m | static lift, from the water surface to the tank
aged: ? off | aged pipe (rougher: the friction factor is 0.030, not 0.018)

The pump is an index into two tables (H0_tab, Qmax_tab), as in the first template. What is new is the output. The sheet solves the crossing in closed form, tabulates both curves with a vector of flows and augment, and draws them with plot, so the form changes the numbers, the table and the chart together.

The whole sheet
<!--sheet-->
# Pump and pipeline: operating point

A template with inputs. Choose **Input** in the results bar to fill in the form. A pump lifts water
through a pipeline to a higher tank. The pump delivers the head $H_p = H_0 \left(1 - (Q/Q_{max})^2\right)$
at the flow $Q$ (a shut-off head $H_0$ and a free delivery $Q_{max}$). The pipeline needs the head
$H_s = H_{st} + f \frac{L}{D}\frac{v^2}{2g}$, the static lift plus the friction loss with a constant friction
factor $f$. The pump runs where the two curves cross. The table and the plot follow the form.

## Inputs
pump: ? (Small = 1, *Medium = 2, Large = 3) | pump
D:    ? [100 mm = 100 mm, *150 mm = 150 mm, 200 mm = 200 mm] | pipe inside diameter
L_p:  ? 400 m | pipe length
H_st: ? 15 m | static lift, from the water surface to the tank
aged: ? off | aged pipe (rougher: the friction factor is 0.030, not 0.018)

## Pump curves
The input above picks one entry of each list.

H0_tab:   [30 m, 40 m, 50 m] | shut-off head
Qmax_tab: [60 L/s, 75 L/s, 90 L/s] | free delivery
H_0:   H0_tab.pump -> m
Q_max: Qmax_tab.pump -> L/s
if pump == 1: "The pump is the small one."
if pump == 2: "The pump is the medium one."
if pump == 3: "The pump is the large one."

## Pipeline
g_acc: 9.81 m/s^2 | gravitational acceleration
f: 0.018 + aged * 0.012 | friction factor
A: pi * D^2 / 4 -> m^2 | flow area
K: f * L_p / D / (2 * g_acc * A^2) -> s^2/m^5 | friction head per flow squared

## Operating point
The two curves cross where $H_0 - H_0 Q^2/Q_{max}^2 = H_{st} + K Q^2$, so
$Q^2 = (H_0 - H_{st}) / (K + H_0/Q_{max}^2)$.

H_net: H_0 - H_st -> m | head the pump has above the static lift
if H_net <= 0 m: "The pump cannot lift the water to the tank: choose a larger pump or lower the static lift."
Q_op: sqrt(max(H_net, 0 m) / (K + H_0 / Q_max^2)) -> L/s | flow at the operating point
H_op: H_0 * (1 - (Q_op / Q_max)^2) -> m | head at the operating point
v:    Q_op / A -> m/s | velocity in the pipe
if v > 3 m/s: "The velocity is above 3 m/s: expect noise and wear, use a larger pipe." else: "The velocity is within 3 m/s."

## Table
Q_v:  [0, 10, 20, 30, 40, 50, 60] * 1 L/s | flows in the table
H_pv: H_0 * (1 - (Q_v / Q_max)^2) -> m | pump head
H_sv: H_st + K * Q_v^2 -> m | head the pipeline needs
T: augment(Q_v / (1 L/s), H_pv / (1 m), H_sv / (1 m)) | columns: flow in L/s, pump head in m, pipeline head in m

## Curves
H_p(Q): H_0 * (1 - (Q / Q_max)^2) -> m | pump head at the flow Q
H_s(Q): H_st + K * Q^2 -> m | pipeline head at the flow Q

plot H_p(x * 1 L/s) / (1 m) as "pump", H_s(x * 1 L/s) / (1 m) as "pipeline" for x in 0..60

The same crossing, found numerically from the two curves:

if H_net > 0 m:
    Q_num: solve H_p(Q) = H_s(Q) for Q in 0 L/s..Q_max -> L/s | flow where the pump head equals the pipeline head

At the defaults (medium pump, 150 mm, 400 m, 15 m lift, new pipe) the pump runs at 40.9 L/s and 28.1 m of head, with 2.31 m/s in the pipe. The table has seven rows, from 0 to 60 L/s: at 40 L/s the pump gives 28.62 m and the pipeline needs 27.53 m, and at 50 L/s the pump gives 22.22 m against 34.59 m, so the crossing lies between them.

ChangeResult
Small pump30.46 L/s at 22.27 m
Large pump49.99 L/s at 34.58 m, 2.83 m/s
Aged pipe35.21 L/s at 31.19 m
Diameter 100 mm19.37 L/s at 37.33 m, 2.47 m/s
Static lift 35 m18.29 L/s at 37.62 m
Small pump and static lift 35 m“The pump cannot lift the water to the tank: choose a larger pump or lower the static lift.” The flow is 0.

Share a template

A template is one text file. Save it (Ctrl+S) as a .sheet file and send that file, or paste the text of the sheet. Whoever opens it gets the same form, in any browser, with nothing to install. Once the app has been visited it runs offline too (see Saving, opening and working offline). Nothing is sent to a server: the numbers are worked out on the reader’s own computer.

  • The values you saved with Save values travel with the file, so a template can be sent already filled in. Send the file without that comment line to send the defaults.
  • Each person who opens it and saves values keeps their own numbers in their own copy.

Writing your own

  1. Write the calculation as an ordinary sheet and check it.
  2. Turn the quantities someone will want to change into inputs: put ? in front of the value.
  3. Put them together under a heading (## Inputs), so the form reads like a form.
  4. Put the results below the inputs, with a note on every line.
  5. Where a result depends on a choice, use an index and tables (worked template 1), or let the choice be the number itself (worked template 3).
  6. Add a message for each check (if util <= 1: "OK" else: "Fails"), so that the report says what the numbers mean.
  7. Test it in Input mode, then in Report with the defaults. That is what a reader without the form sees.

The ribbon’s Input/Output tab inserts a starting line for each kind: Entry, Dropdown, Radio and Checkbox write the ? form in a sheet. Data grid and More input forms (labelled, vector, matrix and formula inputs) have no sheet form and insert #UI lines, marked with >>. See Input forms with #UI.

Model bindings

A '<!--civilkit: bind L = path --> comment before an input can tie it to a quantity in a structural model. The specification and the in-app marker exist; no model is connected yet, so typed values are used.

Related calculators: Simply supported beam, Cantilever beam, Column buckling, Retaining wall stability, Pad footing bearing pressure, Pipe flow, Darcy-Weisbach, Pump operating point. More pages are in Calculators and guides.

Symbolic maths

Video: Symbolic maths for a beam deflection

The calculation engine is numeric: it gives you numbers. The Symbolic dialog gives you formulas. It rearranges an equation, differentiates, integrates, solves for the constants of integration and substitutes values, all exactly, with fractions kept as fractions and symbols kept as symbols. Then you put the result into the sheet and let the engine check it with numbers.

Open it from Functions > Symbolic on the ribbon. The module loads the first time you run something, and it works offline.

Using the dialog

  1. Type an expression, or an equation with =. Write * for every product and ^ for powers. The functions are sin, cos, ln, exp and sqrt; the constants are pi and e. Enter runs it; Shift+Enter starts a new line.
  2. Choose the operation:
OperationWhat it needsWhat you get
Simplifythe expressionlike terms collected, powers combined
Expandthe expressionproducts and powers of sums multiplied out
Factorthe expressioncommon factors, and polynomials in one variable
Differentiatea variable, and an order (1 by default)the derivative
Integratea variable, and for a definite integral both limitsan antiderivative (with no constant), or the value between the limits
Solve forone variable for one equation (write =), or several variables separated by commas for a linear system whose equations are separated by ; or new linesthe solutions; a quadratic gives both roots
Substitutevalues such as x = 2, b = 3*athe exact result
Evaluatea number for every variablea decimal number to 12 digits
  1. The result is typeset (with KaTeX) and also shown as text, with a Copy button.

  2. Insert into worksheet writes the result at the cursor:

    • in a sheet: a display formula block ($$ ... $$, typeset in the preview) or a quantity line name: expression;
    • in a Calcpad worksheet: a calculation line name = expression, or a comment line.

    A quantity line is calculated by the engine, so every symbol in it needs a value in the sheet. Use the formula block to keep a result in terms of symbols.

A worked derivation: the deflection of a simply supported beam

The beam has span L, uniform load w and stiffness EI. The bending moment at x is M(x) = w L x / 2 - w x² / 2, and the deflection y, taken in the direction of the load, satisfies EI y’’ = -M(x). These are the dialog’s results for each step (the inputs are in the first column).

StepOperation and inputResult
1Integrate -(w*L*x/2 - w*x^2/2)/(E*I) for x-L*w*x^2/(4*E*I) + w*x^3/(6*E*I)
2Add a constant C1 yourself and Integrate again: -(w*L*x^2/4 - w*x^3/6)/(E*I) + C1 for x-L*w*x^3/(12*E*I) + w*x^4/(24*E*I) + C1*x
3Add C2. The supports give y(0) = 0 and y(L) = 0, so Solve for C1, C2 the equations C2 = 0; -L^4*w/(12*E*I) + L^4*w/(24*E*I) + C1*L + C2 = 0C1 = L^3*w/(24*E*I); C2 = 0
4Substitute x = L/2 into the curve -L*w*x^3/(12*E*I) + w*x^4/(24*E*I) + L^3*w*x/(24*E*I)5*L^4*w/(384*E*I)

The midspan deflection is 5 w L⁴ / (384 E I). That is the formula to put in the sheet. The dialog can also differentiate it (5*L^3*w/(96*E*I) with respect to L), or evaluate it for given numbers: with w = 12, L = 6, E = 200 and I = 250 the result is 0.00405 (in consistent units of your choice).

Putting the result into a sheet

In the sheet, write the derivation as prose and display formulas, then give the engine the numbers and check the formula against the curve:

## Step 4: midspan

Substituting $x = L/2$ into the curve and simplifying gives

$$y\left(\frac{L}{2}\right) = \frac{5 L^4 w}{384 E I}$$

## Numbers

w: 12 kN/m | design load
L: 6 m | span
E: 200 GPa | modulus of elasticity
I: 250000000 mm^4 | second moment of area
delta: 5 * w * L^4 / (384 * E * I) -> mm | midspan deflection from the formula

y(x): -L * w * x^3 / (12 * E * I) + w * x^4 / (24 * E * I) + L^3 * w * x / (24 * E * I) | the curve with its constants
y_mid: y(L / 2) -> mm | the curve at midspan
ratio: y_mid / delta | 1 when the formula and the curve agree
w = 12 kN/m    design load
L = 6 m    span
E = 200 GPa    modulus of elasticity
I = 250000000 mm⁴    second moment of area
δ = 5·w·L⁴/(384·E·I) = 5 · 12 kN/m · (6 m)⁴ / (384 · 200 GPa · 250000000 mm⁴) = 4.05 mm
y_mid = y(L/2) = y(6 m / 2) = 4.05 mm    the curve at midspan
ratio = y_mid / δ = 4.05 mm / 4.05 mm = 1

The two routes agree: the exact formula from the dialog and the curve with its constants give the same 4.05 mm. The sample Beam deflection derived symbolically (Samples, group Sheet syntax) is this sheet in full, with the deflection curve plotted:

L: 6 m
w: 12 kN/m
E: 200 GPa
I: 250000000 mm^4
y(x): -L * w * x^3 / (12 * E * I) + w * x^4 / (24 * E * I) + L^3 * w * x / (24 * E * I)
plot -y(x * 1 m) / (1 mm) for x in 0..6

(The plot divides by 1 mm to give the plot a plain number, and flips the sign so the beam sags downward on the page.)

Limits

The algebra is exact rational arithmetic, so a result that does not fit in 128 bits is an error rather than a rounded guess, and a refusal is shown in words with the library’s own message (“Cannot integrate: power of a non-linear base.”). Nothing is guessed. The limits:

  • no complex numbers;
  • only sin, cos, ln, exp and sqrt;
  • integration covers a small class of integrands;
  • solving covers a single equation of degree 1 or 2, and linear systems of up to four unknowns;
  • symbols are treated as positive real numbers, so sqrt(x^2) is x.

For anything else, use the numeric tools: $Root, $Area, $Slope, lsolve and friends.

Related pages: The beam deflection formula, derived. More pages are in Calculators and guides.

Importing worksheets

Video: Import an existing worksheet

The worksheet importer converts worksheet files from a spreadsheet-like calculation format, with text, equations, plots and pictures placed freely on a page (files ending .xmcd and .mcdx), into a new Calcpad worksheet that this engine calculates. It evaluates nothing itself: it only translates, and then the one engine runs the result. Every number in the output is a number that was in the source file.

Nothing is uploaded. The file is read and converted in the page, by a module that loads on first use.

How to import

Any one of:

  • File > Import worksheet…
  • the Import worksheet button on the Document tab
  • File > Open… and pick the file
  • drag the file onto the page (a dashed hint shows while you drag)

The converted worksheet opens as a new unsaved tab named after the file, with the extension .cpd. Picture files from the source go into the library under /imported/<file name>/. Importing the same file name again replaces that folder.

A dialog then says how the import went, for example:

Imported tank.xmcd: 18 of 21 regions converted live, 2 shown as static pictures, 1 need attention.

followed by a list of what did not convert, in plain words, by the number of regions affected (for example “calls to a function from an add-in we cannot run” or “embedded objects”). Two toggles re-run the import in the same tab:

  • Pictures of unconverted regions (on by default): a region that cannot be converted is shown as a picture of the original, so the page still reads like the source.
  • Show saved results as static values (off by default): places the values the source file saved where it could not compute them.

The dialog’s last line repeats that the file was read in this page and was not uploaded.

What converts

The importer follows the author’s page: it reads regions in reading order and writes Calcpad lines.

In the sourceIn the result
Text, with heading styles, bold, italic, underline, sub and superscript, paragraph fonts, sizes and coloursText lines. Fonts and sizes can be tidied away (see below).
Definitions (x := ...), evaluations (x =), functionsCalcpad definitions and equation lines, with the source’s names, subscripts and Greek letters.
UnitsThe same units, converted to this engine’s names. A unit the engine does not know is reported.
Vectors, matrices and indexingVectors and matrices. The array origin is shifted to 1, with a note.
Sums, products, integrals, derivatives (supported forms)The engine’s $Sum, $Product, $Area and slope commands.
Programs made of loops and conditions, early exits, grown arraysExpression blocks.
Plots (x-y plots)$Plot lines. A plot’s colours, markers and axis ranges may not carry over (a note says so).
Solve blocks of one or two unknownsSolved here by iteration, and kept only if the equations hold at the answer; otherwise the value the file saved.
Statistics functions, complex numbers, simple text values (codes)Converted.
Referenced worksheetsTheir definitions are read in, when the file holds a copy.
PicturesEmbedded in the library.

The author’s equations are shown as the author wrote them (stacked fractions, sums with bounds, subscripts, a transpose superscript), typeset as maths, and computed out of sight. The page reads like the source, and the Word export turns the typeset equations into Word equations.

What is frozen

Some values cannot be computed here, so the importer takes the number the source file saved and shows it as a literal marked frozen:

  • values that came from an input component (a combo box, a list box, a text box): the stored selection becomes the value, and it does not follow a change of the input;
  • a call into a function from an external library (an add-in) that is not available here, when the file saved a value;
  • a table read from a data file, as the table the worksheet saved;
  • a solve block whose iteration does not verify.

The dialog counts frozen values and says so.

What does not convert

Each gap is counted under a stable code and replaced by a placeholder: a typeset, not-calculated equation or a static picture of the original. The main ones:

  • range variables that fall outside the supported uses, and programs outside the supported subset;
  • solve blocks of more than two unknowns, other solvers, symbolic evaluation;
  • derivative and integral forms the importer does not map, and some summation forms;
  • plots that are not x-y plots, or that store binary items;
  • embedded objects, components, worksheet references with no copy, add-in functions with no saved value;
  • text values that are joined, measured or formatted (concat and similar);
  • a region the source has switched off, and some page headers and footers.

A region that depends on a gap is reported as downstream of it, and the dialog ranks the missing features by the number of regions each blocks. A calculation that depends on an unconverted region shows that region’s names as undefined; read the dialog list first.

The importer is a work in progress. Plan on checking an imported worksheet against the source, line by line, before relying on it, as you would with a hand conversion.

After the import

  • Tidy text (Document tab) removes imported fonts, sizes and colours from paragraphs and turns import markers into short notes. Equations are left alone.
  • Text to Markdown tidies and then writes runs of simple paragraphs as Markdown, which you can then edit as rich text by double-clicking. See Editing.
  • Save. The .cpd refers to the pictures by library path (imported/<name>/R12.svg). Pictures stay as long as the browser’s library does. A .cpd opened later from disk shows its pictures only while the library holds them; export to HTML or Word first for a self-contained file.

Limits

Input over 64 MiB, XML nested deeper than 256, a DTD, and pictures over 16 MiB each or 192 MiB in total are refused or skipped. Errors are messages, not crashes: “… is not a worksheet this importer reads”, “not well-formed XML”, “the file is a zip package that cannot be read”.

Related pages: Opening .xmcd and .mcdx files. More pages are in Calculators and guides.

Importing a spreadsheet

Import spreadsheet reads an Excel or CSV file and lets you pick cells from it and add them to a sheet as named quantities and tables. Use it for a schedule of loads, a list of member sizes or a column of test results that already lives in a spreadsheet.

What it does and does not do. The values are copied into the sheet as ordinary lines, so the sheet carries them and a report prints without the file. Formulas in the file are not recalculated and there is no live link back to the file: a formula cell gives the value the file stored for it (spreadsheet programs save one), and the calculation is done by your sheet from there. If the file changes, import the cells again. Nothing is uploaded; the file is read in the page.

How to import

Any one of:

  • the Import spreadsheet button on the Document tab (next to Import worksheet)
  • File > Import spreadsheet…

Choose a .xlsx, .xlsm, .csv or .tsv file. A panel opens over the page. It is not modal: you can click in the editor to move the cursor between additions, and Close (or Esc) puts it away.

Open or create a sheet first. The lines are sheet lines, so adding into a Calcpad worksheet is refused with a message.

The panel

  • Tabs along the top, one for each sheet of the workbook (a CSV has one).
  • A read-only grid with column letters and row numbers. Formula cells are grey and italic, and hover (or the cell’s tooltip) shows the formula text. Constant cells are plain.
  • Click a cell, or drag over a range, to select it. On a touch screen tap a cell, switch on Select range, then tap the far corner.
  • An action bar under the grid shows the selection, a proposed name and unit you can edit, and the actions that fit the selection.
  • Cells you have added turn green with their name, so you can see what is already used.
SelectionActionWrites
A constant numberAdd as inputspan: ? 6 m (the reader can change it)
A number or formula cellAdd as valueMstar: 56.25 kN*m (the stored result)
A range of numbersAdd as tablea vector [1; 2; 3] or a matrix [1, 2; 3, 4]
A range with textAdd as tablea table of text for the report (not used in calculations)
Two columns, label then valueAdd labelled rowsone quantity line for each row

A formula cell cannot be an input, because its value is a result. A text cell has no number to add.

The lines go at the editor cursor: on the cursor’s line when it is blank, otherwise on the lines after it. Above them goes a short source comment, for example <!-- loads.xlsx, Loads!B1 -->. It is an HTML comment, so it shows in the editor and prints as nothing in the report.

Names and units

The name is guessed from the label to the left of the cell, or the header above it, and turned into a sheet name (see Quantities): several words become camel case (Design load is designLoad), Greek letters become their spellings (φ factor is phiFactor), a leading digit gets an n, and a name that is a keyword gets a _. If the sheet already has the name, a number is added (span2). Edit the name before you add if you want another.

The unit is taken from the label’s brackets (Length (m), Load [kN/m], Area (mm²) is mm^2), or from a unit in the cell beside the value (a unit column), when it looks like a unit. Words in brackets such as (optional) are not taken. A wrong or empty unit is easy to fix in the name and unit boxes, or in the sheet afterwards.

The label becomes the note after the value (span: 6 m | Span).

Tables

A range of numbers becomes a vector (one row or column) or a matrix, with the unit on every element. If the first row is text over numbers, it is treated as a header: the matrix holds the numbers below, and the header names go in the source comment. Empty cells in the numbers read as 0. A table is limited to 5,000 cells. Reach an element with A.(row, column) as for any matrix.

A range that has text in it is added as a plain table of the cells as shown, for the report only.

Labelled rows

Select a range of two columns: the labels, then the values (a third column may hold the units). Each row with a label and a number becomes one line, named from its label. Rows whose value is not a number are left out, and the status line says how many. Tick Rows as inputs to make the constant rows inputs.

Files and limits

  • Excel: .xlsx and .xlsm. Shared and inline strings, numbers, booleans and error values are read. Dates are shown as their serial numbers. Merged cells are ignored (each cell is shown where it is stored). Macros are never run. The old .xls format and password-protected workbooks are refused with a message; save as .xlsx or .csv.
  • CSV and TSV: quotes (and doubled quotes), line breaks inside quotes, a comma, semicolon or tab delimiter found by itself, and a decimal comma when the delimiter is not a comma (6,5).
  • Files over 5 MB, and workbooks with more than 200,000 cells, are refused. Save the part you need as a CSV.
  • A damaged file shows a message and changes nothing.
  • The grid shows 200 rows at a time (a button shows more) and the first 100 columns.
  • Text cells cannot be used as values in calculations; only numbers and booleans (as 1 or 0).

Number format

Some languages write 1,5 where others write 1.5, and group digits as 1.000,5 or 1 000,5. CivilKit Calcs lets you choose how numbers are shown and typed. Your worksheets do not change: a sheet always keeps the decimal point, so a file reads the same on every machine.

Choosing a format

Open Settings (the gear at the right end of the top strip). Number format is on the General tab, under Language.

ChoiceLooks like
Automaticfollows the language of your browser
Point1,234.5
Comma1.234,5
Space and comma1 234,5

Group digits adds the thousands separator; it is off by default. The choice is remembered in this browser. Add ?numfmt=comma to the address to try a format on one page without storing it (point, comma, space or auto, and &numgroup=1 for digit groups).

What changes

Results in the preview, the report, print and PDF, and the HTML export, plus the equations and text of the Word export and the Report sheet of the Excel export. Excel’s variable sheets keep real numbers. Variable names, subscripts, exponents and units are never touched, and neither is text you wrote: a sentence that says “use 1.5 m” stays as typed.

L: 6.5 m
w: 12.5 kN/m
M: w * L^2 / 8 -> kN*m
L = 6.5 m
w = 12.5 kN/m
M = w·L² / 8 = 12.5 kN/m · (6.5 m)² / 8 = 66.02 kN·m

In the Comma format that reads L = 6,5 m and M = ... = 66,02 kN·m, while the sheet itself still says 6.5.

Typing numbers

In a comma format an input box shows 6,5 and accepts both 6,5 and 6.5. The value the engine and the saved values use is always 6.5. A slider moves the box as before, and a message such as “must be from 0,5 to 2,5” uses your format. In an input box a point is always a decimal point, so write 1234,5 or 1 234,5 rather than 1.234.

What does not change

Pasting into the editor is not converted, because a comma in a formula separates arguments. Plot axes, 3D views, Python output and spreadsheet-style grids keep the decimal point.

Exporting

Video: Export a report to Word, Excel and PDF

A calculated sheet leaves the page in four ways: a PDF through the print dialog, a Word document, an Excel workbook and standalone HTML. All of them are built in the page, from the same calculated report, so what you see is what you export. The Word and Excel writers load the first time you use them and work offline.

The Document tab has buttons for Print PDF, Word, Excel and Export…. The File menu has Print PDF…, Export… and Export Excel…. The Export dialog lists the views you can export (Report, Preview, Input form, Unwrapped), each with its own Save PDF, Save Word (not offered for the input form and the unwrapped listing) and Save HTML buttons, and a Plots list that downloads each plot as an image, or all of them as a ZIP.

Which view to export: Report is the usual choice. It applies the values entered in an input form, hides #pre text and shows #post text. Preview shows what the results pane shows.

Page breaks

To start a new page at a point in the report, put a page break line there:

# Loads

w: 12 kN/m | design load

<div style="page-break-after:always"></div>

# Bending

L: 6 m
M: w * L^2 / 8 -> kN*m

Print PDF and Word both start “Bending” on a new page. You do not need to type the line:

  • In a sheet, the + between two blocks has Page break at the end of its menu.
  • The ribbon has Page break on the Document tab (Page group) and the Text Formatting tab. It inserts the line at the cursor.

The preview draws the break as a dashed line labelled “Page break”. The line is not printed and is not in the Word file. A Calcpad worksheet (.cpd) writes the same thing as an HTML comment line, '<div style="page-break-after:always"></div>, and the ribbon button inserts that form there.

Word also honours the other ways HTML forces a break on an element (page-break-before: always, break-before: page, break-after: page). Excel has no pages, so the workbook ignores page breaks.

Page view

To see where the pages of a long report break without printing it, choose Pages in the results bar (Preview and Report). The results are laid out on sheets of the PDF’s paper size, with its margins drawn as a faint dashed box, a label “Page 2 of 5” on each sheet and the manual page breaks honoured. The page is the one the PDF settings describe (Settings, Export tab, or the document’s own PDF settings), so changing the paper size, the orientation or a margin changes the view at once. The sheets are always drawn in the light theme, as they print. On a narrow window the sheet is scaled to fit. The choice is kept.

A block that would run over the bottom margin moves to the top of the next page, a heading stays with the line after it, and a block taller than a page is left to run on. The browser keeps long paragraphs and tables in one piece less often than this does, so on the last line or two of a page the print dialog’s own preview has the last word. The view is on screen only: nothing about it is printed or exported.

Word

Word writes a .docx of the report:

  • Equations are real Word equations (Office Math): fractions, subscripts, sums, matrices, units. In a test sheet with a handful of formulas the document held 21 equations.
  • Headings, paragraphs, lists, links and tables keep their form. A Markdown pipe table gets rules.
  • Plots and other drawings are pictures. A plot is stored as a PNG (the SVG is kept beside it, for versions of Word that read SVG).
  • Pictures from the library are embedded.
  • A formula typeset with LaTeX in a sheet appears as its TeX source in italics, not as a Word equation.
  • An interactive Plotly chart cannot be carried. A paragraph stands where it was. A matplotlib figure from a Python block is carried as a picture.

The Word document has been checked in LibreOffice, not in Microsoft Word.

Excel

Excel writes a workbook that mirrors the calculation:

SheetHolds
ReportThe report in document order. Headings and text in merged cells; every equation a row with its description, name, expression, expression with the numbers put in, value and unit. Text tables are cell ranges.
VariablesEvery variable in the order it was first assigned, with its last value and unit.
One sheet for each vector or matrixIts elements, a row per row, with the unit. A variable’s row on Variables links to it.
InputsThe variables set by input fields and #UI controls.
Plot dataThe points of every plot, two columns per curve.

A plot line or $Plot becomes a native Excel XY chart on the Report sheet at the place of the plot, with its series pointing at the Plot data sheet, so you can edit the data and the chart redraws. For a test sheet with one plot line the workbook held one chart and these sheets: Report, Variables, K, F, u, Inputs and Plot data (K, F and u being a matrix and two vectors).

What the chart loses against the drawing: the faint fill under a curve, the exact fonts and grid style. Colour maps and other drawings are pictures. The cells hold calculated values with the expressions as text, not live Excel formulas.

The workbook opens in LibreOffice and a Python reader. It has not been tried in Microsoft Excel.

PDF

Print PDF opens the browser’s print dialog on the report. Choose “Save as PDF” as the destination. The page size, orientation and margins come from the PDF settings (Settings, Export tab; Document > Header and footer opens it there). Until you choose a paper size there, it follows the browser’s language: Letter in the United States, Canada, Mexico, the Philippines, Chile, Colombia, Venezuela and Costa Rica, and A4 everywhere else. A size you have chosen is kept. The printed page carries the browser’s own header and footer in place of title, date and page numbers; turn “Headers and footers” off in the print dialog if you do not want them.

The printed page is the report: the buttons under plots are not printed, and an interactive chart is printed as a still picture of it (draw the chart on the page first; one that was never drawn is replaced by a note).

HTML

Save HTML writes a standalone page with the report, its styles, fonts and pictures. An exported input form is static: it shows the controls, but nothing recalculates behind them.

Files a worksheet writes

#write and #append save matrices to files. The browser keeps the file in the library and downloads it when its content changes. By default this happens when you make a report; the Export dialog’s Write files choice and Write to Disk button change that.

From the command line

The command-line front end of the engine converts a Calcpad worksheet to HTML, Word or Excel: Cli input.cpd output.xlsx. It is built from the same code. A sheet has to be compiled first (Convert to Calcpad, or the sheet compiler), because the command line reads Calcpad.

Related pages: Export to Word, Excel and PDF, Calculations instead of spreadsheets. More pages are in Calculators and guides.

Editing

There are two places to edit: the source on the left and, in the results, the page itself.

What you can write

A sheet holds prose, quantity and input lines, conditions and loops, plots, Python blocks and diagrams. The line kinds lists each one with its chapter. A diagram is a fenced mermaid block of text that the results draw as boxes and arrows; see Diagrams for a first example and the Diagrams chapter for more.

The source editor

The editor colours a sheet by role (prose, quantity, block, raw Calcpad, plot). It underlines mistakes and lists them in the Errors dialog; the status bar at the bottom shows the error, warning and information counts.

ActionHow
Complete a name, function, unit or keywordjust type; Tab accepts the highlighted entry, Ctrl+Space opens the list by hand
Rename a name everywhereF2, or the editor’s context menu, or the Variables tab (right-click a name)
Find a variable or function and its valueCtrl+; (Cmd+; on a Mac)
Go to a name’s definitionF12, or hover to see the defining line and its Calcpad spelling
Find referencesShift+F12, or the editor’s context menu
Tidy the sheetShift+Alt+F (Format Document)
Wrap long linesAlt+Z
FindCtrl+F (Cmd+F on a Mac)
Insert a symbol, function, unit or snippetthe Insert tab in the sidebar, or the ribbon

Completion

The list opens as you type, in a worksheet and in a sheet alike, and offers what fits where the cursor is:

  • Names defined above the cursor, with their last calculated value next to them (load = 12 kN). A name defined further down is not offered, and neither is the word you are typing. The parameters of the function you are writing on the current line are offered too. Greek letters, subscripts and primes work as in any name: typing σ finds σ_c.
  • Built-in functions, with their parameters and a one-line description. Pick one and Tab fills the call with a placeholder for each argument. In a sheet the arguments are separated with commas, in a worksheet with ;. The same list is what the function reference shows.
  • Units, only units, right after a number (5 k offers kN, kg, kA), and after a unit and * or / (5kN*). A sheet offers units after -> as well. A worksheet’s own custom units are in the list.
  • # directives and $ commands at the start of a line of a worksheet (#fo offers #for).
  • Block keywords and format markers at the start of a line of a sheet: if, else, for, while, repeat, plot, >>, code fences for calcpad and python, $$, the input forms (input, dropdown, slider, radio, checkbox) and <!--sheet--> on the first line.

Nothing is offered where the text is not code: a text or comment line, after a quote mark, in a note (after |), in a string, in a #markdown, #html or #python block, in sheet prose and formulas, and after the ? of an input. The calculated values come from one calculation of the whole worksheet (Python blocks are not run for it), so the first list after an edit may show the value from a moment ago; the list never waits more than a quarter of a second for it.

Rename everywhere

Put the cursor on a variable, function or macro and press F2 (also in the editor’s context menu, and in the Variables tab: right-click a name and choose Rename Everywhere). A small box opens at the top of the editor. It says how many places and lines will change, marks every place in the text and shows the first changed lines as they will read. Enter (or the Rename button) applies it as one undo step; Esc cancels.

  • Scope is respected. A function’s parameters, and the name bound inside $Sum{ ... }, are renamed only on their own line; a macro’s parameters only inside its #def block. Renaming a variable a leaves a parameter a alone, and the other way round. In a sheet the same holds for a function’s parameters and the variable of a plot line.
  • Only code is renamed. Comments and text lines, strings, #markdown and #html blocks, and in a sheet prose, notes after |, headings, $...$ formulas, and the unit after a number (3 psi stays) are left as they are. A formula is typeset text, not a reference to a variable, so it is not renamed.
  • Inputs follow the name. A ? input (L = ?, L: ? 6 m) is an ordinary definition and is renamed with the name.
  • Python is left alone except for what it hands over. The names a Python block passes to the worksheet with export(name=...) or export("name", ...) are the worksheet’s variables, so they are renamed with the name (the box counts them). Any other Python code, which is not a reference to a worksheet variable, is never touched.
  • A name that would collide is refused, with the reason, and Rename stays off: a name that is not valid (it starts with a letter and holds letters, digits, _ and primes), a keyword or built-in function or constant, a name already in use in the document or in an included file, and a name a parameter on a changed line would capture (or that would hide a variable used inside the function). A name that is also a unit is allowed, with a note.
  • A name defined in an #included file cannot be renamed from here (only this document is edited).

The variable palette

Ctrl+; (Cmd+; on a Mac) opens a search box over every variable, function and macro of the document, each with its last calculated value and unit and the line it is defined on. The key is not used by the browsers or by the editor itself. Type to filter: letters in order are enough (sc finds sigma_c), and built-in functions are included once you type something. Up and Down choose, Enter inserts the name at the caret (a function goes in as name() with the caret between the brackets), Alt+Enter (or the arrow button on the row) goes to where it is defined, Esc or the same key closes it. A tap on a row inserts it, so it works on a touch screen. The Variables tab in the sidebar has the same names, with a search box that matches the name, the definition, the parameters and the note.

The Insert tab has a search box that filters the whole library. In a sheet, entries that have no sheet form (the data grid and the other #UI forms, $Map, directives) carry a >> mark and insert Calcpad text as >> lines.

The text toolbar

Select some words in a line of prose, or click into one, and a small toolbar appears above the line: Style (Normal, Heading 1, 2 or 3), B, I, </> for code, Link, a bulleted list and a numbered list. It does not appear on quantity lines, in code fences or inside a $$ formula, where those would only add characters that mean something else. The same toolbar appears over the text in the in-place rich-text editor.

Each button’s tooltip shows the Markdown it types (Bold: **text**, Link: [text](address), Numbered list: 1. item), so you can learn the syntax and type it yourself next time.

  • A button is a toggle: Bold on text that is already bold takes the ** off again, and a list button on a list takes the markers off. A button that is on is shown pressed.
  • With no selection, Bold wraps the word at the caret.
  • Link wraps the selection as [text](url) and selects url, ready for the address.
  • The edit is made in the source, in one undo step, and the editor keeps the focus.
  • On a phone or tablet the floating bar stays away so it does not fight the system selection menu; the in-place editor keeps its fixed bar there.

In-place editing in the results

Edit a sheet where it stands, in the preview.

  • Click a block (a quantity line, a plot line, a table, a formula, a paragraph) and an editor opens over it. Dragging to select text does not open it.
  • Click away applies the change. Esc throws it away. Enter applies at once (Ctrl+Enter for prose, where Enter makes a new line).
  • Input and calculation lines are one-line edits. A paragraph, a heading, a list or a table opens as rich text: a small toolbar over the text with bold, italic, heading levels, bullets, a table and its row and column controls. A line under the box says “Ctrl+Enter or click away to apply · Esc to cancel”.
  • Everything you apply is written back to the source in one undo step. A paragraph or table you open and apply without changing keeps its exact original lines.

In a Calcpad worksheet, prose written as Markdown (a #markdown … #end markdown block) is edited the same way, by double-clicking it. The worksheet importer’s Tidy and Markdown options write this form (see Importing worksheets). To bring numbers from an Excel or CSV file into a sheet as inputs, values and tables, see Importing a spreadsheet.

What the rich-text editor writes is plain Markdown: **bold**, _italic_, ~x~ subscript, ^x^ superscript, ++x++ underline, - lists and pipe tables (no merged cells; a cell is one line). It loads the first time you use it.

Insert between blocks

Move the pointer between two rendered blocks and a dashed line appears with a + in the middle. Click the + for a menu of blocks to insert there: Math line, Text, Heading, List, Table, Plot, Condition, Python or Page break (see Page breaks). The new block goes in front of the next block’s source line, indented like it, and its first word is left selected in the editor so you can type over it. On a touch screen the + stays hidden until you tap a block, and then shows only in the two gaps beside it.

Cut, copy and paste blocks

The block menu (the ⋮ grip at the left of a block) has Cut, Copy and Paste below. Copy puts the block’s source text on the system clipboard, so you can also paste it into another sheet or a chat. Cut does the same and then deletes the block, with an Undo toast. Paste below inserts the clipboard text after the block, with one blank line between, as a single undo step. If the browser will not let the page read the system clipboard, Paste uses the last block you copied or cut in this window. The + menu between blocks also lists Paste whenever there is something to paste.

Ctrl+Shift+K (Cmd+Shift+K on a Mac) deletes the block that holds the editor caret, with the same Undo toast. In a file that is not a sheet it keeps its usual meaning, delete line.

Turning a block off

Disable in the block menu comments a block out: it drops out of the preview and the calculation but stays in the sheet. A sheet has no multi-line comment, so each line of the block is wrapped in an HTML comment (the one comment the language has):

a: 2 m
<!-- b: a * 3 -->

A disabled block is not drawn at all, so it has no grip. To get it back, put the caret in it and press Ctrl+Shift+/ (Cmd+Shift+/ on a Mac), which toggles Disable and Enable, or press Undo right after disabling. Limits: every line is wrapped on its own, a blank line inside the block becomes an empty comment so the block stays in one piece, and a --> inside a line is written as --&gt; while it is disabled and restored on Enable. Anything that used a disabled math line sees an undefined name until it is enabled again.

Collapsing sections

Hover a heading in a sheet and a small arrow shows under its grip. Click it and every block under the heading, up to the next heading of the same or a higher level, folds away; the heading shows how many blocks are hidden. Click the arrow again to open the section. A folded ## section hides only its own blocks, a folded # section hides its ## sub-sections too. The grip menu of a heading also has Collapse all and Expand all.

Folding is only a view: the sheet text and the results do not change, and printing and exporting always include everything. Folds stay as you edit and when you switch between tabs. Headings are matched by level, text and how many headings with the same text come before them.

Sorting a table

Click a column heading of a table in the preview to sort its rows by that column: the first click sorts ascending, the second descending, the third puts the rows back in the order of the source. An arrow next to the heading shows which way it is sorted. A column of numbers sorts by value, even with a unit after the number (2.5 kN comes before 10 kN); any other column sorts as text, with A2 before A10. Empty cells stay at the bottom.

Sorting is only a view, like folding: the sheet text does not change, the sort stays as you edit, and printing and exporting show the rows as they are written. The headings are buttons, so Tab reaches them and Enter or Space sorts; on a phone, tap a heading. See Tables.

Reordering blocks

Drag a block’s grip up or down; a blue line shows where it will land, and the block goes there when you let go. Dragging a heading takes its whole section along: the heading and the blocks up to the next heading of the same or a higher level (folded blocks too). A section cannot be dropped inside itself. The move is one step in the editor’s history, and a toast offers Undo. A click on the grip, or a movement of under 6 pixels, still opens its menu. On a touch screen, tap a block to show its grip, then drag the grip.

Plot chips

Under each plot in the preview there is a row of chips: Log x, Log y, 1:1 (equal axis scale), Copy data, PNG and SVG. Copy data puts the plotted values on the clipboard as tab-separated text, ready for a spreadsheet. The 3D plots have Copy data and PNG only.

Sliders on inputs

Give a number input a range and Input mode shows a slider under its box:

L: ? 6 m [2 .. 12 step 0.5] | span
w: ? 12 kN/m [0 .. 30] | design load
M: w * L^2 / 8 -> kN*m | maximum moment

Dragging the slider (or using the arrow keys, Home and End) fills the box and recalculates the results while you drag; typing in the box moves the slider. The numbers are in the unit of the default, the slider stops at the minimum and maximum, and step is the size of one stop (without it, about a hundredth of the range). A line without brackets has no slider. A typed value outside the bounds is refused with a message beside the box. On a phone the track is taller so a finger can use it. See Templates with inputs.

The math keyboard

The Keyboard item in the status bar opens an on-screen math keyboard with tabs for numbers and operators, functions, calculus and plots (sum, integral, root, parametric plot), matrices, capital and lower-case letters, Greek letters and units. On a computer it is a panel you can drag by its title; on a touch screen it docks at the bottom. A key or template inserts at the cursor of the editor, or of the in-place editor when one is open. In a sheet, angles are degrees unless the sheet has a #rad line.

Convert a selection to a formula

Select an expression you wrote in a sentence, say w*L^2/8, and press Ctrl+Shift+E (Cmd+Shift+E on a Mac), or choose Convert Selection to Formula in the editor’s right-click menu, or = Formula on the text toolbar. In a sheet this

w: 12 kN/m
L: 6 m

The moment at midspan is w*L^2/8.

becomes

w: 12 kN/m
L: 6 m

The moment at midspan is w*L^2/8.
res1: w*L^2/8

The new line goes after the paragraph, and its name is selected: type a better one (Mmid) and it is named. Where the selection lands:

  • In text (prose, a note after |, a Calcpad text line or comment): a line of its own after the paragraph. In a sheet it is a named line, res1: w*L^2/8; in a Calcpad worksheet a plain calculation line, w*L^2/8. If the selection is the whole line, the line itself becomes the formula. A selection written with its name, M = w*L^2/8, keeps that name, and $...$, backticks and a full stop around it are dropped.
  • In a calculation: the expression is pulled out to a named line above, and the selection becomes the name: M: w*L^2/8 -> kN*m turns into res1: w*L^2/8 and M: res1 -> kN*m. Both copies of res1 are selected, so typing a name renames the two at once.

The new name is the first of res1, res2, … that the document does not use yet. The whole change is one undo step. A selection that is not an expression on one line (plain words, a heading, a code fence, an input’s default) is left alone and the editor says so. On a phone or tablet a = Formula button shows under the selection instead of the toolbar.

The sidebar

The sidebar has three tabs: Insert, Contents (the outline of headings) and Variables. Settings, Export, Errors and Prettify open as dialogs from the ribbon (and Errors from the status bar); Esc closes them.

Phones and tablets

At 760 pixels wide or less, the app shows one pane at a time, switched from a bar along the bottom: Edit, Results and Insert. The ribbon starts folded; a tap on its open tab folds it again.

  • A long press (half a second) on a rendered line, paragraph or table opens the same in-place editor as a click. Apply and Cancel stay on screen.
  • The in-place editor stays visible when the on-screen keyboard opens, and its buttons stay above the bottom bar.
  • A row of keys under the line editor offers what a phone keyboard hides: ^ * / ( ) = < > ≤ ≥ √ π ° | _ , ; and the common units (mm, m, kN, MPa, kN·m). A tap inserts at the cursor and keeps the keyboard open. The row scrolls sideways.
  • A plot’s hover toolbar is left out on a phone; pinch and drag still work.
  • Python can need several times longer on a phone. The page offers the longer time limit when a block runs out of its ten seconds. See Python blocks.

The app can be installed to the home screen and works offline. See Saving, opening and working offline.

Embedding a calculator

An embed shows one sample sheet on another web page: its inputs as a small form and its results beside or under it. A reader changes an input and the results recalculate in their own browser, with the workings shown. The page Embed a calculator lists the calculators with a snippet to copy for each.

The embed address

An embed is the app’s address with embed=1 and the id of a sample:

<iframe src="https://civilkit.io/calcs/?embed=1&sample=template-simply-supported-beam"
        width="100%" height="560" style="border:1px solid #ccc" loading="lazy"
        title="Simply supported beam check: CivilKit Calcs" allow=""
        sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"></iframe>

The id is the one the samples browser and the ?sample= links use. The embed shows no ribbon, no sidebar, no tabs and no editor: a slim header with the sheet’s title and an Open in CivilKit Calcs link (it opens the same sample in the full app in a new tab), the form and the results.

The form is drawn from the sheet’s input lines (see Templates with inputs): a number box, a slider for a number with bounds (L: ? 6 m [2 .. 12 step 0.5]), a list, radio buttons or a checkbox. A typed number outside the slider’s bounds is not used and the box says why. A sheet with no inputs at all gets its plain number lines (L: 9.8 m | span) as inputs, so a worked example can still be tried.

OptionValuesWhat it does
samplea sample idThe sheet to show (default: the simply supported beam template).
themelight, dark, autoauto (the default) follows the reader’s system setting.
modeinput, results, bothOnly the form, only the results, or both (the default).
hidetitleLeaves out the title (the Open link stays).
embed1, editedit adds a small text editor below, for changing the sheet itself.
allowpython1Lets the sheet’s Python blocks run (the reader is still asked first).

Without allowpython=1 the Python blocks of a sheet are not run: the embed shows their code and a note, and the results that need them are missing.

The loader script

Instead of writing the frame yourself, put a placeholder where it goes and load the script once:

<div data-civilkit-sample="template-pipe-flow-darcy" data-height="560" data-theme="auto"></div>
<script src="https://civilkit.io/calcs/embed.js" async></script>

The script (about 3 KB, no dependencies) turns each placeholder into the frame above, with the sandbox, and then fits the frame’s height to its content as the reader works. It accepts data-theme, data-mode, data-hide, data-height (the height before the content is measured) and data-title. For a copy of Calcs on your own host, data-origin and data-path say where it lives (https://example.com and /calcs/); the script accepts height messages only from that origin. Each message from the frame is also fired on the iframe as a civilkit event.

Talking to the embed

The embed and the page around it talk with postMessage. The embed answers only its parent page (event.source === window.parent) and checks every value; the page should check that a message comes from https://civilkit.io (or its own copy).

MessageDirectionMeaning
{type: 'civilkit-ready', sample, inputs}embed to pageThe form is built. inputs lists each input: name, kind (number, select, radio, check), label, unit, value, and min, max, step or options.
{type: 'civilkit-results', sample, values}embed to pageAfter each calculation. values maps each name to {value, unit, text}: a number where the value is one, and the text as shown.
{type: 'civilkit-embed-height', height}embed to pageThe embed’s content height in pixels, after every layout change.
{type: 'civilkit-error', errors}embed to pageA civilkit-set was refused in full or in part, with the reasons.
{type: 'civilkit-set', values: {L: 8}}page to embedSets inputs by name, then calculates.
{type: 'civilkit-get'}page to embedSends the last results again.

A value set from the page must name an input of the sheet. A number must be finite and, for a slider, within its bounds; a choice must be one of its option values (or labels); a checkbox takes true, false, 1 or 0. The valid values of a message are applied and the others are reported in one civilkit-error.

const frame = document.querySelector('iframe[src*="embed=1"]');
window.addEventListener('message', (e) => {
  if (e.origin !== 'https://civilkit.io' || e.source !== frame.contentWindow) return;
  if (e.data.type === 'civilkit-results') console.log(e.data.values.M_max.text);
});
// Once the frame says it is ready:
frame.contentWindow.postMessage({ type: 'civilkit-set', values: { L: 8, w: 20 } }, 'https://civilkit.io');

Privacy

The embed runs the same engine as the app, in the reader’s browser. It sends nothing to a server, sets no cookies, loads no analytics and stores nothing: the app’s own saved settings, files and open tabs are not changed by it. It does not register the app’s offline service worker either (a reader who already uses the app gets the embed from the same offline copy).

Using CivilKit Calcs from an AI assistant (MCP)

An AI assistant such as Claude can run your calculations in CivilKit Calcs through the public MCP server at https://civilkit.io/mcp. MCP (the Model Context Protocol) is the standard way assistants connect to tools. With the server added, an assistant can write a sheet, run it in the same engine as the app, read the values and units back, check a hand calculation, convert units, and look things up in this guide, the function reference and the samples.

The server is read only and needs no account. It stores nothing: each request is calculated and answered, and that is all.

Adding the server

Claude Code, in a terminal:

claude mcp add --transport http civilkit-calcs https://civilkit.io/mcp

Claude Desktop and claude.ai: Settings > Connectors > Add custom connector, with the URL https://civilkit.io/mcp.

Other clients (Cursor, VS Code, and any client that takes a remote server): add an HTTP (Streamable HTTP) server with that URL. In a JSON configuration it usually looks like this:

{
  "mcpServers": {
    "civilkit-calcs": { "type": "http", "url": "https://civilkit.io/mcp" }
  }
}

A client that runs only local servers can reach it through the mcp-remote bridge: {"command": "npx", "args": ["-y", "mcp-remote", "https://civilkit.io/mcp"]}.

Opening https://civilkit.io/mcp in a browser shows a short page with the same instructions.

What the assistant can do

ToolWhat it does
calcs_evaluate_sheetRuns a sheet and returns each quantity (name, value, unit, the rendered line, its note and line number), the errors with their lines, and the calculation as text. Input lines (L: ? 6 m) can be given other values.
calcs_evaluate_calcpadThe same for a Calcpad worksheet (.cpd text).
calcs_check_hand_calcRecomputes a calculation with real units and compares it with your answer, within a tolerance.
calcs_convert_unitsConverts a value: 25 kN/m^2 -> kPa.
calcs_search_functions, calcs_function_helpThe function, unit and command reference of the reference chapter.
calcs_search_docs, calcs_get_guide_pageSearch this guide and read a chapter.
calcs_list_samples, calcs_get_sampleThe sample sheets, with the link that opens each in the app.
calcs_sheet_syntaxThe full sheet syntax reference, so the assistant writes sheets that compile.

There are also two prompts, check my hand calc and write a sheet, for clients that show prompts as commands.

Things to ask, for example:

  • “Check my calculation: a 6 m simply supported beam with 12 kN/m, I got M = 56 kN·m.”
  • “Write a CivilKit Calcs sheet for the bearing pressure under a 2 m square pad footing with 800 kN, and run it.”
  • “Open the gable frame sample and tell me the thrust with a rigid ridge.”

The assistant gets the same numbers as the app. This sheet, run by calcs_evaluate_sheet, returns Mstar as 54 with the unit kN*m, and its line as 4:

L: 6 m | span
w: 12 kN/m | design load
Mstar: w * L^2 / 8 -> kN*m | maximum bending moment

A sheet the assistant writes can be pasted into the app (File > New) to see it rendered, print it or export it.

Limits

The server is public, so it limits what it runs:

  • A sheet or worksheet can be up to 64 KB, an expression up to 4 KB.
  • Each address can make 120 requests and 30 calculations a minute.
  • A calculation that runs longer than a few seconds is stopped. Loops with fixed bounds can make up to 200,000 passes.
  • Python blocks, #include, #read, #write and #append are not run: the server has no files and no network. Such a worksheet runs in the app, where everything stays in your browser.
  • Plots and diagrams are not drawn; the result is text and numbers.

Privacy

The server is stateless. What you send is calculated and answered; nothing is stored or logged, there are no cookies, accounts or sessions, and every request runs in a fresh copy of the engine. Requests are counted per address for the rate limit only. The app itself never sends your work anywhere: the MCP server is a separate service for assistants.

Samples tour

The Samples browser (File > Samples…, or the Resources tab) lists 151 worksheets, with groups, a search box and a preview. Opening a sample puts it in a new tab, where you can change it freely: nothing you do changes the original. A sample that has input fields carries an input form tag. The Samples browser never runs a sample’s Python; its preview shows the source, and opening the sample asks first.

Sheets

Written in the sheet format. They are listed first.

GroupWhat is in it
Sheet syntax (15)Beam bending, a short column, a floor-load table with vectors and matrices, a moment diagram with a plot, LaTeX prose, mixing with raw Calcpad and loops, beam and cantilever deflection, a three-span beam explorer with Python and Plotly, a beam deflection derived with the Symbolic dialog, polynomial roots, principal stresses, natural frequencies of a shear frame, principal axes of a section, and the thrust of a gable frame with a pinned or a rigid ridge.
Templates (7)Sheets with input forms: a simply supported beam check, a cantilever with a tip load, rectangular column slenderness, a pad footing bearing pressure check, pipe flow, a retaining wall (sliding and overturning) and a pump and pipeline operating point. Each carries the input form tag. See Templates with inputs.
Plots and diagrams (16)A plot gallery of implicit curves, functions and polylines on a grid, an animated beam with a moving load (Play, Pause, a slider), and fourteen sheets with a diagram drawn from text next to the numbers: a design check as a flow diagram, a load path, the design states of a beam, a review and sign-off sequence, a construction programme (Gantt chart), a dead load share (pie chart), a cost plan (treemap), a site risk matrix (quadrant chart), a bending moment chart (XY chart), the energy flow through a pump (Sankey), a footbridge brief (mind map), requirements traceability, concrete strength gain (timeline) and section shapes (class diagram).
3D plots (5)A plate deflection surface, a column interaction surface, a space frame in 3D lines, a mode-shape explorer with a dropdown, a 3D bar chart of footing reactions.
Physics (1)A tennis ball in flight: drag, spin and the sideways force from spin, integrated in a Python block.

Calcpad worksheets

The bundled worksheets are the CalcpadCE examples, with their input fields written as #UI, plus a few of our own.

GroupWhat is in it
Beams (26)Cantilevers, propped cantilevers, simply supported and fully restrained beams under point, moment, uniform, linear and partial loads; deflection of a cantilever and of a simply supported beam; a continuous beam by the force method.
Reinforced concrete (27)Bars and areas, bending and shear of rectangular and tee sections, columns under axial force and one or two-way bending, an interaction diagram, serviceability, two-way slab panels with every edge condition, punching shear, detailing for ductility.
Steel (3)Section properties of I-sections: by formula, from a catalogue with a drawing, from an Excel catalogue.
Loads (4)Snow, wind and footing-pad optimisation worksheets.
Frames (3)Plane frames with prismatic and tapered members, and a multi-storey frame.
Dynamics (4)Free vibrations of a tapered pole, with plain, Plotly and SVG animations; drop-weight impact on a beam.
Nonlinear (2)A prestressed truss with material and geometric nonlinearity, and a nonlinear truss with an animation.
Soil mechanics (1)Stress and deformation in soil.
Sections (1)Properties of a built-up section.
Maths and plotting (31)Getting started (calculating, functions and plots, unit conversion), matrices (creation, indexing, operators, structural and maths functions), interpolation, custom units (currency and information), numerical differentiation and integration, roots and systems of equations, Newton’s method with animation, a Monte Carlo estimate, elastic solutions and finite-element worksheets for deep beams and slabs.
Python (5)A beam moment diagram with matplotlib, a function plot with matplotlib, a beam explorer with Plotly, a continuous beam with Python results in raw JavaScript Plotly, and a plane truss by the stiffness method.

Good places to start:

  • Getting Started: Calculating, Functions and Plots and Units and Conversion, to see the Calcpad language at its simplest.
  • Template: simply supported beam check (the Templates group), to see an input form: press Input and change the span.
  • Beam bending with real units (sheet) and Bending moment diagram (sheet), the shortest complete sheets.
  • Design check as a flow diagram and the other sheets of the Plots and diagrams group, to see a diagram written as text next to the calculation it describes. See Diagrams.
  • Matrix worksheets, for a tour of the vector and matrix functions.
  • Beam Explorer: Plotly from Python, for the Python and Plotly route.

The samples that were written for other design practices apply rules specific to those practices. Read a sample as an example of the technique and check its assumptions before reusing a number.

Troubleshooting and FAQ

Reading an error

An error appears in the results where the line would, as a red paragraph, in the Errors dialog, and as an underline in the editor. For a sheet, the line number is the sheet line. Click the line number in the report to jump to the source.

MessageCause and fix
Undefined variable or units: "x"The name is not defined above this line, or it is misspelled, or a unit is misspelled. Names are case sensitive. A sheet renames some names (phi is φ); a >> line may use either spelling.
Inconsistent units: "m + s"You added or compared quantities of different dimensions. Fix the formula.
Invalid units: "maximum" (or Invalid symbol: "#" on a heading)The text is being read as a Calcpad worksheet, not as a sheet, so | means a unit conversion and # a directive. The <!--sheet--> marker is missing from the first line. Put it back.
Cannot rewrite existing units: kipA custom unit (.kip = ...) has the name of a built-in unit. Choose another name.
The matrix has complex eigenvalues.eigenvals, eigenvecs and eigen return real values only. Use ceigenvals and ceigenvecs. See Vectors and matrices.
Inconsistent units: "unitless" and "m" in a plotThe plot variable carried a unit. Write plot f(x * 1 m) for x in 0..6. See Plots.
#UI does not support expressions unless 'allowExpression' is true.The value in a #UI line is not a plain number. Use allowExpression or move the formula into a sheet line. In a sheet, an input line with ? takes a number only: 2*3 m is an error on its line. See Input forms with #UI and Templates.
The condition could not be evaluated, so the block is unresolved...An #if or if condition has an error (usually an undefined name). The block runs no branch.
Python was not runYou answered “Not now” to the Python question. The refusal is remembered until the Python code changes; edit it to be asked again.
Sheet syntax: ... in redThe sheet compiler found a bad plot line, an unclosed $$ or similar. The marker is on that line.

Things that go quietly wrong

  • Angles. The default is degrees. sin(π) is not zero in degrees mode. Put >> #rad in the sheet when you work in radians and pass π or radian values. A plot of sin(x) over 0..2*π in degrees mode is nearly flat.
  • g is a gram. Only π and e are built in. Insert the gravity constant from the Insert tab (g = 9.80665m/s^2) before you use g as an acceleration.
  • A variable called m, s or L. After a number m is still the metre. A variable called m is a variable when it stands alone. In Python export names, avoid names that are units.
  • Rounding. The result shows two decimals by default (Settings, Calculation, Decimals), and a number below one keeps three significant figures (0.163, 0.0856). The number inside is full precision: a utilisation of 1.004 is shown as 1, and a check on it (if util <= 1) still sees 1.004.
  • Every line of a sheet shows an error such as Invalid symbol: "#". The first line of the file is not <!--sheet-->. Older versions wrote the comment of Save values above that line; the current one writes it under the marker. Delete the stray first line, or put the marker back as the first line. See Templates.
  • A drop-down opens showing the wrong option. In a raw >> #UI line the default matches none of the values, so the first label is shown while the calculation uses the default. Make the default one of the values. A ? line cannot do this. See the known limits in Input forms with #UI.
  • My saved values are not used. A saved value belongs to the input’s name. If the input was renamed, the old value is ignored. Preview always shows the defaults; use Input or Report.

Frequently asked questions

Is anything sent to a server? No calculation is. The page is static files and the engine runs in your browser. The only network requests are loading the app, and loading Plotly for an interactive chart.

Does it work offline? Yes, after one visit. See Saving.

Can I use my own Python packages? No. A small numpy, matplotlib and Plotly stand-in is built in, and what is missing raises a named error. See Python blocks.

How do I share a calculation? Send the .sheet or .cpd file, or export Word, Excel or PDF.

Can I move a sheet to the Calcpad language? Yes, with Convert to Calcpad. The other direction does not exist.

Why did the interactive chart disappear from my PDF? Print and export cannot run Plotly. Draw a static copy with matplotlib as well.

Is it free? Yes. It is open source under the MIT licence, and the page runs from static files. See Credits and licences.

Where do I report a problem? On the project’s issue tracker at https://github.com/mageaustralia/civilkit-calcs . Say what you typed, what you saw and what you expected.

Appendix: keyboard shortcuts

On a Mac use Cmd where this page says Ctrl. The Resources tab has a Shortcuts button that lists the main ones in the output panel.

ShortcutAction
Ctrl+SSave
Ctrl+Shift+SSave as
Ctrl+OOpen (the desktop app; a browser keeps its own Open command)
Ctrl+Alt+XCalculate. F5 does the same in the desktop app; in a browser F5 reloads the page.
Ctrl+Z, Ctrl+Shift+ZUndo, redo
Ctrl+FFind in the editor
Ctrl+Shift+BShow or hide the sidebar (the desktop app; in a browser use Resources > Sidebar)
Alt+ZWrap long lines
Ctrl+Shift+EConvert the selected expression to a formula line (see Editing)
Shift+Alt+FFormat Document (tidy a sheet)
F12Go to the definition of the name under the cursor
Shift+F12Find references
F2Rename the variable, function or macro under the cursor everywhere in the worksheet (see Editing)
Ctrl+;Variable palette: search every variable and function with its value. Enter inserts the name, Alt+Enter goes to its definition
TabAccept the highlighted completion (Enter makes a new line)
Ctrl+SpaceOpen the completion list by hand
Ctrl+B, Ctrl+I, Ctrl+UBold, italic, underline in text lines of a Calcpad worksheet
Enter, Ctrl+EnterApply an in-place edit (Ctrl+Enter for prose)
EscCancel an in-place edit, or close a dialog
Enter, Shift+EnterIn the Symbolic dialog: run, new line

Keys the browser keeps. In a browser the keys that browsers use themselves are left to the browser, so that the page never takes them: Ctrl+L, D, R, N, P, T, W, Q and J, Ctrl+0 to 9 (tab switching and zoom), Ctrl+plus and Ctrl+minus, and Ctrl+Shift+V. Menu commands such as New sheet are on the ribbon. Save (Ctrl+S) is the page’s own.

On a phone there are no shortcuts; see Editing.

Appendix: deviations from CalcpadCE

CivilKit Calcs reproduces CalcpadCE’s output exactly unless a behaviour is listed in the project’s DEVIATIONS.md. Each entry there names the behaviour, why it differs and the test that pins it. This page is a summary for users.

Behaviour that differs

CalcpadCECivilKit Calcs
A failing #if conditionA condition that throws (a misspelled name) is false, so the #else branch runs without a word.The block is left unresolved: no branch runs, and an error paragraph says why.
Plot loopsA plot grid with a NaN step never ends.Grid loops stop after 100,000 lines. Finite grids are unchanged.
Scripts in a worksheetAny <script> in a worksheet runs from any address.Scripts run only from a library list (Settings, Advanced, Libraries), under a content security policy, with exact file addresses and integrity hashes. A script that is not on the list is replaced by a note naming its address. Scripts cannot send data anywhere. The print frame has no scripts.
C-style operatorsThe desktop app converts ==, !=, >=, <=, %%, &&, ||, <<, <* when it reads a file.The browser does the same when it opens a worksheet.
Input fieldsMany examples use the old name = ? {default} form.The bundled samples are rewritten with #UI, and the editor offers a “Convert to #UI” quick fix.
Select, radio and checkboxA select or radio that names a text box does nothing in the web front end.It fills the text boxes it names and recalculates; the choice is carried into the Report, PDF and Word.
Radio and drop-down defaultsA radio group or drop-down marks its default by comparing text, so a default with a divided unit such as 25kN/m finds no option and opens with nothing chosen (a drop-down shows its first label).The default is found by value: the division sign, middle dot, raised digits and ^ are compared as plain marks, and 1.0 equals 1.
Nested blocksA loop nested in an expression block cannot update the enclosing block’s variable.It can.
Units in arraysA vector or matrix writes the unit on every element.It writes the unit once after the bracket ([16; 12] ft). #settings {"unitPerElement": true} restores the old display.
Eigenvalueseigenvals, eigenvecs and eigen take only a matrix of the symmetric type.They take any square matrix; a symmetric literal no longer needs copy(A, symmetric(n), 1, 1). ceigenvals and ceigenvecs return complex eigenvalues and eigenvectors.
Markdown tables in WordA table without the bordered class has no rules.A Markdown pipe table is ruled.
Word exportSVG pictures are embedded alone. Numbered lists lose their numbers.An SVG is also written as a PNG for readers that lack SVG. Ordered lists are numbered. Unknown elements keep their content.
Print header and footerThe server prints title, date and page numbers.The browser prints; its own header and footer apply.
#writeOverwrites on disk.Keeps the file in the library and downloads it when its content changes.

Additions

  • The sheet format (Markdown prose, name: value lines, LaTeX): a front end to the Calcpad language that is not part of CalcpadCE.
  • The Excel export, with native charts.
  • Python blocks, with matplotlib-style and Plotly-style plotting.
  • The Symbolic dialog.
  • The worksheet importer.
  • Rich-text editing of Markdown prose in the results.
  • Sheet inputs: L: ? 6 m and its drop-down, radio and checkbox forms, which compile to #UI, and sliders with bounds (L: ? 6 m [2 .. 12 step 0.5]), for which #UI takes min, max and step.
  • SI prefixes on every SI unit (3 mN, 5 µm, 40 nF): CalcpadCE lists the prefixed units one by one and lacks many.
  • Folding sections and key results in the sheet format (## Workings {collapse}, {key}, {key results}).
  • Model bindings: a comment that ties an input to a quantity of a structural model, with a marker in the report. No model is connected yet.
  • A ribbon interface, a phone layout and an installable, offline app.

Not supported

Raster (PNG) plots (the web version draws SVG), the #ProjectPath and #LibraryPath roots (they are accepted and ignored), compiled .cpdz worksheets, and step-by-step execution (#pause, #input).

Numerical differences

The platform’s maths library supplies sin, exp, pow and friends, where CalcpadCE uses the .NET runtime’s, so the last printed digit of a result can differ. #write line endings are \n.

The full text, with the tests, is in DEVIATIONS.md.

Appendix: credits and licences

Credit

CivilKit Calcs is built on CalcpadCE, the MIT-licensed continuation of Calcpad by Nedelcho Ganchovski (Proektsoft) and contributors. The worksheet language, the editor’s language support (tokenizer, linter, prettifier, snippet library), the Word export path and the example worksheets all come from that work. This project reimplements the calculation engine, the editor services and the Word export in Rust and changes the web front end. It is not affiliated with the CalcpadCE authors.

The CalcpadCE version this work follows, and the commit its engine was ported from, are recorded in the NOTICE file of the repository. The “About” button on the Resources tab shows the version of the app you are running.

Licence

The project is under the MIT licence. The copyright is held by the CalcpadCE contributors, by Nedelcho Ganchovski (2014 onwards) and by the CivilKit Calcs contributors for the changes and the Rust reimplementation. The text is in the LICENSE file.

What the app includes

The licences of every package in the build are listed in THIRD_PARTY_LICENSES.md. None is outside the MIT, Apache, BSD and ISC families. The ones that matter to a user:

ComponentUsed forLicence
CalcpadCEThe worksheet language, front end, samplesMIT
Monaco editorThe source editorMIT
KaTeXTypesetting LaTeX in sheets and the Symbolic dialogMIT
MicroPythonThe Python runtime of Python blocksMIT
Plotly.jsInteractive charts (loaded from its CDN when needed)MIT
jspreadsheet CEThe editable grid in input formsMIT
Markdig (a port of part of)Markdown in the engineBSD 2-Clause
Fonts: JuliaMono, Jost, DejaVuThe editor and the reporttheir own licences, bundled with them

Sources

  • The app: https://civilkit.io/calcs/
  • The code, the issue tracker and the changelog: https://github.com/mageaustralia/civilkit-calcs
  • CalcpadCE: https://github.com/imartincei/CalcpadCE