Graph Paper

Plot Document Format

A plot document is a JSON object that describes one Graph Paper plot: its formulas, its sliders, its draggable points and its axes. Encode it in a link and Graph Paper opens it as a document that the reader can edit. This page lists every field.
This page is for programs and AI agents that write documents. A program that wants to give a person a plot starts at For Agents: the fastest way is to send the document with POST https://graph-paper.io/plot-link, or with GET https://graph-paper.io/plot-link?doc=<percent-encoded JSON> from a tool that can only fetch an address; the answer has the link, or the errors. For what to write inside a formula, see the Plotting Guide.
Every formula is LaTeX. In a JSON string, write "\\sin(x)", not "sin(x)", and "x^{2}", not "x**2". The validator refuses a function name written as plain text (exp(…), sqrt(…)) and says what to write. A number in scientific notation such as 2.312e-05 is accepted and read as the number, and Graph Paper shows it as 2.312 × 10⁻⁵, the form a person who types it gets. Some literals are shown as written (2.312e − 05, which a person can read as the constant e and a subtraction), and the validator gives a warning for them: a literal with a space inside it, one followed by ^, _ or a prime, one in a subscript or in a bare {…} group, one directly after } or after a command such as \frac, and one whose mantissa starts with a point (.5e3). For those, write a plain decimal (0.00002312) or a\cdot 10^{n} ("2.312\\cdot 10^{-5}" in JSON). A point with no digits after it (1.e5) or a point in the exponent (1e3.5) is not a number that Graph Paper can read, and the validator refuses it.
A program should read the Markdown version of this page, at https://graph-paper.io/plot-document-format/en/index.md, because a summary of the HTML page can lose the tables. Every guide page has a Markdown version: add index.md to its URL, or send Accept: text/markdown. https://graph-paper.io/llms-full.txt is one file that holds the English text of this page, For Agents, the Plotting Guide and Tips and Tricks.

Contents

A Minimal Document

One title and one series:
json{ "title": "Sine wave", "series": [{ "type": "line", "fn": "\\sin(x)" }] }
To open it, encode the JSON as UTF-8, then as base64url (RFC 4648 §5, no padding), and add it to https://graph-paper.io/new#doc=. The complete examples below show the full links. A program that cannot compute base64url can write the JSON, percent-encoded, after https://graph-paper.io/new#json=. A link has one form only. The service https://graph-paper.io/plot-link checks a document and returns its link, with no account. See Check a Document.

Rules and Limits

Top-Level Fields

FieldTypeRequiredMeaning
titlestringyesThe document title, plain text.
seriesarrayyesThe plotted rows, at least one. See Series.
variablesarraynoSliders. See Variables.
pointsarraynoPoints the reader drags on the plot. See Points.
definitionsarraynoNamed values and functions that other rows use. See Definitions.
actionsarraynoRows that change variables, once or on a timer. See Actions.
markersarraynoAnnotations on the plot: labels, segments, rules, bands. See Markers.
domainobjectno2D axis ranges, aspect ratio and coordinate system. See Axes and Scene.
stageobjectno2D appearance: grid, axes, frame.
domain3dobjectno3D axis ranges and aspect.
stage3dobjectno3D scene: environment, lighting, camera, projection.
presetobjectnoThe document appearance: { "base": "basel" }. Bases: basel, vellum, academic, slides.
categorystringno"2d", "3d" or "data". When it is absent, Graph Paper finds it from the series types.
The document opens with its rows in this order: variables, points, definitions, actions, then series. A row can use a name that a row above it defines.
The type of the first series decides whether the document is a 2D or a 3D plot. Do not mix 2D and 3D series in one document.

Variables

A variable is a slider. Each row of variables is an object:
FieldTypeRequiredMeaning
namestringyesThe name, as formulas use it: "a", "c_1", "omega" or "\\omega"; see the naming rules below.
valuestringyesThe start value, LaTeX: "0.3", "\\frac{\\pi}{2}".
domainobjectyesThe values the slider allows. See below.
playbackobjectnoHow the variable animates: { "mode": "bounce", "direction": "forward", "duration": 5000 }. When absent: "bounce", "forward", 4000 ms.
autoplaybooleannotrue starts the animation when the document opens. When absent or false, the variable is at rest.
notestringnoA text shown above the row.
domain takes one of two forms:
playback.mode is "once", "loop", "bounce" or "all-at-once". "all-at-once" does not animate: it draws each series once for each value of a values domain. direction is "forward" or "reverse". duration is the time of one pass, in milliseconds.
Do not use x, y or z as a variable name: these names are the axes of the plot. Do not use e, i or pi either: formulas read them as constants.
t, u, v, r, theta and phi are the names that the plot gives to the parameter of a parametric curve (t), of a parametric surface (u, v), to a polar angle (theta, phi) and to the polar radius (r). A variable can have one of these names. Then every formula of the document that uses the name uses the value of the variable. For example, with a variable t, the parametric series (\cos(t), \sin(t)) draws no curve, because all its points use the same value of t. There is one exception: on the left side of a polar equation, r is the radius. With a variable r, the formula r = 2\cos(\theta) is still a polar curve whose radius is r.
A name is one letter ("M", "s") or the name of a Greek letter ("omega", "epsilon"), with an optional subscript ("c_1"). A subscript in braces follows one letter only ("x_{max}"); after a Greek name, write "theta_0" or "\\theta_{0}", not "theta_{0}", which the validator refuses. Some names are other symbols in a formula when they are written plain: name "\\zeta", "\\Pi", the variants ("\\varphi", "\\vartheta", …) and "\\hbar" as LaTeX, so that the slider drives the formula. In a formula, \delta with a subscript is the Kronecker delta and \mu_0 is a constant: name a variable "d_1" rather than "delta_1", and write \mu_{0}, with braces, for a variable "mu_0". A formula reads a name of several Latin letters, such as mass, as a product of letters. In a formula, write a Greek letter with its LaTeX command: the variable "epsilon" is \epsilon in a formula, and "\\epsilon" in the JSON of fn.
The slider row shows a Greek name as its letter: the variable "omega" shows as \omega. Name a Greek letter by its plain name ("epsilon", "rho"), not by a variant name ("varepsilon"), which Graph Paper shows as an upright word. A capital that looks like a Latin letter ("Alpha", "Mu") also shows as an upright word.

Points

A point is a pair of variables that the reader changes by dragging a marker on the plot. Each row of points is an object:
FieldTypeRequiredMeaning
xobjectyesThe first coordinate: { "name": "c_x", "value": "0.5" }.
yobjectyesThe second coordinate: { "name": "c_y", "value": "1" }.
dragstringno"x" or "y" to allow only that direction, "none" for no drag. By default the point moves freely.
notestringnoA text shown above the row.
Formulas use the two coordinate names as ordinary variables. Points are for 2D documents. An action can also change the two coordinates.

A Point That Moves

A scatter series whose fn is a point formula draws a point that moves. The formula can use variables and definitions:
json{ "type": "scatter", "fn": "(L\\sin(a), -L\\cos(a))", "color": "#c62828", "marker": { "size": 14 } }
When a slider, a drag or an action changes L or a, Graph Paper draws the point again at its new position. The pendulum uses this row for its bob.
A point in points is different. It is an input: the reader drags it, and the drag sets two variables that other rows read. A scatter point is a result: its formula sets its position. Use points for a value that the reader chooses, and a scatter formula for a value that the document computes.

Definitions

A definition names a value or a function. Other rows use the name. Each row of definitions is a LaTeX string, or an object:
FieldTypeRequiredMeaning
latexstringyesThe definition: "m = 100", "f(x) = e^{-x}\\cos(x)".
hiddenbooleannotrue hides the row's own curve. See below.
notestringnoA text shown above the row.
A function of one variable, such as f(x) = x^2, also draws its own curve y = f(x). Set "hidden": true when the function is a helper that must not draw. A hidden definition still works: other rows can use it.
The parameter of a function belongs to the definition only. It can be a letter, a letter with a subscript, or a Greek letter written as a LaTeX command: f(s) = s^2, p(t) = 2t, r(x) = x/3 and q(\sigma) = \sigma + 10 all work. A parameter can have the same name as a variable. Inside the definition, the parameter is used, not the variable: with a slider s at 5, f(s) = s^2 gives f(3) = 9, not 25.

Actions

An action changes variables when it runs. The reader runs it once with its ⚡ button, or a timer runs it again and again. Each row of actions is an object:
FieldTypeRequiredMeaning
latexstringyesThe action: "a \\to a + 1". See Tips and Tricks.
intervalstringnoRun the action again every this many milliseconds (LaTeX: "100").
autoplaybooleannotrue starts the timer when the document opens. It needs interval.
notestringnoA text shown above the row.
An action can change a variable, a coordinate of a point in points, or a list or a point that a definition gives by its value, such as S = [2.5, 0]. It cannot change a name that a formula defines, such as b = 2a. Separate several changes with commas. The action computes all the new values from the old values first, then writes them together. For a timer that steps a state, see A Simulation With a Timer.

Series

A series is one plotted row. Every series has a type. Most types take a formula in fn: see the Plotting Guide for what a formula can contain, and for the where clause and the brace restrictions that limit what is drawn.
fn is LaTeX. Commands such as \frac{a}{b}, \sqrt{x}, \sin(x), \ln(x) and \pi work. Plain text is not LaTeX: Graph Paper reads sqrt(x) as the letters s, q, r and t, not as a square root.
Fields that most series types accept:
FieldTypeMeaning
typestringThe series type. Required. See the tables below.
fnstringThe formula, LaTeX.
domainarray or objectThe range of the formula's variables. The form depends on the type.
colorstring or objectA color ("#c62828"), a palette name ("red-700") or a colormap name ("viridis").
namestringThe label in the legend.
idstringA name that another series can refer to, for example in "fill": { "to": { "series": "lower" } }.
How Graph Paper stores each series in the document:
Every series of the document is saved as a row.

2D Series Types

typeDrawsRequireddomain
liney = f(x)fn, or x and y[min, max] of x
parametrica curve (x(t), y(t))fn[min, max] of t
polarr = f(\theta)fn, or theta and r[min, max] of \theta
implicita curve F(x, y) = 0, or a region from an inequalityfn{ "x": [a, b], "y": [c, d] }
heatmapa color for each point of f(x, y)fn, or x, y and z{ "x": [a, b], "y": [c, d] }
domainColoringa complex function of zfn{ "x": [a, b], "y": [c, d] }
vector-fieldarrows (P(x, y), Q(x, y))fn{ "x": [a, b], "y": [c, d] }
scatterpointsfn, or x and y—
polygon-listfilled polygonsfn, or polygons—
bara bar chartx (labels), y—
histogrambinned counts of a list of valuesvalues—
candlestickopen, high, low and close for each xdata—
boxplotbox-and-whisker plotsdata—
deriveda trendline, an average, a smooth curve, a derivative or an integral of another seriessource, transform—
Notes on some types:
One minimal series of each type, one per line:
json{ "type": "line", "fn": "x^2 - 1", "domain": [-3, 3] } { "type": "parametric", "fn": "(\\cos(3t), \\sin(2t))", "domain": [0, 6.283185307179586] } { "type": "polar", "fn": "1 + \\cos(\\theta)", "domain": [0, 6.283185307179586] } { "type": "implicit", "fn": "x^2 + y^2 \\le 1", "domain": { "x": [-2, 2], "y": [-2, 2] } } { "type": "heatmap", "fn": "\\sin(x)\\cos(y)", "domain": { "x": [-6, 6], "y": [-6, 6] }, "color": "viridis" } { "type": "domainColoring", "fn": "z^2 - 1", "domain": { "x": [-3, 3], "y": [-3, 3] } } { "type": "vector-field", "fn": "(-y, x)", "domain": { "x": [-4, 4], "y": [-4, 4] }, "gridSize": 16 } { "type": "scatter", "x": [1, 2, 3, 4], "y": [2.1, 3.9, 6.2, 7.8] } { "type": "polygon-list", "fn": "[\\operatorname{polygon}((0,0), (1,0), (0,1))]" } { "type": "bar", "x": ["A", "B", "C"], "y": [23, 45, 12] } { "type": "histogram", "values": [1.2, 0.4, -0.3, 0.8, 1.9, -1.1, 0.2] } { "type": "candlestick", "data": [{ "x": 1, "open": 10, "high": 15, "low": 8, "close": 13 }] } { "type": "boxplot", "data": [{ "min": 2, "q1": 5, "median": 7, "q3": 9, "max": 14 }], "x": ["A"] }
There is no separate contour type: use a heatmap with "contours": true, or an implicit equation for one level curve.

A Segment Between Two Points

2D has no segment type. To draw a segment from P = (p_x, p_y) to Q = (q_x, q_y), use a parametric series of (1 - t)P + tQ for 0 \le t \le 1, written with the coordinates:
json{ "type": "parametric", "fn": "((1 - t)p_x + tq_x, (1 - t)p_y + tq_y)", "domain": [0, 1], "stroke": { "width": 3 } }
The ends can be formulas, so the segment moves with them.
A scatter series of two points, joined by a line, also draws a segment. Its fn is a list of the two points. The rod of the pendulum goes from (0, 0) to the bob, which follows the angle a:
json{ "type": "scatter", "fn": "[(0, 0), (L\\sin(a), -L\\cos(a))]", "line": true, "points": false }
Do not use polygon-list for a segment: its polygons are filled.

3D Series Types

typeDrawsRequireddomain
surfacez = f(x, y)fn, or z{ "x": [a, b], "y": [c, d] }
parametric-surfacea surface (x(u, v), y(u, v), z(u, v))fn{ "u": [a, b], "v": [c, d] }
parametric-curvea curve (x(t), y(t), z(t))fn[min, max] of t
implicit-surfacea surface F(x, y, z) = 0fn{ "x": [a, b], "y": [c, d], "z": [e, f] }
scatter3dpoints in spacefn, or x, y and z—
analyticLandscapethe height and phase of a complex functionfn{ "x": [a, b], "y": [c, d] }
primitives3dspheres, segments, arrows and trianglesfn, or items—
meshtriangles between given pointsvertices, faces—
Notes on some types:
One minimal series of each type, one per line:
json{ "type": "surface", "fn": "x^2 - y^2", "domain": { "x": [-3, 3], "y": [-3, 3] }, "color": "coolwarm" } { "type": "parametric-surface", "fn": "(\\sin(u)\\cos(v), \\sin(u)\\sin(v), \\cos(u))", "domain": { "u": [0, 3.141592653589793], "v": [0, 6.283185307179586] } } { "type": "parametric-curve", "fn": "(\\cos(t), \\sin(t), t / (2\\pi))", "domain": [0, 12.566370614359172] } { "type": "implicit-surface", "fn": "x^2 + y^2 + z^2 = 4", "predicate": "=0", "domain": { "x": [-3, 3], "y": [-3, 3], "z": [-3, 3] } } { "type": "scatter3d", "x": [1, 2, 3], "y": [2, 3, 1], "z": [3, 1, 4] } { "type": "analyticLandscape", "fn": "z^3 - 1", "domain": { "x": [-2, 2], "y": [-2, 2] }, "heightMode": "log-magnitude" } { "type": "primitives3d", "fn": "[\\operatorname{segment}((0,0,0), (1,1,1))]" }

Data Without a Formula

A series can give its values as literal data instead of a formula in fn. Graph Paper saves each such series as a row of the document.
typeDataRow
scatterx, ytable
scatter3dx, y, ztable
linex, ytable
polartheta, rtable
barx (labels), ytable
histogramvaluestable
candlestickdatatable
boxplotdata, x (labels)table
heatmapx, y, zdata row
surfacezdata row
polygon-listpolygons, fillColors (optional)data row
meshvertices, faces, normals (optional)data row
primitives3ditemsdata row
The reader can edit the numbers of a table. A data row keeps its data as given: the reader can change its style, hide it, copy it or delete it, but cannot edit its numbers.
The forms of the data:
shapeFields
spherecenter, radius
cubecenter, size (a number, or [width, depth, height])
cylinder, cone, tubefrom, to, radius
linefrom, to, width (optional)
arrowfrom, to, and the optional radius, headRadius and headLength
trianglevertices: three points
One series of each data row type, one per line:
json{ "type": "line", "x": [0, 1, 2, 3], "y": [1, 3, 2, 4] } { "type": "polar", "theta": [0, 1.5708, 3.1416, 4.7124], "r": [1, 2, 1, 2] } { "type": "heatmap", "x": [0, 1, 2], "y": [0, 1], "z": [[1, 2, 3], [4, 5, 6]] } { "type": "polygon-list", "polygons": [{ "x": [0, 1, 0], "y": [0, 0, 1] }], "fillColors": ["#1e88e5"] } { "type": "surface", "z": [[0, 1, 0], [1, 2, 1], [0, 1, 0]], "domain": { "x": [-1, 1], "y": [-1, 1] } } { "type": "mesh", "vertices": [[0, 0, 0], [1, 0, 0], [0, 1, 0]], "faces": [[0, 1, 2]] } { "type": "primitives3d", "items": [{ "shape": "sphere", "center": [0, 0, 0], "radius": 1 }] }

Derived Series

A derived series draws a computation over another series of the document: a trendline, a moving average, a smooth curve, a derivative or an integral. source is the id of that series, and transform says what to compute. Graph Paper saves it as a derived row, which follows the source when the reader edits it.
transformFieldsSource
{ "kind": "trendline", "model": "linear" }model: "linear", "quadratic", "polynomial" (with degree, 1 to 10), "exponential", "power" or "logarithmic"data
{ "kind": "sma", "window": 5 }window: the number of points, 1 or moredata, points, derived
{ "kind": "ema", "alpha": 0.2 }alpha: more than 0, at most 1data, points, derived
{ "kind": "smooth", "tension": 0.5 }tension (optional): 0 to 1data, points, derived
{ "kind": "derivative" }—formula
{ "kind": "integral" }—formula
The source kinds:
source must name the id of exactly one other series, and the transform must be one that the source takes: Graph Paper does not change a transform to fit its source, so a mismatch is an error. On a trendline, "legendEquation": true shows the fitted equation in the legend, and "legendShowR2": true adds R^2. The style fields are color, stroke, legend and legendLabel; name is the text of the legend entry. Without color, the series takes the color of its source.
There is no derived-marker type. For the equation of a fit, use a trendline with "legendEquation": true.

Markers

Markers are annotations on the plot: a label, a segment with an arrow, a rule across the plot, a band, a rectangle, an ellipse. The top-level markers array holds them. Graph Paper gives each marker its id, and the reader can move, style and delete it, as a marker placed by hand. Data goes in series rows; annotations go in markers. A segment between two points of data is a line series, not a marker.
The coordinates of a marker are numbers, not formulas, so a marker does not move when the reader changes a slider. For a point that follows a variable, use a scatter row with a point formula, such as "fn": "(0, A)". For a segment that follows a variable, use a scatter row whose fn is a list of the two points, with "line": true and "points": false:
json{ "type": "scatter", "fn": "[(0, 0), (L\\sin(a), -L\\cos(a))]", "line": true, "points": false }
kindFieldsDimension
pointx, y (and z in 3D)2D, 3D
labelx, y (and z in 3D), text2D, 3D
linex0, y0, x1, y1 (and z0, z1 in 3D): a segment2D, 3D
ruleaxis ("x" or "y"), value: a line across the plot2D
bandaxis ("x" or "y"), from, to2D
rectx0, y0, x1, y12D
ellipsecx, cy, rx, ry (radii, more than 0), angle (optional, degrees)2D
plane-bandaxis ("x", "y" or "z"), from, to3D
A rule with "axis": "x" is a vertical line at x = value. A band with "axis": "x" covers the x values from from to to. The bounds of a band and of a rectangle are sorted. A marker of a 3D document gives its z coordinates; a marker of a 2D document gives none.
style (optional) sets the look:
kindstyle fields
pointsymbol ("circle", "square", "diamond", "cross", "plus", "triangle"), size (pixels), fill, stroke (color, width)
labelcolor, fontSizeOffset (−3 to 3), background
linestroke, arrowFrom, arrowTo (booleans: an arrowhead at the start or the end)
rulestroke
band, rect, ellipse, plane-bandfill, stroke (present, even {}: an outline)
A stroke is { "color", "width", "dash" }, all optional: width in pixels, dash a list of lengths such as [4, 4]. A color is a hex color ("#1e88e5", or "#1e88e533" with transparency) or "transparent".
The text of a label is at most 500 characters. It is plain text, with inline Markdown (**bold**, *italic*) and inline math in $…$; a text that is all one $…$ is a formula.
Rules:
json{ "title": "Annotated parabola", "series": [{ "type": "line", "fn": "x^2", "domain": [-2, 2] }], "markers": [ { "kind": "label", "x": 0, "y": 0.4, "text": "Vertex" }, { "kind": "line", "x0": 1, "y0": 3, "x1": 1.4, "y1": 2.1, "style": { "arrowTo": true, "stroke": { "width": 2 } } }, { "kind": "rule", "axis": "x", "value": 1.5 }, { "kind": "band", "axis": "y", "from": 1, "to": 2, "style": { "fill": "#1e88e533" } } ] }

Axes and Scene

These fields are all optional. When they are absent, Graph Paper fits the view to the series.
domain (2D):
FieldMeaning
x.range, y.rangeThe visible range of an axis: { "x": { "range": [-5, 5] } }. An axis has no min and max fields.
x.scale, y.scale"linear", "log", "symlog" or "asinh".
aspect"equal" for the same scale on both axes, "auto", or a number.
coordinateSystem"cartesian" or "polar".
Graph Paper keeps the x range and derives the y range from it: the visible y extent is the x extent × aspect × (plot height ÷ plot width), and y.range is only the least it shows, so a tall window shows more of the y axis. To show less of the y axis, set aspect to a smaller number, from 0.2 to 5 ("auto" is about 0.618 for a line plot and 1 for an implicit plot or a heat map, "equal" is 1); with a number, when y.range does not fit, the x range widens instead.
stage (2D): gridStyle is true, false, "lines", "dots" or "isometric"; frame is true or false.
domain3d (3D): x.range, y.range, z.range as in 2D, and aspectMode, which sets the shape of the frame. "auto" (the default) and "cube" scale each axis so that the frame is a cube. "data" draws the three axes at the same scale, so the frame has the proportions of the axis ranges (or of the series, when no range is given).
stage3d (3D): environment is "abstract", "outdoor" or "paper"; projection is "perspective" or "orthographic"; axes is true or false; camera is { "position": [x, y, z], "target": [x, y, z], "up": [0, 0, 1] }.
The plot types accept more fields than this page lists. The fields above are the ones a document usually needs.

Patterns

Each pattern below is a short complete document. Start from the one that is closest to what you want.

A Point That Moves Along a Curve

A scatter row with a point formula of the slider a draws a point on the curve, and the point moves when the reader drags the slider.
json{ "title": "A point on a parabola", "variables": [{ "name": "a", "value": "1", "domain": { "type": "range", "min": "-2", "max": "2" } }], "series": [ { "type": "line", "fn": "x^2", "domain": [-2.5, 2.5] }, { "type": "scatter", "fn": "(a, a^2)", "marker": { "size": 10 } } ] }

A Segment That Follows a Variable

A scatter row whose fn is a list of two points, with "line": true and "points": false, draws a segment, and its ends can be formulas.
json{ "title": "A segment that turns", "variables": [{ "name": "a", "value": "0.8", "domain": { "type": "range", "min": "0", "max": "6.28" } }], "series": [ { "type": "scatter", "fn": "[(0, 0), (\\cos(a), \\sin(a))]", "line": true, "points": false }, { "type": "scatter", "fn": "(\\cos(a), \\sin(a))" } ], "domain": { "aspect": "equal", "x": { "range": [-1.5, 1.5] }, "y": { "range": [-1.5, 1.5] } } }

A Helper Function

A definition with arguments, such as E_1(s) = …, is a function that a series can call. E_1 and E_{1} are the same name. A definition of a function also draws its curve, so "hidden": true hides it here.
json{ "title": "A helper function", "variables": [{ "name": "c", "value": "0.5", "domain": { "type": "range", "min": "0", "max": "1" } }], "definitions": [{ "latex": "E_1(s) = e^{-cs}\\cos(4s)", "hidden": true }], "series": [{ "type": "line", "fn": "E_1(x)", "domain": [0, 10] }] }

A Family of Curves From a List

A list in a definition, such as k = [1, 2, 3], makes one curve for each of its values.
json{ "title": "A family of sine curves", "definitions": ["k = [1, 2, 3]"], "series": [{ "type": "line", "fn": "\\sin(kx)", "domain": [0, 6.28] }] }

A Sum With a Number of Terms From a Slider

\sum_{k=0}^{n-1} adds n terms, and n can be a slider. A slider that counts terms needs "step": "1". Here the sum is the Fourier series of a square wave, and the dashed row is the square wave.
json{ "title": "Square wave partial sum", "variables": [{ "name": "n", "value": "3", "domain": { "type": "range", "min": "1", "max": "25", "step": "1" } }], "series": [ { "type": "line", "fn": "\\frac{4}{\\pi}\\sum_{k=0}^{n-1}\\frac{\\sin((2k+1)x)}{2k+1}" }, { "type": "line", "fn": "\\operatorname{sign}(\\sin(x))", "stroke": { "dash": [4, 4] } } ], "domain": { "x": { "range": [-6.283, 6.283] }, "y": { "range": [-2, 2] } } }

A Simulation

An action with an interval and "autoplay": true changes a variable on a timer; here the point goes around the circle. The pendulum is a longer example.
json{ "title": "A point that goes around", "variables": [{ "name": "a", "value": "0", "domain": { "type": "range", "min": "0", "max": "6.28" } }], "actions": [{ "latex": "a \\to \\operatorname{mod}(a + 0.05, 6.28)", "interval": "50", "autoplay": true }], "series": [ { "type": "parametric", "fn": "(\\cos(t), \\sin(t))", "domain": [0, 6.28] }, { "type": "scatter", "fn": "(\\cos(a), \\sin(a))", "marker": { "size": 10 } } ], "domain": { "aspect": "equal", "x": { "range": [-1.5, 1.5] }, "y": { "range": [-1.5, 1.5] } } }

Data With Annotations

A line row with x and y data draws the readings, a label marker names a point, and a band marker shades a range of x.
json{ "title": "Readings with notes", "series": [{ "type": "line", "x": [0, 1, 2, 3, 4], "y": [1, 3, 2, 5, 4] }], "markers": [ { "kind": "label", "x": 3, "y": 5.4, "text": "Peak" }, { "kind": "band", "axis": "x", "from": 1, "to": 2, "style": { "fill": "#1e88e533" } } ] }

Complete Examples

A Line With a Slider

A damped oscillation. The variable c is a slider at rest, with a note. The definition f is hidden, so it does not draw a second curve. The dashed line is the envelope.
json{ "title": "Damped oscillation", "variables": [ { "name": "c", "value": "0.3", "domain": { "type": "range", "min": "0.05", "max": "1" }, "playback": { "mode": "bounce", "direction": "forward", "duration": 5000 }, "note": "The damping coefficient $c$. Drag the slider to change it." } ], "definitions": [{ "latex": "f(x) = e^{-c x} \\cos(6 x)", "hidden": true }], "series": [ { "type": "line", "fn": "f(x)", "domain": [0, 10] }, { "type": "line", "fn": "e^{-c x}", "domain": [0, 10], "stroke": { "dash": [4, 4] } } ], "domain": { "x": { "range": [0, 10] }, "y": { "range": [-1.2, 1.2] } } }

An Implicit Region

A disk that the reader drags, over the region above a parabola. The point (c_x, c_y) is the center of the disk.
json{ "title": "A disk above a parabola", "points": [ { "x": { "name": "c_x", "value": "0.5" }, "y": { "name": "c_y", "value": "1" }, "note": "The center of the disk. Drag it on the plot." } ], "series": [ { "type": "implicit", "fn": "y \\ge x^2 - 2", "domain": { "x": [-3, 3], "y": [-3, 3] }, "fill": "#90caf9" }, { "type": "implicit", "fn": "(x - c_x)^2 + (y - c_y)^2 \\le 1", "domain": { "x": [-3, 3], "y": [-3, 3] }, "color": "#c62828" } ], "domain": { "aspect": "equal" } }

Readings With a Trendline

Six readings, as data, and a linear fit with its equation in the legend. The scatter series has an id, and the derived series names it in source.
json{ "title": "Readings with a trendline", "series": [ { "type": "scatter", "id": "readings", "x": [1, 2, 3, 4, 5, 6], "y": [2.1, 3.9, 6.2, 7.8, 10.1, 12.2], "name": "Readings" }, { "type": "derived", "source": "readings", "transform": { "kind": "trendline", "model": "linear" }, "legendEquation": true } ] }

A Measured Field

A heatmap of measured values: 3 rows (y = 0, 1, 2) of 4 values (x = 0, 1, 2, 3). The null value is a cell with no measure, drawn as a hole.
json{ "title": "Measured field", "series": [ { "type": "heatmap", "x": [0, 1, 2, 3], "y": [0, 1, 2], "z": [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, null, 6]], "color": "viridis", "name": "Temperature" } ] }

A 3D Parametric Surface

A torus.
json{ "title": "Torus", "series": [ { "type": "parametric-surface", "fn": "((2 + \\cos(v))\\cos(u), (2 + \\cos(v))\\sin(u), \\sin(v))", "domain": { "u": [0, 6.283185307179586], "v": [0, 6.283185307179586] }, "color": "viridis" } ], "stage3d": { "environment": "outdoor" }, "domain3d": { "aspectMode": "data" } }
"aspectMode": "data" draws the three axes at the same scale, so the torus keeps its shape. Without it, the frame is a cube, and the torus, which is 2 units tall and 6 units wide, is stretched into a barrel.

A Simulation With a Timer

Graph Paper has no row that solves a differential equation. A document can still simulate a motion: an action steps the state forward on a timer.
The limits:

Example: A Pendulum

A pendulum with large swings. The equation of motion is a'' = -\frac{g}{L}\sin(a), where a is the angle from the vertical. The state is the angle a, the angular velocity w and the time T. The timer runs every 20 ms, and each run is one step of h = 0.02 s:
w \to w - h\frac{g}{L}\sin(a), \quad a \to a + h\left(w - h\frac{g}{L}\sin(a)\right), \quad T \to T + h
The second action puts the pendulum back at the start angle A, at rest. The red point is the bob, the dark segment is the rod (a scatter row of two points, joined by a line), and the dark point marker is the pivot. The sliders do not move by themselves: only the timer changes a, w and T. The gray point follows the small-angle formula a = A\cos(\sqrt{g/L}\,T), for comparison. A large swing takes longer than the formula predicts, so with a start angle of 2.5 radians the gray point moves ahead of the bob at once.
json{ "title": "Pendulum", "variables": [ { "name": "L", "value": "2", "domain": { "type": "range", "min": "0.5", "max": "3" }, "note": "The length $L$ of the rod, in meters." }, { "name": "A", "value": "2.5", "domain": { "type": "range", "min": "0.1", "max": "3.1" }, "note": "The start angle $A$, in radians from the vertical. Run **Reset** after you change it." }, { "name": "a", "value": "2.5", "domain": { "type": "range", "min": "-3.2", "max": "3.2" }, "note": "The state: the angle $a$, the angular velocity $w$ and the time $T$. The timer changes them." }, { "name": "w", "value": "0", "domain": { "type": "range", "min": "-8", "max": "8" } }, { "name": "T", "value": "0", "domain": { "type": "range", "min": "0", "max": "60" } } ], "definitions": [ { "latex": "g = 9.81", "note": "The gravity $g$, in m/s²." }, { "latex": "h = 0.02", "note": "The time step $h$, in seconds." } ], "actions": [ { "latex": "w \\to w - h\\frac{g}{L}\\sin(a), a \\to a + h\\left(w - h\\frac{g}{L}\\sin(a)\\right), T \\to T + h", "interval": "20", "autoplay": true, "note": "One step of the motion every 20 ms: first the new $w$, then the new $a$ from the new $w$." }, { "latex": "a \\to A, w \\to 0, T \\to 0", "note": "Reset: back to the start angle, at rest." } ], "series": [ { "type": "parametric", "fn": "(L\\cos(t), L\\sin(t))", "domain": [0, 6.283185307179586], "color": "#b0bec5", "stroke": { "dash": [4, 4] } }, { "type": "scatter", "fn": "[(0, 0), (L\\sin(a), -L\\cos(a))]", "line": true, "points": false, "color": "#455a64" }, { "type": "scatter", "fn": "(L\\sin(A\\cos(\\sqrt{g/L}T)), -L\\cos(A\\cos(\\sqrt{g/L}T)))", "color": "#90a4ae", "marker": { "size": 10 } }, { "type": "scatter", "fn": "(L\\sin(a), -L\\cos(a))", "color": "#c62828", "marker": { "size": 14 } } ], "markers": [ { "kind": "point", "x": 0, "y": 0, "style": { "fill": "#455a64", "size": 8 } } ], "domain": { "aspect": "equal", "x": { "range": [-3.5, 3.5] }, "y": { "range": [-3.5, 3.5] } } }

Check a Document

A program can check a document without a browser and without an account:
The answer is the link that opens the document, or each error with the path of its field, such as series[0].fn. Warnings name the keys that were ignored. For Agents shows the requests and the answers.
The check covers the fields, their types and the limits on this page. It does not draw the plot. A formula that is valid LaTeX can still draw nothing. Tell the person that you did not see the plot, and prefer the row forms that this page shows.
The link service checks the structure only. Graph Paper checks the formulas when the link opens, and reports the rows that do not work: see When the Person Opens the Link on the For Agents page.

Learn From the Showcase

Every showcase page contains its document in the same shape, in a <script type="application/graph-paper+json" id="gallery-entry"> tag. When the document is large, the tag holds only { "id": … } and a data-payload-href attribute that gives the URL of the full JSON.
A showcase entry is not a document to send as it is. It has an id and no title, and its note values are the names of translated texts, not the texts. To reuse one, remove id, add a title, and replace or remove each note.

Notebook Documents

Graph Paper also has notebook documents: sections of text, formulas, computations and figures. They are a different format, and a /new link cannot open them. Their reference is the notebook file format, with JSON schemas for the export file and the notebook content.