Modified
Can we build a reactive article in a single HTML file?
Yes (by standing on the shoulders of Observable).Before I start, why am I doing this?
I don't think HTML is being used enough as a platform for scientific publishing.
Instead, people will:
- First use an interactive notebook like Jupyter, Pluto.jl or Observable to do data exploration, analysis and visualisation,
- Then move to publishing platforms like Quarto, Typst, Overleaf, pure LaTeX, or a WYSIWYG editor to typeset their work.
I think self-contained HTML files can be used for both of these stages, and prevent a lot of faffing around with CLI tooling, CI steps, or 3rd-party platforms.
HTML's typesetting capabilities are well documented, but its capabilities as a platform for data exploration, analysis and visualisation are not.
I'll try and demonstrate these capabilities, literate programming style.
Cells
First, we'll steal a trick from This page is a truly naked, brutalist html quine, and create a CSS class calledecho
that will display/reflect style
and script
elements inline.
This style
block has effectively styled itself.
Now we'll import the Observable standard library and the Observable runtime, and bind them to window
.
We'll define helper methods cell
and observer
that wrap some of the runtime API.
Now we'll declare a cell called counter
that emits a number every second.
The script
's id
attribute is the same as the name
parameter passed to cell
.
Now that we've created a our counter
cell, we can create other cells that depend on it.
We'll import Hypertext Literal and use it to format the
counter
value.
We'll import Observable Plot and use the counter
value in the plot.
We should always store data in their own script
elements, so that they can be easily referenced by other cells.
Inputs
We'll create a new cell typeviewof
that works specifically with Observable Inputs.
It declares 2 reactive cells: NAME
and viewof NAME
- one for the value, and one for the DOM element itself.
Wiggle the range input and see another dependent cell update.
Mutability
Purely functional dataflow is great, but sometimes you just need to mutate state. We'll create a new cell typemutable
. It registers a Mutable
- an object that yields new Generator
values when the value is mutated - in the runtime.
TeX, Markdown, Graphviz
What's the point otherwise?SQLite
I've hosted the Chinook sample database on my website at https://maxbo.me/chinook.db. Now we'll use a WASM-backed SQLite client to query it.Python
The Pyodide CPython WASM distribution includes NumPy, Pandas, Matplotlib, scikit-learn, and Scipy. We'll rebuild the plot seen above, but using Matplotlib and Python'ssqlite3
module instead.
R
You know the drill. It's R, using WebR. I didn't figure out how to get ggplot2 rendering working, but I assume it's possible. I must disclose that this cell seems to be a bit flaky on iOS. I have not had a chance to investigate further, nor will I.3D models
We can use Google's<model-viewer>
Web Component to display 3D models.
Cell status
Observable'sInspector
can apply an observablehq--running
or
observablehq--error
class to the cell's div
result element.
We'll style them appropriately: