📖 Chapter 02 — Jupyter
The interactive computing environment on the NAS. Where analysis happens.
Learning Objectives
- Set up Jupyter on the NAS
- Use JupyterLab as the modern interface
- Configure JupyterHub for multi-user access
- Manage Python environments and kernels
Introduction
Jupyter is the standard tool for interactive data analysis. A Jupyter notebook is a document that combines code, output, and narrative. You write a code cell, run it, see the result. You write a markdown cell with an explanation. The result is a single document that tells the story of the analysis.
For the data scientist's home lab, Jupyter on the NAS is the right answer. The notebooks live on the NAS, the data lives on the NAS, the analysis runs in a Jupyter container, and you access it from any device on the network.
Jupyter vs JupyterLab vs JupyterHub
Three related tools:
- Jupyter Notebook: the original. A web app for creating and running notebooks. Single-user.
- JupyterLab: the modern interface. A web app that supports notebooks, text editors, terminals, file browsers, and more. The right default for most users.
- JupyterHub: a multi-user server. Multiple people can have their own Jupyter environment, with their own notebooks, on the same JupyterHub instance. Right for teams or families.
For a single-user home lab, JupyterLab is the right default. For a multi-user setup (a data science team, a class), JupyterHub is the answer.
Setting up JupyterLab
The easiest way to run JupyterLab is the official Docker image. The Compose file:
version: "3.9"
services:
jupyter:
image: jupyter/scipy-notebook:latest
restart: unless-stopped
ports:
- "8888:8888"
volumes:
- /mnt/tank/Lab/projects:/home/jovyan/work
- /mnt/tank/Lab/data:/home/jovyan/data:ro
environment:
- JUPYTER_ENABLE_LAB=yes
- JUPYTER_TOKEN=your-secure-token-here
Notes:
jupyter/scipy-notebookis the official Jupyter image with the scientific Python stack pre-installed (NumPy, Pandas, Matplotlib, scikit-learn).- The
workdirectory is where your notebooks live. It's mounted to the NAS's projects directory. - The
datadirectory is mounted read-only — the notebook can read the data but can't accidentally write to it. - The
JUPYTER_TOKENis a password for accessing the Jupyter UI. Use a strong token; anyone with it can run code as the notebook user.
After docker compose up -d, Jupyter is available at http://<nas>:8888. Open it in a browser, enter the token, and you're in.
The "no token" option
For a personal home lab, you can disable the token (use JUPYTER_TOKEN= or set --NotebookApp.token=''). The risk: anyone on the network can run code as the notebook user. For a family network, this is usually acceptable. For a network with other users, keep the token.
The notebook environment
A Jupyter notebook is a sequence of cells. Each cell is either:
- Code: a Python (or R, or Julia) snippet. Run with Shift+Enter. The output appears below.
- Markdown: a text snippet with formatting. The narrative of the analysis.
- Raw: unformatted text. Passes through to the rendered notebook.
The typical structure of a notebook:
- Markdown cell: introduction, what this notebook is, what it analyzes.
- Code cell: imports (pandas, numpy, the libraries you'll use).
- Code cell: load the data.
- Code cell: explore the data (shape, columns, dtypes, summary stats).
- Code cell + markdown: clean the data, with explanations.
- Code cell + markdown: transform the data, with explanations.
- Code cell + markdown: visualize the data (matplotlib, plotly, seaborn).
- Code cell + markdown: model the data, if appropriate.
- Markdown cell: conclusions, next steps.
The narrative is the point. A notebook without markdown is just a script. A notebook with markdown is a story.
Python environments
Different projects have different dependencies. The right way to manage this: conda environments or virtual environments (venv). Each project has its own environment with its own packages.
For a single-user Jupyter, the simplest approach: install the packages you need in the base environment. If a project needs different versions, create a venv for that project.
For a multi-user JupyterHub, each user has their own environment by default. The JupyterHub admin can install common packages for all users.
For full reproducibility, use pip freeze > requirements.txt (for pip) or conda env export > environment.yml (for conda) to capture the exact environment. The file goes in the project directory; the environment can be recreated from it.
Adding kernels
A Jupyter kernel is the runtime that executes the code. The default is Python 3. To add a different kernel (e.g., R, Julia, a different Python version):
- Python venv: create the venv, install ipykernel in it, run
python -m ipykernel install --user --name=<name>. The kernel is available in Jupyter. - R: install R, then install IRkernel in R, then run
IRkernel::installspec(). The R kernel is available in Jupyter.
For most home data science, Python 3 is enough. Add other kernels when you have a specific need.
The "where do notebooks live" pattern
From Chapter 01, the project structure:
Notebooks go in notebooks/. The notebook's name describes what it does: 01-explore.ipynb, 02-clean.ipynb, 03-model.ipynb, 04-report.ipynb. Numbered prefixes keep them in order.
Version control for notebooks
Notebooks are JSON files. They can be put in Git. But the JSON is noisy (output, metadata, cell IDs), which makes diffs hard to read.
The solution: nbdime (a notebook diff/merge tool) and jupyter nbconvert --to script (export to a Python script for review). Or JupyText, which lets you save notebooks as both .ipynb and a paired .py file. The .py is the source of truth; the .ipynb is the rendered view.
For most home data science, the discipline is: commit the .ipynb files (with output cleared) to Git. For collaboration or for serious reproducibility, use JupyText or nbdime.
Notebooks vs scripts
A common question: when to use a notebook, when to use a script?
- Notebook: exploration, one-off analysis, "I want to see what's in this data." Iterative, visual, narrative.
- Script: production code, recurring work, "I want to run this every day." Deterministic, tested, scheduled.
The pattern: explore in a notebook. Once you know what the analysis should do, extract the code into a script. Use the script from a pipeline (Chapter 04) or a notebook (call the script from a notebook cell).
JupyterHub for multi-user
For a family of data scientists, or for a class, or for a team: JupyterHub. Each user has their own Jupyter environment, with their own notebooks, their own Python environment, and their own home directory.
JupyterHub is heavier than JupyterLab. It runs a hub process, a proxy, and a user server for each active user. For a home lab with 1-3 users, the complexity is overkill. For a class of 20 or a team of 10, it's the right answer.
Engineering Note
Jupyter is for thinking, not for production. A notebook is the right tool for exploration, for prototyping, for "let me see what's in this data." It's not the right tool for a scheduled job, a web service, or a system that needs to run unattended. The discipline: explore in a notebook, extract to a script, schedule the script. The notebook is your scratchpad; the script is your deliverable.
Summary
Jupyter on the NAS: JupyterLab for single user, JupyterHub for multi-user. The jupyter/scipy-notebook image is the standard. Mount projects and data from the NAS. Use a token for authentication. Each project gets a directory with notebooks, src, output, and README. Number notebooks to keep them in order. Commit .ipynb to Git (with output cleared). Use JupyText for serious reproducibility. Explore in notebooks, extract to scripts, schedule the scripts.
Checklist
- ⬜ Install JupyterLab via Docker Compose
- ⬜ Mount
/mnt/tank/Lab/projectsas the work directory - ⬜ Mount
/mnt/tank/Lab/dataas a read-only data directory - ⬜ Set a strong token (or accept the no-token risk for a personal lab)
- ⬜ For each new project, create the directory structure with a README
- ⬜ Commit notebooks to Git (with output cleared)
Looking Ahead
Chapter 03 is data storage and format. CSV is usually wrong. Parquet, Arrow, partitioning, the right file format for analysis. The chapter that turns "my dataset is a 10 GB CSV" into "my dataset is 1 GB of Parquet, with proper partitioning, that loads in 2 seconds."