Format des documents de tracé
Un document de tracé est un objet JSON qui décrit un tracé de Graph Paper :
ses formules, ses curseurs, ses points à déplacer et ses axes. Encodez-le dans
un lien, et Graph Paper l'ouvre comme un document que le lecteur peut modifier.
Cette page décrit chaque champ.
Cette page s'adresse aux programmes et aux agents d'IA qui écrivent des
documents. Un programme qui veut donner un tracé à une personne commence par
Pour les agents : le moyen le plus rapide est
d'envoyer le document avec POST https://graph-paper.io/plot-link, ou avec
GET https://graph-paper.io/plot-link?doc=<JSON encodé en pourcentage> depuis
un outil qui peut seulement lire une adresse ; la réponse contient le
lien, ou les erreurs. Pour ce qu'il faut écrire dans une formule, voir le
Guide des tracés.
Chaque formule est en LaTeX. Dans une chaîne JSON, écrivez
"\\sin(x)", pas "sin(x)", et "x^{2}", pas "x**2". Le validateur
refuse un nom de fonction écrit en texte brut (exp(…), sqrt(…)) et dit
quoi écrire. Un nombre en notation scientifique comme 2.312e-05 est
accepté et lu comme le nombre, et Graph Paper l'affiche comme 2.312 × 10⁻⁵,
la forme qu'obtient une personne qui le tape. Certains nombres sont affichés
tels qu'ils sont écrits (2.312e − 05, qu'une personne peut lire comme la
constante e et une soustraction), et le validateur donne un avertissement
pour eux : un nombre avec une espace à l'intérieur, un nombre suivi de
^, _ ou d'un prime, un nombre dans un indice ou dans un groupe {…} seul,
un nombre juste après } ou après une commande comme \frac, et un nombre
dont la mantisse commence par un point (.5e3). Pour ceux-là, écrivez un
décimal simple (0.00002312) ou a\cdot 10^{n}
("2.312\\cdot 10^{-5}" en JSON). Un point sans chiffre après lui (1.e5)
ou un point dans l'exposant (1e3.5) n'est pas un nombre que Graph Paper peut
lire, et le validateur le refuse.
Un programme doit lire la version Markdown de cette page, à l'adresse
https://graph-paper.io/plot-document-format/fr/index.md, car un résumé de la
page HTML peut perdre les tableaux. Chaque page de guide existe en
Markdown : ajoutez index.md à son URL, ou envoyez
Accept: text/markdown. Le fichier https://graph-paper.io/llms-full.txt
contient à lui seul le texte anglais de cette page, de
Pour les agents, du Guide des tracés et des Astuces et
conseils.
Sommaire
- Un document minimal
- Règles et limites
- Champs de premier niveau
- Variables
- Points
- Un point qui bouge
- Définitions
- Actions
- Séries
- Types de séries 2D
- Types de séries 3D
- Données sans formule
- Séries dérivées
- Marqueurs
- Un segment entre deux points
- Axes et scène
- Modèles
- Exemples complets
- Une simulation avec une minuterie
- Vérifier un document
- Apprendre avec la Vitrine
- Les carnets
Un document minimal
Un titre et une série :
json{
"title": "Sinusoïde",
"series": [{ "type": "line", "fn": "\\sin(x)" }]
}
Pour l'ouvrir, encodez le JSON en UTF-8, puis en base64url (RFC 4648 §5, sans
remplissage), et ajoutez-le à https://graph-paper.io/new#doc=. Les
exemples complets ci-dessous montrent les liens entiers.
Un programme qui ne sait pas calculer de base64url peut écrire le JSON, encodé
en pourcentage, après https://graph-paper.io/new#json=. Un lien n'a qu'une
forme. Le service https://graph-paper.io/plot-link vérifie un document et renvoie
son lien, sans compte. Voir Vérifier un document.
Règles et limites
- Le document fait au plus 65 536 octets de JSON en UTF-8.
- title est du texte brut, de 200 caractères au plus.
- Une note (note) est du Markdown avec des mathématiques en ligne $…$, de 2 000 caractères au plus.
- Un document contient au plus 100 séries (series), 100 variables (variables), 100 points (points), 200 définitions (definitions) et 50 actions (actions).
- Chaque nombre doit être fini. Un nombre trop grand pour un double, comme 1e999, rend le document invalide.
- Une formule fn ne doit pas être vide ni contenir seulement des espaces.
- Graph Paper ignore une clé qu'il ne connaît pas, au premier niveau comme dans une ligne. Il ne rejette pas le document. Le service de lien donne un avertissement pour chaque clé ignorée. Si la clé ne diffère d'un champ que par la casse, l'avertissement nomme ce champ.
- Les clés __proto__, constructor et prototype sont retirées, à tous les niveaux.
- Un document imbriqué sur plus de 32 niveaux est refusé. L'objet du document est le niveau 1 : { "series": [ { … } ] } a donc 3 niveaux.
- Un champ interne à Graph Paper, comme fnTemplate ou maskPredicate sur une série, ne fait pas partie du format. Il est ignoré, avec un avertissement.
- Dans stage, domain, stage3d et domain3d, une clé inconnue au premier niveau de l'objet est ignorée, avec un avertissement. Les valeurs sous ce premier niveau sont gardées telles quelles.
- Chaque type de série accepte colorBar : la barre de couleurs d'une série colorée par une carte de couleurs, avec "legend": true. Ses clés sont anchor ("top-left", "top", "top-right", "right", "bottom-right", "bottom", "bottom-left" ou "left"), placement ("inside" ou "outside"), label (une chaîne de 2 000 caractères au plus) et visible (un booléen). Une valeur du mauvais type est une erreur.
- Quand une erreur ou un avertissement répète une clé du document, la clé est coupée à 64 caractères et suivie de ….
- Une série donne une formule dans fn ou des données littérales, pas les deux. Quand une série a un fn, ses données littérales (x, y, z, theta, r, polygons, fillColors ou items) sont ignorées, avec un avertissement.
- Les données littérales doivent être complètes : chaque tableau de données a au moins une valeur, deux tableaux qui vont par paires (x et y, theta et r) ont la même longueur, et une grille a le même nombre de valeurs dans chaque ligne. Une valeur fausse est une erreur. Voir Données sans formule.
- Le service de lien liste au plus 100 erreurs et 100 avertissements. S'il y en a plus, un dernier élément donne le nombre de ceux qui ne sont pas listés.
- Les formules sont des chaînes LaTeX. En JSON, doublez chaque barre oblique inverse : "\\sin(x)" est le LaTeX \sin(x).
- Les valeurs et les bornes des variables sont aussi des chaînes LaTeX ("0.3", "2\\pi"), pour que les valeurs exactes restent exactes. Les intervalles des axes et les domaines sont des nombres JSON.
- Là où une variable, un point ou une action attend une chaîne LaTeX (value, min, max, step, interval), un nombre JSON fini est aussi accepté : "value": 0.3 équivaut à "value": "0.3".
Champs de premier niveau
| Champ | Type | Obligatoire | Signification |
|---|---|---|---|
| title | chaîne | oui | Le titre du document, en texte brut. |
| series | tableau | oui | Les lignes tracées, au moins une. Voir Séries. |
| variables | tableau | non | Les curseurs. Voir Variables. |
| points | tableau | non | Les points que le lecteur déplace sur le tracé. Voir Points. |
| definitions | tableau | non | Les valeurs et fonctions nommées que les autres lignes utilisent. Voir Définitions. |
| actions | tableau | non | Les lignes qui changent des variables, une fois ou à intervalle régulier. Voir Actions. |
| markers | tableau | non | Les annotations sur le tracé : étiquettes, segments, droites, bandes. Voir Marqueurs. |
| domain | objet | non | Intervalles des axes 2D, rapport d'aspect et système de coordonnées. Voir Axes et scène. |
| stage | objet | non | Apparence 2D : grille, axes, cadre. |
| domain3d | objet | non | Intervalles des axes 3D et proportions. |
| stage3d | objet | non | Scène 3D : environnement, éclairage, caméra, projection. |
| preset | objet | non | L'apparence du document : { "base": "basel" }. Bases : basel, vellum, academic, slides. |
| category | chaîne | non | "2d", "3d" ou "data". S'il est absent, Graph Paper le déduit des types de séries. |
Le document s'ouvre avec ses lignes dans cet ordre : variables, points,
définitions, actions, puis séries. Une ligne peut utiliser un nom qu'une ligne
située au-dessus définit.
Le type de la première série décide si le document est un tracé 2D ou 3D. Ne
mélangez pas des séries 2D et 3D dans un même document.
Variables
Une variable est un curseur. Chaque ligne de variables est un objet :
| Champ | Type | Obligatoire | Signification |
|---|---|---|---|
| name | chaîne | oui | Le nom, tel que les formules l'utilisent : "a", "c_1", "omega" ou "\\omega" ; voir les règles de nommage ci-dessous. |
| value | chaîne | oui | La valeur de départ, en LaTeX : "0.3", "\\frac{\\pi}{2}". |
| domain | objet | oui | Les valeurs que le curseur accepte. Voir ci-dessous. |
| playback | objet | non | L'animation de la variable : { "mode": "bounce", "direction": "forward", "duration": 5000 }. En son absence : "bounce", "forward", 4000 ms. |
| autoplay | booléen | non | true démarre l'animation à l'ouverture du document. En son absence, ou avec false, la variable reste au repos. |
| note | chaîne | non | Un texte affiché au-dessus de la ligne. |
domain prend l'une de deux formes :
- Un intervalle : { "type": "range", "min": "0", "max": "2\\pi" }, avec un pas "step" facultatif (en LaTeX).
- Une liste de valeurs : { "type": "values", "values": ["1", "3", "5"] }.
playback.mode vaut "once", "loop", "bounce" ou "all-at-once".
"all-at-once" n'anime pas : il trace chaque série une fois pour chaque
valeur d'un domaine values. direction vaut "forward" ou "reverse".
duration est la durée d'un passage, en millisecondes.
N'utilisez pas x, y ni z comme nom de variable : ces noms sont les
axes du tracé. N'utilisez pas non plus e, i ni pi : les formules les
lisent comme des constantes.
t, u, v, r, theta et phi sont les noms que le tracé donne au
paramètre d'une courbe paramétrique (t), d'une surface paramétrique (u,
v), à un angle polaire (theta, phi) et au rayon polaire (r). Une
variable peut avoir l'un de ces noms. Alors chaque formule du document qui
utilise ce nom utilise la valeur de la variable. Par exemple, avec une variable
t, la série paramétrique (\cos(t), \sin(t)) ne trace aucune courbe, car tous
ses points utilisent la même valeur de t. Il y a une exception : à gauche
d'une équation polaire, r est le rayon. Avec une variable r, la formule
r = 2\cos(\theta) reste une courbe polaire dont le rayon est r.
Un nom est une lettre ("M", "s") ou le nom d'une lettre grecque
("omega", "epsilon"), avec un indice facultatif ("c_1"). Un indice entre
accolades suit une seule lettre ("x_{max}") ; après un nom grec, écrivez
"theta_0" ou "\\theta_{0}", et non "theta_{0}", que le validateur
refuse. Écrits en clair, certains noms sont d'autres symboles dans une
formule : nommez "\\zeta", "\\Pi", les variantes ("\\varphi",
"\\vartheta", …) et "\\hbar" en LaTeX, pour que le curseur agisse sur la
formule. Dans une formule, \delta avec un indice est le delta de Kronecker
et \mu_0 est une constante : nommez une variable "d_1" plutôt que
"delta_1", et écrivez \mu_{0}, avec des accolades, pour une variable
"mu_0". Une
formule lit un nom de plusieurs lettres latines, comme mass, comme un
produit de lettres.
Dans une formule, écrivez une lettre grecque avec sa commande LaTeX : la
variable "epsilon" s'écrit \epsilon dans une formule, et "\\epsilon"
dans le JSON de fn.
La ligne du curseur affiche un nom grec avec sa lettre : la variable
"omega" s'affiche \omega . Nommez une lettre grecque par son nom simple
("epsilon", "rho"), et non par un nom de variante ("varepsilon"), que
Graph Paper affiche comme un mot droit. Une majuscule qui ressemble à une lettre
latine ("Alpha", "Mu") s'affiche aussi comme un mot droit.
Points
Un point est une paire de variables que le lecteur change en déplaçant un
marqueur sur le tracé. Chaque ligne de points est un objet :
| Champ | Type | Obligatoire | Signification |
|---|---|---|---|
| x | objet | oui | La première coordonnée : { "name": "c_x", "value": "0.5" }. |
| y | objet | oui | La seconde coordonnée : { "name": "c_y", "value": "1" }. |
| drag | chaîne | non | "x" ou "y" pour ne permettre que cette direction, "none" pour aucun déplacement. Par défaut, le point se déplace librement. |
| note | chaîne | non | Un texte affiché au-dessus de la ligne. |
Les formules utilisent les deux noms de coordonnées comme des variables
ordinaires. Les points sont réservés aux documents 2D. Une action peut aussi
changer les deux coordonnées.
Un point qui bouge
Une série scatter dont le fn est la formule d'un point trace un point qui
bouge. La formule peut utiliser des variables et des définitions :
json{ "type": "scatter", "fn": "(L\\sin(a), -L\\cos(a))", "color": "#c62828", "marker": { "size": 14 } }
Quand un curseur, un déplacement ou une action change L ou a, Graph Paper
trace à nouveau le point à sa nouvelle position. Le
pendule utilise cette ligne pour sa
masse.
Un point de points est différent. C'est une entrée : le lecteur le
déplace, et le déplacement fixe deux variables que d'autres lignes lisent. Un
point scatter est un résultat : sa formule fixe sa position. Utilisez
points pour une valeur que le lecteur choisit, et une formule scatter pour
une valeur que le document calcule.
Définitions
Une définition nomme une valeur ou une fonction. Les autres lignes utilisent ce
nom. Chaque ligne de definitions est une chaîne LaTeX, ou un objet :
| Champ | Type | Obligatoire | Signification |
|---|---|---|---|
| latex | chaîne | oui | La définition : "m = 100", "f(x) = e^{-x}\\cos(x)". |
| hidden | booléen | non | true masque la courbe de la ligne. Voir ci-dessous. |
| note | chaîne | non | Un texte affiché au-dessus de la ligne. |
Une fonction d'une variable, comme f(x) = x^2, trace aussi sa propre courbe
y = f(x) . Mettez "hidden": true quand la fonction est un outil qui ne doit
pas être tracé. Une définition masquée fonctionne toujours : les autres
lignes peuvent l'utiliser.
Le paramètre d'une fonction appartient à la définition seule. Ce peut être une
lettre, une lettre avec un indice, ou une lettre grecque écrite avec sa
commande LaTeX : f(s) = s^2, p(t) = 2t, r(x) = x/3 et
q(\sigma) = \sigma + 10 fonctionnent tous. Un paramètre peut avoir le même
nom qu'une variable. Dans la définition, c'est le paramètre qui compte, pas la
variable : avec un curseur s à 5, f(s) = s^2 donne f(3) = 9, et
non 25.
Actions
Une action change des variables quand elle s'exécute. Le lecteur l'exécute une
fois avec son bouton ⚡, ou une minuterie l'exécute encore et encore. Chaque
ligne de actions est un objet :
| Champ | Type | Obligatoire | Signification |
|---|---|---|---|
| latex | chaîne | oui | L'action : "a \\to a + 1". Voir Astuces et conseils. |
| interval | chaîne | non | Exécuter l'action à nouveau toutes les N millisecondes (en LaTeX : "100"). |
| autoplay | booléen | non | true démarre la minuterie à l'ouverture du document. Demande interval. |
| note | chaîne | non | Un texte affiché au-dessus de la ligne. |
Une action peut changer une variable, une coordonnée d'un point de points, ou
une liste ou un point qu'une définition donne par sa valeur, comme
S = [2.5, 0]. Elle ne peut pas changer un nom qu'une formule définit, comme
b = 2a. Séparez plusieurs changements par des virgules. L'action calcule
d'abord toutes les nouvelles valeurs à partir des anciennes, puis les écrit
ensemble. Pour une minuterie qui fait avancer un état, voir
Une simulation avec une minuterie.
Séries
Une série est une ligne tracée. Chaque série a un type. La plupart des types
prennent une formule dans fn : voir le
Guide des tracés pour
ce qu'une formule peut contenir, ainsi que pour la clause where et les
restrictions entre accolades qui limitent ce qui est tracé.
fn est du LaTeX. Les commandes comme \frac{a}{b}, \sqrt{x}, \sin(x),
\ln(x) et \pi fonctionnent. Le texte brut n'est pas du LaTeX : Graph
Paper lit sqrt(x) comme les lettres s, q, r et t, et non comme une racine
carrée.
Champs que la plupart des types de séries acceptent :
| Champ | Type | Signification |
|---|---|---|
| type | chaîne | Le type de série. Obligatoire. Voir les tableaux ci-dessous. |
| fn | chaîne | La formule, en LaTeX. |
| domain | tableau ou objet | L'intervalle des variables de la formule. Sa forme dépend du type. |
| color | chaîne ou objet | Une couleur ("#c62828"), un nom de la palette ("red-700") ou un nom de carte de couleurs ("viridis"). |
| name | chaîne | L'étiquette dans la légende. |
| id | chaîne | Un nom auquel une autre série peut faire référence, par exemple dans "fill": { "to": { "series": "lower" } }. |
Comment Graph Paper enregistre chaque série dans le document :
- Une série avec une chaîne fn devient une ligne de formule. Le lecteur peut modifier la formule. Le type de la série est conservé, même si la formule seule donnerait un autre type.
- Une série scatter, scatter3d, bar, histogram, candlestick, boxplot, line ou polar avec des tableaux de données et sans fn devient une ligne de tableau. Le lecteur peut modifier les nombres.
- Une série heatmap, surface, polygon-list, mesh ou primitives3d avec des données et sans fn devient une ligne de données. Graph Paper enregistre les données telles quelles. Le lecteur peut changer le style de la ligne, mais pas ses nombres.
- Une série derived devient une ligne dérivée. Voir Séries dérivées.
Chaque série du document est enregistrée comme une ligne.
Types de séries 2D
| type | Trace | Obligatoire | domain |
|---|---|---|---|
| line | fn, ou x et y | [min, max] de | |
| parametric | une courbe | fn | [min, max] de |
| polar | fn, ou theta et r | [min, max] de | |
| implicit | une courbe | fn | { "x": [a, b], "y": [c, d] } |
| heatmap | une couleur pour chaque point de | fn, ou x, y et z | { "x": [a, b], "y": [c, d] } |
| domainColoring | une fonction complexe de | fn | { "x": [a, b], "y": [c, d] } |
| vector-field | des flèches | fn | { "x": [a, b], "y": [c, d] } |
| scatter | des points | fn, ou x et y | — |
| polygon-list | des polygones remplis | fn, ou polygons | — |
| bar | un diagramme en barres | x (étiquettes), y | — |
| histogram | les effectifs par classe d'une liste de valeurs | values | — |
| candlestick | ouverture, haut, bas et clôture pour chaque | data | — |
| boxplot | des boîtes à moustaches | data | — |
| derived | une droite de tendance, une moyenne, une courbe lissée, une dérivée ou une intégrale d'une autre série | source, transform | — |
Remarques sur certains types :
- implicit : une équation trace une courbe, une inéquation remplit une région. "fill" donne la couleur de remplissage et "stroke" le contour, par exemple { "width": 2 }.
- heatmap : "zRange": [min, max] fixe l'échelle des couleurs, et "contours": true ajoute des lignes de niveau.
- polar : mettez "domain": { "coordinateSystem": "polar" } au premier niveau pour afficher des axes polaires.
- scatter : fn est un point (a, b), une paire de listes (L_x, L_y) ou une liste de points. "line": true relie les points, et "points": false masque les marqueurs.
- polygon-list : fn est une liste de valeurs \operatorname{polygon}(…), et chaque polygone prend ses sommets sous forme de points : [\operatorname{polygon}((0,0), (1,0), (0,1))]. Chaque polygone est rempli, et "stroke" ajoute un contour. Des polygons littéraux sont aussi acceptés : voir Données sans formule.
- bar : "orientation": "horizontal" couche les barres.
- histogram : "bins" est un nombre ou "sturges", "fd" ou "scott".
- boxplot : chaque élément de data est { "min", "q1", "median", "q3", "max" } ; x donne les étiquettes.
Une série minimale de chaque type, une par ligne :
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"] }
Il n'y a pas de type distinct pour les lignes de niveau : utilisez un
heatmap avec "contours": true, ou une équation implicit pour une seule
courbe de niveau.
Un segment entre deux points
La 2D n'a pas de type segment. Pour tracer un segment de P = (p_x, p_y) à
Q = (q_x, q_y) , utilisez une série parametric de (1 - t)P + tQ pour
0 \le t \le 1 , écrite avec les coordonnées :
json{ "type": "parametric", "fn": "((1 - t)p_x + tq_x, (1 - t)p_y + tq_y)", "domain": [0, 1], "stroke": { "width": 3 } }
Les extrémités peuvent être des formules, et le segment bouge alors avec elles.
Une série scatter de deux points reliés par une ligne trace aussi un
segment. Son fn est une liste des deux points. La tige du
pendule va de (0, 0) à la masse, qui
suit l'angle a :
json{ "type": "scatter", "fn": "[(0, 0), (L\\sin(a), -L\\cos(a))]", "line": true, "points": false }
N'utilisez pas polygon-list pour un segment : ses polygones sont
remplis.
Types de séries 3D
| type | Trace | Obligatoire | domain |
|---|---|---|---|
| surface | fn, ou z | { "x": [a, b], "y": [c, d] } | |
| parametric-surface | une surface | fn | { "u": [a, b], "v": [c, d] } |
| parametric-curve | une courbe | fn | [min, max] de |
| implicit-surface | une surface | fn | { "x": [a, b], "y": [c, d], "z": [e, f] } |
| scatter3d | des points dans l'espace | fn, ou x, y et z | — |
| analyticLandscape | la hauteur et la phase d'une fonction complexe | fn | { "x": [a, b], "y": [c, d] } |
| primitives3d | des sphères, des segments, des flèches et des triangles | fn, ou items | — |
| mesh | des triangles entre des points donnés | vertices, faces | — |
Remarques sur certains types :
- surface, parametric-surface : "material" règle l'aspect (par exemple "glass", "ceramic", "chrome"), et "wireframe" ajoute un maillage. "wireframe" vaut true, ou un objet avec ces champs facultatifs : count (le nombre de divisions sur chaque axe, 11 par défaut), width (l'épaisseur des lignes en pixels, 1 par défaut), color (une couleur hexadécimale) et style ("overlay", la valeur par défaut, trace les lignes sur la surface ; "wireframe" ne trace que les lignes ; "lattice" perce des trous dans la surface).
- parametric-curve : "lineWidth" règle l'épaisseur du tube.
- implicit-surface : mettez "predicate": "=0" ; "resolution" (par exemple 64) règle la finesse.
- scatter3d : fn est un point (a, b, c), trois listes (L_x, L_y, L_z) ou une liste de points.
- primitives3d : fn est une liste de valeurs \operatorname{sphere}, \operatorname{segment}, \operatorname{vector} ou \operatorname{triangle}, souvent construite avec \operatorname{for}.
Une série minimale de chaque type, une par ligne :
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))]" }
Données sans formule
Une série peut donner ses valeurs sous forme de données littérales au lieu
d'une formule dans fn. Graph Paper enregistre chacune de ces séries comme
une ligne du document.
| type | Données | Ligne |
|---|---|---|
| scatter | x, y | tableau |
| scatter3d | x, y, z | tableau |
| line | x, y | tableau |
| polar | theta, r | tableau |
| bar | x (étiquettes), y | tableau |
| histogram | values | tableau |
| candlestick | data | tableau |
| boxplot | data, x (étiquettes) | tableau |
| heatmap | x, y, z | ligne de données |
| surface | z | ligne de données |
| polygon-list | polygons, fillColors (facultatif) | ligne de données |
| mesh | vertices, faces, normals (facultatif) | ligne de données |
| primitives3d | items | ligne de données |
Le lecteur peut modifier les nombres d'un tableau. Une ligne de données garde
ses données telles quelles : le lecteur peut changer son style, la
masquer, la copier ou la supprimer, mais pas modifier ses nombres.
Les formes des données :
- line : x et y sont des tableaux de nombres de même longueur. La courbe passe par les points dans l'ordre des tableaux.
- polar : theta et r sont des tableaux de nombres de même longueur. Les angles sont en radians, ou en degrés avec "angleUnit": "degrees" sur la série. L'unité d'angle du document ne les change pas.
- heatmap : x contient les centres des colonnes et y les centres des lignes. z a une ligne pour chaque valeur de y, et chaque ligne a une valeur pour chaque valeur de x : la valeur de la case en y[i], x[j] est z[i][j]. Une valeur null est un trou.
- surface : z est une grille d'au moins 2 lignes et 2 colonnes, avec
le même nombre de valeurs dans chaque ligne.
"domain": { "x": [a, b], "y": [c, d] } la place sur les axes : les
colonnes vont de
a àb et les lignes dec àd . Une valeur null est un trou. - polygon-list : polygons est une liste de { "x": [...], "y": [...] }, chacun avec au moins 2 sommets. "strokeClosed": false sur un polygone trace un chemin ouvert, qui a un contour et pas de remplissage, et "arrowTo": true ajoute une pointe de flèche à son dernier sommet. fillColors donne une couleur de remplissage pour chaque polygone.
- mesh : vertices est une liste de points [x, y, z]. faces est une liste de triangles [i, j, k], chacun un indice dans vertices, à partir de 0. normals, s'il est donné, a un vecteur [x, y, z] pour chaque sommet.
- primitives3d : items est une liste de formes. Chaque forme a un shape, les champs ci-dessous et une color facultative. Un point est [x, y, z] ; un rayon, une épaisseur et une taille sont des nombres supérieurs à 0.
| shape | Champs |
|---|---|
| sphere | center, radius |
| cube | center, size (un nombre, ou [largeur, profondeur, hauteur]) |
| cylinder, cone, tube | from, to, radius |
| line | from, to, width (facultatif) |
| arrow | from, to, et les champs facultatifs radius, headRadius et headLength |
| triangle | vertices : trois points |
Une série de chaque type de ligne de données, une par ligne :
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 }] }
Séries dérivées
Une série derived trace un calcul sur une autre série du document :
une droite de tendance, une moyenne mobile, une courbe lissée, une dérivée
ou une intégrale. source est l'id de cette série, et transform dit ce
qu'il faut calculer. Graph Paper l'enregistre comme une ligne dérivée, qui
suit la source quand le lecteur la modifie.
| transform | Champs | Source |
|---|---|---|
| { "kind": "trendline", "model": "linear" } | model : "linear", "quadratic", "polynomial" (avec degree, de 1 à 10), "exponential", "power" ou "logarithmic" | données |
| { "kind": "sma", "window": 5 } | window : le nombre de points, 1 ou plus | données, points, dérivée |
| { "kind": "ema", "alpha": 0.2 } | alpha : plus de 0, au plus 1 | données, points, dérivée |
| { "kind": "smooth", "tension": 0.5 } | tension (facultatif) : de 0 à 1 | données, points, dérivée |
| { "kind": "derivative" } | — | formule |
| { "kind": "integral" } | — | formule |
Les types de source :
- données : une série scatter, line ou candlestick avec des données littérales ;
- points : une série scatter avec une formule ;
- dérivée : une série derived placée avant celle-ci, qui n'est ni une dérivée ni une intégrale ;
- formule : une série line avec une formule.
source doit nommer l'id d'une seule autre série, et la transformation
doit être une de celles que la source accepte : Graph Paper ne change
pas une transformation pour l'adapter à sa source, donc une incompatibilité
est une erreur. Sur une droite de tendance, "legendEquation": true affiche
l'équation ajustée dans la légende, et "legendShowR2": true ajoute R^2 .
Les champs de style sont color, stroke, legend et legendLabel ;
name est le texte de l'entrée de légende. Sans color, la série prend la
couleur de sa source.
Il n'y a pas de type derived-marker. Pour l'équation d'un ajustement,
utilisez une droite de tendance avec "legendEquation": true.
Marqueurs
Les marqueurs sont des annotations sur le tracé : une étiquette, un
segment avec une flèche, une droite qui traverse le tracé, une bande, un
rectangle, une ellipse. Le tableau markers de premier niveau les contient.
Graph Paper donne son identifiant à chaque marqueur, et le lecteur peut le
déplacer, changer son style et le supprimer, comme un marqueur placé à la
main. Les données vont dans les lignes de séries ; les annotations vont
dans les marqueurs. Un segment entre deux points de données est une série
line, pas un marqueur.
Les coordonnées d'un marqueur sont des nombres, pas des formules : un
marqueur ne bouge pas quand le lecteur change un curseur. Pour un point qui
suit une variable, utilisez une ligne scatter avec une formule de point,
par exemple "fn": "(0, A)". Pour un segment qui suit une variable,
utilisez une ligne scatter dont le fn est une liste des deux points, avec
"line": true et "points": false :
json{ "type": "scatter", "fn": "[(0, 0), (L\\sin(a), -L\\cos(a))]", "line": true, "points": false }
| kind | Champs | Dimension |
|---|---|---|
| point | x, y (et z en 3D) | 2D, 3D |
| label | x, y (et z en 3D), text | 2D, 3D |
| line | x0, y0, x1, y1 (et z0, z1 en 3D) : un segment | 2D, 3D |
| rule | axis ("x" ou "y"), value : une droite qui traverse le tracé | 2D |
| band | axis ("x" ou "y"), from, to | 2D |
| rect | x0, y0, x1, y1 | 2D |
| ellipse | cx, cy, rx, ry (rayons, plus de 0), angle (facultatif, en degrés) | 2D |
| plane-band | axis ("x", "y" ou "z"), from, to | 3D |
Une droite avec "axis": "x" est une droite verticale en x = value. Une
bande avec "axis": "x" couvre les valeurs de x de from à to. Les
bornes d'une bande et d'un rectangle sont triées. Un marqueur d'un document 3D
donne ses coordonnées z ; un marqueur d'un document 2D n'en donne
aucune.
style (facultatif) règle l'aspect :
| kind | Champs de style |
|---|---|
| point | symbol ("circle", "square", "diamond", "cross", "plus", "triangle"), size (pixels), fill, stroke (color, width) |
| label | color, fontSizeOffset (de −3 à 3), background |
| line | stroke, arrowFrom, arrowTo (booléens : une pointe de flèche au début ou à la fin) |
| rule | stroke |
| band, rect, ellipse, plane-band | fill, stroke (présent, même {} : un contour) |
Un stroke est { "color", "width", "dash" }, tous facultatifs :
width en pixels, dash une liste de longueurs comme [4, 4]. Une couleur
est une couleur hexadécimale ("#1e88e5", ou "#1e88e533" avec de la
transparence) ou "transparent".
Le text d'une étiquette a au plus 500 caractères. C'est du texte brut, avec
du Markdown en ligne (**gras**, *italique*) et des maths en ligne entre
$…$ ; un texte qui est un seul $…$ est une formule.
Règles :
- Un document contient au plus 100 marqueurs.
- Les marqueurs special-value (une racine, un extremum, une intersection que Graph Paper trouve) ne peuvent pas être donnés : marquez l'endroit avec un point ou un label.
- stage.markers et stage3d.markers sont ignorés, avec un avertissement : écrivez les marqueurs dans le tableau markers de premier niveau.
- Un document a toujours besoin d'au moins une série.
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 et scène
Ces champs sont tous facultatifs. S'ils sont absents, Graph Paper ajuste la vue
aux séries.
domain (2D) :
| Champ | Signification |
|---|---|
| x.range, y.range | L'intervalle visible d'un axe : { "x": { "range": [-5, 5] } }. Un axe n'a pas de champs min et max. |
| x.scale, y.scale | "linear", "log", "symlog" ou "asinh". |
| aspect | "equal" pour la même échelle sur les deux axes, "auto", ou un nombre. |
| coordinateSystem | "cartesian" ou "polar". |
Graph Paper garde l'intervalle de x et en déduit celui de y : l'étendue
visible de y vaut l'étendue de x × aspect × (hauteur du tracé ÷ largeur du
tracé), et y.range n'est que le minimum affiché, donc une fenêtre haute
montre une plus grande partie de l'axe y. Pour montrer une plus petite partie
de l'axe y, donnez à aspect un nombre plus petit, de 0,2 à 5 ("auto" vaut
environ 0,618 pour une courbe et 1 pour un tracé implicite ou une carte de
chaleur, "equal" vaut 1) ; avec un nombre, si y.range ne tient pas,
c'est l'intervalle de x qui s'élargit.
stage (2D) : gridStyle vaut true, false, "lines", "dots" ou
"isometric" ; frame vaut true ou false.
domain3d (3D) : x.range, y.range, z.range comme en 2D, et
aspectMode, qui fixe la forme du cadre. "auto" (la valeur par défaut) et
"cube" mettent chaque axe à l'échelle pour que le cadre soit un cube.
"data" trace les trois axes à la même échelle, donc le cadre a les
proportions des intervalles des axes (ou des séries, si aucun intervalle n'est
donné).
stage3d (3D) : environment vaut "abstract", "outdoor" ou
"paper" ; projection vaut "perspective" ou "orthographic" ;
axes vaut true ou false ; camera vaut
{ "position": [x, y, z], "target": [x, y, z], "up": [0, 0, 1] }.
Les types de tracés acceptent plus de champs que cette page n'en décrit. Les
champs ci-dessus sont ceux dont un document a le plus souvent besoin.
Modèles
Chaque modèle ci-dessous est un document complet et court. Partez de celui qui
est le plus proche de ce que vous voulez. Les textes des exemples sont en
anglais ; les liens sont les mêmes que sur la page anglaise.
Un point qui se déplace sur une courbe
Une ligne scatter avec une formule de point du curseur a trace un point sur
la courbe, et le point bouge quand le lecteur fait glisser le curseur.
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 } }
]
}
Un segment qui suit une variable
Une ligne scatter dont le fn est une liste de deux points, avec
"line": true et "points": false, trace un segment, et ses extrémités
peuvent être des formules.
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] } }
}
Une fonction auxiliaire
Une définition avec des arguments, comme E_1(s) = …, est une fonction
qu'une série peut appeler. E_1 et E_{1} sont le même nom. Une définition
de fonction trace aussi sa courbe : "hidden": true la cache ici.
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] }]
}
Une famille de courbes à partir d'une liste
Une liste dans une définition, comme k = [1, 2, 3], donne une courbe pour
chacune de ses valeurs.
json{
"title": "A family of sine curves",
"definitions": ["k = [1, 2, 3]"],
"series": [{ "type": "line", "fn": "\\sin(kx)", "domain": [0, 6.28] }]
}
Une somme dont le nombre de termes vient d'un curseur
\sum_{k=0}^{n-1} additionne n termes, et n peut être un curseur. Un
curseur qui compte des termes a besoin de "step": "1". Ici, la somme est la
série de Fourier d'un signal carré, et la ligne en tirets est le signal carré.
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] } }
}
Une simulation
Une action avec un interval et "autoplay": true change une variable avec
une minuterie ; ici, le point fait le tour du cercle. Le
pendule est un exemple plus long.
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] } }
}
Des données annotées
Une ligne line avec des données x et y trace les mesures, un marqueur
label nomme un point, et un marqueur band colore un intervalle de 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" } }
]
}
Exemples complets
Les textes de ces exemples sont en anglais ; les liens sont les mêmes que
sur la page anglaise.
Une courbe avec un curseur
Une oscillation amortie. La variable c est un curseur au repos, avec une note.
La définition f est masquée, pour qu'elle ne trace pas une seconde courbe. La
courbe en pointillés est l'enveloppe.
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] } }
}
Une région implicite
Un disque que le lecteur déplace, sur la région située au-dessus d'une parabole.
Le point (c_x, c_y) est le centre du disque.
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" }
}
Des mesures avec une droite de tendance
Six mesures, sous forme de données, et un ajustement linéaire avec son
équation dans la légende. La série scatter a un id, et la série dérivée le
nomme dans 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 }
]
}
Un champ mesuré
Une carte de chaleur de valeurs mesurées : 3 lignes (y = 0, 1, 2 ) de
4 valeurs (x = 0, 1, 2, 3 ). La valeur null est une case sans mesure,
tracée comme un trou.
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"
}
]
}
Une surface paramétrique 3D
Un tore.
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" trace les trois axes à la même échelle, donc le tore
garde sa forme. Sans ce champ, le cadre est un cube, et le tore, haut de 2
unités et large de 6, est étiré en tonneau.
Une simulation avec une minuterie
Graph Paper n'a pas de ligne qui résout une équation différentielle. Un
document peut tout de même simuler un mouvement : une action fait avancer
l'état sur une minuterie.
- Gardez l'état dans des variables, ou dans une définition de liste comme S = [2.5, 0].
- Écrivez une action qui donne l'état suivant à partir de l'état actuel. L'action calcule toutes les nouvelles valeurs à partir des anciennes, puis les écrit ensemble. Quand une nouvelle valeur a besoin d'une autre nouvelle valeur, écrivez celle-ci en entier.
- Donnez à l'action un interval en millisecondes, et "autoplay": true pour démarrer la minuterie à l'ouverture du document.
- Ajoutez une seconde action sans interval qui remet les valeurs de départ. Le lecteur l'exécute avec son bouton ⚡.
- Tracez l'état avec des lignes qui le lisent, comme un point scatter.
Les limites :
- Le pas de temps est fixe. Vous le choisissez, par exemple avec une définition h = 0.02. Donnez à interval la valeur du pas en millisecondes, et le mouvement se joue à peu près en temps réel. Quand le navigateur est occupé, le mouvement ralentit : une exécution manquée n'est pas rattrapée.
- Le schéma d'intégration est la formule que vous écrivez. Un pas d'Euler
simple (
a \to a + hw ,w \to w - h\frac{g}{L}\sin(a) , tous deux à partir des anciennes valeurs) ajoute de l'énergie à chaque pas, et un pendule monte alors de plus en plus haut. Le pas d'Euler semi-implicite ci-dessous calcule d'abord le nouveauw , puis le nouveaua à partir de lui, et l'oscillation garde sa hauteur. Pour plus de précision, les entrées de la Vitrine Projectile avec résistance de l'air et Proies et prédateurs écrivent un pas de Runge–Kutta d'ordre quatre sous forme d'une chaîne de définitions. - Une action peut écrire une valeur hors de l'intervalle de son curseur. La valeur est conservée, et le bouton du curseur reste au bout du rail.
- Pendant que la minuterie tourne, l'annulation n'est pas disponible.
Exemple : un pendule
Un pendule à grandes oscillations. L'équation du mouvement est
a'' = -\frac{g}{L}\sin(a) , où a est l'angle avec la verticale. L'état
est l'angle a , la vitesse angulaire w et le temps T . La minuterie
s'exécute toutes les 20 ms, et chaque exécution est un pas de
h = 0.02 s :
La seconde action remet le pendule à l'angle de départ A , au repos. Le point
rouge est la masse, le segment sombre est la tige (une ligne scatter de deux
points reliés par une ligne), et le marqueur de point sombre est le pivot. Les
curseurs ne bougent pas seuls : seule la minuterie change a , w et
T . Le point gris suit la
formule des petits angles a = A\cos(\sqrt{g/L}\,T) , pour comparaison. Une
grande oscillation dure plus longtemps que ne le prévoit la formule : avec
un angle de départ de 2,5 radians, le point gris prend tout de suite de
l'avance sur la masse.
Les textes de cet exemple sont en anglais ; le lien est le même que sur la
page anglaise.
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] } }
}
Vérifier un document
Un programme peut vérifier un document sans navigateur et sans compte :
- Envoyez-le avec POST https://graph-paper.io/plot-link, comme corps JSON. Un programme qui peut seulement lire une URL peut utiliser GET https://graph-paper.io/plot-link?doc=<JSON encodé en pourcentage> (une espace s'écrit %20 et un signe plus %2B). Un GET répond toujours avec le statut 200 ; le champ status de la réponse est le statut qu'un POST obtiendrait.
- Ou appelez l'outil make_plot_link du serveur MCP https://graph-paper.io/mcp.
La réponse est le lien qui ouvre le document, ou chaque erreur avec le chemin
de son champ, comme series[0].fn. Les avertissements nomment les clés
ignorées. La page Pour les agents montre les requêtes et les
réponses.
La vérification porte sur les champs, leurs types et les limites de cette
page. Elle ne trace pas le tracé. Une formule en LaTeX valide peut quand même
ne rien tracer. Dites à la personne que vous n'avez pas vu le tracé, et
préférez les formes de lignes que cette page montre.
Le service de liens vérifie seulement la structure. Graph Paper vérifie les
formules à l'ouverture du lien, et signale les lignes qui ne fonctionnent
pas : voir
Quand la personne ouvre le lien
sur la page Pour les agents.
Apprendre avec la Vitrine
Chaque page de la Vitrine contient son document sous la même
forme, dans une balise
<script type="application/graph-paper+json" id="gallery-entry">. Quand le
document est grand, la balise ne contient que { "id": … } et un attribut
data-payload-href qui donne l'URL du JSON complet.
Une entrée de la Vitrine n'est pas un document à envoyer tel quel. Elle a un
id et pas de title, et ses valeurs note sont les noms de textes traduits,
pas les textes. Pour en réutiliser une, retirez id, ajoutez un title, et
remplacez ou retirez chaque note.
Les carnets
Graph Paper a aussi des carnets : des sections de texte, de formules, de
calculs et de figures. C'est un autre format, et un lien /new ne peut pas les
ouvrir. Leur référence est le
format de fichier des carnets (en anglais),
avec des schémas JSON pour le fichier d'export
et le contenu du carnet.