Notebook HTML réactif
(maxbo.me)- Il est possible de réunir dans un même document l’exploration, l’analyse, la visualisation, la mise en page et la diffusion de données avec un unique fichier HTML exécuté par le navigateur, ce qui réduit le flux classique notebook → outil de publication → PDF
- L’implémentation centrale consiste à combiner des cellules echo qui affichent à l’écran
styleetscript,contenteditableet l’Observable Runtime pour créer des cellules réactives éditables cell(name, inputs, definition)suit le modèle de dépendances d’Observable afin de composer des unités d’exécution reliées entre elles, commecounter, un rendu FizzBuzz, des cellules masquées ou des cellules intermédiaires sans sortie- Le même document HTML fait la démonstration d’Observable Plot, TeX, Markdown, Graphviz, SQLite basé sur WASM, Python basé sur Pyodide, R basé sur WebR, Observable Inputs et de l’état Mutable
- Le résultat est un document scientifique et technique qui s’exécute dans le navigateur sans plateforme séparée, et l’implémentation a ensuite été publiée sous forme de bibliothèque
@celine/celine
Réduire la séparation notebook-publication à un seul fichier HTML
- HTML est largement utilisé pour la mise en page, mais il a été relativement peu exploité comme plateforme d’exploration, d’analyse et de visualisation de données
- Le flux de travail habituel passe par plusieurs outils
- L’exploration, l’analyse et la visualisation sont réalisées dans des notebooks interactifs comme Jupyter, RStudio, Pluto.jl ou Observable
- Le contenu est transféré vers une plateforme de publication comme Typst, Overleaf, LaTeX ou un éditeur WYSIWYG pour la mise en page
- Il est exporté en
.pdfpour la diffusion
- Si un seul fichier HTML prend en charge ces trois étapes, cela réduit les procédures manuelles, les outils CLI, les étapes de CI et la dépendance à des plateformes tierces
- L’implémentation est fortement influencée par In-browser code playgrounds d’Anton Zhiyanov, Self-modifying HTML notes de Cristóbal Sciutto, Quarto et Observable Framework
Créer des cellules éditables
- La première étape consiste à rendre visibles tels quels dans le document les éléments
styleetscriptgrâce à la classe CSSecho - En y ajoutant une police avec coloration syntaxique intégrée et l’attribut
contenteditable, on peut s’en servir comme d’un éditeur de code basique - Un
scriptauquelcontenteditableest appliqué est réévalué lorsqu’il perd le focus- Le
scriptexistant est cloné pour créer un nouvel élémentscript, puis l’original est supprimé - Cette méthode est nécessaire, car
evalne fonctionne pas avec du code contenant des instructionsimport
- Le
- Deux bibliothèques sont chargées pour l’exécution basée sur Observable
- Seuls deux symboles,
libraryetcell, sont exposés globalement
Flux de données réactif basé sur l’Observable Runtime
- La fonction
cell(name, inputs, definition, observerVisibility)définit une cellule en utilisant la portée de module de l’Observable Runtime - Si une variable portant le même nom existe déjà, elle est récupérée ; sinon, une nouvelle variable est créée et définie
- Grâce à cette structure, lorsqu’une cellule
contenteditableest réévaluée, la nouvelle définition se propage aux cellules connectées
- Grâce à cette structure, lorsqu’une cellule
- L’
Inspectord’Observable est utilisé pour afficher la sortie des cellules au-dessus du blocscript - La cellule
counterest composée comme un générateur asynchrone qui émet un nombre chaque seconde- L’attribut
idduscriptet l’argumentnamedecellsont identiques - Si l’on modifie la valeur initiale
ipuis que l’on retire le focus, la nouvelle valeur est prise en compte
- L’attribut
- On peut aussi créer des cellules qui dépendent de
counter- Hypertext Literal est chargé pour rendre la valeur de
countersous forme de FizzBuzz htlimplémente un parseur HTML5 et gère l’échappement automatique ainsi que l’interpolation de valeurs non sérialisables comme les écouteurs d’événements, les objets de style et les nœuds DOM
- Hypertext Literal est chargé pour rendre la valeur de
Cellules visibles, masquées et sans sortie
- Si l’on n’ajoute pas la classe
echo, on peut masquer la définition de la cellule tout en observant sa sortie- Ce type de cellule peut servir de primitive de rendu
- Il est aussi possible de créer un type de cellule qui n’affiche pas la sortie elle-même
silent(name, inputs, definition)définitobserverVisibilitysur masqué afin de pouvoir stocker des valeurs intermédiaires ou des structures de données
- Les cellules peuvent fonctionner indépendamment de leur ordre de déclaration
- Dans l’exemple, la cellule
reallyNegativedépend de la cellulenegative, déclarée plus tard
- Dans l’exemple, la cellule
- La même valeur de cellule est aussi utilisée pour des sorties plus complexes
- Observable Plot est chargé pour tracer un tableau de nombres sous forme de courbe et afficher une règle verticale à la position
counter % 40
- Observable Plot est chargé pour tracer un tableau de nombres sous forme de courbe et afficher une règle verticale à la position
Extension des sorties documentaires et de visualisation
- Une cellule peut retourner n’importe quel élément DOM
- Les démos TeX, Markdown et Graphviz retournent chacune des éléments de formes différentes
- La cellule
texretourne un élémentspan - La cellule
mdretourne un élémenttable - La cellule
dotretourne un élémentsvg
- La cellule
- Une cellule peut retourner une
Promiseou lancer uneError- L’
Inspectord’Observable applique la classeobservablehq--runningaudivextérieur d’une cellule en cours d’exécution - Il applique la classe
observablehq--erroraux cellules en erreur - Le document définit son style en fonction de ces états
- L’
SQLite, Python et R dans le navigateur
- La démo SQLite place la base d’exemple Chinook sur
https://maxbo.me/chinook.dbet l’interroge avec un client SQLite basé sur WASM- On peut essayer d’ajouter
WHERE Milliseconds < 1000000à la requête SQL
- On peut essayer d’ajouter
- La démo Python utilise la distribution CPython WASM Pyodide
- Pyodide inclut NumPy, Pandas, Matplotlib, scikit-learn et Scipy
- Le graphique créé plus haut est recréé avec Matplotlib et le module Python
sqlite3
- La démo R utilise WebR
Entrées et état mutable
- Le type de cellule
viewofest créé pour être utilisé avec Observable Inputs viewofdéclare deux cellules réactivesNAME: la valeur de l’entréeviewof NAME: l’élément DOM lui-même
- Pour afficher l’entrée au-dessus de la cellule, il faut définir l’
idde la cellule surviewof NAME - Dans l’exemple, une entrée de plage est créée avec
Inputs.range([0, 100], { step: 1 }), et la cellulerangePlotest mise à jour en fonction de cette valeur - Le fonctionnement d’Observable Inputs est assez déroutant, et la démo Synchronized Inputs peut aider
- Pour les cas où un flux de données purement fonctionnel ne suffit pas, un helper
mutableest aussi créémutableenregistre un objetMutablequi émet une nouvelle valeur lorsque la valeur change
Publication de la bibliothèque et diapositives de présentation
- Cette implémentation devait d’abord s’appeler
incel, puis a ensuite été envisagée sous le nomceline - La bibliothèque est publiée sous le nom @celine/celine
- Ce document a été présenté en démo à SydJS
- Du code est aussi inclus pour transformer le document en diaporama
Shift+N: démarrer le diaporama ou passer à la diapositive suivanteShift+B: diapositive précédenteShift+E: quitter le diaporama
- Le code de l’implémentation est disponible sous forme de source code
1 commentaires
Avis sur Hacker News
Je suis fortement d’accord avec le postulat de l’article. HTML peut constituer une excellente base pour des notebooks computationnels.
Cela dit, les choix d’implémentation ici ne me plaisent pas. Du HTML dynamique et réactif peut être rendu bien plus déclaratif que cela, et Observable est génial, mais il s’écarte par certains aspects du JavaScript standard.
J’ai commencé à créer un système de HTML réactif appelé Heximal, auquel j’ajouterai plus tard la prise en charge des notebooks. C’est un système déclaratif basé sur des templates HTML et des éléments personnalisés, avec par-dessus un système d’expressions/réactivité fondé sur la proposition TC39 Signals.
https://github.com/elematic/heximal
Cela ressemble plutôt à un mélange de HTMX, Tangle, Curvenote et Polymer, et j’imagine que c’est à cela que ressemblerait HTML s’il avait été réactif dès le départ. Je pense que cela conviendrait assez bien aux cas d’usage d’édition graphique et de notebooks.
C’est pourquoi les expressions de débogage JavaScript ordinaires fonctionnent correctement dans Observablehq.
https://github.com/observablehq/parser
J’aime tellement le runtime Observable que j’ai aussi créé un décompilateur capable de convertir dans les deux sens entre le code source frontend et la représentation compilée en JS pur.
https://observablehq.com/@tomlarkworthy/observablejs-toolcha...
Vraiment excellent. J’ai particulièrement aimé la démo Python et SQLite. C’est intéressant de partir d’une boucle d’édition via le Web (TTW) et d’appeler cela une quine ; c’est défendable, mais le principal point faible reste la persistance.
TiddlyWiki fait en fait à peu près la même chose, mais l’enregistrement du travail est problématique. Car pour rendre quelque chose persistant, il faut au bout du compte un processus serveur headless distinct.
Quand j’ai voulu construire quelque chose de similaire[0], j’ai personnellement commencé par la persistance, ce qui voulait évidemment dire des fichiers. Des fichiers en texte brut, éditables avec un éditeur pour programmeurs et stockables/déployables via le système de fichiers. Cela permet d’éviter d’avoir à réimplémenter un éditeur pour programmeurs dans le navigateur, ce qui est loin d’être trivial.
En contrepartie, il faut écrire un serveur rapide, mais c’est aussi un problème assez amusant[1]. Ici, ce problème a été évité en utilisant des sections
contenteditablede base, mais c’est le plus gros sujet après la persistance.L’impossibilité de faire des
exportdans les scripts embarqués me semble relever du même mur. Ce serait utile pour éviter d’encombrer l’objet globalwindow, et dans mon cas d’usage cela faciliterait aussi la génération de code.0 - Literate Markdown : https://simpatico.io/lit.md
1 - Reflector, un petit serveur node qui transforme, compresse et met en cache du Markdown, avec invalidation par surveillance de fichiers : https://simpatico.io/reflector
Je respecte la réflexion et les efforts investis, mais l’utilisabilité de cette approche est atroce. Je ne vois pas pourquoi, alors qu’on essaie de faire de l’analyse exploratoire de données, il faudrait aussi se préoccuper d’éléments de style.
C’est précisément pour cela que des outils comme les notebooks Jupyter fonctionnent bien. Cela dit, j’apprécie beaucoup la curiosité et le fait d’avoir concrétisé une idée alternative.
Ce n’est pas encore suffisant comme plateforme d’analyse exploratoire de données. Il n’y a pas la réactivité immédiate d’un véritable éditeur de code web comme Observable Notebooks, ni le hot reloading basé sur la surveillance de fichiers qu’offre Observable Framework. Le nouveau kernel Jupyter pour Deno + VSCode offre lui aussi une expérience assez fluide.
Donc, pour l’utilisabilité en analyse exploratoire, euh… je suis d’accord pour dire qu’elle est mauvaise, mais je trouve que l’utilisabilité pour la diffusion n’est pas si mauvaise. En fait, elle est bonne. Tout simplement parce que c’est un fichier unique. Si l’on veut envoyer à quelqu’un un graphe et des résultats de traitement de données, pas besoin de maintenir une énorme toolchain ni de payer un service tiers : il suffit de déposer un fichier HTML dans Slack ou de l’héberger quelque part.
La flexibilité qui permet de styliser les résultats d’analyse permet aussi de les publier dans des contextes où le style compte, comme un blog ou un article de recherche.
ivoryparredmodifie la coloration syntaxique en temps réel l’illustre bien.Je comprends le cheminement qui a mené jusque-là, mais je trouve dommage qu’il ne soit pas plus facile de jouer avec des frameworks et bibliothèques JavaScript dans le navigateur. Au bout du compte, ce n’est que du JS, et on devrait pouvoir expérimenter rapidement dans un environnement léger. Cette approche est forte sur ce point.
C’est une manière de retrouver le potentiel ludique et expérimental de HTML/JS. J’aimerais voir davantage d’initiatives de ce genre plutôt que TS, rollup, webpack, etc.
Ajout : après avoir lu un peu plus, je vois que c’est proposé pour l’analyse de données. Je ne pense pas que ce soit très adapté à cet usage.
Je pense qu’il y a beaucoup de valeur dans une alternative aux notebooks Jupyter qui ne finissent pas simplement à la poubelle. L’expérience utilisateur actuelle est vraiment médiocre, mais cela peut être amélioré. La question est de savoir si cette configuration est meilleure que le chaos JSON des notebooks Jupyter ; personnellement, j’aurais tendance à dire que oui.
L’auteur original de Lit a récemment quitté Google et, à ma connaissance, travaille sur quelque chose de très similaire.
https://github.com/elematic/heximal
J’aime le format de cet article. Il part de zéro et construit progressivement quelque chose d’intéressant. Ce n’est pas une fuite en avant tape-à-l’œil consistant à empiler des dépendances ou à greffer des frameworks dans tous les sens.
Pour suivre, il me semble qu’il suffit de copier-coller les fragments proposés et de comprendre étape par étape comment ils fonctionnent. Si j’écrivais quelque chose comme ça, je pense que je le ferais en programmation lettrée avec org-mode, puis que je l’exporterais en HTML pour en faire un billet de blog.
En revanche, une police avec coloration syntaxique intégrée continue de me laisser perplexe.
On parle de HTML réactif, mais est-ce que ce n’est pas presque entièrement du JavaScript, ou est-ce que j’ai mal compris quelque chose ?
À part le navigateur, il ne dépend d’aucun logiciel tiers ; comme HTML, il est durable, portable et facile à utiliser.
J’essaierai bientôt de prendre en charge ce type de notebook HTML dans Raku, ou pour Raku.
Actuellement, les « solutions de notebook » de Raku sont soit basées sur Jupyter, soit sur Mathematica.
Je ne comprends pas bien l’argument qui consiste à rendre ce processus plus complexe en y ajoutant des technologies web. Quel problème cette complexité supplémentaire résout-elle ? Au contraire, cela semble plutôt ralentir le processus et supprimer des fonctionnalités nécessaires comme l’autocomplétion, les snippets et les extensions.
En plus, il y a de fortes chances que les autres ne soient pas habitués à cette configuration, ce qui rend aussi la collaboration plus difficile.
Il suffit de configurer l’environnement une fois, puis de continuer à l’utiliser en ajoutant seulement de petites améliorations au fil de l’évolution des technologies.
Pour les utilisateurs de n/vim, ce qui suit suffit largement. 1- Exploration des données : utiliser https://github.com/untitled-ai/jupyter_ascending pour relier du texte à un notebook Jupyter. Comme cela utilise jupytext, on peut éditer et exécuter efficacement du code depuis un éditeur de texte.
2- Rédaction : pour LaTeX, on peut utiliser https://github.com/lervag/vimtex.
En ajoutant tmux et tmuxp par-dessus, on peut ouvrir un projet instantanément. Dans Emacs, org mode[1][2] et/ou Auctex permettent de mettre en place un processus fluide.
[1] https://sqrtminusone.xyz/posts/2021-05-01-org-python/
[2] https://martibosch.github.io/jupyter-emacs-universe/
Cela dit, comme je n’aime pas particulièrement Python, j’ai envie d’utiliser des outils qui ne soient pas centrés sur Python. C’est pour cela que j’ai parlé de Raku et de Mathematica.
Au passage, merci de m’avoir signalé https://github.com/imbue-ai/jupyter_ascending.
Je suis globalement d’accord avec le postulat de cet article, à savoir que HTML est sous-exploité comme support de diffusion pour l’écriture scientifique.
Il y a des travaux récents de Will Crichton sur ce sujet.
https://willcrichton.net/nota/
https://willcrichton.net/notes/portable-epubs/.
Les notebooks ont clairement le vent en poupe en ce moment. Nous avons aussi lancé une version de notebook TypeScript[1], mais nous avons fait des choix assez différents en termes de compromis.
Comme nous voulons exécuter du code backend node, contrairement à l’approche de cet article ou à Observable, nous n’essayons pas de l’exécuter dans un environnement navigateur. Cela dit, pour beaucoup d’applications, cette idée peut être une meilleure solution.
Bravo à l’auteur.
https://github.com/srcbookdev/srcbook