Demos and Recipes LSE ME204 · Data Engineering Principles for the Social Sciences
🖥️ Week 03 Day 03 Lecture

Dashboards, Responsible Reporting, and Quarto

🛠️ Final Project Support

10:00 – 11:00

I’ll be going around the room to help you. Use this hour to make progress on your project.

What you could be doing right now:

  • Closing off any data collection that is still open, so you can spend the rest of the week on analysis
  • Building the charts and tables that answer the question you set out to ask
  • Drafting the writing that goes around them, in whatever form you have to hand
  • Come talk to me about scope, feasibility, or a technical problem

💡 Deadline reminder: submit your final project by 5pm Friday 31 July.

☕ Coffee Break

11:00 – 11:15

When we come back:

  • Two published data reports and how each one is put together
  • Whether a chart still makes its finding clear on its own
  • In-class demo: building and rendering a Quarto page

The Data Science Workflow

Let’s see how the final project maps to this diagram.

Data science workflow from collecting and storing data through preparation, exploration, investigation, modelling, and communication.

1️⃣ Learning to Tell a Story with Data

11:15 – 11:50

Two ways a reader can move through a report like the one you are building.

The reader ends at the findings

report_shape_a q What the report set out to find data Where the numbers come from q->data find Each finding in turn data->find synth What it all means find->synth

Technical detail goes in an appendix.

The reader starts at the chart

report_shape_b chart A chart they cannot read yet p1 One part of it explained chart->p1 p2 Then the next part p1->p2 whole They can read the whole chart p2->whole

Worth doing when the visualisation is rich.

Smaller towns, better results

Read the headings in order and you have the whole story.

The article’s six section headings, in order:

  1. Smaller towns have better attainment
  2. Educational outcomes are worse in income deprived towns
  3. The relationship between attainment and income deprivation differs between English regions
  4. The gap in attainment between pupils in high and low deprivation towns widens through school
  5. Around a third of young people from towns of all sizes enter higher education
  6. Young people see better education outcomes if the local community in their town are highly qualified

🔗 Why do children and young people in smaller towns do better academically? (ONS, July 2023)

Where the numbers go

They go over six major findings in the article, and how things are measured only shows up as an appendix, not the main text.

On the page

  • Towns grouped by size and by income deprivation
  • One chart per finding, each one titled with the finding
  • A tool at the end to look up your own town

Under “Measuring the data”

  • Which datasets were joined, and on what
  • How town size and deprivation were banded
  • What the numbers cannot tell you

Anyone can read the findings. Anyone who wants to check the work can, too. Neither reader blocks the other.

Eight AI search engines, all bad at it

The findings are in the headings again. What differs is where the method goes.

The article’s section headings, in order:

  1. Methodology
  2. Chatbots’ responses to our queries were often confidently wrong
  3. Premium models provided more confidently incorrect answers than their free counterparts
  4. Platforms retrieved information from publishers that had intentionally blocked their crawlers
  5. Platforms often failed to link back to the original source
  6. The presence of licensing deals didn’t mean publishers were cited more accurately
  7. Conclusion, then Limitations of our experiment

🔗 We compared eight AI search engines. They’re all bad at citing news. (Columbia Journalism Review, March 2025)

Would this chart survive on its own?

The same chart, with the article taken away.

If you write a big report, there is a good chance you will want to reuse your main figures elsewhere: in a slide deck, or in an email making the same point more concisely to someone else. It is a good idea, then, to make sure your chart works as a standalone piece, so it still states its finding once the surrounding writing is gone.

⚠️ A title naming the variables tells a reader what they are looking at. A title naming the finding tells them what you found.

2️⃣ Two lines moving together is not a finding

11:50 – 12:00

We saw this chart on 🖥️ W02D01, in the bad plot hunt.

A chart like this is already making a claim. Two lines, one axis each, scaled until they move together.

Adding “of course this is only a correlation” underneath does not undo it. You still chose these two variables, put them on one chart, and gave it space in your report. You are still leading your reader to believe one causes the other.

⚠️ The hedge does not save you. If you cannot defend the causal claim, do not put up the chart that makes it.

What if I want to talk about a correlation?

Then be careful how much weight you put on it.

  • In a big dataset almost any two things correlate a little, so finding a correlation is not yet a finding (McElreath, Statistical Rethinking, ch. 5).
  • If other people have looked at the same pattern, or worked out what is behind it, cite them and let your data back up what they found.
  • Something can feel like common sense and still need a source. Resist writing “British people care about rain more than anyone else” unless you can point at a reputable study that showed this.

💡 A claim about how the world works needs a source, including when it seems too obvious to need one.

How to write about a pattern in your data

Cities near the sea cool down more slowly at night, because the sea keeps the air above it warm and humid (NOAA). My own data agrees for every city except one. (your case here) cools faster overnight than the other coastal cities, and it is also the furthest above sea level, so I cannot separate height from distance to the sea.

  • The reason, and where it came from
  • What your own data shows
  • What you could not rule out

3️⃣ Publishing Your Story

12:00 – 12:50

Two group projects from DS105, our sister course. Both teams communicated their findings so well that you can follow everything they did without ever opening their notebooks.

The football one is a Quarto page rendered into docs/. The sewage one uses a JavaScript framework we never teach.

Write in Markdown → see it as HTML

Anything you put in docs/index.md comes back as a web page.

  • You set a repository up this way in 🖥️ W02D03. GitHub finds the Markdown in docs/, converts it, and serves the result.
  • Nothing to install, and no command to run.
  • The page on the right is one .md file: a title, three headings, a paragraph each, and one image.
  • It looks like that because you never told GitHub how it should look. Every page published this way looks the same.

🔗 GitHub Pages documentation, and the quickstart if you want to set up a second site from scratch.

Two files change that

Jekyll is the converter GitHub runs on your Markdown. Give it a _config.yml and it applies a theme.

What the repository contains:

your-repo
└── docs
    ├── _config.yml
    ├── index.md
    └── assets
        └── entries-by-hour.png

Settings → Pages → Deploy from a branch → main/docs.

index.md opens with a settings block:

---
layout: default
title: The Last Train Home
---

Three dashes, some setting: value lines, three dashes again. That format is called YAML, and we call this block the front matter. Everything below it is ordinary Markdown.

🔗 About GitHub Pages and Jekyll · front matter

Choosing the theme

Change the theme line in _config.yml to see your website with a different look.

theme: jekyll-theme-minimal

theme: jekyll-theme-hacker

⚠️ This is a fully vibecoded website. Do not take the content, or the sloppy writing, seriously.

🔗 You can find all the default themes here, and the Jekyll docs explain what else you can change.

Asking an LLM for the HTML

Keep writing in Markdown. Hand that to the chatbot and ask for the HTML at the end.

  • Write your content and section order in a .md file, and keep it as your reference.
  • Rearrange the structure with the chatbot before you ask for any HTML.
  • Ask for one column, one accent colour, and heading sizes you chose yourself.
  • Keep charts and images in docs/assets/, and have the HTML point at them.
  • Find your own numbers in the finished file, and delete anything you cannot trace to your data.

Gemini, ChatGPT, and Claude will all do this. What you ask for matters more than which one you pick.

Remember to specify how it should look

The content and the structure

Here is the Markdown for a page I want to publish on GitHub Pages. Turn it into a single HTML file I can put in docs/.

  • Keep my sections in the order I wrote them
  • One page, not several
  • Two images, both in assets/: entries-by-hour.png in the findings section, station-map.png under the data section. Point an <img> at each relative path
  • I have attached both so you can see what they look like
  • Write the alt text from my own captions

The styling

  • All the CSS inside the file, in one <style> block
  • One centred column, about 65 characters to a line, with plenty of space between the lines, and the chart and table full width inside it
  • Responsive, so it fits a phone screen and I never scroll sideways
  • Headings #3995ba, links #c63c4a, body text #333333, background white
  • #F8CE0A for one thing that must stand out, never for text
  • System fonts, and all the colours as CSS variables at the top

Here is how I would specify it if I wanted the ME204 colours, for example. Pick your own, and give the hex codes.

Tell the chatbot what NOT to do

Add these to the same message

  • Do not add findings or conclusions I have not written myself
  • Do not round my numbers or reword my sentences
  • Do not load anything from a CDN, and no web fonts
  • Do not put the chart inside the HTML as base64
  • No build step, and nothing I have to install

If you are using Plotly and want to keep the interactive bits, save the chart with write_html, put that file in docs/assets/, and embed it with an <iframe>.

You are the one answering for what it says

You answer for every number and every claim on the page, whether you typed it yourself or a chatbot wrote it for you.

  1. Every number on the page is one you can point to in your own data.
  2. Every sentence about what the data shows is one you would defend.

Images have to be inside docs/

GitHub Pages publishes one folder. Anything outside it does not exist as far as your website is concerned.

Broken

your-repo
├── figures
│   └── chart.png
└── docs
    └── index.md

The Markdown points up and out of docs/ with ../figures/chart.png. It works on your machine. On the published site the image is missing.

Works

your-repo
└── docs
    ├── index.md
    └── assets
        └── chart.png

Now the path is assets/chart.png, and everything the page needs is in the folder GitHub publishes.

⚠️ It is very common to only notice your images are not loading on the published site very close to the deadline. Copy your figures into docs/ and check the published page, not the local one, well before you need to submit.

Write Markdown, choose how it looks

You write Markdown and set the look yourself.

  • Every lecture page, every lab page, and every slide deck on this course site is a .qmd file, including the one on screen now.
  • You write one source file and render it as a website, a slide deck, a PDF, or a Word document.
  • A .qmd file can contain Python code as well as text. Quarto runs that code on your machine when you render, then puts the chart into the page it builds.
  • If you code in R, you have probably used Quarto already. Quarto Markdown replaced R Markdown as the standard way to write reproducible reports in R, and it does the same job for Python.

We will build one of these together in a moment, starting from a blank file.

🔗 quarto.org

quarto --help

Open a terminal on Nuvolos and type this.

quarto --help

Quarto is already installed on the workspace. Nothing to set up.

Two of these commands are the ones you will use today: render and publish.

Building docs/index.qmd

The top of the file:

---
title: "My ME204 Final Project"
format:
  html:
    toc: true
    embed-resources: true
---

Then in the terminal:

quarto render docs/index.qmd

The top of the page.

Scroll down and the chart is there, drawn by the code in the file.

The front matter does the styling

Three dashes, some setting: value lines, three dashes again. The same shape as the Jekyll block from earlier, read by a different program.

The least you can get away with

---
title: "My ME204 Final Project"
format: html
---

This renders. You get a page with a title on it and nothing else decided.

What the page you just saw uses

---
title: "The Last Train Home"
subtitle: "What entry counts say about where London goes after work"
author: "Your name"
date: today
format:
  html:
    toc: true
    toc-location: right
    toc-title: "On this page"
    embed-resources: true
    code-fold: true
    code-summary: "Show the code"
    fig-align: center
---

There are tons of things you can customise about how the page looks. Check out 🔗 HTML format options for a full reference of what you can configure under html:.

Why embed-resources

Render the same file with and without that one line, then look at your folder.

Without it

docs
├── data
│   └── example.csv
├── index.qmd
├── index.html          25K
└── index_files         980K
    ├── figure-html
    │   └── cell-3-output-1.png
    └── libs
        ├── bootstrap
        ├── clipboard
        └── quarto-html

Quarto split the output in two, so index.html contains your text while the chart, the fonts, and the styling went into index_files beside it. Push the HTML alone and the page loads with no styling and a broken chart.

With it

docs
├── data
│   └── example.csv
├── index.qmd
└── index.html          1.4M

The chart, the fonts, and the styling are all inside those 1.4M. Copy that one file anywhere and the page still works.

Change something, render again

Change something and re-render the page to see what changed.

What you write in docs/index.qmd

## Bank empties after 7pm, Camden Town fills up

Bank spikes to 3,100 entries at nine in the morning and 3,400 at six in
the evening, with barely 1,000 to 1,600 an hour in between.

::: {.callout-important}
The numbers on this page are invented.
:::

What the browser shows

Bank empties after 7pm, Camden Town fills up

Bank spikes to 3,100 entries at nine in the morning and 3,400 at six in the evening, with barely 1,000 to 1,600 an hour in between.

⚠️ The numbers on this page are invented.

The ## heading gets converted to an <h2>, and the ::: {.callout-important} block is converted to a <div>.

Rendering from inside VS Code

The same render, from a button in the editor.

Open the Extensions panel, search for Quarto, and select Install. Same panel you used for SQLite Viewer in 💻 W03D02.

You get a Render button and a preview pane beside the file. Make a small edit and see the result without switching to the terminal.

The one you want is published by Quarto, identifier quarto.quarto.

The Markdown you wrote, as HTML

How Quarto converts your markdown to the relevant HTML

docs/index.qmd

## Bank empties after 7pm, Camden Town fills up

Bank spikes to 3,100 entries at nine in the morning and 3,400 at six in
the evening, with barely 1,000 to 1,600 an hour in between.

::: {.callout-important}
## The numbers on this page are invented
:::

docs/index.html

<section id="bank-empties-after-7pm-camden-town-fills-up" class="level2">
<h2 class="anchored" data-anchor-id="bank-empties-after-7pm-camden-town-fills-up">Bank empties after 7pm, Camden Town fills up</h2>

<p>Bank spikes to 3,100 entries at nine in the morning and 3,400 at six in the evening, with barely 1,000 to 1,600 an hour in between.</p>

<div class="callout callout-style-default callout-important callout-titled">
  <div class="callout-header d-flex align-content-center">
    <div class="callout-title-container flex-fill">
      <span class="screen-reader-only">Important</span>The numbers on this page are invented</div>
  </div>
</div>
</section>

Three of those class names, in the CSS Quarto put inside the same file:

.callout-important {
  border-left: 5px solid #cc1f1a;
  background-color: #fdf2f2;
  border-radius: 4px;
}

Why the box is red.

.callout-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.75rem;
}

Why the icon and the title share one row.

.screen-reader-only {
  position: absolute;
  width: 1px;
  height: 1px;
  clip: rect(0, 0, 0, 0);
}

One hidden pixel. Never on screen, still announced by a screen reader.

Putting it on the web

Rendering gives you HTML on your own machine. Publishing puts it somewhere other people can open.

  • The same GitHub Pages route you already used works here: render into docs/, push, done
  • Quarto also publishes to Netlify, Posit Connect, and others

🔗 Publishing with Quarto is the page to follow. We will walk through it together now, and you do the publish yourself afterwards.

Scrollytelling with Closeread

An extension for reports where the reader scrolls and the chart responds. Useful for the second shape from this morning.

Install it:

quarto add qmd-lab/closeread

Then in your YAML:

format:
  closeread-html: default

Check them out if you are curious. Experience it as a reader first, then look at how it was put together.

🏁 Thanks!

12:50 – 13:00

This afternoon

Pick the route your own project will take. Markdown in docs/ with a Jekyll theme, one HTML file from a chatbot, or a Quarto page you render yourself.

Then work on your charts and your website, with your class teacher there to help you.

💻 Start by writing down which route you picked and why. Your class teacher will ask you.

Where you want to be by tonight

  • One route chosen, and a page that renders or publishes, even if the writing is still rough.
  • Your charts in docs/assets/ or docs/figures/, and the page pointing at them.
  • Every chart title stating the finding a reader should take from it.
  • Any claim about why a pattern appears either sourced or written as something you could not separate.

LSE Summer School 2026 | ME204 Week 03 Day 03