Jupyter Notebooks and Git

import matplotlib
if not hasattr(matplotlib.RcParams, "_get"):
    matplotlib.RcParams._get = dict.get

2.2. Jupyter Notebooks and Git#

Jupyter notebooks, ipynb, are a special case in the discussion text vs binary, and thus require special attention when using version control: the text and code of each cell is stored inside a more complex structure (although still text-based). Furthermore, if you run a cell, a counter register how many times you did that. That information is stored in the JSON format too, which means that if you have two exact same version but the counter is different, you might run into trouble. This unfortunately makes it a little more difficult to use notebooks with version control, but if we are aware of the issue, it is not a problem—we will show you how.

If you tried opening up a notebook in the text editor you would have noticed a structure with curly braces, {}. This is JSON-format (another file type), which the notebook uses to store information in each cell.

For example, the following two cells in a jupyter notebook:

import numpy as np
np.linspace(0, 1, 10)
array([0.        , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
       0.55555556, 0.66666667, 0.77777778, 0.88888889, 1.        ])

Look as follows:

{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e7dcf271",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "24165ce8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0.        , 0.11111111, 0.22222222, 0.33333333, 0.44444444,\n",
       "       0.55555556, 0.66666667, 0.77777778, 0.88888889, 1.        ])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linspace(0, 1, 10)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "mude-base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}

Although the JSON format is text-based files that should be easy for git to handle, However, there’s another issue. When we run cells, the output is stored in the notebook, which can lead to challenges. For example, if you create a plot using matplotlib and save the notebook, that plot output will be binary: an image will be converted to a text block that encodes the color of every single pixel inside it. This can quickly become thousands of characters long, which makes it challenging to read.

This is a problem because it becomes impractical to use git to work out the conflicts between files when making new commits in a repository. It requires you to compare the JSON format and the binary output of those files, which is not as intuitive as rendered notebooks you’re probably used too.

Good practice is to at least clear output before committing notebooks into your git timeline. There are some tools to ease you in this process, like Jupytext and ReviewNB, but this requires all your collaborators to use the same tools. Therefore, it’s best to limit collaboration in ipynb. Alternatively, consider spitting text and code, using other file formats for your code.

Attribution

This chapter reuses material from Learn Programming for Engineers and was written by Kiril Vasilev, Riccardo Taormina, Robert Lanzafame, Tom van Woudenberg. Find out more here