Notebook HTML reativo
(maxbo.me)- Com apenas um arquivo HTML único executado pelo navegador, é possível reunir exploração, análise, visualização de dados, composição tipográfica e publicação em um só documento, reduzindo o fluxo tradicional notebook → ferramenta de publicação → PDF
- A implementação central combina células de echo que exibem
styleescriptna tela,contenteditablee o Observable Runtime para criar células reativas editáveis cell(name, inputs, definition)segue o modelo de dependências do Observable para compor unidades de execução conectadas entre si, comocounter, renderização de FizzBuzz, células ocultas e células intermediárias sem saída- Dentro do mesmo documento HTML, são demonstrados Observable Plot, TeX, Markdown, Graphviz, SQLite baseado em WASM, Python com Pyodide, R com WebR, Observable Inputs e até estado
Mutable - O resultado é um documento científico ou técnico executado no navegador sem depender de plataforma separada, e a implementação depois foi publicada como a biblioteca
@celine/celine
Reduzindo a separação entre notebook e publicação com um único arquivo HTML
- O HTML é amplamente usado para composição tipográfica, mas foi relativamente menos explorado como plataforma de exploração, análise e visualização de dados
- O fluxo de trabalho comum passa por várias ferramentas
- Se um único arquivo HTML assumir essas três etapas, é possível reduzir procedimentos manuais, ferramentas de CLI, etapas de CI e dependência de plataformas de terceiros
- A implementação foi fortemente influenciada por Anton Zhiyanov em In-browser code playgrounds, Cristóbal Sciutto em Self-modifying HTML notes, Quarto e Observable Framework
Criando células editáveis
- A primeira etapa é usar a classe CSS
echopara fazer com que elementosstyleescriptfiquem visíveis dentro do documento - Com uma fonte com realce de sintaxe embutido e o atributo
contenteditable, isso pode funcionar como um editor de código básico - Um
scriptcomcontenteditableé reavaliado quando perde o foco- O
scriptexistente é clonado para criar um novo elementoscript, e o original é removido - Isso é necessário porque
evalnão funciona com código que contém instruçõesimport
- O
- Para execução baseada em Observable, duas bibliotecas são carregadas
- Apenas dois símbolos são expostos no escopo global:
libraryecell
Fluxo de dados reativo com Observable Runtime
- A função
cell(name, inputs, definition, observerVisibility)define células usando o escopo de módulo do Observable Runtime - Se já existir uma variável com o mesmo nome, ela é reutilizada; caso contrário, cria-se uma nova variável para defini-la
- Graças a essa estrutura, quando uma célula
contenteditableé reavaliada, a nova definição se propaga para as células conectadas
- Graças a essa estrutura, quando uma célula
- O
Inspectordo Observable é usado para mostrar a saída das células acima do blocoscript - A célula
counteré composta como um gerador assíncrono que emite um número a cada segundo- O atributo
iddoscripte o argumentonamedecellsão iguais - Se o valor inicial
ifor alterado e o foco for removido, o novo valor passa a ser refletido
- O atributo
- Também é possível criar células que dependem de
counter- Importa-se Hypertext Literal para renderizar o valor de
counterno formato FizzBuzz htlimplementa um parser HTML5 e lida com escape automático, listeners de evento, objetos de estilo e interpolação de valores não serializáveis, como nós DOM
- Importa-se Hypertext Literal para renderizar o valor de
Células visíveis, ocultas e sem saída
- Sem a classe
echo, é possível ocultar a definição da célula e ainda assim observar a saída- Essas células podem ser usadas como primitivas de renderização
- Também é possível criar um tipo de célula que não exibe a própria saída
silent(name, inputs, definition)defineobserverVisibilitycomo oculto, podendo ser usada para armazenar valores intermediários ou estruturas de dados
- As células podem funcionar independentemente da ordem de declaração
- No exemplo, a célula
reallyNegativedepende da célulanegative, declarada mais tarde
- No exemplo, a célula
- O mesmo valor de célula também pode ser usado em saídas mais complexas
- Importa-se Observable Plot para desenhar um gráfico de linha a partir de um array numérico e mostrar uma linha vertical na posição
counter % 40
- Importa-se Observable Plot para desenhar um gráfico de linha a partir de um array numérico e mostrar uma linha vertical na posição
Expandindo a saída de documentos e visualizações
- Uma célula pode retornar qualquer elemento DOM
- As demos de TeX, Markdown e Graphviz retornam elementos de tipos diferentes
- A célula
texretorna um elementospan - A célula
mdretorna um elementotable - A célula
dotretorna um elementosvg
- A célula
- Uma célula pode retornar uma
Promiseou lançar umError- O
Inspectordo Observable aplica a classeobservablehq--runningàdivexterna da célula em execução - Em células com erro, aplica a classe
observablehq--error - O documento define estilos de acordo com esses estados
- O
SQLite, Python e R no navegador
- A demo de SQLite hospeda o Chinook sample database em
https://maxbo.me/chinook.dbe faz consultas com um cliente SQLite baseado em WASM- É possível tentar adicionar
WHERE Milliseconds < 1000000à consulta SQL
- É possível tentar adicionar
- A demo de Python usa a distribuição WASM do CPython do Pyodide
- O Pyodide inclui NumPy, Pandas, Matplotlib, scikit-learn, Scipy
- O gráfico criado antes é refeito com Matplotlib e o módulo
sqlite3do Python
- A demo de R usa WebR
- A renderização com ggplot2 não foi implementada, mas parece viável
- Essa célula parece um pouco instável no iOS, e não houve investigação adicional
Entradas e estado mutável
- O tipo de célula
viewoffoi criado para uso com Observable Inputs viewofdeclara duas células reativasNAME: o valor da entradaviewof NAME: o próprio elemento DOM
- Para mostrar a entrada acima da célula, é preciso definir o
idda célula comoviewof NAME - No exemplo, cria-se uma entrada de faixa com
Inputs.range([0, 100], { step: 1 }), e a célularangePloté atualizada de acordo com esse valor - O funcionamento do Observable Inputs é um pouco difícil de entender, e a demo Synchronized Inputs pode ajudar
- Para casos em que um fluxo de dados puramente funcional não basta, também foi criado o helper
mutablemutableregistra um objetoMutableque emite um novo valor quando ele é alterado
Publicação da biblioteca e slides para apresentação
- A implementação inicialmente pensou no nome
incel, mas depois passou a ser chamada deceline - A biblioteca foi publicada como @celine/celine
- Este documento foi demonstrado no SydJS
- Também há código incluído para transformar o documento em apresentação de slides
Shift+N: iniciar o slideshow ou avançar para o próximo slideShift+B: slide anteriorShift+E: encerrar o slideshow
- O código da implementação está disponível como source code
1 comentários
Comentários do Hacker News
Concordo fortemente com a premissa do texto. HTML pode ser uma excelente base para notebooks computacionais
Dito isso, não gosto das escolhas de implementação feitas aqui. HTML dinâmico e reativo pode ser feito de forma muito mais declarativa do que isso, e o Observable é legal, mas em alguns pontos foge do JavaScript padrão
Comecei a criar um sistema de HTML reativo chamado Heximal, e depois pretendo adicionar suporte a notebooks também. É um sistema declarativo baseado em templates HTML e elementos personalizados, com uma camada de expressões/reatividade baseada na proposta TC39 Signals por cima
https://github.com/elematic/heximal
É mais ou menos uma mistura de HTMX, Tangle, Curvenote e Polymer, e parece como o HTML seria se já tivesse sido reativo desde o início. Acho que combina muito bem com casos de uso de edição gráfica e notebooks
Por isso, expressões normais de depuração em JavaScript funcionam corretamente no Observablehq
https://github.com/observablehq/parser
Gosto tanto do runtime do Observable que até criei um descompilador capaz de converter nos dois sentidos entre o código-fonte do frontend e sua representação compilada em JS puro
https://observablehq.com/@tomlarkworthy/observablejs-toolcha...
Muito legal. Gostei especialmente da demo de Python e SQLite. É interessante que isso parta do loop de edição via web (TTW) e o chame de quine; faz sentido, mas a principal fraqueza é a persistência
O TiddlyWiki essencialmente faz a mesma coisa, mas salvar o trabalho é um grande problema. Porque, no fim, para persistir qualquer coisa, você precisa de um processo de servidor headless separado
Quando quis criar algo parecido[0], pessoalmente comecei pela persistência, e isso naturalmente significava arquivos. Eram arquivos de texto puro que podiam ser editados em um editor para programadores e salvos/publicados via sistema de arquivos. Isso evita o problema de ter de reimplementar um editor para programadores dentro do navegador, o que não é nada trivial
Em troca, surge o problema de escrever um servidor rápido, mas esse também é um problema bem divertido[1]. Aqui isso foi contornado usando seções contenteditable básicas, mas esse é o segundo maior problema, depois da persistência
O fato de não ser possível usar export dentro de scripts embutidos também parece ser a mesma barreira. Seria bom ter esse tipo de recurso para evitar bagunçar o objeto global window, e no meu caso de uso isso também tornaria a geração de código mais fácil
0 - Literate Markdown: https://simpatico.io/lit.md
1 - Reflector, um pequeno servidor node que transforma, comprime e faz cache de markdown, além de invalidar observação de arquivos: https://simpatico.io/reflector
Respeito as ideias e o esforço investidos, mas a usabilidade dessa abordagem é terrível. Não entendo por que eu teria que me preocupar até com elementos de estilo enquanto tento fazer análise exploratória de dados
Esse é exatamente o motivo de ferramentas como o Jupyter Notebook funcionarem tão bem. Ainda assim, valorizo bastante o fato de terem implementado uma ideia alternativa por curiosidade
Ainda não é suficiente como plataforma de análise exploratória de dados. Não tem a responsividade imediata de um editor de código web completo como o Observable Notebooks, nem é o Observable Framework, que oferece hot reloading baseado em monitoramento de arquivos. O novo kernel Jupyter para Deno + VSCode também proporciona uma experiência bem fluida
Então, quanto à usabilidade para análise exploratória, é... concordo que é ruim, mas acho que a usabilidade para publicação não é tão ruim assim. Na verdade, é boa. Porque é simplesmente um arquivo único. Para enviar a alguém gráficos e resultados de processamento de dados, você não precisa manter uma cadeia enorme de ferramentas nem pagar por um serviço de terceiros; basta jogar um arquivo HTML no Slack ou hospedá-lo em algum lugar
Graças à flexibilidade para estilizar os resultados da análise, também dá para publicar em contextos onde o estilo importa, como blogs ou artigos de pesquisa
ivoryporredaltera o syntax highlighting em tempo real mostra issoEntendo o contexto que levou até aqui, mas é uma pena que ainda não seja fácil brincar com frameworks e bibliotecas JavaScript no navegador. No fim das contas, é só JS, então deveria dar para experimentar rápido em um ambiente leve. Essa abordagem tem força nesse ponto
É uma forma de recuperar o potencial lúdico e experimental de HTML/JS. Queria ver mais tentativas assim do que TS, rollup, webpack e afins
Adendo: lendo mais um pouco, vi que isso está sendo proposto para análise de dados. Para esse uso, não acho que se encaixe bem
Acho que há muito valor em uma alternativa ao Jupyter Notebook que não seja algo para jogar fora depois. A experiência do usuário está realmente péssima agora, mas isso pode melhorar. A questão é se essa configuração é melhor do que o caos em JSON do Jupyter Notebook, e pessoalmente acho que sim
O autor original do Lit saiu recentemente do Google e, pelo que sei, está trabalhando em algo muito parecido com isso
https://github.com/elematic/heximal
Gosto do formato deste texto. Ele começa do básico e vai construindo até chegar a algo interessante. Não segue aquela onda exagerada de amontoar dependências ou colar frameworks por todo lado
Para acompanhar, parece que basta copiar e colar os trechos apresentados e entender passo a passo como funcionam. Se eu fosse escrever algo assim, provavelmente faria com programação literária no org-mode e depois exportaria para HTML para virar um post de blog
Ainda assim, continuo em dúvida sobre a fonte com syntax highlighting embutido
Chamam isso de HTML reativo, mas não é quase tudo JavaScript? Ou entendi algo errado?
Tirando o navegador, não depende de software de terceiros e, como o HTML, é duradouro, portátil e fácil de escrever
Em breve quero tentar dar suporte a esse tipo de notebook HTML em Raku, ou para Raku
No momento, as “soluções de notebook” de Raku são baseadas em Jupyter ou em Mathematica
Não entendo a lógica de usar tecnologias web para complicar esse processo. O que essa complexidade adicional resolve? Na verdade, parece mais algo que torna o processo mais lento e remove recursos necessários como autocompletar, snippets e extensões
Além disso, é bem provável que outras pessoas não estejam familiarizadas com essa configuração, então colaborar também fica mais difícil
O ambiente pode ser configurado uma vez e depois continuar sendo usado, acrescentando apenas pequenas melhorias conforme a tecnologia evolui
Se você usa n/vim, o seguinte já é suficiente. 1- Exploração de dados: use https://github.com/untitled-ai/jupyter_ascending para conectar texto a notebooks Jupyter. Como usa jupytext, dá para editar e executar código com eficiência no editor de texto
2- Escrita: para LaTeX, você pode usar https://github.com/lervag/vimtex
Se adicionar tmux e tmuxp a isso, dá para abrir projetos instantaneamente. No Emacs, é possível montar um processo fluido com org mode[1][2] e/ou Auctex
[1] https://sqrtminusone.xyz/posts/2021-05-01-org-python/
[2] https://martibosch.github.io/jupyter-emacs-universe/
Só que eu não gosto tanto de Python, então quero usar ferramentas que não sejam centradas em Python. Foi por isso que mencionei Raku e Mathematica
E obrigado por indicar https://github.com/imbue-ai/jupyter_ascending
Concordo em grande parte com a premissa deste texto, ou seja, que HTML não está sendo aproveitado o suficiente como meio de publicação para escrita científica
Há um trabalho recente de Will Crichton relacionado a isso
https://willcrichton.net/nota/
https://willcrichton.net/notes/portable-epubs/
Notebooks estão em alta ultimamente. Nós também lançamos uma versão de notebook em TypeScript[1], mas escolhemos um lado bem diferente nos trade-offs
Queríamos executar código node no backend, então, diferentemente da abordagem deste texto ou do Observable, não tentamos rodar no ambiente do navegador. Ainda assim, para muitas aplicações, essa ideia pode ser uma solução melhor
Palmas para o autor
https://github.com/srcbookdev/srcbook