Code interactif et exécutable dans Quarto : webR, Pyodide, OJS et Shinylive

Laissez le lecteur exécuter et modifier le code, pas seulement lire la sortie

Ajoutez à un document Quarto du code que le lecteur peut vraiment exécuter — R en direct avec webR, Python en direct avec Pyodide, entrées réactives avec Observable JS et applications complètes sans serveur avec Shinylive. Transformez un rapport statique en une analyse interactive et reproductible qu’une personne, ou un agent IA, peut exécuter et vérifier.

Date de publication

19 juillet 2026

Modifié

19 juillet 2026

AstucePoints clés
  • Quatre mécanismes, un seul but — du code exécutable sur la page. webR exécute R, Pyodide exécute Python, Observable JS (OJS) relie des entrées réactives à une sortie en direct, et Shinylive intègre toute une app sans serveur.
  • webR et Pyodide s’exécutent dans le navigateur. Remplacez {r} par {webr} (ou {python} par {pyodide}), ajoutez format: live-html et l’include Quarto Live, et la cellule devient un éditeur modifiable et exécutable — sans serveur.
  • Les options de cellule pilotent l’éditeur en direct de la même façon que #| pilote un bloc statique : autorun, edit, runbutton, timelimit, persist, et l’ensemble exercise / hint / solution pour les tâches notées.
  • OJS apporte la réactivité sans téléchargement WASM — un curseur viewof pilote une sortie qui se recalcule à l’instant où l’entrée change, entièrement en JavaScript.
  • Un document exécutable est le document défendable. Du code qu’un lecteur (ou un agent IA) peut exécuter et vérifier est une preuve, pas une affirmation — ce qu’un chatbot sans runtime ne peut pas vous donner.
Histogram of eruption waiting times from the faithful dataset, azure bars showing a clear bimodal shape with peaks near 55 and 80 minutes.
Figure 1: A histogram rendered at build time from a Quarto chunk. Later on this page, the same chart becomes interactive — drag a slider and the bins update in your browser.

Introduction

Vous avez un rapport Quarto. Les figures sont rendues, les tableaux sont propres — mais le lecteur ne peut que regarder la sortie. Dès qu’il veut essayer le code sur ses propres chiffres, changer un paramètre ou vérifier qu’un résultat tient vraiment, il doit copier le code, ouvrir R ou Python ailleurs et reconstruire votre environnement. Le code interactif comble ce fossé : le code vit sur la page, et le lecteur l’exécute et le modifie sur place.

Quarto vous offre quatre façons de le faire, chacune s’exécutant côté client — dans le navigateur du lecteur, sans serveur à héberger ni à payer :

  • webR — une version de R compilée en WebAssembly (un format binaire rapide et portable qui tourne dans tous les navigateurs modernes). Une cellule {webr} est un éditeur R en direct.
  • Pyodide — l’équivalent Python : CPython compilé en WebAssembly. Une cellule {pyodide} est un éditeur Python en direct.
  • Observable JS (OJS) — le JavaScript réactif intégré à Quarto. Réactif signifie qu’une sortie se recalcule automatiquement à l’instant où une entrée dont elle dépend change, comme une cellule de tableur se met à jour quand vous en modifiez une autre. OJS est la façon de construire un curseur qui redessine un graphique en direct.
  • Shinylive — une version sans serveur de Shiny qui intègre toute une app multi-widgets (entrées, réactivité et logique serveur) dans le document.

À l’ère de l’IA, cela compte davantage, pas moins. Un document dont un agent IA peut réellement exécuter et vérifier le code est un artefact différent d’un bloc de texte généré par un chatbot — the runtime is the judge. C’est le fil conducteur de chaque leçon Datanovia, et cette page est celle où vous apprenez à construire l’artefact. La référence complète est la documentation Quarto sur l’interactivité ; cette leçon en est le chemin pratique.

Quatre façons de rendre un document exécutable — la carte

Avant le comment, le quand. Les quatre mécanismes ne sont pas concurrents ; chacun répond à une question différente.

Vous voulez que le lecteur puisse… À utiliser Exécution
Exécuter et modifier un bloc de R webR ({webr}) R dans le navigateur (WebAssembly)
Exécuter et modifier un bloc de Python Pyodide ({pyodide}) Python dans le navigateur (WebAssembly)
Déplacer un contrôle et voir la sortie se mettre à jour en direct Observable JS ({ojs}) JavaScript, instantanément (aucun téléchargement)
Utiliser une app complète — plusieurs entrées, logique serveur Shinylive Une app Shiny sans serveur (WebAssembly)

La règle générale : une seule cellule de code exécutable → webR ou Pyodide ; une entrée réactive qui redessine une sortie → OJS ; toute une application → Shinylive. Le reste de cette leçon les aborde dans cet ordre.

R en direct avec webR

Un bloc {r} statique s’exécute une fois, au moment du rendu, et fige sa sortie dans la page. Une cellule {webr} envoie la source au navigateur et y démarre webR, de sorte que le lecteur obtient un éditeur modifiable avec un bouton Run. Trois choses transforment une leçon R statique en leçon en direct :

  1. Définissez le format du document à live-html et ajoutez l’include Quarto Live (la ligne {{< include … >}}) en haut du fichier.
  2. Déclarez tous les packages R dont les cellules en direct ont besoin sous une clé webr: dans le YAML — ils sont récupérés sous forme de versions WebAssembly lorsque le lecteur exécute une cellule.
  3. Écrivez la cellule avec une balise {webr} au lieu de {r}.

L’en-tête ressemble à ceci :

---
format: live-html
webr:
  packages:
    - ggplot2
---

Et une cellule R en direct n’est qu’une balise {webr}. En voici une vraie — appuyez sur Run Code pour démarrer webR et l’exécuter dans votre navigateur (le premier lancement télécharge le moteur R, laissez-lui donc un moment) :

La cellule ci-dessus est réellement en direct : changez mean = 50 en mean = 100, ou remplacez hist() par boxplot(), et exécutez-la de nouveau. Rien n’a été précalculé — webR a exécuté votre code modifié. C’est tout l’intérêt de #| autorun: false : le lourd moteur WebAssembly ne se charge que lorsque le lecteur choisit d’exécuter, si bien que la page reste rapide pour tous ceux qui se contentent de lire (voir Options d’exécution du code dans Quarto pour les options de bloc statique sur lesquelles elles reposent).

La documentation webR indique quels packages disposent de versions WebAssembly. Réduisez la liste webr: packages: au strict minimum réellement appelé par une cellule — chaque package est un téléchargement que le lecteur doit attendre.

Options de cellule pour les cellules en direct

Les cellules en direct prennent des options #| comme les blocs statiques, mais ces options pilotent l’éditeur et son exécution plutôt que ce qui est figé dans le HTML. Elles proviennent de l’extension Quarto Live, qui anime les cellules {webr} et {pyodide}. Celles que vous utiliserez :

Option Défaut Rôle
autorun false Exécute la cellule automatiquement dès que le moteur est chargé, au lieu d’attendre un clic.
edit true Indique si la cellule est modifiable. edit: false crée une cellule en lecture seule qui s’exécute quand même.
runbutton true Affiche le bouton Run Code. false exécute à chaque frappe au clavier.
include true Affiche à la fois la source et sa sortie. false exécute silencieusement.
persist false Enregistre les modifications du lecteur dans le navigateur pour qu’elles survivent à un rechargement.
startover true Affiche un bouton Start Over qui réinitialise la cellule à son code d’origine.
timelimit 30 Nombre de secondes qu’une cellule peut s’exécuter avant d’être arrêtée (0 désactive la limite).
min-lines / max-lines 0 / ∞ Pilotent la hauteur visible de l’éditeur.

Pour un exercice noté, trois options supplémentaires vous donnent des boutons Run / Hint / Solution intégrés : exercise (un identifiant qui regroupe les parties), hint et solution. Vous les verrez dans la section Testez vos connaissances ci-dessous. La liste complète figure dans la référence des options de cellule Quarto Live ; le tableau ci-dessus en est le sous-ensemble utile.

Python en direct avec Pyodide

Tout ce qui vaut pour webR a un jumeau Python. Pyodide est CPython compilé en WebAssembly, et une cellule {pyodide} est un éditeur Python en direct. Déclarez les packages Python sous une clé pyodide: (laissez-la vide pour un exemple de la bibliothèque standard), et écrivez la cellule avec une balise {pyodide} :

---
format: live-html
pyodide:
  packages:
    - numpy
    - matplotlib
---

Voici une cellule Python en direct — appuyez sur Run Code pour démarrer Pyodide et l’exécuter :

Le modèle mental est identique à celui de webR : la source est envoyée au navigateur, le moteur WebAssembly démarre à la demande, et le lecteur modifie et exécute. Choisissez le moteur selon le langage de la leçon — une cellule {webr} pour un document R, une cellule {pyodide} pour un document Python — et utilisez les mêmes options #|. Pour un flux complet d’analyse de données en Python, la série Fondations Python utilise ces cellules d’un bout à l’autre.

Entrées réactives avec Observable JS

webR et Pyodide vous donnent une cellule exécutable. Observable JS vous en donne une réactive : une entrée que le lecteur manipule, et une sortie qui se redessine à l’instant où l’entrée change — sans moteur à télécharger, car OJS est du simple JavaScript que Quarto embarque nativement.

Deux éléments le font fonctionner : une entrée déclarée avec le mot-clé viewof (qui lie un widget à une variable), et une cellule de sortie qui utilise cette variable. Comme OJS est réactif, toute cellule qui référence la variable se réexécute automatiquement quand le lecteur déplace le contrôle.

Le motif le plus propre est de précalculer les données en R au moment du build, de les transmettre à OJS avec ojs_define(), et de laisser un curseur les redessiner en direct. D’abord, R prépare les données (c’est un bloc {r} statique normal, exécuté une fois au rendu) :

```{r}
#| label: ojs-bridge
faithful_wait <- data.frame(waiting = faithful$waiting)
ojs_define(faithful_wait = faithful_wait)
```

OJS prend le relais. transpose() transforme les colonnes transmises en un tableau de lignes, un curseur viewof choisit le nombre de classes, et un graphique se redessine chaque fois que le curseur bouge — déplacez-le et observez :

wait = transpose(faithful_wait)
viewof bins = Inputs.range([5, 40], {value: 18, step: 1, label: "Number of bins:"})
Plot.plot({
  height: 260,
  x: { label: "Eruption waiting time (min)" },
  y: { label: "Count" },
  marks: [
    Plot.rectY(wait, Plot.binX({ y: "count" }, { x: "waiting", thresholds: bins })),
    Plot.ruleY([0])
  ]
})

Inputs, transpose et Plot sont tous intégrés au runtime OJS de Quarto — aucun import. Déplacez le curseur et l’histogramme (les mêmes temps d’attente faithful que la figure statique en haut de cette page) se reconstruit instantanément, entièrement dans votre navigateur. Voilà la réactivité : vous n’appelez jamais de fonction « redessiner », vous déclarez simplement que le graphique dépend de bins et OJS les garde synchronisés.

Vous pouvez aussi pousser une entrée OJS dans une cellule webR ou Pyodide avec l’option #| input:, pour qu’un curseur pilote du R ou du Python en direct au lieu du JavaScript :

```{webr}
#| input:
#|   - bins
hist(faithful$waiting, breaks = bins, col = "#3a86d4", border = "white")
```

Optez pour OJS quand l’interaction est « déplacer un contrôle, redessiner une sortie » et que le dessin peut se faire en JavaScript — c’est l’option la plus légère et la plus rapide. Optez pour le pont #| input: quand la sortie réactive a réellement besoin de R ou de Python. La documentation Observable JS couvre l’ensemble des entrées et la bibliothèque de tracé.

Intégrer une app complète avec Shinylive

Quand une seule entrée réactive ne suffit pas — vous avez besoin de plusieurs contrôles, d’une logique côté serveur et de sorties coordonnées — intégrez toute une app. Shinylive est une version sans serveur de Shiny : l’app s’exécute entièrement dans le navigateur via WebAssembly, si bien que vous pouvez la déposer dans une page Quarto statique sans aucun serveur Shiny derrière.

Elle utilise sa propre balise (issue de l’extension quarto-ext/shinylive), par exemple une app Python :

```{shinylive-python}
#| standalone: true
from shiny import App, render, ui

app_ui = ui.page_fluid(
    ui.input_slider("n", "Sample size", 10, 500, 100),
    ui.output_plot("hist"),
)
# ... server logic ...
app = App(app_ui, server)
```

Shinylive est une leçon à part entière — installer l’extension, les variantes R et Python, les apps mono-fichier ou multi-fichiers, et les compromis liés à l’envoi de toute une app dans le navigateur. Plutôt que de la reprendre ici, rendez-vous à la leçon dédiée : Exécuter une app Shiny dans le navigateur avec Shinylive. Utilisez Shinylive quand le lecteur a besoin d’une application ; utilisez une cellule {webr}/{pyodide} ou OJS quand il a besoin d’un extrait exécutable ou d’une seule entrée réactive.

Quel mécanisme, quand

En résumé :

Mécanisme Idéal pour Coût pour le lecteur
webR {webr} Une cellule R modifiable et exécutable Télécharge le moteur WebAssembly de R au premier Run
Pyodide {pyodide} Une cellule Python modifiable et exécutable Télécharge le moteur WebAssembly de Python au premier Run
OJS {ojs} Une entrée réactive → sortie en direct (un curseur redessine un graphique) Aucun — du JavaScript pur, instantané
Shinylive Une app complète : plusieurs entrées, logique serveur, sorties coordonnées Télécharge le runtime WebAssembly de l’app

Un bon rapport interactif les mêle souvent : des figures statiques pour le récit, un curseur OJS pour le moment « explorez par vous-même », et une cellule {webr} là où le lecteur devrait exécuter le vrai code d’analyse.

Le document qu’un agent peut vérifier

L’interactivité n’est pas réservée aux humains. Un document Quarto à cellules exécutables est un document qu’un agent IA peut exécuter — lancer le code, lire la sortie réelle et vérifier qu’une affirmation tient — au lieu de croire la prose sur parole. C’est la différence entre un rapport qui affirme un résultat et un rapport qui le prouve. Un chatbot sans runtime peut décrire une analyse ; il ne peut pas vous remettre une page dont chaque figure a été produite par du code que vous (ou votre agent) pouvez réexécuter et vérifier. Construire cette page, c’est exactement à cela que servent les mécanismes ci-dessus.

Essayez en direct

Changez la distribution, la taille d’échantillon ou le graphique, puis exécutez. C’est une vraie cellule webR — rien ici n’a été précalculé.

🟢 Avec un agent IA

Vous transformez un rapport statique en rapport interactif et ne savez pas quel mécanisme convient ? Demandez à Prova — décrivez ce que le lecteur doit pouvoir faire (exécuter un extrait, déplacer un curseur, utiliser une app complète) et elle recommande webR, Pyodide, OJS ou Shinylive et écrit la cellule. The runtime is the judge. Ask Prova →

Problèmes fréquents

Une cellule {webr} signale qu’un package n’a pas pu être chargé. Tous les packages R n’ont pas de version WebAssembly, et tout package utilisé par une cellule doit être listé sous webr: packages: dans le YAML — un package installé sur votre machine n’est pas automatiquement disponible dans le navigateur. Consultez la liste des packages webR, ajoutez le nom à webr: packages:, et gardez la liste minimale pour que le lecteur n’attende pas des téléchargements dont il n’a pas besoin.

Une cellule OJS renvoie l’erreur « … is not defined » ou « duplicate definition ». OJS est réactif, pas de haut en bas : une variable peut être utilisée avant d’apparaître dans la source, mais elle doit être définie quelque part, et chaque nom ne peut être défini qu’une seule fois dans le document. Un viewof bins déclaré deux fois, ou un graphique qui référence wait alors qu’aucune cellule ne le définit, casse le graphe réactif. Donnez à chaque entrée viewof et à chaque ojs_define() un nom unique.

Rien ne s’exécute, alors que le code est correct. Le document est probablement encore en format: html, ou l’include Quarto Live manque. Les cellules en direct ont besoin de format: live-html et de la ligne {{< include … r-wasm/live/_knitr.qmd >}} en haut du fichier. Sans les deux, les balises {webr} et {pyodide} s’affichent comme des blocs de code inertes.

Une cellule en direct n’est pas affectée par freeze. Freeze met en cache la sortie du code qui s’exécute au moment du rendu (les blocs statiques {r}/{python} — voir Rendu des documents Quarto). Une cellule {webr}/{pyodide} s’exécute dans le navigateur du lecteur, elle n’est donc jamais figée ; seul un bloc statique qui alimente OJS via ojs_define() l’est.

Questions fréquentes

Définissez format: live-html, ajoutez la ligne d’include Quarto Live en haut du fichier, et écrivez votre cellule avec une balise {webr} (pour R) ou {pyodide} (pour Python) au lieu de {r}/{python}. Déclarez tous les packages dont la cellule a besoin sous une clé webr: ou pyodide: dans le YAML. Le lecteur obtient alors un éditeur modifiable avec un bouton Run — le code s’exécute dans son navigateur, sans serveur requis.

C’est la même idée pour deux langages. webR est R compilé en WebAssembly ; une cellule {webr} exécute R dans le navigateur. Pyodide est CPython compilé en WebAssembly ; une cellule {pyodide} exécute Python dans le navigateur. Choisissez celui qui correspond au langage de votre document — webR pour une leçon R et Pyodide pour une leçon Python.

Les deux sont possibles, mais les fonctionnalités interactives de cette leçon s’exécutent côté client, dans le navigateur du lecteur, sans serveur. webR, Pyodide et Shinylive utilisent WebAssembly, et Observable JS est du simple JavaScript. Cela signifie que vous pouvez héberger un document Quarto interactif comme du HTML statique ordinaire — sur GitHub Pages, Netlify ou n’importe quel serveur de fichiers — et il fonctionne quand même. (Le Shiny classique adossé à un serveur fait exception ; Shinylive existe précisément pour éviter d’avoir besoin de ce serveur.)

Utilisez Observable JS. Déclarez le curseur avec viewof myslider = Inputs.range([min, max], {value: …, label: …}), puis écrivez une cellule de tracé qui référence myslider. Comme OJS est réactif, le graphique se réexécute automatiquement chaque fois que le curseur bouge. Transmettez des données depuis R ou Python vers OJS avec ojs_define() et tracez-les avec la bibliothèque intégrée Plot.

Non. webR, Pyodide, OJS et Shinylive s’exécutent tous dans le navigateur, si bien qu’un document Quarto en direct n’est que du HTML statique que vous pouvez héberger partout. Le seul cas qui nécessite un serveur est le Shiny classique ; pour une alternative sans serveur, intégrez l’app avec Shinylive à la place.

Tâche 1. La cellule ci-dessous devrait tracer un histogramme des temps d’attente entre éruptions du jeu de données faithful, en s’exécutant en direct dans le navigateur. Complétez le blanc avec la fonction base R qui trace un histogramme, puis appuyez sur Run Code.

Note

La fonction base R porte le nom du graphique qu’elle trace — elle prend un vecteur numérique et le répartit en classes. Son nom compte quatre lettres, et vous l’avez déjà vue dans la cellule webR plus tôt dans cette leçon.

Note

hist() est la fonction histogramme de base R — elle n’a besoin que du vecteur numérique. Comme il s’agit d’une cellule {webr}, elle s’exécute dans votre navigateur lorsque vous appuyez sur Run Code, sans aucun R installé sur votre machine.

hist(faithful$waiting, col = "#3a86d4", border = "white",
     main = "Eruption waiting times")

Tâche 2. Vous voulez un rapport où le lecteur déplace un curseur et un graphique se redessine instantanément, et vous préféreriez ne pas lui faire télécharger un moteur WebAssembly pour cela. Quel mécanisme convient, et quel mot-clé déclare le curseur ?

Observable JS (OJS) — il est réactif et ne nécessite aucun téléchargement de moteur car c’est du simple JavaScript. Déclarez le curseur avec le mot-clé viewof lié à un contrôle Inputs.range(...), puis référencez cette variable dans une cellule de tracé ; OJS réexécute le graphique automatiquement quand le curseur bouge.

Vous changez la balise d’un bloc de {r} à {webr}, mais sur la page rendue ce n’est qu’un bloc de code ordinaire et non exécutable. Quelle en est la cause la plus probable ?

A. webR ne fonctionne qu’avec Python B. Le document est encore en format: html, ou la ligne d’include Quarto Live manque C. Les cellules {webr} ne peuvent pas contenir d’appels library()

B. Les cellules en direct ont besoin de deux choses que la balise seule n’apporte pas : format: live-html dans le YAML et la ligne {{< include … r-wasm/live/_knitr.qmd >}} en haut du fichier. Sans les deux, Quarto affiche {webr} comme un bloc de code inerte.

Conclusion

Rendre un document Quarto exécutable revient à accorder le mécanisme à l’interaction. Une seule cellule R ou Python que le lecteur modifie et exécute → webR ou Pyodide (format: live-html, la ligne d’include et une balise {webr}/{pyodide}). Un contrôle qui redessine une sortie en direct, sans rien à télécharger → Observable JS et une entrée viewof. Toute une application → Shinylive. Les options de cellule que vous connaissez déjà des blocs statiques se transposent, pilotant désormais un éditeur en direct plutôt que le HTML rendu. Le résultat est un rapport qui ne se contente pas de montrer un résultat — il permet au lecteur, ou à un agent, de le reproduire.

Leçons connexes

Cette page vous a-t-elle été utile ?

Recevez les nouvelles leçons R & Python par e-mail

Pratique, reproductible, sans spam. Désinscription à tout moment.

Double opt-in. Nous ne partageons jamais votre e-mail.

Partager cette pageXLinkedInRedditHN
Note

Cette leçon est interactive et reproductible : les figures statiques ont été produites par le code affiché, et les cellules en direct {webr}, {pyodide} et {ojs} s’exécutent dans votre navigateur — modifiez-en n’importe laquelle et cliquez sur Run pour reproduire et prolonger les résultats vous-même. The runtime is the judge.

Réutilisation

Citation

BibTeX
@online{2026,
  author = {},
  title = {Code interactif et exécutable dans Quarto : webR, Pyodide,
    OJS et Shinylive},
  date = {2026-07-19},
  url = {https://www.datanovia.com/learn/programming/quarto/interactive-live-code},
  langid = {fr}
}
Veuillez citer ce travail comme suit :
“Code interactif et exécutable dans Quarto : webR, Pyodide, OJS et Shinylive.” 2026. July 19. https://www.datanovia.com/learn/programming/quarto/interactive-live-code.