Precomputing with Pluto

This post will be mainly about precomputing a Pluto notebook with the PlutoSliderServer package. But first, a little background is in order (but if you want to just skip ahead use the links below)

Introduction

I first heard of the Julia programming language back in 2018 from a student visiting CSL from Belgium. Shortly after, I tried using it in my nascent cyclicity analysis project and gave up on the endeavor within a couple of weeks. Simply put - back in 2018 the Julia eco-system was just not rich enough to accommodate the tasks that I wanted to accomplish.

Fast forward five years, and in Spring 2023 I taught a course where I made heavy use of Julia to create the course website (fun fact: even this website is created using a static website generation system powered by Julia). Apart from the explosive organic growth that the Julia ecosystem has experienced in the intervening time, the single greatest addition - in my humble opinion - to the Julia ecosystem has been Fons van der Plas' Pluto notebook system (for all the Pythonistas do you see what he did there?)

Articles that extol the virtues of the Julia programming language over its competition (mainly Python) are dime-a-dozen and I will not list the pros or cons here; except maybe to opine that:

  • As much as I love working in Julia, I still don't see it as a good first language to learn computation or programming for the CS/CE or EC/EE departments[1]. Indeed the features that make it advantageous over Python (type system, multiple dispatch, functional paradigm, metaprogramming, etc.) are not introductory topics for CS101.

  • However, it is a solid candidate for a second language (more so if you would like a functional language in your toolbelt) or (and this might sound controversial to some departments) as a replacement to proprietary scientific languages like MATLAB, especially if the program only intends to teach a scientific computing language.

That being said let us dive into the meat of this post; that is how to export a Pluto notebook as an HTML page while maintaining interactivity. As a side note if you have not seen what Pluto notebooks can do visit: https://plutojl.org/ and check it out.

Exporting from Pluto

Apart from a built-in within-notebook package management system to ensure reproducibility, excellent aesthetics, and obvious reactivity, another place that Pluto excels in is the options it offers for export. The typical options that Pluto offers are shown below:

 Figure 1: Default export options available in Pluto
Figure 1: Default export options available in Pluto

Static exports

The first and third options are relatively straightforward. They allow you to download the current state of the notebook as a Julia script file or (when e-mailing code attachments are not supported) a PDF file. With the first approach, your recipient will need to run the script in Julia[2] or load it up in Pluto, while with the latter approach, you get a static PDF which may not look all that great. The second option, a static export to HTML is the middle ground - but wouldn't it be great if we could maintain interactivity? For example, you might simply want to post the notebook to your website while making sure the sliders and UI work.

Dynamic exports

This is what the PlutoSliderServer package is all about. The elaborate (or in some sense proper) way is to run a Linode or DigitalOcean or <insert-prefered-platform> server that will serve the results of computations dynamically whenever a slider or dropdown or some interactive element in the HTML page is updated by the visitor. This is the approach the MIT Intro to Computational Thinking course website takes (though only the current offering is likely to be interactive). This method is a bit involved and is roughly outlined in the GitHub README file of the package.

However, there is a second way which is not all that well documented (mostly because it is a work-in-progress) but it is quite usable for small notebooks and select UI elements: see example. This second method is what we will do in the next section but before that I should mention that the last option in the image above is pretty cool as well: it will record an HTML file with an embedded screencast of your notebook along with any audio/voiceover you choose to add!

Precomputing with Pluto

The key idea with precomputation is that if the combinatorial graph produced by considering all the interactive elements is not too large; then the possible outputs that a server would compute and serve, can be precomputed and stored ahead of time to simulate interactivity.

⚠️ Note
Since Fons is still working on this feature; these instructions may become out of date at some point. We also assume that you have a working installation of Julia callable from a *nix terminal.

For the next part here is a simple Pluto notebook file to test things out: example.jl

Set up

We will try to create a precomputed static export of the example.jl file using PlutoSliderServer.

First place a copy of the example file in a fresh direcotry, cd into it and open a Julia prompt there in Pkg mode. That is, after the standard Julia REPL prompt appears, hit ] to go into package mode) and initialize a new project.

> julia --project=. 
] instantiate
❗ Caution
In the above > is the shell prompt, and ] the Julia package mode prompt. If you are using the copy button, make sure you remove the extra characters and enter the commands at the right prompts

To get out of the package mode hit Delete (or backspace). Next hit ; to go into the shell mode without exiting Julia. Create a new directory called pluto-slider-server-environment then cd into it and run the git clone command.

> mkdir pluto-slider-server-environment
> cd pluto-slider-server-environment
> git clone -b static-export-bundled --single-branch https://github.com/JuliaPluto/PlutoSliderServer.jl.git

The above command will clone the source code from the branch of the PlutoSliderServer package that has precompute enabled.

Next open a new Julia REPL from inside the pluto-slider-server-environment directory and in the package mode add the just downloaded package:

> julia --project=.
] add ./PlutoSliderServer.jl

The first line will start Julia with the pluto-slider-server-environment directory as the project directory and the second line will install the locally available (because we just cloned it) version of the package.

Configuration

Next create a PlutoDeployment.toml file within the pluto-slider-server-environment directory using your favourite text editor. This will hold some configuration variables that mostly do what you think they do:

[Export]
offer_binder = false
disable_ui = true
enabled = true
output_dir = "../www"
ignore_cache = [
    "index.jl",
]

[SliderServer]
port = 8000
host = "0.0.0.0"

[Pluto]
[Pluto.compiler]
threads = 2

[Precompute]
enabled = true
max_filesize_per_group = 10000000

Export

At this point we are ready to try and export the example.jl file as a precomputed HTML file. To do so open a Julia prompt from the pluto-slider-server-environment directory and issue from the Julia REPL (signified with a julia>)

julia> using PlutoSliderServer 
julia> export_notebook("../example.jl")

To test interactivity of the precomputed file run a http server on the local host through some port. For example, cd into the www output folder that should have been created and do:

> python3 -m http.server 8000

to serve the page on port 8000. To see the page visit localhost:8000 in your browser.


Footnotes

[1] I should note that MIT has been teaching their Introduction to Computational Thinking Course in Julia, but MIT invented the langauge so 🤷.
[2] Pluto notebooks are runnable as standalone Julia scripts; but the onus on package management is then with the user.