Hey, that's me!

Phil Mayer

Full-stack software engineer currently learning the Rust programming language. All opinions are my own.

C++ to Jupyter Notebooks

Published Updated

When I was in college, I decided to take a course in computational physics. With one final required science course left to take and a few programming courses under my belt, the choice was a natural one. I'm glad that I took the course because I hadn't yet worked with numerical methods, the problems were interesting, and who could say no to a cool graph?

Motion of a pendulum Example: motion of a pendulum via the Euler-Cromer method accounting for friction and driving force.

For the course, we used CERN's Root, a data analysis framework for C++. Classwork, homework, and projects were written in single files compiled with make. The typical assignment involved using well-known numerical methods to solve differential equations. Root is relatively easy to use and has an extensive API. I enjoyed solving the problems and being able to compile and run a native executable — it was overkill in the best way.

Round Two with Python

After a few years working in industry, I realized that revisiting some of the problems from the course would be a great way to learn something new by translating my old C++ solutions to Python, working with libraries like NumPy and Matplotlib, and writing the new solutions as Jupyter notebooks. I was also curious to try running the notebooks in a Docker container, attaching Visual Studio Code via the Remote Containers extension, and seeing the rendered results inline.

Overall, the setup took some work but ended up being worth it. To start off, I created a Dockerfile with the following contents:

FROM jupyter/minimal-notebook:python-3.9.12

To dust off my knowledge of the theory, I wanted the ability to include LaTeX in my notebooks to typeset math. Fortunately, the minimal-notebook image includes a TeX distribution. I also wanted to create a dev container to automate some aspects of the editor setup in the future. I defined my Visual Studio Code dev container with a few extensions:

  "name": "Existing Dockerfile",
  "context": "<path_to_workspace_root>",
  "dockerFile": "<path_to_dockerfile>",
  "extensions": ["ms-toolsai.jupyter", "donjayamanne.python-extension-pack"]

Finally, I opened the workspace in Visual Studio Code, was prompted to reopen the workspace in a dev container, accepted, and was good to go. After creating a few .ipynb files, I got the hang of things.

Despite the environment and program execution being considerably slower than the compiled, native solution, Jupyter provides a lot of wins. The ability to typeset math inside a notebook alongside code is incredibly helpful:

Screenshot of Jupyter notebook with LaTeX formulas and Python code

The ability to quickly re-run statements to generate new result strings, data frames, and charts makes for a solid user/developer experience. Working in a Jupyter notebook feels a bit like using MATLAB with a much cleaner UI. Finally, the ability to export a PDF of the notebook feels like it could potentially be a useful way for users to quickly share results (example).

To continue learning the tooling, dusting off my computational physics knowledge, and making fun charts, I ported my program which charts the Lorenz model. See the image below. Note the famous butterfly attractor in the graph of zz v. xx.

Lorenz model