4 Tools for Reproducible Jupyter Notebooks | by Rebecca Vickery | Towards Data Science

Jupyter notebooks have a somewhat poor reputation in the wider programming community. Joel Grus’ famous “I don’t like notebooks” talk, which he bravely gave at JupyterCon in 2018, covered many of the reasons why. Typically notebooks are seen to promote poor coding practices as they can be difficult to version control, often rely on cells being run in a specific order to return correct results and can be tricky to test and debug.
However, Jupyter notebooks are still the number one choice for most data scientists when it comes to performing tasks such as exploratory data analysis and initial machine learning model development. The ability to visualise outputs such as graphs and tables in line with your code, and to add rich annotations to analyses are simply not replicated with any other tool.
While notebooks remain such a popular choice it is worth looking at some of the options that are available to overcome some of the issues that can make notebook code less robust. In this article, I will give a brief introduction, with code examples, to four tools that provide solutions to some of the issues. These include:
Nbdime for better version control.Run linters on notebook code with nbQA.Jupyter-nbrequirements for managing dependencies within notebooks.Notebook validation with nbval.
Nbdime for better version control.
Run linters on notebook code with nbQA.
Jupyter-nbrequirements for managing dependencies within notebooks.
Notebook validation with nbval.
Versioning notebooks with tools like Github can be difficult. Version control tools do not render diffs well as they do not understand the logical structure of a typical notebook. This can make tracking changes and merging code challenging,
Nbdime is a tool that seeks to solve this issue by providing richer, visual diffs which make it very easy to see changes between different versions of the same notebook.
Nbdime can be installed via pip.
pip install nbdime
This should automatically install and enable the extension for Jupyter notebooks. If it doesn’t install correctly you can manually do this with the following command, adding one of the flags to determine which users it is installed for --system (system-wide), --user (current user), --sys-prefix (current virtual environment).
nbdime extensions --enable [--sys-prefix/--user/--system]
Once everything is installed if you open a Jupyter notebook you should now have the following new icons available in your toolbar.
I have created a notebook to showcase the functionality of nbdime which trains a simple linear model on the Boston house prices toy dataset. This is part of a project that I have stored on a repository in Github. The notebook is shown below and the code for this can be found at this link.
The new icons that should now be available on the toolbar of the notebook form the web view functionality of nbdime. This view gives a rich visual representation of the changes that are made to the notebooks.
Clicking the git button will show the diff between the last commit and the currently saved version of the notebook.
Clicking the icon that looks like a clock face will show the diff between the latest checkpoint and the currently saved version.
I’ll make a few changes to the notebook and view the diff from the last commit using the web view.
In the notebook, I have changed the model that I am using and made a small change to the residuals plot. Let’s take a look at the resulting diff that nbdime provides.
As you can see from the image below nbdime shows a line by line and cell by cell picture of exactly what has changed since the previous commit. It even shows how the outputs of each cell have changed including the graph.
Linting is a process for checking code quality. A linting tool scans your code and checks for common styling errors. Python linters, for example, typically check for code that doesn’t conform to widely used style guides such as Pep8.
NbQa is a tool that allows you to run any standard python linter on a Jupyter notebook. The following linters are currently accessible from this tool: pylint, black, auto flake, check-ast, doctest, flake8, mypy and yapf.
To install simply run the following.
pip install nbqa
Let’s run pylint, a commonly used python linter on a notebook that I created recently. To do this you need to run the following on the command line.
$ nbqa pylint dataframe_basics.ipynb
This gives me the standard pylint output which highlights the errors in my code.
Every project that you work on using notebooks may require a different set of dependencies. Traditionally these are managed outside Jupyter notebooks using virtual environments.
Jupyter nbrequirements is a tool that enables you to manage dependencies and create a separate and optimised environment all managed within the notebook.
To get started pip install the library and enable the notebook extension using the commands shown below.
$ pip install jupyter-nbrequirements$ jupyter nbextension install --user --py jupyter_nbrequirements
You can install libraries within the notebook either by using cell magic commands or by using the UI which will be displayed at the top of the notebook.
To install a library such as pandas using the cell magic simply type the following into a notebook cell.
%dep add pandas --version ">=0.24.0"
As described earlier in this post, notebooks are most often used for exploratory analysis and initial development of models. Often it is useful to store this type of analysis and initial project development for both documentation purposes and to potentially build on findings from this work at a later date.
The py.test plugin, nbval, is a useful tool for validating stored notebooks. Nbval will automatically run each cell in a notebook and checks that the current output matches the outputs stored in the last saved version of the .ipynb file. This acts as a check that nothing has changed in the underlying source code and therefore validates that the results of the original analysis or experiment are still reliable.
To use this tool first pip install via the following command.
pip install nbval
Tests can be executed either on all files contained in a directory by running the following.
py.test --nbval
Or on a specific notebook by running this line of code.
py.test ---notebook-name.ipynb
I ran py.test on two of my existing notebooks. The first runs without error and gives the following output.
The below gives an example of failing tests in a notebook.
Although often used for exploratory analysis and initial model development rather than production code, notebooks should still be seen as an important store of work. Initial experiments and analysis are useful records of past results and it should be possible to return to a notebook at a later date to build on your work. It is, therefore, worth exploring tools that can help to make code written in notebooks more robust and reproducible.
This article covered four tools that can help to make code in notebooks better and more reusable. For more tips on reproducible data science code in general see my earlier articles below.
towardsdatascience.com
towardsdatascience.com
Thanks for reading!
I send out a monthly newsletter if you would like to join please sign up via this link. Looking forward to being part of your learning journey