Quarto for preprints

Author
Affiliation

Ivan Abraham

University of Illinois, Urbana-Champaign

Published

July 9, 2023

Abstract: We discuss how the Quarto ecosystem can be used to create HTML output that retains some of elements of interactivity without requiring the use of a droplet or server like Pluto. This page showcases an article/preprint layout.

1 Background

In the last post, we described how one can use Pluto notebooks to export analysis, results, graphs, etc. as HTML pages while retaining some of the interactivity and reactivity. If you are unfamiliar with the Pluto ecosystem the last post has a small introduction or better yet head over to: https://plutojl.org/ and take a look for yourself.

Apart from using Julia to generate the course website for the last course I taught, I also started transitioning away from Python for my research and analysis in the last year. The impetus has been (a) my interest in Julia and (b) the advantages of Pluto notebooks. They have been an excellent way to do analysis and share results with colleagues or co-authors asynchronously - i.e., face-to-face meetings are not possible and Zoom meetings are sporadic. The dynamic, interactive & reproducible nature of the notebooks meant that I could run a small Ubuntu droplet/server instance accumulating and presenting the results which co-authors could peruse in detail at their convenience and reproduce if interested.

Now running a server/droplet is not free forever, so this got me interested in looking for publishing methods (primarily to share preprints) that could provide as much of the functionality of a server running Pluto as possible (a true compute node cannot be replaced of course) but can be done so statically. We explored one such option with precomputation in Pluto in the last post. However, this is limited by the requirement of a modest combinatorial graph as well as being far from production ready. Enter Quarto

This very page is written using the Quarto system - hence the different look/feel and absence of the menu at the top of the page. Quarto allows one to intersperse LaTeX, Markdown, (one of) Julia, Python, or R code to create documents in several formats. Of the three languages currently supported, R actually seems to be the native language for Quarto in some sense; its syntax is based on RMarkdown and true interactivity via Observable is currently only available if using R and finally, in RStudio one can directly create a Quarto document from the file menu. Overall, my feeling has been that Quarto toolkit/chain is mature, and both actively maintained and developed. Since there is extensive documentation available for those who are interested in how to get started; I will not go attempt to recreate those; rather I will share some tips/observations and tricks I have had to use with Quarto.

This page uses Julia in Quarto and you can find the source here. or by cliciking on the </> icon next to the floating menu at the top.

2 How to?

To use Quarto with Julia requires some initial setup since it uses Julia via the Jupyter notebook system. Therefore for using Quarto with Julia; one will need a working Julia installation with the IJulia package installed (for Jupyter to find a Julia kernel).

Note

In the following we assume that the reader has a working Julia installation callable from the terminal and that they have been able to install the Quarto toolkit without much effort.

While Quarto documentation has a page on using Julia I found it to be a bit of overkill in terms of just getting started. Moreover, if you simply follow their instructions you will likely end up installing packages to global Julia environment. The recommended modus operandi in Julia is to instantiate or create a project directory for each siloed project.

Let us assume the contents of the archive in the link to the right have been placed in a directory called quartopage. To get started one would run:

Find the source files for this page in this archive.

$> julia --project=.

from inside the quartopage folder to open the Julia REPL, switch to the package mode (hit ] on the keyboard) and issue the command

(quartopage)> instantiate

which will set up the Julia environment (could take a few minutes).

Tip

The $> signifies the standard shell prompt and (quartopage)> signifies the changed Julia prompt on switching to package mode. In particular neither of these are part of the command to be issued. In the following julia> will also signify the standard Julia REPL prompt.

2.1 Jupyter set up

Next we need to make sure a Julia kernel is available to use for Quarto. Running in the Julia REPL (hit the backspace key to quit the package mode):

julia> using IJulia 
julia> notebook()

will prompt permission to install a Jupyter kernel private to Julia via the Conda.jl package. We recommend saying yes to keep this (mini)conda installation separate from any other on your system. The notebook() command will open up a Jupyter window in your browser but you can click Quit and close the window.

2.1.1 Optional - install jupyter-cache

For the cache option to work we need to have conda (the one just created above) install the jupyter-cache package. To find out where conda was installed type in the Julia REPL:

julia> import Conda; Conda.BINDIR

Navigate to the reported directory and run (from the shell not Julia REPL):

$> ./conda install jupyter-cache

to get caching set up and ready.

2.2 Kernel name specification

Note that the front matter of the souce .qmd file of this document lists:

execute: 
  echo: true
  cache: true 
  keep-ipynb: false
  freeze: auto
citation-location: document 
bibliography: references.bib 
csl: citestyle_ita.csl 
number-sections: true
jupyter: julia-1.9

where the very last line is the name of the Jupyter kernel that was installed. You may need to change this depending on your Julia version. To list all available kernels do

$> ./jupyter kernelspec list

from the Conda.BINDIR directory.

Tip

If you have followed along so far in your terminal and just want to see if Julia and Quarto will play well together skip ahead to Section 2.5.

2.3 Including code and figures

For the purposes of illustration, let us implement the crosscross function from [1] in Julia here.

We will talk about adding references in a little bit. Note: In the code blocks to the left we assume all the necessary packages have been installed in the applicable Julia environment for the quartopage folder.

# This is Julia code; it will not run in MATLAB or Python.
using  StatsBase

function crosscorr(x, y)
    lx, rxx, lags = length(x), AbstractFloat[], Integer[]
    x = vcat(zeros(lx-1), x, zeros(lx-1))
    lags_ranges = [(k-lx, k:k+lx-1) for k=1:2*lx-1]
    
    foreach(lags_ranges) do (lag, range)
        push!(rxx, mean(x[range].*y))
        push!(lags, lag)
    end
    return lags, rxx
end;

Now let us find the cross-correlation between a sine wave and a sinc function. We will additionally write a function to plot them but refrain from calling it until the Section 3 (just to illustrate cross-referencing and that code we write is common to the whole document).

using Plots, Plots.Measures

function make_plot(sigs, ccorr)
    t, x, y = sigs 
    local p1 = plot(t, x, label="Sine wave")
    local p1 = plot!(p1, t, y, label="Sinc function", xlabel="Time",
                     ylabel="Amplitude")
    local p2 = plot(ccorr..., label=false, xlabel="Lag", 
                    ylabel="Correlation value", color=:green)
    return plot(p2, p1, layout=(1, 2), plot_title="Example", 
                size=(700, 400), margin=5mm)
end;

t = 0:0.01:2π;
x,y  = sin.(t), sinc.(t);

Note that the above code is actually run by Quarto in a Jupyter notebook and the output cells (if any) are transplanted into the rendered HTML documents.

2.4 Adding citations

The frontmatter of this document’s source .qmd file lists:

bibliography: references.bib 
csl: citestyle_ita.csl

The first file is a standard .bib file familiar to LaTeX users. The second is a Citation Specification Language file we cooked up for this page. Both should be available in the archive file you can download.

2.5 Using Quarto

We will skip the Quarto installation instructions because they are beautifully detailed elsewhere. If Julia and its Jupyter kernel have been set up correctly then you should be simply able to run

$> quarto preview

from the quartopage directory and see this very page in a new window in your browser.

3 Results

The result of calling the makeplot function defined above is presented in Figure 1 below. Note that you are able to interact with the image to some extend thanks to Julia’s integration with plotly.

plotly()
pp = make_plot((t, x, y), crosscorr(x, y))
display(pp)
Figure 1: A cross correlation example

4 Post-script

If you ran into trouble; leave a comment for me using the Hypothesis annotation service on the right side of the page; click < and expand the hidden menu.

Warning

I should say I haven’t had a chance to try this annotation service out myself; so it remains experimental.

Hopefully, I should be able to post a few more such documents and pre-prints in the near future and see how much we can achieve within the Quarto ecosystem vis-à-vis posting interactive pre-prints.

References

1.
Semmlow, John. 2018. Chapter 2 - signal analysis in the time domain. In Circuits, signals and systems for bioengineers (third edition), ed. John Semmlow, Third Edition, 51–110. Biomedical Engineering. Academic Press. https://doi.org/https://doi.org/10.1016/B978-0-12-809395-5.00002-3.