# Format des documents de tracé

Un document de tracé est un objet JSON qui décrit un tracé de Graph Paper&nbsp;:
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](/for-agents/fr/)&nbsp;: 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&nbsp;; la réponse contient le
lien, ou les erreurs. Pour ce qu'il faut écrire dans une formule, voir le
[Guide des tracés](/plotting-guide/fr/).

**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&nbsp;: 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&nbsp;: 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](/for-agents/fr/), du Guide des tracés et des Astuces et
conseils.

## Sommaire

- [Un document minimal](#un-document-minimal)
- [Règles et limites](#rgles-et-limites)
- [Champs de premier niveau](#champs-de-premier-niveau)
- [Variables](#variables)
- [Points](#points)
- [Un point qui bouge](#un-point-qui-bouge)
- [Définitions](#dfinitions)
- [Actions](#actions)
- [Séries](#sries)
- [Types de séries 2D](#types-de-sries-2d)
- [Types de séries 3D](#types-de-sries-3d)
- [Données sans formule](#donnes-sans-formule)
- [Séries dérivées](#sries-drives)
- [Marqueurs](#marqueurs)
- [Un segment entre deux points](#un-segment-entre-deux-points)
- [Axes et scène](#axes-et-scne)
- [Modèles](#modles)
- [Exemples complets](#exemples-complets)
- [Une simulation avec une minuterie](#une-simulation-avec-une-minuterie)
- [Vérifier un document](#vrifier-un-document)
- [Apprendre avec la Vitrine](#apprendre-avec-la-vitrine)
- [Les carnets](#les-carnets)

## Un document minimal

Un titre et une série&nbsp;:

```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](#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](#vrifier-un-document).

## Règles et limites

- Le document fait au plus 65&nbsp;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&nbsp;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](#vrifier-un-document) 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&nbsp;: `{ "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`&nbsp;: 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&nbsp;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&nbsp;: 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](#donnes-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&nbsp;: `"\\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é&nbsp;: `"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](#sries).                                                          |
| `variables`   | tableau | non        | Les curseurs. Voir [Variables](#variables).                                                                       |
| `points`      | tableau | non        | Les points que le lecteur déplace sur le tracé. Voir [Points](#points).                                           |
| `definitions` | tableau | non        | Les valeurs et fonctions nommées que les autres lignes utilisent. Voir [Définitions](#dfinitions).                |
| `actions`     | tableau | non        | Les lignes qui changent des variables, une fois ou à intervalle régulier. Voir [Actions](#actions).               |
| `markers`     | tableau | non        | Les annotations sur le tracé&nbsp;: étiquettes, segments, droites, bandes. Voir [Marqueurs](#marqueurs).          |
| `domain`      | objet  | non         | Intervalles des axes 2D, rapport d'aspect et système de coordonnées. Voir [Axes et scène](#axes-et-scne).         |
| `stage`       | objet  | non         | Apparence 2D&nbsp;: grille, axes, cadre.                                                                          |
| `domain3d`    | objet  | non         | Intervalles des axes 3D et proportions.                                                                           |
| `stage3d`     | objet  | non         | Scène 3D&nbsp;: environnement, éclairage, caméra, projection.                                                     |
| `preset`      | objet  | non         | L'apparence du document&nbsp;: `{ "base": "basel" }`. Bases&nbsp;: `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&nbsp;: 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&nbsp;:

| Champ      | Type    | Obligatoire | Signification                                                                                 |
| ---------- | ------- | ----------- | --------------------------------------------------------------------------------------------- |
| `name`     | chaîne  | oui         | Le nom, tel que les formules l'utilisent&nbsp;: `"a"`, `"c_1"`, `"omega"` ou `"\\omega"`&nbsp;; voir les règles de nommage ci-dessous.  |
| `value`    | chaîne  | oui         | La valeur de départ, en LaTeX&nbsp;: `"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&nbsp;: `{ "mode": "bounce", "direction": "forward", "duration": 5000 }`. En son absence&nbsp;: `"bounce"`, `"forward"`, 4000&nbsp;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&nbsp;:

- Un intervalle&nbsp;: `{ "type": "range", "min": "0", "max": "2\\pi" }`, avec
  un pas `"step"` facultatif (en LaTeX).
- Une liste de valeurs&nbsp;: `{ "type": "values", "values": ["1", "3", "5"] }`.

`playback.mode` vaut `"once"`, `"loop"`, `"bounce"` ou `"all-at-once"`.
`"all-at-once"` n'anime pas&nbsp;: 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&nbsp;: ces noms sont les
axes du tracé. N'utilisez pas non plus `e`, `i` ni `pi`&nbsp;: 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&nbsp;: à 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}"`)&nbsp;; 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&nbsp;: 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&nbsp;: 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&nbsp;: 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&nbsp;: 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&nbsp;:

| Champ  | Type   | Obligatoire | Signification                                                                                          |
| ------ | ------ | ----------- | ------------------------------------------------------------------------------------------------------ |
| `x`    | objet  | oui         | La première coordonnée&nbsp;: `{ "name": "c_x", "value": "0.5" }`.                                     |
| `y`    | objet  | oui         | La seconde coordonnée&nbsp;: `{ "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&nbsp;:

```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](#une-simulation-avec-une-minuterie) utilise cette ligne pour sa
masse.

Un point de `points` est différent. C'est une entrée&nbsp;: le lecteur le
déplace, et le déplacement fixe deux variables que d'autres lignes lisent. Un
point `scatter` est un résultat&nbsp;: 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&nbsp;:

| Champ    | Type    | Obligatoire | Signification                                            |
| -------- | ------- | ----------- | -------------------------------------------------------- |
| `latex`  | chaîne  | oui         | La définition&nbsp;: `"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&nbsp;: 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&nbsp;: `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&nbsp;: 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&nbsp;:

| Champ      | Type    | Obligatoire | Signification                                                                                      |
| ---------- | ------- | ----------- | -------------------------------------------------------------------------------------------------- |
| `latex`    | chaîne  | oui         | L'action&nbsp;: `"a \\to a + 1"`. Voir [Astuces et conseils](/tips-and-tricks/fr/#changer-des-valeurs-avec-des-actions). |
| `interval` | chaîne  | non         | Exécuter l'action à nouveau toutes les N millisecondes (en LaTeX&nbsp;: `"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](#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`&nbsp;: voir le
[Guide des tracés](/plotting-guide/fr/#comment-graph-paper-lit-une-ligne) 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&nbsp;: 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&nbsp;:

| 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&nbsp;:

- 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](#sries-drives).

Chaque série du document est enregistrée comme une ligne.

## Types de séries 2D

| `type`           | Trace                                                     | Obligatoire              | `domain`                         |
| ---------------- | --------------------------------------------------------- | ------------------------ | -------------------------------- |
| `line`           | $y = f(x)$                                                | `fn`, ou `x` et `y`      | `[min, max]` de $x$              |
| `parametric`     | une courbe $(x(t), y(t))$                                 | `fn`                     | `[min, max]` de $t$              |
| `polar`          | $r = f(\theta)$                                           | `fn`, ou `theta` et `r`  | `[min, max]` de $\theta$         |
| `implicit`       | une courbe $F(x, y) = 0$, ou une région d'après une inéquation | `fn`                | `{ "x": [a, b], "y": [c, d] }`   |
| `heatmap`        | une couleur pour chaque point de $f(x, y)$                | `fn`, ou `x`, `y` et `z` | `{ "x": [a, b], "y": [c, d] }`   |
| `domainColoring` | une fonction complexe de $z$                              | `fn`                     | `{ "x": [a, b], "y": [c, d] }`   |
| `vector-field`   | des flèches $(P(x, y), Q(x, y))$                          | `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 $x$           | `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&nbsp;:

- `implicit`&nbsp;: 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`&nbsp;: `"zRange": [min, max]` fixe l'échelle des couleurs, et
  `"contours": true` ajoute des lignes de niveau.
- `polar`&nbsp;: mettez `"domain": { "coordinateSystem": "polar" }` au premier
  niveau pour afficher des axes polaires.
- `scatter`&nbsp;: `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`&nbsp;: `fn` est une liste de valeurs
  `\operatorname{polygon}(…)`, et chaque polygone prend ses sommets sous forme
  de points&nbsp;: `[\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&nbsp;: voir
  [Données sans formule](#donnes-sans-formule).
- `bar`&nbsp;: `"orientation": "horizontal"` couche les barres.
- `histogram`&nbsp;: `"bins"` est un nombre ou `"sturges"`, `"fd"` ou
  `"scott"`.
- `boxplot`&nbsp;: chaque élément de `data` est
  `{ "min", "q1", "median", "q3", "max" }`&nbsp;; `x` donne les étiquettes.

Une série minimale de chaque type, une par ligne&nbsp;:

```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&nbsp;: 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&nbsp;:

```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](#une-simulation-avec-une-minuterie) va de $(0, 0)$ à la masse, qui
suit l'angle $a$&nbsp;:

```json
{ "type": "scatter", "fn": "[(0, 0), (L\\sin(a), -L\\cos(a))]", "line": true, "points": false }
```

N'utilisez pas `polygon-list` pour un segment&nbsp;: ses polygones sont
remplis.

## Types de séries 3D

| `type`               | Trace                                                    | Obligatoire                  | `domain`                                     |
| -------------------- | -------------------------------------------------------- | ---------------------------- | -------------------------------------------- |
| `surface`            | $z = f(x, y)$                                            | `fn`, ou `z`                 | `{ "x": [a, b], "y": [c, d] }`               |
| `parametric-surface` | une surface $(x(u, v), y(u, v), z(u, v))$                | `fn`                         | `{ "u": [a, b], "v": [c, d] }`               |
| `parametric-curve`   | une courbe $(x(t), y(t), z(t))$                          | `fn`                         | `[min, max]` de $t$                          |
| `implicit-surface`   | une surface $F(x, y, z) = 0$                             | `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&nbsp;:

- `surface`, `parametric-surface`&nbsp;: `"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&nbsp;: `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&nbsp;; `"wireframe"` ne
  trace que les lignes&nbsp;; `"lattice"` perce des trous dans la surface).
- `parametric-curve`&nbsp;: `"lineWidth"` règle l'épaisseur du tube.
- `implicit-surface`&nbsp;: mettez `"predicate": "=0"`&nbsp;; `"resolution"`
  (par exemple `64`) règle la finesse.
- `scatter3d`&nbsp;: `fn` est un point `(a, b, c)`, trois listes
  `(L_x, L_y, L_z)` ou une liste de points.
- `primitives3d`&nbsp;: `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&nbsp;:

```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&nbsp;: le lecteur peut changer son style, la
masquer, la copier ou la supprimer, mais pas modifier ses nombres.

Les formes des données&nbsp;:

- `line`&nbsp;: `x` et `y` sont des tableaux de nombres de même longueur. La
  courbe passe par les points dans l'ordre des tableaux.
- `polar`&nbsp;: `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`&nbsp;: `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`&nbsp;: la valeur de la case en `y[i]`,
  `x[j]` est `z[i][j]`. Une valeur `null` est un trou.
- `surface`&nbsp;: `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&nbsp;: les
  colonnes vont de $a$ à $b$ et les lignes de $c$ à $d$. Une valeur `null`
  est un trou.
- `polygon-list`&nbsp;: `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`&nbsp;: `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`&nbsp;: `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]`&nbsp;; 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`&nbsp;: trois points                                  |

Une série de chaque type de ligne de données, une par ligne&nbsp;:

```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&nbsp;:
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`&nbsp;: `"linear"`, `"quadratic"`, `"polynomial"` (avec `degree`, de 1 à 10), `"exponential"`, `"power"` ou `"logarithmic"` | données                   |
| `{ "kind": "sma", "window": 5 }`                | `window`&nbsp;: le nombre de points, 1 ou plus                                                            | données, points, dérivée  |
| `{ "kind": "ema", "alpha": 0.2 }`               | `alpha`&nbsp;: plus de 0, au plus 1                                                                        | données, points, dérivée  |
| `{ "kind": "smooth", "tension": 0.5 }`          | `tension` (facultatif)&nbsp;: de 0 à 1                                                                     | données, points, dérivée  |
| `{ "kind": "derivative" }`                      | —                                                                                                          | formule                   |
| `{ "kind": "integral" }`                        | —                                                                                                          | formule                   |

Les types de source&nbsp;:

- données&nbsp;: une série `scatter`, `line` ou `candlestick` avec des
  données littérales&nbsp;;
- points&nbsp;: une série `scatter` avec une formule&nbsp;;
- dérivée&nbsp;: une série `derived` placée avant celle-ci, qui n'est ni une
  dérivée ni une intégrale&nbsp;;
- formule&nbsp;: 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&nbsp;: 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`&nbsp;;
`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é&nbsp;: 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&nbsp;; 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&nbsp;: 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`&nbsp;:

```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)&nbsp;: un segment | 2D, 3D    |
| `rule`       | `axis` (`"x"` ou `"y"`), `value`&nbsp;: 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`&nbsp;; un marqueur d'un document 2D n'en donne
aucune.

`style` (facultatif) règle l'aspect&nbsp;:

| `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&nbsp;: une pointe de flèche au début ou à la fin) |
| `rule`                                   | `stroke`                                                                       |
| `band`, `rect`, `ellipse`, `plane-band`  | `fill`, `stroke` (présent, même `{}`&nbsp;: un contour)                        |

Un `stroke` est `{ "color", "width", "dash" }`, tous facultatifs&nbsp;:
`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
`$…$`&nbsp;; un texte qui est un seul `$…$` est une formule.

Règles&nbsp;:

- 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&nbsp;: marquez l'endroit
  avec un `point` ou un `label`.
- `stage.markers` et `stage3d.markers` sont ignorés, avec un
  avertissement&nbsp;: é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" } }
  ]
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkFubm90YXRlZCBwYXJhYm9sYSIsInNlcmllcyI6W3sidHlwZSI6ImxpbmUiLCJmbiI6InheMiIsImRvbWFpbiI6Wy0yLDJdfV0sIm1hcmtlcnMiOlt7ImtpbmQiOiJsYWJlbCIsIngiOjAsInkiOjAuNCwidGV4dCI6IlZlcnRleCJ9LHsia2luZCI6ImxpbmUiLCJ4MCI6MSwieTAiOjMsIngxIjoxLjQsInkxIjoyLjEsInN0eWxlIjp7ImFycm93VG8iOnRydWUsInN0cm9rZSI6eyJ3aWR0aCI6Mn19fSx7ImtpbmQiOiJydWxlIiwiYXhpcyI6IngiLCJ2YWx1ZSI6MS41fSx7ImtpbmQiOiJiYW5kIiwiYXhpcyI6InkiLCJmcm9tIjoxLCJ0byI6Miwic3R5bGUiOnsiZmlsbCI6IiMxZTg4ZTUzMyJ9fV19)

## Axes et scène

Ces champs sont tous facultatifs. S'ils sont absents, Graph Paper ajuste la vue
aux séries.

`domain` (2D)&nbsp;:

| Champ                | Signification                                                                    |
| -------------------- | -------------------------------------------------------------------------------- |
| `x.range`, `y.range` | L'intervalle visible d'un axe&nbsp;: `{ "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&nbsp;: 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)&nbsp;; avec un nombre, si `y.range` ne tient pas,
c'est l'intervalle de x qui s'élargit.

`stage` (2D)&nbsp;: `gridStyle` vaut `true`, `false`, `"lines"`, `"dots"` ou
`"isometric"`&nbsp;; `frame` vaut `true` ou `false`.

`domain3d` (3D)&nbsp;: `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)&nbsp;: `environment` vaut `"abstract"`, `"outdoor"` ou
`"paper"`&nbsp;; `projection` vaut `"perspective"` ou `"orthographic"`&nbsp;;
`axes` vaut `true` ou `false`&nbsp;; `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&nbsp;; 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 } }
  ]
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkEgcG9pbnQgb24gYSBwYXJhYm9sYSIsInZhcmlhYmxlcyI6W3sibmFtZSI6ImEiLCJ2YWx1ZSI6IjEiLCJkb21haW4iOnsidHlwZSI6InJhbmdlIiwibWluIjoiLTIiLCJtYXgiOiIyIn19XSwic2VyaWVzIjpbeyJ0eXBlIjoibGluZSIsImZuIjoieF4yIiwiZG9tYWluIjpbLTIuNSwyLjVdfSx7InR5cGUiOiJzY2F0dGVyIiwiZm4iOiIoYSwgYV4yKSIsIm1hcmtlciI6eyJzaXplIjoxMH19XX0)

### 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] } }
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkEgc2VnbWVudCB0aGF0IHR1cm5zIiwidmFyaWFibGVzIjpbeyJuYW1lIjoiYSIsInZhbHVlIjoiMC44IiwiZG9tYWluIjp7InR5cGUiOiJyYW5nZSIsIm1pbiI6IjAiLCJtYXgiOiI2LjI4In19XSwic2VyaWVzIjpbeyJ0eXBlIjoic2NhdHRlciIsImZuIjoiWygwLCAwKSwgKFxcY29zKGEpLCBcXHNpbihhKSldIiwibGluZSI6dHJ1ZSwicG9pbnRzIjpmYWxzZX0seyJ0eXBlIjoic2NhdHRlciIsImZuIjoiKFxcY29zKGEpLCBcXHNpbihhKSkifV0sImRvbWFpbiI6eyJhc3BlY3QiOiJlcXVhbCIsIngiOnsicmFuZ2UiOlstMS41LDEuNV19LCJ5Ijp7InJhbmdlIjpbLTEuNSwxLjVdfX19)

### 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&nbsp;: `"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] }]
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkEgaGVscGVyIGZ1bmN0aW9uIiwidmFyaWFibGVzIjpbeyJuYW1lIjoiYyIsInZhbHVlIjoiMC41IiwiZG9tYWluIjp7InR5cGUiOiJyYW5nZSIsIm1pbiI6IjAiLCJtYXgiOiIxIn19XSwiZGVmaW5pdGlvbnMiOlt7ImxhdGV4IjoiRV8xKHMpID0gZV57LWNzfVxcY29zKDRzKSIsImhpZGRlbiI6dHJ1ZX1dLCJzZXJpZXMiOlt7InR5cGUiOiJsaW5lIiwiZm4iOiJFXzEoeCkiLCJkb21haW4iOlswLDEwXX1dfQ)

### 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] }]
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkEgZmFtaWx5IG9mIHNpbmUgY3VydmVzIiwiZGVmaW5pdGlvbnMiOlsiayA9IFsxLCAyLCAzXSJdLCJzZXJpZXMiOlt7InR5cGUiOiJsaW5lIiwiZm4iOiJcXHNpbihreCkiLCJkb21haW4iOlswLDYuMjhdfV19)

### 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] } }
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IlNxdWFyZSB3YXZlIHBhcnRpYWwgc3VtIiwidmFyaWFibGVzIjpbeyJuYW1lIjoibiIsInZhbHVlIjoiMyIsImRvbWFpbiI6eyJ0eXBlIjoicmFuZ2UiLCJtaW4iOiIxIiwibWF4IjoiMjUiLCJzdGVwIjoiMSJ9fV0sInNlcmllcyI6W3sidHlwZSI6ImxpbmUiLCJmbiI6IlxcZnJhY3s0fXtcXHBpfVxcc3VtX3trPTB9XntuLTF9XFxmcmFje1xcc2luKCgyaysxKXgpfXsyaysxfSJ9LHsidHlwZSI6ImxpbmUiLCJmbiI6Ilxcb3BlcmF0b3JuYW1le3NpZ259KFxcc2luKHgpKSIsInN0cm9rZSI6eyJkYXNoIjpbNCw0XX19XSwiZG9tYWluIjp7IngiOnsicmFuZ2UiOlstNi4yODMsNi4yODNdfSwieSI6eyJyYW5nZSI6Wy0yLDJdfX19)

### Une simulation

Une action avec un `interval` et `"autoplay": true` change une variable avec
une minuterie&nbsp;; ici, le point fait le tour du cercle. Le
[pendule](#une-simulation-avec-une-minuterie) 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] } }
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkEgcG9pbnQgdGhhdCBnb2VzIGFyb3VuZCIsInZhcmlhYmxlcyI6W3sibmFtZSI6ImEiLCJ2YWx1ZSI6IjAiLCJkb21haW4iOnsidHlwZSI6InJhbmdlIiwibWluIjoiMCIsIm1heCI6IjYuMjgifX1dLCJhY3Rpb25zIjpbeyJsYXRleCI6ImEgXFx0byBcXG9wZXJhdG9ybmFtZXttb2R9KGEgKyAwLjA1LCA2LjI4KSIsImludGVydmFsIjoiNTAiLCJhdXRvcGxheSI6dHJ1ZX1dLCJzZXJpZXMiOlt7InR5cGUiOiJwYXJhbWV0cmljIiwiZm4iOiIoXFxjb3ModCksIFxcc2luKHQpKSIsImRvbWFpbiI6WzAsNi4yOF19LHsidHlwZSI6InNjYXR0ZXIiLCJmbiI6IihcXGNvcyhhKSwgXFxzaW4oYSkpIiwibWFya2VyIjp7InNpemUiOjEwfX1dLCJkb21haW4iOnsiYXNwZWN0IjoiZXF1YWwiLCJ4Ijp7InJhbmdlIjpbLTEuNSwxLjVdfSwieSI6eyJyYW5nZSI6Wy0xLjUsMS41XX19fQ)

### 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" } }
  ]
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IlJlYWRpbmdzIHdpdGggbm90ZXMiLCJzZXJpZXMiOlt7InR5cGUiOiJsaW5lIiwieCI6WzAsMSwyLDMsNF0sInkiOlsxLDMsMiw1LDRdfV0sIm1hcmtlcnMiOlt7ImtpbmQiOiJsYWJlbCIsIngiOjMsInkiOjUuNCwidGV4dCI6IlBlYWsifSx7ImtpbmQiOiJiYW5kIiwiYXhpcyI6IngiLCJmcm9tIjoxLCJ0byI6Miwic3R5bGUiOnsiZmlsbCI6IiMxZTg4ZTUzMyJ9fV19)

## Exemples complets

Les textes de ces exemples sont en anglais&nbsp;; 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] } }
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkRhbXBlZCBvc2NpbGxhdGlvbiIsInZhcmlhYmxlcyI6W3sibmFtZSI6ImMiLCJ2YWx1ZSI6IjAuMyIsImRvbWFpbiI6eyJ0eXBlIjoicmFuZ2UiLCJtaW4iOiIwLjA1IiwibWF4IjoiMSJ9LCJwbGF5YmFjayI6eyJtb2RlIjoiYm91bmNlIiwiZGlyZWN0aW9uIjoiZm9yd2FyZCIsImR1cmF0aW9uIjo1MDAwfSwibm90ZSI6IlRoZSBkYW1waW5nIGNvZWZmaWNpZW50ICRjJC4gRHJhZyB0aGUgc2xpZGVyIHRvIGNoYW5nZSBpdC4ifV0sImRlZmluaXRpb25zIjpbeyJsYXRleCI6ImYoeCkgPSBlXnstYyB4fSBcXGNvcyg2IHgpIiwiaGlkZGVuIjp0cnVlfV0sInNlcmllcyI6W3sidHlwZSI6ImxpbmUiLCJmbiI6ImYoeCkiLCJkb21haW4iOlswLDEwXX0seyJ0eXBlIjoibGluZSIsImZuIjoiZV57LWMgeH0iLCJkb21haW4iOlswLDEwXSwic3Ryb2tlIjp7ImRhc2giOls0LDRdfX1dLCJkb21haW4iOnsieCI6eyJyYW5nZSI6WzAsMTBdfSwieSI6eyJyYW5nZSI6Wy0xLjIsMS4yXX19fQ)

### 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" }
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IkEgZGlzayBhYm92ZSBhIHBhcmFib2xhIiwicG9pbnRzIjpbeyJ4Ijp7Im5hbWUiOiJjX3giLCJ2YWx1ZSI6IjAuNSJ9LCJ5Ijp7Im5hbWUiOiJjX3kiLCJ2YWx1ZSI6IjEifSwibm90ZSI6IlRoZSBjZW50ZXIgb2YgdGhlIGRpc2suIERyYWcgaXQgb24gdGhlIHBsb3QuIn1dLCJzZXJpZXMiOlt7InR5cGUiOiJpbXBsaWNpdCIsImZuIjoieSBcXGdlIHheMiAtIDIiLCJkb21haW4iOnsieCI6Wy0zLDNdLCJ5IjpbLTMsM119LCJmaWxsIjoiIzkwY2FmOSJ9LHsidHlwZSI6ImltcGxpY2l0IiwiZm4iOiIoeCAtIGNfeCleMiArICh5IC0gY195KV4yIFxcbGUgMSIsImRvbWFpbiI6eyJ4IjpbLTMsM10sInkiOlstMywzXX0sImNvbG9yIjoiI2M2MjgyOCJ9XSwiZG9tYWluIjp7ImFzcGVjdCI6ImVxdWFsIn19)

### 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 }
  ]
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IlJlYWRpbmdzIHdpdGggYSB0cmVuZGxpbmUiLCJzZXJpZXMiOlt7InR5cGUiOiJzY2F0dGVyIiwiaWQiOiJyZWFkaW5ncyIsIngiOlsxLDIsMyw0LDUsNl0sInkiOlsyLjEsMy45LDYuMiw3LjgsMTAuMSwxMi4yXSwibmFtZSI6IlJlYWRpbmdzIn0seyJ0eXBlIjoiZGVyaXZlZCIsInNvdXJjZSI6InJlYWRpbmdzIiwidHJhbnNmb3JtIjp7ImtpbmQiOiJ0cmVuZGxpbmUiLCJtb2RlbCI6ImxpbmVhciJ9LCJsZWdlbmRFcXVhdGlvbiI6dHJ1ZX1dfQ)

### Un champ mesuré

Une carte de chaleur de valeurs mesurées&nbsp;: 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"
    }
  ]
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6Ik1lYXN1cmVkIGZpZWxkIiwic2VyaWVzIjpbeyJ0eXBlIjoiaGVhdG1hcCIsIngiOlswLDEsMiwzXSwieSI6WzAsMSwyXSwieiI6W1sxLDIsMyw0XSxbMiwzLDQsNV0sWzMsNCxudWxsLDZdXSwiY29sb3IiOiJ2aXJpZGlzIiwibmFtZSI6IlRlbXBlcmF0dXJlIn1dfQ)

### 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.

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IlRvcnVzIiwic2VyaWVzIjpbeyJ0eXBlIjoicGFyYW1ldHJpYy1zdXJmYWNlIiwiZm4iOiIoKDIgKyBcXGNvcyh2KSlcXGNvcyh1KSwgKDIgKyBcXGNvcyh2KSlcXHNpbih1KSwgXFxzaW4odikpIiwiZG9tYWluIjp7InUiOlswLDYuMjgzMTg1MzA3MTc5NTg2XSwidiI6WzAsNi4yODMxODUzMDcxNzk1ODZdfSwiY29sb3IiOiJ2aXJpZGlzIn1dLCJzdGFnZTNkIjp7ImVudmlyb25tZW50Ijoib3V0ZG9vciJ9LCJkb21haW4zZCI6eyJhc3BlY3RNb2RlIjoiZGF0YSJ9fQ)

## 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&nbsp;: 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&nbsp;:

- 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&nbsp;: 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 nouveau $w$, puis le nouveau $a$ à 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](/showcase/fr/projectile-with-drag) et
  [Proies et prédateurs](/showcase/fr/predator-prey) é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&nbsp;: 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&nbsp;ms, et chaque exécution est un pas de
$h = 0.02$&nbsp;s&nbsp;:

$$
w \to w - h\frac{g}{L}\sin(a), \quad
a \to a + h\left(w - h\frac{g}{L}\sin(a)\right), \quad
T \to T + h
$$

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&nbsp;: 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&nbsp;: 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&nbsp;; 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] } }
}
```

[Ouvrir ce document dans Graph Paper](https://graph-paper.io/new#doc=eyJ0aXRsZSI6IlBlbmR1bHVtIiwidmFyaWFibGVzIjpbeyJuYW1lIjoiTCIsInZhbHVlIjoiMiIsImRvbWFpbiI6eyJ0eXBlIjoicmFuZ2UiLCJtaW4iOiIwLjUiLCJtYXgiOiIzIn0sIm5vdGUiOiJUaGUgbGVuZ3RoICRMJCBvZiB0aGUgcm9kLCBpbiBtZXRlcnMuIn0seyJuYW1lIjoiQSIsInZhbHVlIjoiMi41IiwiZG9tYWluIjp7InR5cGUiOiJyYW5nZSIsIm1pbiI6IjAuMSIsIm1heCI6IjMuMSJ9LCJub3RlIjoiVGhlIHN0YXJ0IGFuZ2xlICRBJCwgaW4gcmFkaWFucyBmcm9tIHRoZSB2ZXJ0aWNhbC4gUnVuICoqUmVzZXQqKiBhZnRlciB5b3UgY2hhbmdlIGl0LiJ9LHsibmFtZSI6ImEiLCJ2YWx1ZSI6IjIuNSIsImRvbWFpbiI6eyJ0eXBlIjoicmFuZ2UiLCJtaW4iOiItMy4yIiwibWF4IjoiMy4yIn0sIm5vdGUiOiJUaGUgc3RhdGU6IHRoZSBhbmdsZSAkYSQsIHRoZSBhbmd1bGFyIHZlbG9jaXR5ICR3JCBhbmQgdGhlIHRpbWUgJFQkLiBUaGUgdGltZXIgY2hhbmdlcyB0aGVtLiJ9LHsibmFtZSI6InciLCJ2YWx1ZSI6IjAiLCJkb21haW4iOnsidHlwZSI6InJhbmdlIiwibWluIjoiLTgiLCJtYXgiOiI4In19LHsibmFtZSI6IlQiLCJ2YWx1ZSI6IjAiLCJkb21haW4iOnsidHlwZSI6InJhbmdlIiwibWluIjoiMCIsIm1heCI6IjYwIn19XSwiZGVmaW5pdGlvbnMiOlt7ImxhdGV4IjoiZyA9IDkuODEiLCJub3RlIjoiVGhlIGdyYXZpdHkgJGckLCBpbiBtL3PCsi4ifSx7ImxhdGV4IjoiaCA9IDAuMDIiLCJub3RlIjoiVGhlIHRpbWUgc3RlcCAkaCQsIGluIHNlY29uZHMuIn1dLCJhY3Rpb25zIjpbeyJsYXRleCI6IncgXFx0byB3IC0gaFxcZnJhY3tnfXtMfVxcc2luKGEpLCBhIFxcdG8gYSArIGhcXGxlZnQodyAtIGhcXGZyYWN7Z317TH1cXHNpbihhKVxccmlnaHQpLCBUIFxcdG8gVCArIGgiLCJpbnRlcnZhbCI6IjIwIiwiYXV0b3BsYXkiOnRydWUsIm5vdGUiOiJPbmUgc3RlcCBvZiB0aGUgbW90aW9uIGV2ZXJ5IDIwIG1zOiBmaXJzdCB0aGUgbmV3ICR3JCwgdGhlbiB0aGUgbmV3ICRhJCBmcm9tIHRoZSBuZXcgJHckLiJ9LHsibGF0ZXgiOiJhIFxcdG8gQSwgdyBcXHRvIDAsIFQgXFx0byAwIiwibm90ZSI6IlJlc2V0OiBiYWNrIHRvIHRoZSBzdGFydCBhbmdsZSwgYXQgcmVzdC4ifV0sInNlcmllcyI6W3sidHlwZSI6InBhcmFtZXRyaWMiLCJmbiI6IihMXFxjb3ModCksIExcXHNpbih0KSkiLCJkb21haW4iOlswLDYuMjgzMTg1MzA3MTc5NTg2XSwiY29sb3IiOiIjYjBiZWM1Iiwic3Ryb2tlIjp7ImRhc2giOls0LDRdfX0seyJ0eXBlIjoic2NhdHRlciIsImZuIjoiWygwLCAwKSwgKExcXHNpbihhKSwgLUxcXGNvcyhhKSldIiwibGluZSI6dHJ1ZSwicG9pbnRzIjpmYWxzZSwiY29sb3IiOiIjNDU1YTY0In0seyJ0eXBlIjoic2NhdHRlciIsImZuIjoiKExcXHNpbihBXFxjb3MoXFxzcXJ0e2cvTH1UKSksIC1MXFxjb3MoQVxcY29zKFxcc3FydHtnL0x9VCkpKSIsImNvbG9yIjoiIzkwYTRhZSIsIm1hcmtlciI6eyJzaXplIjoxMH19LHsidHlwZSI6InNjYXR0ZXIiLCJmbiI6IihMXFxzaW4oYSksIC1MXFxjb3MoYSkpIiwiY29sb3IiOiIjYzYyODI4IiwibWFya2VyIjp7InNpemUiOjE0fX1dLCJtYXJrZXJzIjpbeyJraW5kIjoicG9pbnQiLCJ4IjowLCJ5IjowLCJzdHlsZSI6eyJmaWxsIjoiIzQ1NWE2NCIsInNpemUiOjh9fV0sImRvbWFpbiI6eyJhc3BlY3QiOiJlcXVhbCIsIngiOnsicmFuZ2UiOlstMy41LDMuNV19LCJ5Ijp7InJhbmdlIjpbLTMuNSwzLjVdfX19)

## Vérifier un document

Un programme peut vérifier un document sans navigateur et sans compte&nbsp;:

- 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&nbsp;; 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](/for-agents/fr/) 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&nbsp;: voir
[Quand la personne ouvre le lien](/for-agents/fr/#quand-la-personne-ouvre-le-lien)
sur la page Pour les agents.

## Apprendre avec la Vitrine

Chaque page de la [Vitrine](/showcase/fr/) 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&nbsp;: 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](/docs/notebook-file-format.md) (en anglais),
avec des schémas JSON pour [le fichier d'export](/docs/schema/export-envelope.schema.json)
et [le contenu du carnet](/docs/schema/notebook-content.schema.json).
