Create beautiful documents with R, Python, Julia and Observable


Data and Digital Storytelling Lead, 360info


  1. Hello!
  2. What are reproducible reports?
  3. What’s Quarto? Why can anyone use it?
  4. Web content



(Code for these slides is at https://github.com/jimjam-slam/talk-runapp-quarto-2022)


A picture of me and my PhD supervisor, Lisa Alexander, at my graduation.

A picture of me and MCCCRH staff members on Zoom.

A picture of me and MCCCRH staff members on a work trip.

A picture of Graham Creed from the ABC presenting climate projections.

A picture of Jane Bunn presenting statistics on shrinking winters.

I used to be a climate + health researcher

Worked with CLEX and MCCCRH on climate change communication

Now I’m a data journalist with

Poll: what tools do you use?

A picture of a QR code to the survey.

What are
reproducible reports?


  • Contain:
    • Writing
    • Code
    • Results in the file too

A picture of a Jupyter notebook loaded into Visual Studio Code.

Reproducible reports

Source documents are rendered to produce results

An R Markdown source document in a plain text code editor

An R Markdown document rendered into HTML with a plot in it.

The RMarkdown ecosystem

R packages for just about every kind of document:

xaringandistillblogdownhugodownbookdownthesisdownoxforddownunswthesisdownpagedownflexdashboardrmdformatsrticlesprettydocmarkdowntemplates • and more…

Literate programming foreveryone

Notebooks or documents

A picture of the same Quarto document side-by-side, written in notebook form on the left and document form on the right.

R, Python, Julia

A picture of the same Quarto document side-by-side, written in notebook form on the left and document form on the right.


Visual Studio Code logo

RStudio logo

Jupyter logo

RStudio visual editor

Editing a Quarto document in RStudio in the plain text view.

Editing a Quarto document in RStudio in the visual editor

Spicing up Quarto
with reactivity and Observable JS



Example: footy scores

menu + slider => chart of footy scores

Code is usually about doing things

  • Write code to create a control
  • Write code to check its value all the time
  • Write code to do things every time it changes
  • Write code to pass updates from one thing to another

This gets old quickly!


Reactive code just updates itself

Describe a control or input

Describe an output that reacts to the control’s changes

… there is no step 3

(the output takes care of itself!)

This is how Shiny and Dash work!

menu + slider => chart of footy scores

# describe some controls - a dropdown menu
# and a slider - and a plot

ui <- fluidPage(

    label = "Footy team",
    choices = c("Pies", "Blues",
      "Bombers", "Cats"),
    selected = "Blues"),
  sliderInput("year", label = "Year",
    1990, 2005, value = 1991),
# for the plot, filter our data and
# draw a line chart

server <- function(input, out) {
  output$footyScores <- renderPlot({

    scores %>%
      year == input$year,
      house == input$footyTeam) %>%
      ggplot(.) +
        aes(x = game, y = score) +

So why not use Shiny?

Shiny already works with R Markdown, and it works with Quarto too

But you need R running to react to things as people read the document, not just when you render it

This requires a special web server! (eg. shinyapps.io)

So why not use Shiny?

In media, charts could be viewed 100k+ times in days

(If I’m lucky…)

I can’t afford a Shiny server for that kind of traffic!

Enter Observable JS

Quarto gives us a new kind of code chunk called OJS

It lets us write JavaScript that is naturally reactive

Observable JS: no server required

We make a slider called x

viewof x = Inputs.range(
  [0, 100], { step: 1 })

… and then reference it:

md`The square of ${x} is ${x**2}!
  How about that!`

The text reacts to the changing value of x. Nice!

Footy example with Quarto + OJS

viewof footyTeam = Inputs.select(
  ["Pies", "Blues", "Bombers", "Cats"],
  { value: "Blues", label: "Footy team" })

viewof year = Inputs.range(
  [1990, 2005],
    value: 1990,
    step: 1, label: "Year",
    width: 300
scores = FileAttachment("data/footy-scores.csv")
  .csv({ typed: true })

// filter it using the controls
filteredScores = scores.filter(
  d => d.team == footyTeam &&
  d.year == year)

// make the chart
  marks: [
    Plot.barY(filteredScores, {
      x: "game",
      y: "score",
      fill: "game"
  x: {
    label: "Game number",
    labelOffset: 70
  y: { label: "Score" },
  width: 800,
  height: 500,
  marginLeft: 60,
  marginBottom: 90,
  marginTop: 60,
  style: { fontSize: 24 }

Quarto +

OJS means

  • You can do your data analysis in R, Python or Julia
  • You can make visuals that react to users
  • You don’t need to worry about the cost if it gets popular
  • Learning JavaScript is as easy as possible

R/Python Widgets

“Web content” in R Markdown usually involves a special R or Python package (eg. htmlwidgets)

👍 Convenient

👎 Customising means learning JavaScript and learning how an R package works

Quarto + OJS

It’s just JavaScript!

You get great libraries bundled in to try out JS:

  • Observable Plot for making charts
  • Observable Inputs for making controls
  • Arquero for data analysis (it’s just like dplyr)

Seriously, just like dplyr, I’m not even kidding

Remember the survey before?

I did that with Observable Plot and Arquero.

Here’s the code I used to tally up survey responses:

countsUsed = aq.from(surveyResults)
    used: d => op.split(d.responseUsed, ", ")
  .derive({ measure: d => "Have used" })
  .rename({ used: "tool" })

Use the whole web


Quarto helps you write documents…

… whether you use R, Python or Julia

… whether you like notebooks or documents

… whether you write in a code editor or a notebook editor

Quarto help you make documents that react to users

… and you might learn JavaScript by accident!

A checklist for trying Quarto

🔴 Download Quarto from quarto.org and have a look at the Guide

🟠 Try to render an existing R Markdown document or Jupyter notebook using Quarto and your favourite editor

🟢 Switch out one of your charts for an Observable Plot chart

🔵 Try switching some dplyr or pandas verbs for some Arquero verbs

🟣 Try adding something to your document by importing an Observable notebook or a JavaScript library

Thanks for listening!