Markdown, pandoc & Jupyter Notebooks
Write in plain text, publish to HTML, PDF, or Word — and mix live code with prose in notebooks.
Module 6 · OverviewBy the end of this module you can…
- Explain why programmers prefer text-based document formats
- Write Markdown: headings, lists, emphasis, links, code, tables, and math
- Install
pandocand render Markdown to HTML, PDF, and Word - Explain “literate programming” and what a Jupyter notebook is
- Launch Jupyter Lab inside a uv-managed environment
- Create, run, and tidy a notebook — and know its pitfalls
Text Is King
Why programmers write documents in plain text — and how Markdown makes it pretty.
Why text?What’s inside a Word document?
Rename report.docx to report.zip and open it:
report.zip\
├── [Content_Types].xml
├── _rels\
├── docProps\
└── word\
├── document.xml your words, buried in XML
├── styles.xml
├── settings.xml
└── theme\
A .docx is a compressed bundle of machine-oriented files.
Plain-text documents are…
- Diffable — Git shows exactly which sentence changed
- Searchable —
Select-Stringworks on them - Future-proof — readable in any editor in 30 years
- Tool-neutral — no license required
- Automatable — code can generate and convert them
MarkdownThe bridge between plain text and rich documents
.txtPortable, but no headings, links, or tables
.mdPlain text with light conventions that render as rich documents
.docx / .pagesBeautiful, but opaque to Git and scripts
Markdown is designed to be readable as-is — the source looks like a neatly typed email — and to render beautifully when processed.
You’ll meet it everywhere: GitHub READMEs, Jupyter, VS Code, Teams & Slack messages, Obsidian notes, Quarto reports… and these slides.
MarkdownSyntax in five minutes
# Lapse Study 2026
## Summary
Lapses were **higher** than expected in
policy years 2–3, *especially* for
single-premium business.
- Data: `claims_2025.csv`
- Method: actual vs. expected
- See the [SOA table](https://mort.soa.org)
1. Load data
2. Clean data
3. Compare to basis
> Draft — not for distribution.
Lapse Study 2026
Summary
Lapses were higher than expected in policy years 2–3, especially for single-premium business.
- Data:
claims_2025.csv - Method: actual vs. expected
- See the SOA table
- Load data
- Clean data
- Compare to basis
Draft — not for distribution.
MarkdownCode, tables, and math
Run the model with:
```powershell
uv run python src/model.py
```
| Policy year | A/E |
|------------:|-----:|
| 1 | 0.94 |
| 2 | 1.12 |
| 3 | 1.07 |
Annuity-due: $\ddot{a}_x = \sum_{k\ge0} v^k\,{}_kp_x$
Run the model with:
uv run python src/model.py
| Policy year | A/E |
|---|---|
| 1 | 0.94 |
| 2 | 1.12 |
| 3 | 1.07 |
Annuity-due: $\ddot{a}_x = \sum_{k\ge0} v^k\,{}_kp_x$
Math uses LaTeX notation between $…$ (inline) or $$…$$ (display). Supported by pandoc, Jupyter, and GitHub.
pandoc: The Universal Converter
One Markdown source → HTML, PDF, Word, slides, and more.
pandocOne source, many outputs
Install
winget install --id JohnMacFarlane.Pandoc -e
# new terminal:
pandoc --version
Write the valuation memo in Markdown next to the code. Produce a Word copy for the reviewer — with the company template — in one command.
pandocPDFs need a “PDF engine”
pandoc converts to PDF by handing a typesetting program the job. Pick one:
Typst — recommended for this course
Small, fast, modern, single .exe.
winget install --id Typst.Typst -e
pandoc README.md -o README.pdf --pdf-engine=typst
LaTeX (MiKTeX) — the classic
Gorgeous math typesetting; a large install. Also needed later by nbconvert --to pdf.
winget install --id MiKTeX.MiKTeX -e
pandoc README.md -o README.pdf
Zero-install fallback: render to HTML, open it in a browser, and Print → Save as PDF.
pandocCommands and options you’ll use
pandoc README.md -o README.html # HTML fragment
pandoc README.md -s -o README.html # complete, standalone page
pandoc README.md -s --toc --mathml -o README.html # + table of contents + math
pandoc README.md -s -c style.css --embed-resources -o README.html # styled, single file
pandoc README.md -o README.pdf --pdf-engine=typst # PDF
pandoc memo.md -o memo.docx --reference-doc=company_template.docx # Word, house style
-o file | Output file; the extension picks the format | -s | Standalone: full document with header |
--toc | Add a table of contents | --mathml | Render math in HTML (no internet needed) |
-c style.css | Apply a stylesheet | --embed-resources | Inline CSS & images into one file |
pandocDocument metadata: YAML front matter
---
title: "Lapse Experience Study"
author: "Jane Doe"
date: 2026-09-29
---
## Summary
Lapses were higher than expected…
- A block between
---lines at the very top of the file - pandoc uses it for the title block, PDF metadata, and the HTML
<title> - Start your sections at
##— the title is already the top heading
Without a title, pandoc -s warns you. Either add front matter or pass --metadata title="…".
Jupyter Notebooks
Literate programming: code, results, and explanation in one document.
ConceptLiterate programming
Write programs for people first, computers second.
— the idea behind Donald Knuth’s “literate programming” (1984)
A Jupyter notebook (.ipynb) interleaves:
- Markdown cells — explanation, assumptions, math
- Code cells — Python you can run
- Outputs — tables and charts, saved with the file
Lapse rates by policy year
Exposure is measured in policy-years; rates are crude.
| year | exposure | lapses | rate | |
|---|---|---|---|---|
| 0 | 1 | 1000 | 120 | 0.120000 |
| 1 | 2 | 880 | 90 | 0.102273 |
| 2 | 3 | 790 | 55 | 0.069620 |
ConceptWhy notebooks are great for analysis
Interactive
Run one step, look at the result, adjust, run again. Ideal for exploring a new dataset.
Shows its working
The reasoning, the code, and the numbers sit together — a reviewer can follow every step.
Shareable
GitHub renders .ipynb files; export to HTML or PDF for non-programmers (Module 8).
Think of a notebook as an Excel workbook where every formula is visible, documented, and re-runnable from top to bottom.
SetupJupyter Lab inside your managed environment
cd C:\actuarial_work\lapse_analytics
uv add --dev jupyterlab # once per project (done in Module 4)
uv run jupyter lab # every session
- Jupyter Lab opens in your browser
- Left: file browser, rooted at your project
- The kernel — the Python that runs your cells — is the project’s
.venvPython
Because Jupyter runs via uv run, every notebook sees exactly the packages in uv.lock. No “but it worked in my notebook” mysteries.
Finished? Save, close the browser tab, then Ctrl+C in the terminal to stop the server.
Using notebooksThe keys that make you fast
Two modes: Edit (typing in a cell, Enter) and Command (acting on cells, Esc).
| Shift+Enter | Run cell, move to next |
| Ctrl+Enter | Run cell, stay put |
| Esc / Enter | Command / edit mode |
In command mode:
| A / B | Insert cell above / below |
| M / Y | Make cell Markdown / code |
| D D | Delete cell |
| Z | Undo cell deletion |
| 0 0 | Restart the kernel |
Using notebooksPitfalls — and the habits that avoid them
| Pitfall | Why it bites | Habit |
|---|---|---|
| Hidden state | Cells run out of order; a deleted cell’s variable still exists in memory | Kernel → Restart Kernel and Run All Cells before trusting or sharing results |
| Noisy diffs | .ipynb is JSON with outputs embedded; Git diffs are hard to read | Clear outputs before committing when outputs don’t matter |
| Everything in one notebook | Reusable logic gets copy-pasted between notebooks | Move stable functions into src\*.py and import them (Module 8) |
| Absolute paths | C:\Users\Jane\… breaks for everyone else | Relative paths from the project root (Module 1!) |
Hands-on Lab · 40 minDocument and explore your project
Part A — README
- Install
pandocand Typst withwinget - Write
README.mdforlapse_analytics(Module 5 repo) - Render it to HTML and PDF in
output\ - Commit the README (not the renders)
Part B — Notebook
- Launch Jupyter Lab with
uv run - Create
notebooks\01_first_look.ipynb - Mix Markdown and code cells; restart & run all
- Commit the notebook
Lab · Part AWrite the README
cd C:\actuarial_work\lapse_analytics then notepad README.md — replace uv’s stub with something like:
---
title: "Lapse Analytics"
author: "Your Name"
date: 2026-09-29
---
## Purpose
Explore policy **lapse experience** by policy year.
## Setup
```powershell
uv sync
uv run check_env.py
```
## Layout
| Folder | Contents |
|--------------|-----------------------|
| `data/` | inputs (not in Git) |
| `notebooks/` | exploratory notebooks |
| `output/` | rendered reports |
## Method
Crude lapse rate in policy year $t$:
$$ w_t = \frac{L_t}{E_t} $$
Lab · Part ARender and commit
mkdir output -Force
pandoc README.md -s --mathml -o output\README.html
pandoc README.md -o output\README.pdf --pdf-engine=typst
start output\README.html
start output\README.pdf
git status # output\ is ignored — only README.md shows
git add README.md
git commit -m "Write project README"
Edit, re-render, refresh the browser. Tweak until you’re happy — then commit.
Push to GitHub (if you set up a remote) and see GitHub render the same README on your repo’s front page.
Lab · Part BYour first notebook
mkdir notebooks -Force
uv run jupyter lab
- In the file browser, open
notebooks, then File → New → Notebook (kernel: Python 3) - Rename it
01_first_look.ipynb - Cell 1 (Markdown): a title and one sentence of purpose
- Cell 2 (code): the lapse table from the earlier slide
- Cell 3 (Markdown): what you notice about the rates
- Kernel → Restart Kernel and Run All Cells
Then, in a second terminal tab:
git add notebooks\01_first_look.ipynb
git commit -m "Add first-look lapse notebook"
git log --oneline
Stretch: add a cell computing the average rate with df["rate"].mean(), and a Markdown cell with the formula in $$…$$.
RecapModule 6 checklist
- I can explain why text formats suit version control
- I can write Markdown headings, lists, emphasis, links, code blocks, tables, and math
pandocand a PDF engine are installed; I can render HTML and PDF- I know
-s,-o,--toc, and YAML front matter - I can launch Jupyter Lab with
uv run jupyter laband stop it cleanly - I “Restart & Run All” before trusting a notebook
- My repo now has a README and a notebook, both committed
Introduction to Visual Studio Code
Terminal, Git, notebooks, and Python — all in one window.