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 (en anglais) : 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.
Deux schémas JSON (draft-07) décrivent le document de tracé. Utilisez
https://graph-paper.io/docs/schema/plot-document.schema.json pour vérifier ce
que le service accepte : comme le validateur, il accepte une clé inconnue,
que le validateur ignore avec un avertissement. Utilisez
https://graph-paper.io/docs/schema/plot-document.strict.schema.json pour
trouver un nom de champ mal écrit ou inconnu avant d'envoyer le document :
il refuse chaque clé qui reçoit un avertissement du validateur, et le service
lui-même donne seulement un avertissement. Les deux listent chaque champ, et
vérifient les types, les valeurs permises, les clés que chaque type de série
exige et les limites, comme le validateur. Ils ne peuvent pas vérifier le LaTeX
d'une formule, la taille du document, ni une règle qui compare deux valeurs ou
deux lignes : le service de liens peut donc encore refuser un document
qu'un schéma accepte.
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
- Prélude
- 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 (sauf dans une ligne scatter ou scatter3d, dont les tableaux peuvent être vides : la ligne n'a alors aucun point), 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. |
| prelude | chaîne | non | Un programme en Epsil dont les autres lignes utilisent les fonctions et les valeurs. Voir Prélude. |
| 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,
prélude, 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. |
| control | chaîne | non | "dial" affiche un cadran (une valeur qui boucle, un angle), "toggle" un interrupteur (une valeur sur deux). En son absence : un curseur. |
| 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"] }.
Un "toggle" demande un domaine de deux valeurs : une liste de deux
valeurs, ou un intervalle dont le pas step est l'étendue
({ "type": "range", "min": "0", "max": "1", "step": "1" }). Sur un autre
domaine, la variable affiche un curseur ; le document n'est pas refusé.
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.
Prélude
prelude est le texte d'un programme en Epsil, le langage de programmation du
Compute Engine (https://cortexjs.io). Les autres lignes utilisent ses fonctions
et ses valeurs par leur nom. Utilisez-le pour un calcul qui demande une boucle,
des variables locales ou plusieurs étapes. Graph Paper affiche le programme dans
une cellule de prélude, après les variables et les points. Il vérifie et exécute
le programme à l'ouverture du document, et de nouveau quand le lecteur le
modifie ; la cellule affiche les erreurs et les avertissements du programme.
Ce document trace la somme des n premières harmoniques impaires d'un signal
carré. La fonction W contient une boucle, et le curseur n est son deuxième
paramètre :
json{
"title": "Signal carré par harmoniques impaires",
"prelude": "// La somme des n premières harmoniques impaires d'un signal carré.\nfunction W(x: real, n: integer) -> real {\n let s = 0.0\n for k in 1..n {\n s = s + sin((2*k - 1)*x) / (2*k - 1)\n }\n 4 / pi * s\n}\n",
"variables": [
{
"name": "n",
"value": "5",
"domain": { "type": "range", "min": "1", "max": "40", "step": "1" }
}
],
"series": [{ "type": "line", "fn": "W(x, n)" }]
}
Le programme de la chaîne, avec ses retours à la ligne :
// La somme des n premières harmoniques impaires d'un signal carré.
function W(x: real, n: integer) -> real {
let s = 0.0
for k in 1..n {
s = s + sin((2*k - 1)*x) / (2*k - 1)
}
4 / pi * s
}
- Au premier niveau, function f(…) { … }, let a = … ou const a = … définit un nom que les lignes peuvent utiliser. Un nom déclaré dans une fonction ou une boucle est local au programme.
- Une formule écrit le nom comme LaTeX l'écrit. Le nom Epsil H_0 s'écrit H_0 dans une formule, et un nom de plusieurs lettres, comme step, s'écrit \\operatorname{step} dans le JSON de fn.
- Le programme ne peut pas utiliser un nom du document : une variable, un point ou une définition. Une fonction qui a besoin de la valeur d'un curseur la reçoit en paramètre, comme W reçoit n. Le programme s'exécute une fois, et pas de nouveau à chaque mouvement d'un curseur.
- Le programme ne peut pas utiliser de nombres aléatoires : chaque lecteur obtiendrait d'autres valeurs.
- Certains noms sont refusés : une valeur nommée x, y, z, t, u, v, r, theta ou phi, une fonction nommée x ou y, dt, et un nom qu'une formule lit comme une fonction ou une constante de la bibliothèque (max, sin, e, pi, total).
- Un nom que le prélude et une définition définissent tous les deux est une erreur sur les deux lignes.
- Une action ne peut pas changer une valeur du prélude. Pour faire évoluer une liste que le prélude calcule, ajoutez une définition qui part d'elle, comme H = H_0, et laissez l'action changer H.
- Le programme doit se terminer en 30 secondes. Il s'exécute dans un worker, le document reste donc réactif pendant ce temps, et un programme qui calcule toute une image dans une boucle convient : le Buddhabrot de la galerie calcule 1,2 million d'échantillons en une demi-seconde environ. Les outils d'agent qui calculent sur un document exécutent le programme sur un interpréteur au budget réduit : pour un document avec une telle boucle, ces outils n'ont pas de valeur pour les lignes qui lisent son résultat.
- Un document a un seul prélude. Le validateur vérifie seulement que prelude est une chaîne ; Graph Paper vérifie le programme à l'ouverture du document, et un document dont le programme a une erreur s'ouvre avec l'erreur affichée dans la cellule de prélude. Le prélude compte dans les 65 536 octets du document.
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 :
- line : "independentAxis": "y" trace
x = f(y) à la place : fn est une formule dey et domain est le [min, max] dey , par exemple { "type": "line", "fn": "y^2", "independentAxis": "y" }. Une telle courbe n'a pas de remplissage. - parametric, polar, line : "arrowTo": true trace une pointe de flèche à la fin de la courbe, et "arrowFrom": true une pointe à son début. Un style de pointe ("sharp", "thin", "wings", "chevron", "triangle", "diamond", "bar" ou "disc") à la place de true choisit sa forme. Une série line avec fn ne les trace qu'aux bornes de son domain, et seulement quand cette borne est visible.
- 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". Les classes ont la même largeur, de la plus petite valeur à la plus grande ; "binEdges", une liste triée de nombres, fixe les bornes à la place. La hauteur d'une barre est l'effectif, ou avec "normalize" : "density" (l'intégrale des barres vaut 1, pour une courbe de densité par-dessus) ou "probability" (la somme des barres vaut 1).
- 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] } |
| spherical-surface | une surface | fn | { "theta": [a, b], "phi": [c, d] } |
| cylindrical-surface | fn, form | { "r": [a, b], "theta": [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). Avec "lattice", cellFraction (de 0 à 1) donne la largeur des nervures en part d'une maille, à la place de width ; 1 ne laisse aucun trou. latticeGrid choisit la grille que suivent les nervures : "uv", la valeur par défaut, la grille propre de la surface, celle des lignes ; "xy", des plans de x et de y constants, et une parametric-surface, une spherical-surface ou une cylindrical-surface ne trace alors aucune ligne. Sur une surface, les deux sont identiques.
- spherical-surface : fn est
\rho , la distance à l'origine, en fonction de\theta (\theta, l'angle depuis l'axe des x positifs dans le plan xy) et de\phi (\phi, l'angle depuis l'axe des z positifs). Le domain par défaut est\theta dans[0, 2\pi] et\phi dans[0, \pi] , en radians. Un\rho négatif est tracé de l'autre côté de l'origine. "material" et "wireframe" s'emploient comme pour surface. fn n'est que le corps, sans \rho = ; Graph Paper affiche la ligne sous la forme\rho = \ldots , avec fn après le signe égal. - cylindrical-surface :
r est la distance à l'axe des z et\theta (\theta) l'angle depuis l'axe des x positifs dans le plan xy. Avec "form": "z", fn est la hauteurz en fonction der et de\theta , tracée pourr dans[0, 5] et\theta dans[0, 2\pi] , sauf si domain donne "r" ou "theta". Avec "form": "r", fn est le rayonr en fonction de\theta et dez , tracé pour\theta dans[0, 2\pi] et l'intervalle des z du graphique ; unr négatif est tracé de l'autre côté de l'axe des z. fn n'est que le corps ; Graph Paper affiche la ligne sous la formez = \ldots our = \ldots . Avec "form": "r" et une formule qui n'emploie pasz ("fn": "2", un cylindre), la ligne est écrite avec une restriction surz à domain.z, ou à l'intervalle des z du graphique quand domain n'a pas de "z" : une ligner = 2 seule est le cercle dans le planz = 0 . - 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": "spherical-surface", "fn": "2 + \\sin(4\\phi)^3\\cos(3\\theta)" }
{ "type": "cylindrical-surface", "form": "z", "fn": "\\sin(r\\theta)" }
{ "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. Le champ facultatif lineWidth de la série donne la taille des flèches qui n'ont pas de radius : leur tige est aussi épaisse qu'une courbe 3D de même lineWidth.
| 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. Une
droite, une bande, un segment ou une forme n'a pas de texte : pour en
nommer un, ajoutez un marqueur label à côté, en un point de la zone tracée
(pour un histogramme, y entre 0 et le plus grand effectif).
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, pas aux marqueurs : un marqueur hors de l'étendue des séries
n'est pas visible tant que la personne ne dézoome pas. Donnez x.range ou
y.range quand un marqueur doit être dans la première vue.
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.
background est la couleur du graphique, par exemple "#1d2433" ; en son
absence, le graphique a l'arrière-plan du thème. La couleur décide si le
graphique utilise ses couleurs de premier plan claires ou foncées (axes, grille,
texte) : le graphique est le même dans les thèmes clair et sombre de
l'application, et à l'impression. Donnez une couleur opaque. Une couleur que le
graphique ne sait pas lire est ignorée. vignette assombrit le graphique vers
ses bords, de 0 (aucun assombrissement, la valeur par défaut) à 1. autoplay
vaut false quand les transitions (transitions) ne doivent pas être jouées à
l'ouverture du document : le graphique montre alors leur état final. En son
absence, elles sont jouées une fois à l'ouverture du document.
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] } ; orbit
fait tourner la caméra autour de sa cible dès l'ouverture du document, pour
chaque lecteur : true à 0,2 radian par seconde, ou { "speed": r } à r
radians par seconde. Un r positif fait tourner la caméra dans le sens
antihoraire vue d'en haut, donc la scène dans le sens horaire ; un r
négatif les fait tourner dans l'autre sens. Un clic, un glissement ou la
réinitialisation de la vue l'arrête jusqu'à la prochaine ouverture du document.
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. La section
Une simulation avec une minuterie a un
exemple plus long, un pendule.
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$."
}
],
"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 calcule d'abord le nouveauw , puis le nouveaua à partir de lui :w \to w - h\frac{g}{L}\sin(a) , puisa \to a + hw avec le nouveauw . L'oscillation garde alors 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 (en anglais) 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
When the Person Opens the Link
sur la page Pour les agents (en anglais).
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.