Function reference

A complete overview of every built-in function, operator and constant.

Free vs. Pro

Free

CategoryFunctions / features
Constantspi, e, inf, today, now
Operators+ - * / ^ %, < > <= >= == !=, and or not, ..
Trigonometrysin, cos, tan, asin, acos, atan, atan2
Mathsqrt, abs, exp, log, log10, log2, floor, ceil, round, min, max, pow, sign, clamp, lerp, mod
Number systems0x/0b/0o literals, hex, bin, oct, dec, band, bor, bxor, bnot, shl, shr
Stringsstr, len, print
Date & timedate, datetime, day, month, year, hour, minute, weekday, days, addmonths, addyears, monthstart, monthend, dformat
Proportionproportion
CSVcsv, csvwrite (manual load/save)
LanguageVariables, labels, line references (@n), comments, units
Files & sharing.dply / .dplylib / .dplybundle, share, open-with
ShortcutsDesktop keyboard shortcuts

Pro

CategoryFunctions / features
Matricesdet, inv, transpose, trace, norm, eye, zeros, ones, size
Listslen, range, push, pop, first, last, sort, reverse, contains, list, append
Statisticssum, mean, median, std, variance, mode, percentile, quantile, corr, cov
Financepv, fv, pmt, nper, rate, npv, irr
Control flowfor / while loops with break / continue, if / elif / else
Chartsplot, scatter, bar, hist
Symbolic algebrasolve, simplify, factor
Differentiationdiff (symbolic and numeric)
Integrationintegrate (symbolic and numeric)
User-defined functionsf(x) = …, def name(…): (including recursion)
Classes & objectsclass Name(…):, methods, instances
Form viewTurn a sheet into a fillable form (inputs, outputs, charts, CSV)

Constants

NameValue / meaning
piπ ≈ 3.14159265358979…
eEuler's number ≈ 2.71828182845904…
infInfinity (∞)
todayToday's date (no time component)
nowCurrent date and time

Operators

Arithmetic

OperatorMeaningExample
+Addition3 + 47
-Subtraction10 - 37
*Multiplication2 * 510
/Division7 / 23.5
^Power2^8256
%Modulo10 % 31

A number or parenthesised expression directly in front of a parenthesis is an implicit multiplication: 3(x + 5) = 3 * (x + 5), (1 + 2)(3 + 4)21.

Percentages

A % written after a value is a percentage: 19% is 0.19. It binds tighter than * and /, so the percentage stays in one piece — 238 / 119% is 238 / 1.19200, not (238 / 119) / 100.

With + and - a percentage is taken of the left-hand value — that is how you add or remove a markup:

ExpressionResultReads as
100 + 10%110100 plus 10 % of 100
4 + 20%4.84 plus 20 % of 4
250 - 15%212.5250 minus 15 % of 250
100 + 10% + 10%121two markups in a row

This applies only to a percentage written directly to the right of + or -. Everywhere else % keeps its plain meaning of "divide by 100":

1200 * 19%      → 228     // * and / are unaffected
4 + 20% * 2     → 4.4     // the right side is a product, not a percentage
p = 20%
4 + p           → 4.2     // p is 0.2; there is no % in the expression
4 + 5/100       → 4.05    // a real division, not a percentage

A % between two values is the modulo operator (10 % 31).

Comparison

OperatorMeaning
<Less than
>Greater than
<=Less than or equal
>=Greater than or equal
==Equal
!=Not equal

Result: 1 (true) or 0 (false).

Logic

OperatorMeaningExample
andLogical andx > 0 and x < 10
orLogical orx < 0 or x > 10
notNegationnot (x == 0)

Conditional expression

value_if_true if condition else value_if_false — an inline conditional (Python-style). It makes one-liner functions and recursive definitions practical:

discount(n) = 0.1 if n > 100 else 0
fact(n)     = 1 if n <= 1 else n * fact(n - 1)
grade(p)    = "A" if p >= 90 else "B" if p >= 80 else "C"

It chains right-associatively, so a if c1 else b if c2 else c reads as a if c1 else (b if c2 else c).

Range

SyntaxMeaning
a..bInteger range from a to b (inclusive)

Used in for loops and plot.

Trigonometry

All angles are in radians.

FunctionSyntaxResult
sinsin(x)Sine of x
coscos(x)Cosine of x
tantan(x)Tangent of x
asinasin(x)Arcsine, result in [−π/2, π/2]
acosacos(x)Arccosine, result in [0, π]
atanatan(x)Arctangent, result in (−π/2, π/2)
atan2atan2(y, x)Arctangent of y/x (preserves the quadrant)
sin(pi / 2)      → 1
cos(0)           → 1
atan2(1, 1)      → 0.7853… (= π/4)

Basic math functions

FunctionSyntaxResult
sqrtsqrt(x)Square root of x
absabs(x)Absolute value
expexp(x)
loglog(x)Natural logarithm (base e)
log10log10(x)Logarithm base 10
log2log2(x)Logarithm base 2
floorfloor(x) / floor(x, digits)Round down; to digits decimals if given
ceilceil(x) / ceil(x, digits)Round up; to digits decimals if given
roundround(x) / round(x, digits)Round half away from zero; to digits decimals if given
convertconvert(x, "from", "to")Convert between units, incl. temperatures (see below)
defunitdefunit("name") / defunit("name", "base") / defunit("name", factor, "base")Define a custom unit (see below)
minmin(a, b) / min(list)The smaller of two values, or the smallest element of a list
maxmax(a, b) / max(list)The larger of two values, or the largest element of a list
powpow(x, n)x to the power of n (same as x^n)
signsign(x)Sign: −1, 0 or 1
clampclamp(x, min, max)Clamp x to the range [min, max]
lerplerp(a, b, t)Linear interpolation: a + t*(b−a); t=0 → a, t=1 → b
modmod(a, b)Remainder of a÷b (same as a % b, but as a function)
sqrt(144)          → 12
log(e)             → 1
log10(1000)        → 3
floor(3.7)         → 3
ceil(3.2)          → 4
round(3.14159, 2)  → 3.14
round(3.14159 m, 2)→ 3.14 m      (keeps the unit)
sign(-5)           → -1
min(3, 5)          → 3
max([3, 1, 2])     → 3
clamp(15, 0, 10)   → 10
clamp(-3, 0, 10)   → 0
lerp(0, 100, 0.25) → 25
mod(17, 5)         → 2

Unit conversion — convert

convert(value, "from", "to") converts a value between units. The units are given as text. Temperatures (C/°C, F/°F, K) are converted with their offset; all other units multiplicatively. Only units of the same physical kind convert into each other (length↔length, not length↔mass), and currencies are rejected (no fixed rate).

convert(20, "C", "F")      → 68
convert(0, "C", "K")       → 273.15
convert(5, "km", "m")      → 5000 m
convert(1000, "nm", "µm")  → 1 µm
convert(5, "mm", "µm")     → 5000 µm
convert(2, "h", "min")     → 120 min
convert(36, "km/h", "m/s") → 10 m/s
convert(5, "km", "cm")     → 500000 cm   (exact — no rounding artifacts)

Length supports the full metric range: nm, µm (or um), mm, cm, dm, m, km. The µ sign only works inside the convert text arguments; for an inline unit (5um + 3um) use the ASCII alias um.

Conversions across many powers of ten are computed exactly: the decimal shift is applied to numerator/denominator instead of multiplying by an inexact factor, so integer results such as convert(5, "km", "cm") → 500000 stay clean.

Imperial units. Common imperial units are built in and mix freely with metric ones via convert:

Length: in, ft, yd, mi Mass: lb, oz * Volume (US measures): gal, qt, pt, floz

convert(1, "mi", "km")     → 1.609344 km
convert(1, "mi", "ft")     → 5280 ft
convert(1, "lb", "oz")     → 16 oz
convert(1, "gal", "L")     → 3.785411784 L
3ft + 2ft                  → 5 ft

The result carries the target unit (except temperatures, which are plain numbers), so it keeps calculating: convert(5, "km", "m") + 100 m5100 m.

More physical quantities. Beyond length, mass and time these units are built in and convert within their own kind:

Volume (metric): ml, dl, L (or l) Energy: J, kJ, Wh, kWh Power: W, kW, MW Force: N, kN Pressure: Pa, bar Frequency: Hz, kHz, MHz

convert(1, "kWh", "J")     → 3600000 J
2kWh + 500Wh               → 2.5 kWh
convert(1, "bar", "Pa")    → 100000 Pa
1.5L + 3dl                 → 1.8 L

Custom units — defunit

Define your own units, e.g. for an electrical-engineering library. Once defined, a unit works both inline (12 V) and in convert.

FormMeaning
defunit("V")New base unit with its own dimension
defunit("Ohm", "V/A")Derived unit (factor 1) from existing units
defunit("kOhm", 1000, "Ohm")Scaled unit: 1 kOhm = 1000 Ohm
defunit("V")
defunit("A")
defunit("Ohm", "V/A")
defunit("kOhm", 1000, "Ohm")
convert(1, "kOhm", "Ohm")  → 1000 Ohm
U = 12 V                   → 12 V

Custom units are document-local (they reset per document). Put defunit(...) calls at the top of a .dplylib library and import it to share a unit set across documents. Only units of the same dimension convert into each other.

Multiplying and dividing units reduces the result to its base unit whenever one has the same dimension, converting the value accordingly. Because Ohm is defined as V/A, the compound units cancel to the expected named result:

470 Ohm * 10 mA  → 4.7 V        (Ohm·A cancels to voltage)
5 V / 25 mA      → 200 Ohm      (reduced to base Ohm, not 0.2 kOhm)
12 V / 4 A       → 3 Ohm
1 / Ohm          → 1 S          (reciprocal → conductance)
H / Ohm          → 1 s          (time constant)

Two units of the same dimension combine into a power (the value is converted): 5 mm 10 m → 0.05 m², 2 Ohm 3 kOhm → 6000 Ohm². If no named unit matches (e.g. 100 W * 2 h → 200 W·h), the compound form is kept.

A power belongs to the unit, not to the quantity: 54 m^2 and 54 m² are both 54 square metres. Put the quantity in brackets to square it as a whole ((54 m)^2 → 2916 m²).

Automatic prefix for display. When a result falls outside the range [0.1, 1000), it is shown in the unit that brings it into a nice range — chosen among your own units and the metric 1000-step prefixes:

1 V / 1 mA   → 1 kOhm     (not 1000 Ohm)
0.001 V      → 1 mV
1500 m       → 1.5 km
0.008 m      → 8 mm

This is display-only: the stored value is unchanged, so @n references and further math keep full precision. Values already in range (200 Ohm, 0.5 m), compounds (50 km/h), powers (20 m²) and currencies are left as-is, and it never switches between metric and imperial.

Number systems (binary, octal, hex)

Numbers can be entered in binary, octal or hexadecimal using the prefixes 0b, 0o and 0x. They are ordinary numbers and mix freely with decimal values and all other functions. Conversion functions turn a value back into a string in a given base, and dec parses such a string into a number.

FunctionSyntaxResult
0x…0xFFHexadecimal literal (0xFF → 255)
0b…0b1010Binary literal (0b1010 → 10)
0o…0o100Octal literal (0o100 → 64)
hexhex(x)x as a hexadecimal string (0x…)
binbin(x)x as a binary string (0b…)
octoct(x)x as an octal string (0o…)
decdec("0xFF")Parse a 0x/0b/0o/decimal string to a number
0xFF               → 255
0b1010             → 10
0o100              → 64
0xFF + 1           → 256
hex(255)           → 0xFF
bin(10)            → 0b1010
oct(64)            → 0o100
hex(-255)          → -0xFF
dec("0xFF")        → 255
dec(hex(1234))     → 1234

Bitwise operations

Bitwise functions operate on integers (fractional parts are truncated). ^ is reserved for exponentiation, so XOR is the bxor function rather than an operator.

FunctionSyntaxResult
bandband(a, b)Bitwise AND
borbor(a, b)Bitwise OR
bxorbxor(a, b)Bitwise XOR
bnotbnot(a)Bitwise NOT (complement)
shlshl(a, n)Shift a left by n bits
shrshr(a, n)Shift a right by n bits
band(12, 10)       → 8
bor(12, 10)        → 14
bxor(12, 10)       → 6
bnot(0)            → -1
shl(1, 4)          → 16
shr(256, 2)        → 64
hex(band(0xF0, 0x3C)) → 0x30

Calculus Pro

Symbolic (2 arguments)

FunctionSyntaxResult
diffdiff(expr, var)Symbolic derivative with respect to var
integrateintegrate(expr, var)Symbolic indefinite integral
diff(x^3, x)          → 3x²
diff(sin(x), x)        → cos(x)
integrate(x^2, x)     → x³/3
integrate(sin(x), x)  → −cos(x)

Numeric (3 or 4 arguments)

FunctionSyntaxResult
diffdiff(expr, var, point)Numeric derivative at a point (central difference)
integrateintegrate(expr, var, a, b)Numeric integral from a to b (Simpson's rule)
diff(x^2, x, 3)              → 6
integrate(x^2, x, 0, 3)     → 9

Symbolic algebra (CAS) Pro

FunctionSyntaxResult
solvesolve(expr, var)Roots / solutions
solvesolve(eq1, eq2, …, var1, var2, …)Solve a system of equations
simplifysimplify(expr)Expand & combine a polynomial
factorfactor(expr)Factor an expression
solve(x^2 - 4, x)                       → x = -2,  x = 2
solve(x^2 + 2*x + 1 == 0, x)           → x = -1
solve(x + y == 3, x - y == 1, x, y)    → x = 2,  y = 1
simplify(2*x + 3*x)                     → 5x
simplify((x + 1)^2)                     → x² + 2x + 1
factor(x^2 - 4)                         → (x − 2)(x + 2)
factor(x^2 + 2*x + 1)                  → (x + 1)²

simplify expands and combines polynomials (powers with non-negative integer exponents). It does not cancel divisions by a variable (x^2 / x) or apply trigonometric identities (sin(x)^2 + cos(x)^2) — those report an error.

Matrices Pro

Inside […], , and ; separate elements and ;; separates rows:

v = [1, 2, 3]        // row vector
v = [1; 2; 3]        // row vector (semicolon also separates elements)
A = [1, 2 ;; 3, 4]   // 2×2 matrix (;; = new row)
c = [1 ;; 2 ;; 3]    // column vector (3×1)

Comma-decimal mode: when the number format uses a comma as the decimal point, , is the decimal sign, so use ; to separate values unambiguously — [1,5; 2,5] is the vector [1.5, 2.5], and ;; still starts a new row. The same applies to function arguments: sum(1,5; 2,5).

FunctionSyntaxResult
detdet(A)Determinant (square matrix)
invinv(A)Inverse (square matrix)
transposetranspose(A)Transpose
tracetrace(A)Trace (sum of diagonal elements)
normnorm(A)Frobenius norm; for a scalar: abs(x)
eyeeye(n)n×n identity matrix (up to 1000×1000)
zeroszeros(n) / zeros(r, c)Matrix of zeros
onesones(n) / ones(r, c)Matrix of ones
sizesize(A) / size(A, dim)[rows, cols]; dim=1 → rows, dim=2 → cols
det([1, 2 ;; 3, 4])        → -2
inv([1, 2 ;; 3, 4])        → [[-2, 1], [1.5, -0.5]]
transpose([1, 2 ;; 3, 4])  → [[1, 3], [2, 4]]
trace([1, 2 ;; 3, 4])      → 5
eye(3)                   → [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
zeros(2, 3)              → [[0, 0, 0], [0, 0, 0]]
size([1, 2 ;; 3, 4])       → [2, 2]
size([1, 2 ;; 3, 4], 1)    → 2

Collapsing tall outputs

Multi-row matrix results can be collapsed to a one-line summary ([42×1] 1…) — click the chevron next to the line number, or tap the summary to expand again. On small screens (phones in portrait) tall matrix outputs start collapsed, like plots.

Lists & arrays Pro

Lists are internally 1×n matrices: [1, 2, 3].

FunctionSyntaxResult
lenlen(list)Number of elements
rangerange(end)Integers 0 to end−1
rangerange(start, end)Integers start to end−1 (up to 100,000)
rangerange(start, end, step)With a custom step
pushpush(list, value)Append an element (returns a new list)
poppop(list)Remove the last element (returns a new list)
firstfirst(list)First element
lastlast(list)Last element
sortsort(list)Sorted ascending (returns a new list)
reversereverse(list)Reversed order (returns a new list)
containscontains(list, value)1 if present, otherwise 0
listlist(a, b, …)Generic list of arbitrary values (see below)
appendappend(list, value)Append to a generic list (returns a new list)
mapmap(f, list)Apply function f to each element
filterfilter(f, list)Keep elements where f(element) is true (≠ 0)
len([10, 20, 30])          → 3
range(5)                   → [0, 1, 2, 3, 4]
range(2, 6)                → [2, 3, 4, 5]
range(0, 10, 2)            → [0, 2, 4, 6, 8]
push([1, 2], 3)            → [1, 2, 3]
pop([1, 2, 3])             → [1, 2]
first([5, 6, 7])           → 5
last([5, 6, 7])            → 7
sort([3, 1, 2])            → [1, 2, 3]
reverse([1, 2, 3])         → [3, 2, 1]
contains([1, 2, 3], 2)     → 1

Generic lists

A generic list holds arbitrary values — whole vectors, named lists, strings or numbers — without flattening them. It is the tool for collecting results in a loop and reading them back one by one.

Create one with list(...) (or list() for an empty list) and grow it with append. A bracket literal whose elements are not plain numbers — such as [v1, v2] with vectors — also forms a generic list.

Results = list()
for i in 1..3:
  Results = append(Results, [i, i*2, i*3])

Results                    → [[1, 2, 3], [2, 4, 6], [3, 6, 9]]
Results[1]                 → [2, 4, 6]     (the whole second vector)
sum(Results[1])            → 12
len(Results)               → 3

Access is 0-based; negative indices count from the end (Results[-1] is the last element). Results[0] = [9, 9, 9] replaces an element, for v in Results: iterates over the elements, and first/last/reverse/push/pop work element-wise. Aggregations such as sum and mean flatten all numeric values inside the list, including the elements of contained vectors.

map & filter

map(f, list) applies a function to each element; filter(f, list) keeps the elements for which the function is true. The first argument is a function name — a reference, not a call — and may be a builtin or one of your own functions. They replace many explicit for loops.

square(x) = x^2
map(square, [1, 2, 3])     → [1, 4, 9]
map(sqrt, [1, 4, 9])       → [1, 2, 3]

even(n) = n % 2 == 0
filter(even, [1, 2, 3, 4, 5, 6]) → [2, 4, 6]

sum(map(square, [1, 2, 3]))      → 14

Named lists

A named list labels each value with a key, so you can read it back by name instead of by position. Write the entries as key: value inside the brackets. Keys may be quoted ("Strom") or, if they are a single word, bare (Strom). The list can span several lines.

Expenses = [
  "Electricity": 120,
  "Water":        80,
  "Rent":        900
]

Expenses["Electricity"]    → 120
sum(Expenses)              → 1100
len(Expenses)              → 3
mean(Expenses)             → 366.67

Access and update entries by key; assigning a new key adds it:

Expenses["Internet"] = 40   // adds a new entry
sum(Expenses)               → 1140

Entries can also be read by position (0-based, like a list), which keeps the unit too:

Expenses[0]                 → 120   (first entry)
Expenses[-1]                → 40    (last entry)

List and statistics functions (sum, mean, median, std, min, max, sort, len, …) operate on the values, in the order the entries were written.

Entries may carry units, and they are kept — both when reading a single entry and when aggregating, as long as all entries share the same unit:

Costs = ["Electricity": 120 €, "Water": 80 €]
Costs["Electricity"]       → 120 €
sum(Costs)                 → 200 €
max(Costs)                 → 120 €

Values may also be anything — vectors, lists, strings — not just numbers:

Series = ["Jan": [10, 12, 9], "Feb": [11, 8, 14]]
Series["Feb"]              → [11, 8, 14]     (the whole vector)
keys(Series)               → [Jan, Feb]
values(Series)             → [[10, 12, 9], [11, 8, 14]]

keys(d) and values(d) return the keys and values as a list. Aggregations still work over the numeric entries and skip non-numeric ones.

Statistics Pro

All statistics functions accept either a list or comma-separated values.

FunctionSyntaxResult
sumsum(list) / sum(a, b, …)Sum of all values
meanmean(list) / mean(a, b, …)Arithmetic mean
medianmedian(list) / median(a, b, …)Median (middle value)
stdstd(list) / std(a, b, …)Sample standard deviation (÷ n−1)
variancevariance(list) / variance(a, b, …)Sample variance (÷ n−1)
modemode(list) / mode(a, b, …)Most frequent value
percentilepercentile(list, p)p-th percentile (p: 0–100), linear interpolation
quantilequantile(list, q)q-th quantile (q: 0–1), linear interpolation
corrcorr(xs, ys)Pearson correlation coefficient
covcov(xs, ys)Sample covariance (÷ n−1)
linreglinreg(xs, ys)Linear regression → [slope, intercept, r2]
sum([1, 2, 3, 4])            → 10
mean(2, 4, 6)                → 4
median([1, 3, 5, 7])         → 4
std(2, 4, 4, 4, 5, 5, 7, 9) → 2
variance([2, 4, 4, 4, 5, 5, 7, 9]) → 4
mode([1, 2, 2, 3])           → 2
percentile([1, 2, 3, 4, 5], 75) → 4
quantile([1, 2, 3, 4, 5], 0.5)  → 3
xs = [1, 2, 3, 4, 5]
ys = [2, 4, 5, 4, 5]
corr(xs, ys)                 → 0.9079
cov(xs, ys)                  → 1.75

linreg fits a straight line y = slope·x + intercept and returns a named list with slope, intercept and the coefficient of determination r2:

r = linreg([1, 2, 3, 4], [2.1, 3.9, 6.2, 7.8])
r["slope"]                   → 1.9…
r["intercept"]               → 0.1…
r["r2"]                      → 0.99…

Finance Pro

All finance functions use standard Excel-compatible sign conventions: inflows positive, outflows negative. rate as a decimal (5 % = 0.05).

FunctionSyntaxResult
pvpv(rate, nper, pmt [, fv])Present value of an annuity; fv defaults to 0
fvfv(rate, nper, pmt [, pv])Future value of an annuity; pv defaults to 0
pmtpmt(rate, nper, pv [, fv])Periodic payment; fv defaults to 0
npernper(rate, pmt, pv [, fv])Number of periods; fv defaults to 0
raterate(nper, pmt, pv [, fv])Interest rate per period (Newton–Raphson, 300 iter.)
npvnpv(rate, cashflows)Net present value of future cashflows (list)
irrirr(cashflows)Internal rate of return (Newton–Raphson, 300 iter.)
// Monthly payment on a 200 000 € loan, 5 % p.a. over 20 years
rate_m = 0.05 / 12
pmt(rate_m, 240, 200000)     → -1319.91

// Future value of 200 €/month over 10 years at 4 % p.a.
fv(0.04 / 12, 120, -200)     → 29 411.03

// Present value of receiving 1 000 €/year for 5 years at 6 %
pv(0.06, 5, 1000)            → 4212.36

// IRR of a project: invest 1 000 €, receive 400 € each of 3 years
irr([-1000, 400, 400, 400])  → 0.0974  // ≈ 9.74 %

Strings

FunctionSyntaxResult
strstr(value)Convert a number, matrix or date to text
lenlen(text)Length of the string (number of characters)
ordord(text)Unicode code point(s): a single character → a number, a longer string → the list of its code points
charchar(code)The character(s) for a code point or a list of code points — the inverse of ord
printprint(value)Print value or string in the result column
str(42)             → "42"
str([1, 2, 3])      → "[[1, 2, 3]]"
len("Hello")        → 5
ord("A")            → 65
ord("Hi")           → [72, 105]
char(65)            → "A"
char([72, 105])     → "Hi"
char(ord("draft"))  → "draft"      (round-trips)

ord/char bridge text and numbers, so a string can be processed byte-wise (hashing, XOR/Caesar ciphers, checksums) and turned back into text.

Date & time

Constructors

FunctionSyntaxResult
datedate(year, month, day)Date value
datetimedatetime(year, month, day, hour, minute)Date with time
datetimedatetime(year, month, day, hour, minute, second)Date with seconds

Extractors

FunctionSyntaxResult
dayday(d)Day (1–31)
monthmonth(d)Month (1–12)
yearyear(d)Year (e.g. 2025)
hourhour(d)Hour (0–23)
minuteminute(d)Minute (0–59)
weekdayweekday(d)Weekday: 1 = Monday … 7 = Sunday (ISO 8601)

Arithmetic & formatting

FunctionSyntaxResult
daysdays(d1, d2)Difference in days (d1 − d2)
addmonthsaddmonths(d, n)Add n months (day clamped to month end if needed)
addyearsaddyears(d, n)Add n years (Feb 29 → Feb 28 in non-leap years)
monthstartmonthstart(d)First day of the month
monthendmonthend(d)Last day of the month
dformatdformat(d)Default format (e.g. "13.06.2026")
dformatdformat(d, "pattern")Custom format (see placeholders below)
-d1 - d2Difference in days (shorthand)

Placeholders for dformat:

PlaceholderMeaning
yyyyFour-digit year
MMTwo-digit month (01–12)
ddTwo-digit day (01–31)
HHTwo-digit hour (00–23)
mmTwo-digit minute (00–59)
ssTwo-digit second (00–59)
d = date(2026, 6, 13)
day(d)                         → 13
weekday(d)                     → 6   // Saturday
days(date(2026, 12, 31), d)    → 201
dformat(d, "dd.MM.yyyy")       → "13.06.2026"
addmonths(d, 3)                → 2026-09-13
addmonths(date(2026, 1, 31), 1) → 2026-02-28   // clamped to Feb end
addyears(d, 1)                 → 2027-06-13
monthstart(d)                  → 2026-06-01
monthend(d)                    → 2026-06-30
datetime(2026, 6, 13, 14, 30)
today                          → current date
now                            → current date and time

Charts Pro

plot — line chart

plot(expr)
plot(expr, from..to)
plot(expr, from, to)
plot(expr, from..to, yFrom..yTo)
plot(expr, from..to, yFrom..yTo, steps)
plot(expr1, expr2, …, from..to)
plot(expr, ..., "title", "x axis", "y axis")
plot(expr, ..., "logy")
ParameterMeaningDefault
exprExpression in x
from..tox range (range syntax)−2π .. 2π
from, tox range (legacy syntax, 3 arguments)−2π, 2π
yFrom..yToFix the y axisautomatic
stepsNumber of sample points (2 – 10,000)300
"…" stringsChart title, x-axis and y-axis label (in order)none
"logx", "logy", "loglog"Logarithmic scaling of the x, y, or both axeslinear

String arguments may appear in any position; the scaling keywords "logx", "logy" and "loglog" are recognized as options, all other strings are assigned in order as title, x-axis label and y-axis label.

On a logarithmic axis only positive values are shown (non-positive points are skipped) and the gridlines snap to full decades. Tooltips and CSV/SVG export keep the real (un-transformed) values.

Several curves in one plot: pass more than one expression before the range. Each gets its own colour and an automatic legend (labelled with the expression), and the CSV export gets one column per curve:

plot(sin(x), cos(x), 0..2*pi)
plot(x, 2*x, 3*x, 0..5, "Comparison")
plot(sin(x))
plot(x^2, -5..5)
plot(x^3, -10, 10)
plot(sin(x), -pi..pi, -1..1, 500)
plot(sin(x), "Oscillation", "time t", "amplitude")
plot(exp(x), 1..20, "logy")
plot(x^3, 1..1000, "loglog")

scatter — point cloud

scatter(xs, ys)
scatter(xs, ys, "title", "x axis", "y axis")

Both data arguments must be lists or vectors of equal length. String arguments are assigned in order as title, x-axis and y-axis label.

scatter([1, 2, 3, 4], [1, 4, 9, 16])
scatter(xs, ys, "Measurements", "time", "value")

bar — bar chart

bar(values)
bar(values, xs)
bar(values, ..., "title", "x axis", "y axis")

Draws a bar chart. values is a list of bar heights. The optional xs argument provides explicit x positions (must have the same length as values); without it the bars are numbered 0, 1, 2, …

ParameterMeaningDefault
valuesList of bar heights
xsExplicit x positions for the bars0, 1, 2, …
"…" stringsChart title, x-axis and y-axis label (in order)none
bar([12, 7, 19, 5])
sales = [4200, 5100, 3800, 6300]
bar(sales)
bar([10, 20, 30], [2020, 2021, 2022])
bar([12, 19, 7], "Revenue", "month", "kEUR")

hist — histogram

hist(data)
hist(data, bins)
hist(data, ..., "title", "x axis", "y axis")

Bins the data into a frequency histogram and draws it. Bars touch to emphasise the continuous distribution.

ParameterMeaningDefault
dataList of values to bin
binsNumber of bins (2 – 200)10
"…" stringsChart title, x-axis and y-axis label (in order)none
data = [2, 5, 3, 8, 5, 7, 5, 3, 4, 6, 7, 5]
hist(data)
hist(data, 5)
hist(data, 5, "Distribution", "value", "count")

Labeled chart lines: a label in front of any chart call becomes the chart title if no explicit title string is given — Revenue: bar([12, 19, 7]) draws the chart with the title "Revenue".

Export: every chart has overlay buttons for SVG, PNG and CSV. Title and axis labels are included in the SVG export.

CSV import / export

CSV files are read and written manually — never automatically on every keystroke. A load/save button appears in the result row of any line that uses csv(…) or csvwrite(…).

total = csv("sales")          // column 1 of the picked file
q2    = csv("sales", 2)       // column 2 (1-based)
rev   = csv("sales", "revenue") // column by header name
csvwrite([1, 2, 3], "out")    // shows a save button
FunctionMeaning
csv("name")First column as a list
csv("name", n)Column n (1-based)
csv("name", "header")Column by header name
csvwrite(data, "name")Export a list/matrix as CSV (manual save button)

What the name is for

The string in csv("name") is a display name / key, not a file path. Clicking the load button opens a native file dialog; the name only labels the import. It does three things:

1. Tells imports apart. Several independent sources can live in one document, each with its own load button and its own file: `` revenue = csv("revenue") costs = csv("costs") ` 2. Load once, use many columns. Every call with the same name shares the one loaded table, so you pick the file only once: ` month = csv("sales", 1) units = csv("sales", 2) price = csv("sales", "price") `` 3. Drives the load indicator. The button shows, per name, whether data is already in memory (a check mark) or still needs loading.

Loaded data lives in memory only — after restarting the app you load it again, and the name is the stable label that reconnects a formula to its source. The delimiter (;, tab or ,) and a header row are detected automatically; with ;/tab a decimal comma is accepted.

Proportion

FunctionSyntaxResult
proportionproportion(a, b, c)a · c / b

Solves: a : b = ? : c

proportion(3, 4, 8)    → 6    // 3:4 = 6:8

Control flow (user functions) Pro

For loop

for i in 1..n:
  …

for i in list:
  …

Maximum 10,000 iterations. Integer range: at most 10,000 steps.

Use break to exit the loop immediately, continue to skip ahead to the next iteration:

for i in 1..10:
  if i == 5:
    break
  if i % 2 == 0:
    continue
  …

While loop

while condition:
  …

break and continue work the same way as in for.

If / elif / else

if condition:
  …
elif another_condition:
  …
elif yet_another:
  …
else:
  …

Any number of elif branches are allowed; else is optional.

Return

return value

Recursion

Maximum 100 levels of call depth.

User-defined functions Pro

Short form (single line)

f(x) = x^2 + 2*x

Long form with def

def name(param1, param2, optParam = defaultValue):
  …
  return result
def factorial(n):
  s = 1
  for i in 1..n:
    s = s * i
  return s

factorial(6)    → 720

Parameters may be numbers, lists/vectors or strings — a function can take a whole vector and index into it:

def dot(a, b):
  s = 0
  for i in 0..len(a) - 1:
    s = s + a[i] * b[i]
  return s

dot([1, 2, 3], [4, 5, 6])   → 32

Classes Pro

class Name(param1, param2, …):
  def method():
    return …

The parameters in the class header become fields of the instance; inside a method you read them as self.param1.

class Circle(r):
  def area():
    return pi * self.r^2
  def circumference():
    return 2 * pi * self.r

c = Circle(5)
c.area()           → 78.5398…
c.circumference()  → 31.4159…

Form view Pro

The form view turns a sheet into a clean, fillable form: labelled input fields at the top, computed results below, plus any charts and CSV load/save buttons. The underlying document is unchanged — the form only reads and writes the variables you point it at, so switching back to the editor shows the same sheet.

Open the Form menu:

  • Edit form… opens the form editor.
  • Form view (appears once a form is defined) toggles between the code editor
  • and the filled-in form.

Inputs

Each input links a label to a variable in the sheet. In the form, an input is one of two kinds:

  • A number field. Typing a value writes it back to that variable's
  • assignment (kapital = 1000). An optional unit is shown as a suffix and appended automatically, so kapital = 1000 € stays intact while you only edit the number.

  • A choice of chips. Give the input a set of label : value options and it
  • becomes a row of tap-to-select chips — handy for switching an assignment between a few fixed values (e.g. Reinvest? → Yes = 1 / No = 0).

Outputs

An output links a label to a variable whose computed result is shown read-only, formatted with the sheet's precision and its unit. Outputs update as soon as an input changes.

Charts and CSV

  • Charts — pick which chart lines (plot, scatter, bar,
  • hist) appear in the form.

  • CSV — each csv(…) load and csvwrite(…) save in
  • the sheet gets a row in the form; you can give it a friendlier label or hide it.

Automatic mode

The editor can read the sheet and propose a starting point instead of adding every field by hand. When it finds candidates, a banner offers Apply:

  • Inputs — every variable set to a plain value without a formula
  • (kapital = 1000, weg = 12 km); its unit is filled in automatically.

  • Outputs — every variable that (directly or indirectly) depends on one of
  • those inputs (zinsen = kapital * satz / 100).

It only fills fields that aren't already present, and it never runs on its own — apply it, then remove what you don't need and add the labels. Variables defined inside for/while/if/def blocks and function definitions are ignored.

How it is stored

A form lives in the sheet's frontmatter as form_* fields, so it travels with the .dply file:

---
form_title: Compound interest
form_description: Quick estimate
form_inputs: Capital|kapital{€}, Reinvest?|reinvest[Yes:1,No:0]
form_outputs: Net gain (€)|net_gain
form_plots: 1
---

| separates the label from the variable, {unit} adds a unit, and [label:value,…] defines chip options.

Miscellaneous

Line references

@1, @2, … — refer to the result of that line.

5 * 3          → 15
@1 + 10        → 25

Comments

// single-line comment
# also a comment

Labels

VAT: 0.19 * 100    → VAT:  19

The label is the text before the :. It may contain letters, digits, spaces and hyphens. If it needs other characters — parentheses, /, a currency sign — wrap it in quotes; the quotes are dropped from the output:

"Area (m²)": 4.5 * 12    → Area (m²):  54

Running total

A line containing just total sums the results of the lines above it, back to the last blank line, heading/comment or a previous total. Ideal for shopping lists and budgets:

# Groceries
12.50
8.00
3.20
total              → 23.70

It keeps a shared unit (10 kg + 20 kg = 30 kg) and takes an optional label (Total: total).

Library import

import "file.dplylib"

Debug / print

print(x)        // prints x in the result column

Bracket matching

The editor helps you keep parentheses () and brackets [] balanced:

  • Unbalanced brackets are marked red. If a bracket has no partner — an
  • opening ( that is never closed, or a stray closing ) — it is highlighted in red so you can see exactly where the problem is.

  • Matching pair highlight. Place the cursor next to a bracket and its
  • matching partner is highlighted (like a spreadsheet), so nested expressions are easy to follow.

  • Clear error message. A line with a missing closing bracket now reports
  • e.g. "Unclosed bracket: 1× ) missing" instead of a generic "Unknown input".

cos((1+2)*3        → Unclosed bracket: 1× ) missing   (first ( shown red)

Number format

Settings → Number format controls how results and numbers in the editor are displayed:

  • Decimal separatorAutomatic (follows your system language), Period
  • (1,234.56) or Comma (1.234,56). In comma mode use ; to separate list and function-argument values (see Lists & arrays).

  • Thousands separator — a toggle to turn digit grouping on or off. With it
  • off, numbers are shown without grouping (1234567 instead of 1,234,567); the decimal separator is unaffected. Applies to both results and the editor.

Files, sharing & open-with

draftply files are plain text with a small header, so they travel well.

ExtensionContents
.dplyA notebook (document).
.dplylibA function/unit library you import into a document.
.dplybundleA notebook packaged together with its libraries in one file.

Sharing. File → Share sends the current draft through your operating system's share sheet. If the document uses imported libraries, it is shared as a self-contained .dplybundle (so it still works for the recipient); otherwise as a plain .dply. Library → Share exports the document's functions as a .dplylib. Sharing appears where the OS provides a share sheet (iOS, Android, macOS, Windows).

Open with draftply. Opening a .dply, .dplylib or .dplybundle from another app or your file manager opens it in draftply as a new draft (the content is copied in — the original file is not linked). For safety, a document that arrives from another app is not evaluated automatically: a banner lets you review the content first and press Evaluate to run it.

Keyboard shortcuts

Desktop shortcuts. On macOS use ⌘ (Cmd) instead of Ctrl.

ShortcutAction
Ctrl + NNew draft
Ctrl + OOpen file
Ctrl + SSave
Ctrl + Shift + SSave as…
Ctrl + PPrint / Save as PDF
Ctrl + ,Settings
Ctrl + FSearch in the document
Ctrl + Z · Ctrl + Shift + Z / Ctrl + YUndo · Redo
Ctrl + C · Ctrl + X · Ctrl + V · Ctrl + ACopy · Cut · Paste · Select all
Tab or EnterAccept autocomplete
· Navigate the autocomplete list