{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# jupyter-diff\n", "\n", "From Jupyter Lab Open Studio! (at Bloomberg HQ)\n", "\n", "Kunal Marwaha\n", "and Saul\n", "Shanabrook // June 22 2019\n", "\n", "This is an experiment in using version\n", "control for Jupyter notebooks, using the\n", "tool\n", "[notedown](https://github.com/aaren/notedown) to automatically store\n", "notebooks\n", "in Markdown." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "attributes": { "classes": [], "id": "", "n": "2" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "I ❤ Jupyter!\n" ] } ], "source": [ "print(\"I ❤ Jupyter!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Why\n", "\n", "Jupyter is a great tool for creating *notebooks* (`.ipynb` files). With\n", "notebooks, one can explore new computational ideas and share narratives with\n", "code. \n", "\n", "Ideas can change, and many turn to a form of version control to track\n", "changes.\n", "\n", "![PhD Comics by Jorge Cham](phd101212s.png)\n", "\n", "However, the underlying\n", "format\n", "of notebooks is\n", "JSON. It is relatively difficult to see changes to JSON\n", "objects\n", "in classic tools\n", "like [diff][diff].\n", "There is still\n", "not consensus on how\n", "to put Jupyter\n", "notebooks in version control.\n", "See\n", "[here][j1], \n", "[here][j2],\n", "and\n", "[here][j3],\n", "with\n", "varied solutions like\n", "[nbdime](https://nbdime.readthedocs.io/en/latest/),\n", "[nbstripout](https://github.com/kynan/nbstripout), or\n", "[jupytext](https://github.com/mwouts/jupytext). \n", "\n", "Here, I will use\n", "[notedown](https://github.com/aaren/notedown) to work with `.md` files in\n", "Jupyter Lab, and use [git](https://git-scm.com/) for version control.\n", "[diff]:http://man7.org/linux/man-pages/man1/diff.1.html\n", "[j1]:https://stackoverflow.com/q/18734739\n", "\n", "[j2]:http://tiny.cc/7ofo8y\n", "[j3]:http://tiny.cc/fofo8y" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "attributes": { "classes": [], "id": "", "n": "5" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bool(\"Markdown\") and bool(\"Jupyter\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Setup\n", "First, boot up Jupyter Lab.\n", "\n", "Let's install notedown [directly from the\n", "notebook][jakevdp]:\n", "\n", "[jakevdp]:http://tiny.cc/onfo8y" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "attributes": { "classes": [], "id": "", "n": "3" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: numpy in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (1.15.1)\n", "\u001b[33mYou are using pip version 19.0.1, however version 19.1.1 is available.\n", "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n" ] } ], "source": [ "import sys\n", "!{sys.executable} -m pip install numpy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "Now, we'll add the below line to your Jupyter settings:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "attributes": { "classes": [], "id": "", "n": "5" } }, "outputs": [], "source": [ "LINE_TO_ADD = \"c.NotebookApp.contents_manager_class = 'notedown.NotedownContentsManager'\"" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "attributes": { "classes": [], "id": "", "n": "8" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Writing 'LINE_TO_ADD' (str) to file '/Users/kmarwaha/.jupyter/jupyter_notebook_config.py'.\n" ] } ], "source": [ "%store LINE_TO_ADD >> ~/.jupyter/jupyter_notebook_config.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "If you're following along, you can relaunch Jupyter, and create a new\n", "Markdown\n", "file. Once you create the file,\n", "right-click and `Open With ->\n", "Notebook`.\n", "![\"Open With\" image](open-with.png)\n", "\n", "## Issues\n", "Not everything is\n", "perfect. Here are the issues I've seen:\n", "1. **Links\n", "wrap, and occasionally get\n", "spaces added to them.** This is from 80-character\n", "line limits in Markdown\n", "format. Some links will be broken because of this. One\n", "partial solution is to\n", "reference links (see examples [here][mdcheat]).\n", "You can also use URL shortening\n", "services like http://tiny.cc.\n", "\n", "2. **Sometimes, Markdown cells\n", "get pasted\n", "together.** It can be easier to edit\n", "Markdown cells in smaller\n", "chunks. To\n", "separate them, I sometimes add little code\n", "snippets.\n", "\n", "3. **GitHub\n", "doesn't render\n", "the markdown as a notebook!** Maybe if\n", "more people use it, they\n", "can try it out.\n", "As a compromise, I converted to\n", "notebook-output.ipynb for you to\n", "read online :)\n", "This was done with \n", "`notedown notebook.md > notebook-output.ipynb`\n", "\n", "[mdcheat]:\n", "https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "attributes": { "classes": [], "id": "", "n": "26" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "~~~~~~~~~~~~~~~~~~~~~\n", "~~~~~~~~~:-)~~~~~~~~~\n", "~~~~~~~~~~~~~~~~~~~~~\n" ] } ], "source": [ "for i in range(3):\n", " print(\"~\"*9 + (\":-)\" if i==1 else \"~~~\") + \"~\"*9)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sample project\n", "Let's look at some GeoJSON data in San Francisco." ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "attributes": { "classes": [], "id": "", "n": "57" } }, "outputs": [], "source": [ "import json\n", "data = None\n", "with open('san-francisco.geojson') as json_file: \n", " data = json.load(json_file)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can see a list of neighborhoods (at least, according to this dataset):" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "attributes": { "classes": [], "id": "", "n": "58" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Seacliff\n", "Marina\n", "Pacific Heights\n", "Nob Hill\n", "Presidio Heights\n", "Downtown/Civic Center\n", "Excelsior\n", "Bernal Heights\n", "Western Addition\n", "Chinatown\n", "North Beach\n", "Haight Ashbury\n", "Outer Mission\n", "Crocker Amazon\n", "West of Twin Peaks\n", "South of Market\n", "Potrero Hill\n", "Inner Richmond\n", "Bayview\n", "Noe Valley\n", "Inner Sunset\n", "Diamond Heights\n", "Lakeshore\n", "Russian Hill\n", "Treasure Island/YBI\n", "Twin Peaks\n", "Outer Richmond\n", "Visitacion Valley\n", "Golden Gate Park\n", "Parkside\n", "Financial District\n", "Ocean View\n", "Mission\n", "Presidio\n", "Castro/Upper Market\n", "Outer Sunset\n", "Glen Park\n" ] } ], "source": [ "## get a list of neighborhoods\n", "for i in range(len(data['features'])):\n", " print(data['features'][i]['properties']['name'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's install GeoPandas!" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "attributes": { "classes": [], "id": "", "n": "75" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: geopandas in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (0.5.0)\n", "Requirement already satisfied: descartes in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (1.1.0)\n", "Requirement already satisfied: pyproj in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from geopandas) (2.2.0)\n", "Requirement already satisfied: fiona in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from geopandas) (1.8.6)\n", "Requirement already satisfied: pandas in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from geopandas) (0.24.1)\n", "Requirement already satisfied: shapely in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from geopandas) (1.6.4.post2)\n", "Requirement already satisfied: matplotlib in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from descartes) (2.2.3)\n", "Requirement already satisfied: aenum; python_version < \"3.6\" in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from pyproj->geopandas) (2.1.2)\n", "Requirement already satisfied: attrs>=17 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from fiona->geopandas) (18.1.0)\n", "Requirement already satisfied: click-plugins>=1.0 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from fiona->geopandas) (1.1.1)\n", "Requirement already satisfied: click<8,>=4.0 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from fiona->geopandas) (7.0)\n", "Requirement already satisfied: munch in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from fiona->geopandas) (2.3.2)\n", "Requirement already satisfied: six>=1.7 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from fiona->geopandas) (1.11.0)\n", "Requirement already satisfied: cligj>=0.5 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from fiona->geopandas) (0.5.0)\n", "Requirement already satisfied: python-dateutil>=2.5.0 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from pandas->geopandas) (2.7.3)\n", "Requirement already satisfied: numpy>=1.12.0 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from pandas->geopandas) (1.15.1)\n", "Requirement already satisfied: pytz>=2011k in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from pandas->geopandas) (2018.5)\n", "Requirement already satisfied: cycler>=0.10 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from matplotlib->descartes) (0.10.0)\n", "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from matplotlib->descartes) (2.2.0)\n", "Requirement already satisfied: kiwisolver>=1.0.1 in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from matplotlib->descartes) (1.0.1)\n", "Requirement already satisfied: setuptools in /Users/kmarwaha/miniconda3/lib/python3.5/site-packages (from kiwisolver>=1.0.1->matplotlib->descartes) (40.2.0)\n", "\u001b[33mYou are using pip version 19.0.1, however version 19.1.1 is available.\n", "You should consider upgrading via the 'pip install --upgrade pip' command.\u001b[0m\n" ] } ], "source": [ "import sys\n", "!{sys.executable} -m pip install geopandas descartes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ok! Let's use it!" ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "attributes": { "classes": [], "id": "", "n": "79" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
namecartodb_idcreated_atupdated_atgeometry
0Seacliff12013-02-10T05:44:042013-02-10T05:44:04(POLYGON ((-122.484089 37.78791, -122.484346 3...
1Marina202013-02-10T05:44:042013-02-10T05:44:04(POLYGON ((-122.446806 37.805401, -122.44678 3...
2Pacific Heights232013-02-10T05:44:042013-02-10T05:44:04(POLYGON ((-122.446825 37.787251, -122.447228 ...
3Nob Hill252013-02-10T05:44:042013-02-10T05:44:04(POLYGON ((-122.418609 37.78891, -122.421954 3...
4Presidio Heights292013-02-10T05:44:042013-02-10T05:44:04(POLYGON ((-122.4626 37.789041, -122.460923 37...
\n", "
" ], "text/plain": [ " name cartodb_id created_at updated_at \\\n", "0 Seacliff 1 2013-02-10T05:44:04 2013-02-10T05:44:04 \n", "1 Marina 20 2013-02-10T05:44:04 2013-02-10T05:44:04 \n", "2 Pacific Heights 23 2013-02-10T05:44:04 2013-02-10T05:44:04 \n", "3 Nob Hill 25 2013-02-10T05:44:04 2013-02-10T05:44:04 \n", "4 Presidio Heights 29 2013-02-10T05:44:04 2013-02-10T05:44:04 \n", "\n", " geometry \n", "0 (POLYGON ((-122.484089 37.78791, -122.484346 3... \n", "1 (POLYGON ((-122.446806 37.805401, -122.44678 3... \n", "2 (POLYGON ((-122.446825 37.787251, -122.447228 ... \n", "3 (POLYGON ((-122.418609 37.78891, -122.421954 3... \n", "4 (POLYGON ((-122.4626 37.789041, -122.460923 37... " ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import descartes\n", "import geopandas as gpd\n", "import matplotlib.pyplot as plt\n", "file = gpd.read_file('san-francisco.geojson')\n", "file.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also see nice maps :-)" ] }, { "cell_type": "code", "execution_count": 82, "metadata": { "attributes": { "classes": [], "id": "", "n": "82" } }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "ax = file.plot(color='blue')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Does it work?\n", "\n", "You can decide for yourself. Explore the diffs on GitHub, for\n", "example [here][1] or [here][2].\n", "\n", "In my opinion, this is still a prototype, but a\n", "cool possibility for using Jupyter and Git together.\n", "[1]:https://github.com/marwahaha/jupyter-diff/commit/8479a35\n", "[2]:https://github.com/marwahaha/jupyter-diff/commit/e0faff\n", "\n", "## Thanks!\n", "\n", "Check out the latest [Jupyter Lab\n", "interface](https://jupyterlab.readthedocs.io/en/stable/getting_started/overview.html)\n", "for working with notebooks in a friendly, responsive way." ] } ], "metadata": {}, "nbformat": 4, "nbformat_minor": 2 }