{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Running and Timing Programs\n",
    "\n",
    "In this notebook, we'll learn how to write programs that can launch other programs and time how long it takes to do things (you'll often be combining these skills to time how long it takes to run a program).\n",
    "\n",
    "Both these skills are covered in much more detail in an optional reading, Chapter 17 of Automate the Boring Stuff: https://automatetheboringstuff.com/2e/chapter17/.  If you decide to read that, we recommend skipping the middle sections, \"Multithreading\" through \"Project: Multithreaded XKCD Downloader\"\n",
    "\n",
    "## Running Programs\n",
    "\n",
    "### Example 1: Running `pwd`\n",
    "\n",
    "Remember that running the `pwd` program in a shell tells you what directory you're currently in.  Let's write some Python code to run the `pwd` program automatically and capture the output.  We'll do this with the `check_output` function in the `subprocess` module (https://docs.python.org/2/library/subprocess.html#subprocess.check_output) -- let's import that."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from subprocess import check_output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the simplest form, we can run pass a program name (as a string) to the function, which will capture and return the output:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'/home/trh/lec3\\n'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "output = check_output(\"pwd\")\n",
    "output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What type is that output?  It looks like a string, but with a \"b\" in front.  Hmmmm...."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "bytes"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(output)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `bytes` type in Python is a sequence, like a string.  The difference is that `bytes` may contain letters (as in this case), or other types.  If we know the encoding of a bytes sequence, we can convert to a string as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'/home/trh/lec3\\n'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "str_output = str(output, encoding=\"utf-8\")\n",
    "str_output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "str"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(str_output)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 2: Checking Versions\n",
    "\n",
    "What version of git do we have on this computer?  From the command line, we could run `git --version` to find out.  But let's do that in code.  This is a little trickier because we have both a program name, `git`, and an argument, `--version`.  The `checkout_output` function supports two ways of running programs with arguments.\n",
    "\n",
    "Way 1: pass `shell=True`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'git version 2.17.1\\n'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_output(\"git --version\", shell=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or (preferred), we can pass the program and arguments in one list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b'git version 2.17.1\\n'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_output([\"git\", \"--version\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's actually do the string manipulation work to isolate the version:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'git version 2.17.1\\n'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "output = str(check_output([\"git\", \"--version\"]), encoding=\"utf-8\")\n",
    "output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['git', 'version', '2.17.1']"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "parts = output.strip().split()\n",
    "parts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2.17.1'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "version = parts[-1]\n",
    "version"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we needed to have a specific version, we might use the above to have an assert like this:\n",
    "\n",
    "```\n",
    "assert version == `2.17.1`\n",
    "```\n",
    "\n",
    "What if the program isn't installed, or we pass it some arguments that cause it to crash, as in the following example?  We'll want to have catch some exceptions in these scenarios:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "program crashed\n",
      "OUTPUT: b''\n"
     ]
    }
   ],
   "source": [
    "import subprocess\n",
    "\n",
    "try:\n",
    "    output = str(check_output([\"git\", \"--oops\"]), encoding=\"utf-8\")\n",
    "except FileNotFoundError:\n",
    "    print(\"program not installed?\")\n",
    "except subprocess.CalledProcessError as e:\n",
    "    print(\"program crashed\")\n",
    "    # if there were any output before it crashed, we could look at it\n",
    "    # with this:\n",
    "    print(\"OUTPUT:\", e.output)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 3: Making Animations\n",
    "\n",
    "A common situation is that there will be some program that does something useful that we can't directly do in Python, and we'll want to write Python code to run these external programs to make use of their features.\n",
    "\n",
    "For example, the `ffmpeg` program can make an animated video by glueing together a bunch of `.png` image files in sequence.  There are ways to make animations directly in Python, but for now let's see how we can execute `ffmpeg` with `check_output` to make a video.\n",
    "\n",
    "First, you should install the `ffmpeg` program on Ubuntu so we can use it -- run the following in the shell:\n",
    "\n",
    "```\n",
    "sudo apt install ffmpeg\n",
    "```\n",
    "\n",
    "Now, let's write some code to make a series of plots with a red dot in different positions, and save those plots as `0.png`, `1.png`, etc.  The idea is that these images are similar enough that if you flipped through them, it would look like a rough video."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import matplotlib\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "matplotlib.rcParams[\"font.size\"] = 16"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYoAAAEDCAYAAAArwUMAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAUlklEQVR4nO3dfZBldX3n8feHGQXBrRJ2h9pKwtMECmYojDGzG0pMArMxoJsadgtXLYNBSx7UMpK4MYHCEANUFqOLlmFXGJZdXCClwrKBdRND5MFEKpgakgUZjDxkBkhKi0GG5yeB7/5xbmfaS8/vnunbfW83vl9Vt073757fOd/zm+776fM4qSokSdqZ3aZdgCRpaTMoJElNBoUkqcmgkCQ1GRSSpCaDQpLU1CsokvxEkj9M8ldJnk5SSQ7s2Xe3JGcm2Zrk2SS3JzlhnKIlSZPTd4/iYOAdwHbgL3dxHecCnwAuBN4K3ApcleRtu7gcSdIUpM8Nd0l2q6qXBl+fDFwCHFRVW0f02xd4EDi/qn53VvsNwKqqev0YtUuSJqDXHsVMSMzDscCrgSuG2q8Ajkhy0DyXK0makMU+mX048Bxw71D75sF07SKvX5I0ppWLvPx9gEfr5ce3Hpn1/sskORU4FWCvvfb6mcMOO2zxKpSkV6Dbbrvt4apatRDLWuygmJeq2ghsBFi3bl1t2rRpyhVJ0vKS5P6FWtZiH3raDrwuSYbaZ/YkHkGStKQtdlBsBnYHfnKofebcxF2LvH5J0pgWOyi+CvwA+JWh9hOBO6tqyyKvX5I0pt7nKJK8ffDlzwymb02yDdhWVV8fzPMC8IWqej9AVT2U5ALgzCRPAH8DvBNYD2xYoG2QJC2iXTmZfdXQ9/91MP06cPTg6xWD12xnAU8CpwP/EvgO8I6q+souVSpJmoreQVFVwyeke81TVS8C5w1ekqRlxqfHSpKaDApJUpNBIUlqMigkSU0GhSSpyaCQJDUZFJKkJoNCktRkUEiSmgwKSVKTQSFJajIoJElNBoUkqcmgkCQ1GRSSpCaDQpLUZFBIkpoMCklSk0EhSWoyKCRJTQaFJKnJoJAkNRkUkqQmg0KS1GRQSJKaDApJUpNBIUlqMigkSU0GhSSpyaCQJDUZFJKkpl5BkWS/JFcneSzJ40muSbJ/z777J/lCkgeSPJPk7iTnJdlrvNIlSZOwctQMSfYEbgSeA04CCjgPuCnJ66vqqUbfvYCvAa8Cfgd4APhXwO8BhwDvHHcDJEmLa2RQAKcAq4FDq+pegCR3APcApwEXNPoeRRcIx1bV9YO2m5LsA/xmkj2r6ul5Vy9JWnR9Dj1tAG6dCQmAqtoC3AIcP6LvqwfTx4faHx2sOz3rlCRNSZ+gOBy4c472zcDaEX2/Rrfn8ckka5O8Nsl64HTgotZhK0nS0tAnKPYBts/R/giwd6tjVT0LvHmwns3AE8ANwFeAD++sX5JTk2xKsmnbtm09SpQkLZZFvTw2yR7Al4B9gfcAvwB8jO4k9n/ZWb+q2lhV66pq3apVqxazREnSCH1OZm9n7j2Hne1pzPZ+4Gjg4Kq6b9D2F0keAzYmuaiqbu9brCRp8vrsUWymO08xbC1w14i+RwDbZ4XEjL8eTNf0WL8kaYr6BMV1wJFJVs80JDmQ7tLX60b0/R6wd5KDh9p/djD9x35lSpKmpU9QXAJsBa5NcnySDcC1wIPAxTMzJTkgyQtJzp7V9zK6E9h/kuSkJMck+RjwaeA2uktsJUlL2MigGFzCuh64G7gcuBLYAqyvqidnzRpgxexlVtVW4Ejg/9Hdzf0ndDfwbQTeUlUvLchWSJIWTZ+T2VTVA8AJI+bZyhw30FXVXcA75lOcJGn6fHqsJKnJoJAkNRkUkqQmg0KS1GRQSJKaDApJUpNBIUlqMigkSU0GhSSpyaCQJDUZFJKkJoNCktRkUEiSmgwKSVKTQSFJajIoJElNBoUkqcmgkCQ1GRSSpCaDQpLUZFBIkpoMCklSk0EhSWoyKCRJTQaFJKnJoJAkNRkUkqQmg0KS1GRQSJKaDApJUlOvoEiyX5KrkzyW5PEk1yTZv+9KkqxJclWSh5M8k+Q7SU6ff9mSpElZOWqGJHsCNwLPAScBBZwH3JTk9VX11Ij+6wb9bwZOBh4DDgFeO1blkqSJGBkUwCnAauDQqroXIMkdwD3AacAFO+uYZDfgfwI3VNW/n/XWTfOuWJI0UX0OPW0Abp0JCYCq2gLcAhw/ou/RwBoaYSJJWtr6BMXhwJ1ztG8G1o7o++bBdI8ktyb5QZKHknwuyWt2pVBJ0nT0CYp9gO1ztD8C7D2i748Npl8CrgfeAvwB3bmKP9pZpySnJtmUZNO2bdt6lChJWix9zlGMYyaIrqiqswdf35xkBXB+kjVV9e3hTlW1EdgIsG7dulrkGiVJDX32KLYz957DzvY0Zvv+YPrnQ+3XD6Y/3WP9kqQp6hMUm+nOUwxbC9zVo2/LSz3WL0maoj5BcR1wZJLVMw1JDgSOGrzX8qd0918cO9R+3GC6qVeVkqSp6RMUlwBbgWuTHJ9kA3At8CBw8cxMSQ5I8kKSmXMRVNX3gf8EfCDJ7yf5xSRnAGcDX5h9ya0kaWkaeTK7qp5Ksh74DHA5EOAG4Ner6slZswZYwcvD5xzgCeBDwG8C3wU+BZw7dvWSpEXX66qnqnoAOGHEPFvpwmK4vehuuPOmO0lahnx6rCSpyaCQJDUZFJKkJoNCktRkUEiSmgwKSVKTQSFJajIoJElNBoUkqcmgkCQ1GRSSpCaDQpLUZFBIkpoMCklSk0EhSWoyKCRJTQaFJKnJoJAkNRkUkqQmg0KS1GRQSJKaDApJUpNBIUlqMigkSU0GhSSpyaCQJDUZFJKkJoNCktRkUEiSmgwKSVKTQSFJauoVFEn2S3J1kseSPJ7kmiT77+rKkpyRpJJ8Y9dLlSRNw8igSLIncCNwGHAS8B7gEOCmJHv1XVGS1cDHgYfmV6okaRpW9pjnFGA1cGhV3QuQ5A7gHuA04IKe6/o8cCVwaM/1SpKWgD6HnjYAt86EBEBVbQFuAY7vs5Ik7wbeCJw5nyIlSdPTJygOB+6co30zsHZU5yR7A58BfquqHtm18iRJ09YnKPYBts/R/giwd4/+nwLuBi7rW1SSU5NsSrJp27ZtfbtJkhbBol4em+TngF8FPlhV1bdfVW2sqnVVtW7VqlWLV6AkaaQ+J5W3M/eew872NGa7GLgU+Ickr5u1zhWD75+pquf6FitJmrw+QbGZ7jzFsLXAXSP6rhm8PjDHe9uB3wA+26MGSdKU9AmK64BPJ1ldVX8PkORA4CjgjBF9j5mj7bPACuDXgHvneF+StIT0CYpLgA8D1yb5OFDAucCDdIeWAEhyAHAfcE5VnQNQVTcPLyzJo8DKud6TJC09I09mV9VTwHq6K5cup7tpbguwvqqenDVr6PYUfH6UJL2C9LpDuqoeAE4YMc9WurAYtayj+6xTkrQ0+Ne/JKnJoJAkNRkUkqQmg0KS1GRQSJKaDApJUpNBIUlqMigkSU0GhSSpyaCQJDUZFJKkJoNCktRkUEiSmgwKSVKTQSFJajIoJElNBoUkqcmgkCQ1GRSSpCaDQpLUZFBIkpoMCklSk0EhSWoyKCRJTQaFJKnJoJAkNRkUkqQmg0KS1GRQSJKaDApJUlOvoEiyX5KrkzyW5PEk1yTZv0e/dUk2Jvm7JE8neSDJlUkOGr90SdIkjAyKJHsCNwKHAScB7wEOAW5KsteI7u8CDgc+B7wVOAN4I7ApyX5j1C1JmpCVPeY5BVgNHFpV9wIkuQO4BzgNuKDR95NVtW12Q5JbgC2D5Z49n6IlSZPT59DTBuDWmZAAqKotwC3A8a2OwyExaLsf2Ab8+K6VKkmahj5BcThw5xztm4G1u7rCJGuAfYFv72pfSdLk9QmKfYDtc7Q/Auy9KytLshK4iG6P4tLGfKcm2ZRk07ZtL9spkSRN0KQvj70QeBNwYlXNFT4AVNXGqlpXVetWrVo1ueokSS/T52T2dubec9jZnsackpwPnAqcVFXX9+0nSZquPkGxme48xbC1wF19VpLkLOC3gV+rqsv7lydJmrY+h56uA45MsnqmIcmBwFGD95qSfAQ4Dzirqi6cX5mSpGnpExSXAFuBa5Mcn2QDcC3wIHDxzExJDkjyQpKzZ7W9C/gs8FXgxiRHznrt8hVTkqTJG3noqaqeSrIe+AxwORDgBuDXq+rJWbMGWMEPh89xg/bjBq/Zvg4cPe/KJUkT0eccBVX1AHDCiHm20oXC7Lb3Au+dX2mSpKXAp8dKkpoMCklSk0EhSWoyKCRJTQaFJKnJoJAkNRkUkqQmg0KS1GRQSJKaDApJUpNBIUlqMigkSU0GhSSpyaCQJDUZFJKkJoNCktRkUEiSmgwKSVKTQSFJajIoJElNBoUkqcmgkCQ1GRSSpCaDQpLUZFBIkpoMCklS09IPittug913hzVr4EMfgm99a9oVSdKPlFTVtGtoWpfUpplvVqzoQuMNb4DLL4fVq6dZmiQtWUluq6p1C7Gspb9HMduLL8LTT8M3vwlHHAFf/vK0K5KkV7zlFRQzZgLjve81LCRpkS3PoJjxzDPwvvfBli3TrkSSXrF6BUWS/ZJcneSxJI8nuSbJ/j377pHkU0m+m+SZJH+V5OfHK3uW556DE09csMVJkn7YyKBIsidwI3AYcBLwHuAQ4KYke/VYx6XAKcDZwC8D3wX+LMkb5lv0D3nxRfjbv/VqKElaJH32KE4BVgP/rqr+uKquBTYABwCntTom+Sng3cBvVNUlVXUD8A7gAeCcsSqf7fnn4aKLFmxxkqQd+gTFBuDWqrp3pqGqtgC3AMf36PsD4Euz+r4AfBE4Nsnuu1zxXF58EW66aUEWJUn6YX2C4nDgzjnaNwNre/TdUlVPz9H31cDBPdbfz333LdiiJEk7rOwxzz7A9jnaHwH2HqPvzPsvk+RU4FSAfw70umPk+ee5Lbmtz6zL2L8AHp52EUuEY7GDY7GDY7HDoQu1oD5BMXFVtRHYCJBk08MLdHfhcpdk00LdabncORY7OBY7OBY7JNk0eq5++hx62s7cew4721vo2xd27FlIkpaoPkGxme5cw7C1wF09+h40uMR2uO/zwL0v7yJJWkr6BMV1wJFJ/ukJfEkOBI4avNfyf4BXAf9hVt+VwDuB66vquR7r39hjnh8VjsUOjsUOjsUOjsUOCzYWI58eO7ip7nbgGeDjQAHnAv8MeH1VPTmY7wDgPuCcqjpnVv8vAscCHwO2AB+ku/HuTVX1Nwu1IZKkxTFyj6KqngLWA3cDlwNX0n3gr58JiYEAK+ZY5vuA/wGcB/xfYD/gOENCkpaHJf//UUiSpmsqT49d0g8ZnLD5jkWSdUk2Jvm7JE8neSDJlUkOmkTdi2Gcn4uh5ZyRpJJ8YzHqnIRxxyLJmiRXJXl48HvynSSnL2bNi2XMz4v9k3xh8PvxTJK7k5zX8zl1S06Sn0jyh4PPvacHP+cH9uy7W5Izk2xN8myS25Oc0KfvxINiyT9kcILGHIt30V2N9jngrcAZwBuBTUn2W7SiF8kC/FzMLGc13bm0hxajzkkYdyySrAO+CewOnAy8DfjPdIeGl5VxxmLw/teAnwd+h24c/hvwH4H/vohlL6aD6Z6Xtx34y13sey7wCeBCus+MW4GrkrxtZM+qmugLOB14ETh4VttBwAvAR0f0/Sm6k+nvm9W2EvgOcN2kt2XKY7FqjrYDgJfoLiiY+vZNaiyGlvNnwMXAzcA3pr1dU/i52I3usvX/Pe3tWAJj8UuDz4tfGmo/f9B/z2lv3zzGY7dZX5882L4De/TbF3gO+L2h9huAO0b1n8ahp6X/kMHJmfdYVNW2OdruB7YBP77AdU7COD8XACR5N91e1ZmLUuHkjDMWRwNrgAsWrbrJGmcsXj2YPj7U/ihdoGahipyUqnppnl2PpRuPK4barwCOGHXIehpBsTweMjgZ44zFyyRZQ/eXw7fHrGsaxhqLJHsDnwF+q6qW+x3/44zFmwfTPZLcmuQHSR5K8rkkr1nQKidjnLH4GnAP8Mkka5O8Nsl6ur2Ui6q7ovNHxeF0exTDNzlvHkybYzmNoJj4QwaXsHHG4ocMbmS8iG6P4tLxS5u4ccfiU3SXcF+2gDVNyzhj8WOD6ZeA64G3AH9Ad5jijxaqwAma91hU1bN0wbkb3QfiE3SHWr4CfHhhy1zy9gEercHxpll6fXYuyYcCal4uBN4E/NuqGvUMrleUJD8H/Crwxjl+EX7UzPzxd0VVnT34+uYkK4Dzk6ypquW4x7nLkuxBF5j70p0EfwD413QXwrxAd/OvephGUIz7kMEDdtIXlt9DBscZi3+S5Hy6x7KfVFXXL1BtkzbOWFxMtxf1D0leN2hbCawYfP9M9XtczFIxzlh8fzD986H26+lO4v40y+vQ5Dhj8X66czYHV9XMf1jzF0keAzYmuaiqbl+wSpe27cDrkmToj6len53TOPTkQwZ3GGcsAEhyFvDbwEeq6vIFrG3SxhmLNcAH6H4ZZl5HAUcOvl5ufzmO+zvSMt+TodMyzlgcAWyfFRIz/nowXTNmbcvJZrrLpX9yqH3m3ERzLKcRFNN+yOBSMs5YkOQjdI9GOauqLlykGidlnLE4Zo7X7XQnQY8Brl74chfVOGPxp3QnLY8daj9uMF2w/6NgQsYZi+8BeycZvsjlZwfTf1ygGpeDr9JdMforQ+0nAncOriTbuSlcB7wX3V/+36K7vG0D3S/13wOvnTXfAXTHEc8e6v9Fur8STwb+Dd2HwLN0x6enfp3zpMaC7oa7l+g+GI4ceq2d9rZN+udijuXdzPK9j2Lc35HfHbT/PvCLdDdjPgNcNu1tm+RYAAfSXRp7N93NesfQPZz0cbrA3G3S27NAY/L2wevzdPdRfHDw/S/MmucF4NKhfucPPis/SndI7vODz5BfHrnOKW3o/sD/GvyDPQH8MUM3jQz+kQv4xFD7a+iuEf/eYKO/CRw97X+8SY8F3dU9tZPXzdPerkn/XMyxrGUbFOOOBd39AR8dfMA+D9wPnAO8atrbNYWxWAt8GXiQLizvBj4N7D3t7RpjPEb+3g++v2yo3wq6pxbcT7fXeQfw9j7r9KGAkqSmqTwUUJK0fBgUkqQmg0KS1GRQSJKaDApJUpNBIUlqMigkSU0GhSSp6f8DTQw2hUckP+4AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYoAAAEDCAYAAAArwUMAAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAVrUlEQVR4nO3dfZBc1X3m8e/DCPEib5VFRdRWEt5kKJAoiO0ogTJOAto4YG9K1BZe7HIgwBqQ7XJM1hsnUDjEASqLYy92OTgGsSywgpQNhF1Yb+IQ8+LEqoiUnBghYZs3CZGUXchGvAsB4uwft2c1bs2cvpqe7p6B76eqq2dO33Pvr49m+plz35RSCpIkTWWvURcgSZrdDApJUpVBIUmqMigkSVUGhSSpyqCQJFW1CookP5/kz5L8Q5KXkpQkh7bsu1eSi5JsTvJykgeSnNZP0ZKk4Wk7ozgcOB3YBvz9Hm7jMuAzwFXAe4G1wK1J3reH65EkjUDaXHCXZK9Syuudr88FrgUOK6Vs7tHvQOBJ4IpSyh9NaL8bWFRKObaP2iVJQ9BqRjEeEtNwMjAfuKmr/SbgmCSHTXO9kqQhGfTB7KOBHcCjXe0bO89LB7x9SVKf5g14/QcAz5Td9289PeH13SQ5HzgfYMGCBb941FFHDa5CSXoD+s53vvPjUsqimVjXoINiWkopq4BVAMuWLSvr1q0bcUWSNLckeWKm1jXoXU/bgLcmSVf7+EziaSRJs9qgg2IjsA/wtq728WMTDw14+5KkPg06KL4BvAr8Vlf7GcCGUsqmAW9fktSn1scokry/8+Uvdp7fm2QrsLWU8q3OMq8BN5ZSPgxQSnkqyZXARUmeB/4J+ACwHFgxQ+9BkjRAe3Iw+9au7/+88/wt4MTO12Odx0QXAy8AFwD/FvgBcHop5et7VKkkaSRaB0UppfuAdKtlSik7gcs7D0nSHOPdYyVJVQaFJKnKoJAkVRkUkqQqg0KSVGVQSJKqDApJUpVBIUmqMigkSVUGhSSpyqCQJFUZFJKkKoNCklRlUEiSqgwKSVKVQSFJqjIoJElVBoUkqcqgkCRVGRSSpCqDQpJUZVBIkqoMCklSlUEhSaoyKCRJVQaFJKnKoJAkVRkUkqQqg0KSVGVQSJKqDApJUlWroEhyUJLbkjyb5Lkktyc5uGXfg5PcmGRLku1JHk5yeZIF/ZUuSRqGeb0WSLI/cA+wAzgLKMDlwL1Jji2lvFjpuwD4JrA38IfAFuCXgD8GjgA+0O8bkCQNVs+gAM4DFgNHllIeBUiyHngEWAlcWel7Ak0gnFxKuavTdm+SA4DfS7J/KeWlaVcvSRq4NrueVgBrx0MCoJSyCVgDnNqj7/zO83Nd7c90tp2WdUqSRqRNUBwNbJikfSOwtEffb9LMPD6bZGmStyRZDlwAXF3bbSVJmh3aBMUBwLZJ2p8GFtY6llJeBt7d2c5G4HngbuDrwMen6pfk/CTrkqzbunVrixIlSYMy0NNjk+wLfA04EDgT+DXgUzQHsb88Vb9SyqpSyrJSyrJFixYNskRJUg9tDmZvY/KZw1QzjYk+DJwIHF5KeazT9ndJngVWJbm6lPJA22IlScPXZkaxkeY4RbelwEM9+h4DbJsQEuP+sfO8pMX2JUkj1CYo7gSOT7J4vCHJoTSnvt7Zo++PgIVJDu9qP67z/K/typQkjUqboLgW2AzckeTUJCuAO4AngWvGF0pySJLXklwyoe8NNAew/yrJWUlOSvIp4PPAd2hOsZUkzWI9g6JzCuty4GFgNXAzsAlYXkp5YcKiAcYmrrOUshk4HvguzdXcf0VzAd8q4D2llNdn5F1IkgamzcFsSilbgNN6LLOZSS6gK6U8BJw+neIkSaPn3WMlSVUGhSSpyqCQJFUZFJKkKoNCklRlUEiSqgwKSVKVQSFJqjIoJElVBoUkqcqgkCRVGRSSpCqDQpJUZVBIkqoMCklSlUEhSaoyKCRJVQaFJKnKoJAkVRkUkqQqg0KSVGVQSJKqDApJUpVBIUmqMigkSVUGhSSpyqCQJFUZFJKkKoNCklRlUEiSqloFRZKDktyW5NkkzyW5PcnBbTeSZEmSW5P8OMn2JD9IcsH0y5YkDcu8Xgsk2R+4B9gBnAUU4HLg3iTHllJe7NF/Waf/fcC5wLPAEcBb+qpckjQUPYMCOA9YDBxZSnkUIMl64BFgJXDlVB2T7AX8T+DuUsp/mPDSvdOuWJI0VG12Pa0A1o6HBEApZROwBji1R98TgSVUwkSSNLu1CYqjgQ2TtG8Elvbo++7O875J1iZ5NclTSb6UZL89KVSSNBptguIAYNsk7U8DC3v0/dnO89eAu4D3AH9Kc6ziL6bqlOT8JOuSrNu6dWuLEiVJg9LmGEU/xoPoplLKJZ2v70syBlyRZEkp5XvdnUopq4BVAMuWLSsDrlGSVNFmRrGNyWcOU800JvpJ5/lvu9rv6jy/o8X2JUkj1CYoNtIcp+i2FHioRd+a11tsX5I0Qm2C4k7g+CSLxxuSHAqc0Hmt5q9prr84uav9lM7zulZVSpJGpk1QXAtsBu5IcmqSFcAdwJPANeMLJTkkyWtJxo9FUEr5CfBfgY8k+ZMkv57kQuAS4MaJp9xKkmanngezSykvJlkOfAFYDQS4G/jdUsoLExYNMMbu4XMp8DzwMeD3gB8CnwMu67t6SdLAtTrrqZSyBTitxzKbacKiu73QXHDnRXeSNAd591hJUpVBIUmqMigkSVUGhSSpyqCQ2nrwQfjYx2DJEthnH0ia5yVLmvYHHxx1hdJADPpeT9Lc9/jjcOaZ8N3vwo4dsHPnrtdeeQW+/3145BG48UZ4+9th9WpYvHjq9UlzjDMKqeaWW+CYY+D+++Gll346JCbaubN5/f77m+VvuWW4dUoD5IxCmsott8DZZ8P27e37jAfG2Wc3359++iAqk4bKGYU0mccfh3PO2bOQmGj79qb/pk0zW5c0AgaFNJkzz2yOR/Rjxw4444yZqUcaIYNC6rZ+fXPgeqrjEW3t3An//M+eDaU5z6CQul19df+ziXGvvNKsT5rDDAqp27339j+bGLdzZ7M+aQ4zKKRujz8+s+t77LGZXZ80ZAaF1O2VV2Z2fa++OrPrk4bMoJC6zZ8/s+vbe++ZXZ80ZAaF1G2mb7/xtrfN7PqkITMopG4nnQRjYzOzrrGxZn3SHGZQSN0+8pHmrrAzYf78Zn3SHGZQSN2OPba5C2y/s4qxMXjHO5qbBEpzmEEhTWb16v5nFfvsAzfdNDP1SCNkUEiTWbwYrr8e9ttvev3326/pf9hhM1uXNALeZlyayvgtws85Z/f/sGgqY2PNTOL6673FuN4wnFFINaef3tzU77jjmlnCVMctxsaa1487DjZsMCT0hmJQSL0sXgxr1jT/e93Klc3/kT1/fvN/Zs+f33y/cmXz+po17m7SG467nqS2jjkGvvzlUVchDZ0zCklSlUEhSaoyKCRJVQaFJKnKoJAkVbUKiiQHJbktybNJnktye5KD93RjSS5MUpJ8e89LlSSNQs+gSLI/cA9wFHAWcCZwBHBvkgVtN5RkMfBp4KnplSpJGoU211GcBywGjiylPAqQZD3wCLASuLLltr4C3Awc2XK7kqRZoM2upxXA2vGQACilbALWAKe22UiSDwHvBC6aTpGSpNFpExRHAxsmad8ILO3VOclC4AvA75dSnt6z8iRJo9YmKA4Atk3S/jSwsEX/zwEPAze0LSrJ+UnWJVm3devWtt0kSQMw0NNjk/wK8NvAR0sppW2/UsqqUsqyUsqyRYsWDa5ASVJPbQ4qb2PymcNUM42JrgGuA/4lyVsnbHOs8/32UsqOtsVKkoavTVBspDlO0W0p8FCPvks6j8n+d/ltwH8GvtiiBknSiLQJijuBzydZXEp5HCDJocAJwIU9+p40SdsXgTHgd4BHJ3ldkjSLtAmKa4GPA3ck+TRQgMuAJ2l2LQGQ5BDgMeDSUsqlAKWU+7pXluQZYN5kr0mSZp+eB7NLKS8Cy2nOXFpNc9HcJmB5KeWFCYuGZqbg/aMk6Q2k1RXSpZQtwGk9ltlMExa91nVim21KkmYH//qXJFUZFJKkKoNCklRlUEiSqgwKSVKVQSFJqjIoJElVBoUkqcqgkCRVGRSSpCqDQpJUZVBIkqoMCklSlUEhSaoyKCRJVQaFJKnKoJAkVRkUkqQqg0KSVGVQSJKqDApJUpVBIUmqMigkSVUGhSSpyqCQJFUZFJKkKoNCklRlUEiSqgwKSVKVQSFJqmoVFEkOSnJbkmeTPJfk9iQHt+i3LMmqJN9P8lKSLUluTnJY/6VLkoahZ1Ak2R+4BzgKOAs4EzgCuDfJgh7dPwgcDXwJeC9wIfBOYF2Sg/qoW5I0JPNaLHMesBg4spTyKECS9cAjwErgykrfz5ZStk5sSLIG2NRZ7yXTKVqSNDxtdj2tANaOhwRAKWUTsAY4tdaxOyQ6bU8AW4Gf27NSJUmj0CYojgY2TNK+EVi6pxtMsgQ4EPjenvaVJA1fm6A4ANg2SfvTwMI92ViSecDVNDOK6yrLnZ9kXZJ1W7fuNimRJA3RsE+PvQp4F3BGKWWy8AGglLKqlLKslLJs0aJFw6tOkrSbNgeztzH5zGGqmcakklwBnA+cVUq5q20/SdJotQmKjTTHKbotBR5qs5EkFwN/APxOKWV1+/IkSaPWZtfTncDxSRaPNyQ5FDih81pVkk8AlwMXl1Kuml6ZkqRRaRMU1wKbgTuSnJpkBXAH8CRwzfhCSQ5J8lqSSya0fRD4IvAN4J4kx0947PEZU5Kk4eu566mU8mKS5cAXgNVAgLuB3y2lvDBh0QBj/HT4nNJpP6XzmOhbwInTrlySNBRtjlFQStkCnNZjmc00oTCx7Wzg7OmVJkmaDbx7rCSpyqCQJFUZFJKkKoNCklRlUEiSqgwKSVKVQSFJqjIoJElVBoUkqcqgkCRVGRSSpCqDQpJUZVBIkqoMCklSlUEhSaoyKCRJVQaFJKnKoJAkVRkUkqQqg0KSVGVQSJKqDApJUpVBIUmqMigkSVUGhSSpyqCQJFUZFJKkKoNCklRlUEiSqgwKSVKVQSFJqmoVFEkOSnJbkmeTPJfk9iQHt+y7b5LPJflhku1J/iHJr/ZXtiRpWHoGRZL9gXuAo4CzgDOBI4B7kyxosY3rgPOAS4DfBH4I/E2St0+3aEnS8Mxrscx5wGLgyFLKowBJ1gOPACuBK6fqmOQXgA8B/6mUcn2n7VvARuBSYEVf1UuSBq7NrqcVwNrxkAAopWwC1gCntuj7KvC1CX1fA74KnJxknz2uWJI0VG2C4mhgwyTtG4GlLfpuKqW8NEnf+cDhLbYvSRqhNrueDgC2TdL+NLCwj77jr+8myfnA+Z1vdySZLKjejH4G+PGoi5glHItdHItdHItdjpypFbUJiqErpawCVgEkWVdKWTbikmYFx2IXx2IXx2IXx2KXJOtmal1tdj1tY/KZw1SzhbZ9YdfMQpI0S7UJio00xxq6LQUeatH3sM4ptt19XwEe3b2LJGk2aRMUdwLHJ1k83pDkUOCEzms1/wfYG/iPE/rOAz4A3FVK2dFi+6taLPNm4Vjs4ljs4ljs4ljsMmNjkVJKfYHmoroHgO3Ap4ECXAb8G+DYUsoLneUOAR4DLi2lXDqh/1eBk4FPAZuAj9JcePeuUso/zdQbkSQNRs8ZRSnlRWA58DCwGriZ5gN/+XhIdAQYm2Sd5wDXA5cD/xc4CDjFkJCkuaHnjEKS9OY2krvHepPBXaY7FkmWJVmV5PtJXkqyJcnNSQ4bRt2D0M/PRdd6LkxSknx7EHUOQ79jkWRJkluT/Ljze/KDJBcMsuZB6fPz4uAkN3Z+P7YneTjJ5S3vUzfrJPn5JH/W+dx7qfNzfmjLvnsluSjJ5iQvJ3kgyWlt+g49KLzJ4C59jsUHac5G+xLwXuBC4J3AuiQHDazoAZmBn4vx9SymOZb21CDqHIZ+xyLJMuB+YB/gXOB9wH+j2TU8p/QzFp3Xvwn8KvCHNOPw34H/AvyPAZY9SIcDp9NcevD3e9j3MuAzwFU0nxlrgVuTvK9nz1LKUB/ABcBO4PAJbYcBrwGf7NH3F2gOpp8zoW0e8APgzmG/lxGPxaJJ2g4BXqc5oWDk729YY9G1nr8BrgHuA7496vc1gp+LvWhOW/9fo34fs2AsfqPzefEbXe1XdPrvP+r3N43x2GvC1+d23t+hLfodCOwA/rir/W5gfa/+o9j15E0Gd5n2WJRStk7S9gSwFfi5Ga5zGPr5uQAgyYdoZlUXDaTC4elnLE4EllC5q/Mc089YzO88P9fV/gxNoGamihyWUsrr0+x6Ms143NTVfhNwTK9d1qMICm8yuEs/Y7GbJEto/nL4Xp91jUJfY5FkIfAF4PdLKXP9iv9+xuLdned9k6xN8mqSp5J8Kcl+M1rlcPQzFt+k+e8QPptkaZK3JFlOM0u5ujRndL5ZHE0zo+i+yHlj57k6lqMIiqHfZHAW62csfkrnQsaraWYU1/Vf2tD1OxafozmF+4YZrGlU+hmLn+08fw24C3gP8Kc0uyn+YqYKHKJpj0Up5WWa4NyL5gPxeZpdLV8HPj6zZc56BwDPlM7+pglafXbOypsCalquAt4F/PtSSq97cL2hJPkV4LeBd07yi/BmM/7H302llEs6X9+XZAy4IsmSUspcnHHusST70gTmgTQHwbcAv0xzIsxrNBf/qoVRBEW/Nxk8ZIq+MPduMtjPWPx/Sa6guS37WaWUu2aotmHrZyyuoZlF/UuSt3ba5gFjne+3l3a3i5kt+hmLn3Se/7ar/S6ag7jvYG7tmuxnLD5Mc8zm8FLKY522v0vyLLAqydWllAdmrNLZbRvw1iTp+mOq1WfnKHY9eZPBXfoZCwCSXAz8AfCJUsrqGaxt2PoZiyXAR2h+GcYfJwDHd76ea3859vs7UjPdg6Gj0s9YHANsmxAS4/6x87ykz9rmko00p0u/rat9/NhEdSxHERSjvsngbNLPWJDkEzS3Rrm4lHLVgGocln7G4qRJHg/QHAQ9Cbht5ssdqH7G4q9pDlqe3NV+Sud5xv6PgiHpZyx+BCxM0n2Sy3Gd53+doRrngm/QnDH6W13tZwAbOmeSTW0E5wEvoPnL/0Ga09tW0PxSPw68ZcJyh9DsR7ykq/9Xaf5KPBf4dzQfAi/T7J8e+XnOwxoLmgvuXqf5YDi+67F01O9t2D8Xk6zvPubudRT9/o78Uaf9T4Bfp7kYcztww6jf2zDHAjiU5tTYh2ku1juJ5uakz9EE5l7Dfj8zNCbv7zy+QnMdxUc73//ahGVeA67r6ndF57PykzS75L7S+Qz5zZ7bHNEbPRj4y84/2PPA/6bropHOP3IBPtPVvh/NOeI/6rzp+4ETR/2PN+yxoDm7p0zxuG/U72vYPxeTrGvOBkW/Y0FzfcAnOx+wrwBPAJcCe4/6fY1gLJYCtwBP0oTlw8DngYWjfl99jEfP3/vO9zd09RujuWvBEzSzzvXA+9ts05sCSpKqRnJTQEnS3GFQSJKqDApJUpVBIUmqMigkSVUGhSSpyqCQJFUZFJKkqv8Hfap78/lQZB4AAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_circle(filename, x, y):\n",
    "    fig, ax = plt.subplots()\n",
    "    ax.set_xlim(0, 1)\n",
    "    ax.set_ylim(0, 1)\n",
    "    ax.plot(x, y, 'ro', markersize=20)\n",
    "    fig.savefig(os.path.join(\"img\", filename))\n",
    "\n",
    "if not os.path.exists(\"img\"):\n",
    "    os.mkdir(\"img\")\n",
    "\n",
    "plot_circle(\"0.png\", x=0, y=0)\n",
    "plot_circle(\"1.png\", x=0.25, y=0.25)\n",
    "plot_circle(\"2.png\", x=0.5, y=0.5)\n",
    "plot_circle(\"3.png\", x=0.75, y=0.25)\n",
    "plot_circle(\"4.png\", x=1, y=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check that we created the png files in the `img` directory:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['0.png', '1.png', '4.png', '2.png', '3.png']"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "os.listdir(\"img\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's also check that they look right.  In the `IPython.display` module, there are `Image(...)` and `HTML(...)` functions that are useful for loading pictures and HTML directly into our notebook.  Let's use the first function to check that our `0.png` file looks right."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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p8YGAFjCsYBFRUWppKREo0eP1rx58zRnzhwlJSWppKREgwcPbv88Y4yCwaDa2tra1xITE1VeXq4f//jHWrlypW677Tbl5+fL6/Vq586d6tePWzgCwOXOZS7RnwpOTU2V3+/v7TEAwCo2fe3kUgYAYCUCBgCwEgEDAFiJgAEArETAAABWImAAACsRMACAlQgYAMBKBAwAYCUCBgCwEgEDAFiJgAEArETAAABWImAAACsRMACAlQgYAMBKBAwAYCUCBgCwEgEDAFiJgAEArETAAABWImAAACsRMACAlQgYAMBKBAwAYCUCBgCwEgEDAFiJgAEArETAAABWImAAACsRMACAlRwP2OHDhzVz5kzFxsYqJiZGM2bMUF1dXZf3V1ZWatasWRo6dKgiIyN13XXXaePGjQ5ODACwQZiTD97c3KyMjAyFh4eroKBALpdLK1eu1NSpU7V3715FRUWdd7/f71dGRoamTJmiLVu2KDY2VgcPHtSxY8ecHBsAYAFHA5afn6+qqiodOHBAo0aNkiRNmDBBycnJ2rx5s5YtW3bOvW1tbfrtb3+radOm6e23325fnzp1qpMjAwAs4ei3EIuKipSWltYeL0lKSkpSenq6CgsLz7u3rKxMlZWV540cAODy5WjAAoGAUlJSOq17PB5VVFScd++uXbskSSdOnFBaWpoGDBigYcOG6e6779bx48cdmRcAYA9HA1ZfXy+3291pPS4uTg0NDefd+/XXX0uSZs+erczMTO3cuVP333+/tmzZojvvvNOReQEA9nD0NbBQtLW1SZLmzp2rvLw8SdKUKVMUDAaVm5uryspKjR07tsMen88nn88nSTp69GjPDgwA6FGOXoG53e6zXmmd68rsTFdccYUk6ZZbbumwnpmZKUn67LPPOu3xer3y+/3y+/2Kj4+/2LEBABZwNGAej0eBQKDTekVFhcaNG3fBvefTrx8/gw0AlzNHK5CVlaXy8nJVVVW1r9XU1Gj37t3Kyso6795bb71V4eHhKi4u7rC+Y8cOSVJqamr3DwwAsIajAVu0aJESExOVnZ2twsJCFRUVKTs7WyNGjNDixYvbP6+2tlZhYWHtr3VJ330L8YEHHtCmTZv04IMP6v3339e6deuUl5en+fPnd3hrPgDg8uPomziioqJUUlKipUuXat68eTLGaNq0adqwYYMGDx7c/nnGGAWDwfY3bpyyevVqRUdH6/nnn9eTTz6p4cOHa/ny5Vq1apWTYwMALOAyxpjeHsIJqamp8vv9vT0GAFjFpq+dvBMCAGAlAgYAsBIBAwBYiYABAKxEwAAAViJgAAArETAAgJUIGADASgQMAGAlAgYAsBIBAwBYiYABAKxEwAAAViJgAAArETAAgJUIGADASgQMAGAlAgYAsBIBAwBYiYABAKxEwAAAViJgAAArETAAgJUIGADASgQMAGAlAgYAsBIBAwBYiYABAKxEwAAAViJgAAArOR6ww4cPa+bMmYqNjVVMTIxmzJihurq6H/w469atk8vl0o033ujAlAAA2zgasObmZmVkZGj//v0qKCjQtm3bdPDgQU2dOlVNTU1dfpyqqio99thjGjZsmIPTAgBsEubkg+fn56uqqkoHDhzQqFGjJEkTJkxQcnKyNm/erGXLlnXpcf7whz9ozpw5OnDggFpbW50cGQBgCUevwIqKipSWltYeL0lKSkpSenq6CgsLu/QYr776qvbs2aO1a9c6NSYAwEKOBiwQCCglJaXTusfjUUVFxQX3NzQ0aOnSpXr88ccVFxfnxIgAAEs5GrD6+nq53e5O63FxcWpoaLjg/uXLl2v06NFasGCBA9MBAGzm6Gtgofjggw/00ksvac+ePXK5XF3a4/P55PP5JElHjx51cjwAQC9z9ArM7Xaf9UrrXFdmZ1q8eLEWLlyoq6++Wo2NjWpsbFRra6uCwaAaGxt18uTJTnu8Xq/8fr/8fr/i4+O77XkAAPoeR6/APB6PAoFAp/WKigqNGzfuvHsrKytVWVmpTZs2dfo1t9utP//5z7rnnnu6bVYAgF0cDVhWVpbuu+8+VVVV6dprr5Uk1dTUaPfu3Vq3bt1595aWlnZau+eeexQMBvXMM890eGcjAODy4zLGGKcevKmpSRMnTlRkZKQee+wxuVwurVq1St9884327t2rwYMHS5Jqa2s1cuRIrV69WqtXrz7n402ZMkWtra3atWvXBX/v1NRU+f3+bnsuAHA5sOlrp6OvgUVFRamkpESjR4/WvHnzNGfOHCUlJamkpKQ9XpJkjFEwGFRbW5uT4wAALiGOXoH1Jpv+FgEAfYVNXzu5Gz0AwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAKxEwAICVCBgAwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAKxEwAICVCBgAwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAKxEwAICVCBgAwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAKzkesMOHD2vmzJmKjY1VTEyMZsyYobq6ugvu8/v98nq9GjNmjAYNGqSEhATNmTNH1dXVTo8MALCAowFrbm5WRkaG9u/fr4KCAm3btk0HDx7U1KlT1dTUdN69r732mgKBgO6++2699957Wrdunfbs2aPU1FQdPnzYybEBABYIc/LB8/PzVVVVpQMHDmjUqFGSpAkTJig5OVmbN2/WsmXLzrl3xYoVio+P77CWnp6upKQk5efnKy8vz8nRAQB9nKNXYEVFRUpLS2uPlyQlJSUpPT1dhYWF5937/XhJ0jXXXKP4+Hh99dVX3T4rAMAujgYsEAgoJSWl07rH41FFRcUPfrzKykodOXJEY8eO7Y7xAAAWczRg9fX1crvdndbj4uLU0NDwgx6rtbVVOTk5io+P18KFC7trRACApRx9Daw7LVmyRB9++KHefffds0ZRknw+n3w+nyTp6NGjPTkeAKCHOXoF5na7z3qlda4rs3PJzc2Vz+fTiy++qMzMzHN+ntfrld/vl9/vP+traACAS4ejV2Aej0eBQKDTekVFhcaNG9elx1izZo3Wr1+vZ555RvPmzevuEQEAlnL0CiwrK0vl5eWqqqpqX6upqdHu3buVlZV1wf1PP/20Vq5cqTVr1mjJkiVOjgoAsIyjAVu0aJESExOVnZ2twsJCFRUVKTs7WyNGjNDixYvbP6+2tlZhYWEdfrbrtdde0z333KPp06crIyND5eXl7R8X8w5GAMClxdFvIUZFRamkpERLly7VvHnzZIzRtGnTtGHDBg0ePLj984wxCgaDamtra1/bsWOHjDHasWOHduzY0eFxJ0+erLKyMidHBwD0cS5jjOntIZyQmpoqv9/f22MAgFVs+trJ3egBAFYiYAAAKxEwAICVCBgAwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAKxEwAICVCBgAwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAKxEwAICVCBgAwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAK126Afv0Uyk8XBo7VvrjH6V9+3p7IgBAN7p0AyZJLS3S/v2SzyelpUnp6VJVVW9PBQDoBpd2wE4JBqXmZumjj6Tx46U33ujtiQAAIbo8AnbKqZAtWEDEAMByjgfs8OHDmjlzpmJjYxUTE6MZM2aorq6uS3tPnDih5cuXa/jw4YqMjNQNN9ygf/7zn6EPdfy49LvfSdXVoT8WAKBXOBqw5uZmZWRkaP/+/SooKNC2bdt08OBBTZ06VU1NTRfcv3DhQuXn5ysvL09///vfNXz4cP385z/X559/HvpwJ09Kc+eG/jgAgN5hHLRhwwbTr18/c/Dgwfa1qqoq079/f/PUU0+dd+/nn39uJJkXX3yxfe3bb781o0ePNnfccccFf+9JkjEX+oiMNGbv3ot/ggBwiZk0aVJvj9Bljl6BFRUVKS0tTaNGjWpfS0pKUnp6ugoLCy+4d8CAAZo9e3b7WlhYmH7zm9+ouLhYJ0+eDH3AlhZp06bQHwcA0OMcDVggEFBKSkqndY/Ho4qKigvuTUpK0qBBgzrtbWlp0aFDh0IfMBiUSktDfxwAQI9zNGD19fVyu92d1uPi4tTQ0HDRe0/9erf44ovueRwAQI8K6+0BupPP55PP55Mk1UhK7cqmlhYptUufaa2jR48qPj6+t8foEziL0ziL0ziL0/bv39/bI3SZowFzu91nvdI619XV9/fW1taeda90+krsTF6vV16vV5KUmpoqv99/MWNfcjiL0ziL0ziL0ziL01It+gu9o99C9Hg8CgQCndYrKio0bty4C+6trq5Wc3Nzp70DBw7s8MYQAMDlx9GAZWVlqby8XFVn3H+wpqZGu3fvVlZW1nn33nHHHfr222+1ffv29rXW1la9/vrryszMVHh4uGNzAwD6vv4PP/zww049+Pjx4/Xaa6/pzTff1FVXXaV///vf8nq9ioiI0NatWzVw4EBJUm1trYYOHSpJmjx5siRp+PDh2r9/v5577jkNHTpUDQ0Nys3N1ccff6yXX35Zw4cPv+DvP2nSJKeemnU4i9M4i9M4i9M4i9NsOQuXMcY4+RvU1dVp6dKl2rlzp4wxmjZtmjZs2KDExMT2z6mpqVFSUpIeeughndnT48eP609/+pNeffVVNTY2auLEiVq/fr2mTJni5MgAAAs4HjAAAJxg1d3o++SNgXvJxZ6F3++X1+vVmDFjNGjQICUkJGjOnDmqtvjGxqH8uTjTunXr5HK5dOONNzowZc8I9SwqKys1a9YsDR06VJGRkbruuuu0ceNGByd2TihnUVdXp/nz5yshIUGRkZEaPXq0Vq5c2aV7uPZFX375pe666y7dcMMNGjRokFwul2pqarq0t62tTWvXrlViYqIiIiI0ceJEvfXWW84O3FW9eiOrH6CpqcmMGjXKeDwe8/bbb5t33nnHpKSkmGuvvdYcO3bsgvvvvPNOExsba3w+n3n//ffNL3/5SxMREWE+++yzHpi+e4VyFvfee6/56U9/ap577jlTVlZmXnnlFTNmzBgTFxdn6urqeugZdJ9Q/1yc8sUXX5ioqCgzbNgwk56e7uDEzgn1LD755BMTHR1t7rjjDvP222+bkpISs3nz5gvet7QvCuUsjh07ZpKTk01iYqL5y1/+YkpKSsz69etNRESE+fWvf91Dz6B7lZaWmmHDhplbb73VZGZmGkmmurq6S3sffPBBM3DgQPPEE0+YkpIS4/V6jcvlMu+++66zQ3eBNQHrzRsD9zWhnMWRI0c6rdXU1BiXy2VWrVrV7bM6LZSzOFNmZqbxer1m8uTJ1gYslLMIBoNm7Nix5he/+IXTY/aIUM6iuLjYSDLFxcUd1lesWGH69+9vmpqaHJnZScFgsP1/5+fndzlg//3vf83AgQPN6tWrO6xnZGSY8ePHd/eYP5g130Ls8zcG7kGhnMXZ7jZwzTXXKD4+Xl999VW3z+q0UM7ilFdffVV79uzR2rVrnRqzR4RyFmVlZaqsrNSyZcucHrNHhHIWLS0tkqSYmJgO60OGDFFbW5uMhW8b6Nfv4r7UFxcXq6WlRXO/909PzZ07V/v27ev1lx6sCVifvzFwDwrlLM6msrJSR44c0dixY7tjvB4V6lk0NDRo6dKlevzxx896dxebhHIWu3btkvTda8VpaWkaMGCAhg0bprvvvlvHjx93ZF4nhXIWN998s5KTk7VixQpVVFTo2LFjKikp0caNG5WTk6OoqCinxu5zAoGAwsPDO904wuPxSNJFfb3pTtYEzIobA/eQUM7i+1pbW5WTk6P4+HgtXLiwu0bsMaGexfLlyzV69GgtWLDAgel6Vihn8fXXX0uSZs+erczMTO3cuVP333+/tmzZojvvvNOReZ0UyllERERo165damtrk8fjUXR0tKZNm6bbb79dzz77rFMj90n19fUaMmSIXC5Xh/W+8rXzkrqZL364JUuW6MMPP9S77757wftTXmo++OADvfTSS9qzZ0+n/0AvN21tbZK++9ZQXl6eJGnKlCkKBoPKzc1VZWWllVfoF+PEiROaPXu2jhw5om3btikhIUEff/yx8vLyFBYWphdeeKG3R8T/syZgPX1j4L4slLM4U25urnw+nwoKCpSZmdmdI/aYUM5i8eLFWrhwoa6++mo1NjZK+u6KNBgMqrGxUZGRkVbdsiyUs7jiiiskSbfcckuH9czMTOXm5uqzzz6zKmChnMXWrVtVVlamQ4cOaeTIkZKkm266SbGxsfJ6vcrJydHEiRMdmbuvcbvdamxslDGmw1/y+srXTmu+hciNgU8L5SxOWbNmjdavX6+nn35a8+bN6+4Re0woZ1FZWalNmzbJ7Xa3f+zevVvl5eVyu93W/U071P9Gzudi3wTQW0I5i3379sntdrfH65Trr79e0nd/bi4XHo9HJ0+e1Bff+3cTT7321dWvN06x5k8lNwY+LZSzkKSnn35aK1eu1Jo1a7RkyRInR3VcKGdRWlra6WPixIlKSUlRaWmpZs6c6fT43SqUs7j11lsVHh6u4uLiDus7duyQZNc/sSGFdhZXXnmlGhoaOr2566OPPpIkXXXVVd0/cB81ffp0DRgwQK+88kqH9ZdfflkpKSlKSkrqpcn+X2+/j7+rjh07ZkaOHGlSUlLMO++8YwoLC82ECRNMUlKS+eabb9o/r6amxvTv39888sgjHfbPnj3bDBkyxOTn55v333/f/OpXvzLh4eHm008/7emnErJQzuKvf/2rcblcZvr06eZf//pXh49AINAbTyckof65+D6bfw4s1LN4+OGHTf/+/c0DDzxgdu7cadauXWsiIiLM/Pnze/iZhC6Us6iurjbR0dEmOTm5/QeZH3/8cRMdHW0mTZrU4WeqbLJ9+3azfft2k5OTYySZ559/3mzfvt2UlZW1f07//v3N73//+w77VqxYYcLDw81TTz1lSktLTU5OjnG5XOZvf/tbTz+FTqwJmDHG1NbWmhkzZpjo6GgzePBgk52d3emH8aqrq40k89BDD3VYb25uNkuXLjU/+tGPTHh4uLn++utNaWlpj83e3S72LObPn28knfVj8uTJPfocuksofy6+z+aAGRPaWbS1tZmnnnrKjBw50gwYMMAkJCSYVatWmZaWlp57At0olLMIBAJm1qxZ5uqrrzYREREmOTnZ3Hvvvaa+vr7nnkA368p/95I6/YWltbXVPProoyYhIcEMHDjQjB8/3mzfvr1nhz8HbuYLALCSNa+BAQBwJgIGALASAQMAWImAAQCsRMAAAFYiYAAAKxEwAICVCBgAwEoEDABgJQIGALASAQMAWImAAQCsRMAAAFYiYAAAKxEwAICVCBgAwEr/B8+LHljcNL8DAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.display import Image, HTML\n",
    "Image(filename='img/0.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Great!  Now, from the command line, try running this command, inside the same directory where this notebook is running:\n",
    "\n",
    "```\n",
    "'ffmpeg -y -framerate 5 -i img/%d.png out.mp4\n",
    "```\n",
    "\n",
    "If it succeeds, there should be an out.mp4 file generated.  Try downloading it to your computer via the Jupyter interface (don't try to open it directly from Jupyter) and open it on your laptop.  Cool, huh?\n",
    "\n",
    "Now let's try running that same command with `check_output`.  We'll need to break up all the arguments into different entries in a list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "b''"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "check_output(['ffmpeg', '-y', '-framerate', '5', '-i', 'img/%d.png', 'out.mp4'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There was no output, which is fine.  But it should have created an `out.mp4` file, as before.  You can embed `.mp4` video files in websites with the `<video>` tag.  This is great because we can inject HTML using the `HTML(...)` function from earlier:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "This is <b>bold</b> text."
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "HTML(\"This is <b>bold</b> text.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The natural thing to do is to inject some HTML to embed the `out.mp4` animation we just created:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<video width=\"320\" height=\"240\" controls>\n",
       "  <source src=\"out.mp4\" type=\"video/mp4\">\n",
       "</video>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "HTML(\"\"\"\n",
    "<video width=\"320\" height=\"240\" controls>\n",
    "  <source src=\"out.mp4\" type=\"video/mp4\">\n",
    "</video>\n",
    "\"\"\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Measuring Time\n",
    "\n",
    "The easiest way to measure how long something takes is to check the time before and after we do it.  We can check with the `time` function inside the `time` module.  This function returns the number of seconds elapsed since Jan 1, 1970:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1580137926.8447468"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import time\n",
    "now = time.time()\n",
    "now"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "50.10584496590395"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "minutes = now / 60\n",
    "hours = minutes / 60\n",
    "days = hours / 24\n",
    "years = days / 365\n",
    "years # should be about number of years since 1970 -- is it?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's use this to time how long a print call takes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I'm printing something\n",
      "It took 0.0007390975952148438 seconds to print\n"
     ]
    }
   ],
   "source": [
    "before = time.time()\n",
    "print(\"I'm printing something\")\n",
    "after = time.time()\n",
    "print(\"It took\", (after-before), \"seconds to print\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A slightly cleaner version of the same that computers milliseconds (1ms is 1/1000 seconds):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "I'm printing something\n",
      "It took 0.7138252258300781 ms to print\n"
     ]
    }
   ],
   "source": [
    "t0 = time.time()\n",
    "print(\"I'm printing something\")\n",
    "t1 = time.time()\n",
    "ms = (t1-t0) * 1000\n",
    "print(\"It took\", ms, \"ms to print\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "How long does it take to append something to the end of a list?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "microseconds: 57.45887756347656\n"
     ]
    }
   ],
   "source": [
    "L = []\n",
    "t0 = time.time()\n",
    "L.append(\"test\")\n",
    "t1 = time.time()\n",
    "us = (t1-t0) * 1e6 # microseconds (there are 1 second has 1000000 microseconds)\n",
    "print(\"microseconds:\", us)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The problem with the above measurement is that it is it varies significantly each time you try it, and we can easily end up measuring something other than append time.  For example, what if calling `time.time()` is much slower than calling `L.append(\"test\")`?  It is better to perform an operation many times between checking the start+stop times and then divide to get the average cost of the operation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "microseconds: 0.11862897872924805\n"
     ]
    }
   ],
   "source": [
    "L = []\n",
    "append_count = 1000000 # do 1 million appends\n",
    "t0 = time.time()\n",
    "for i in range(append_count):\n",
    "    L.append(\"test\")\n",
    "t1 = time.time()\n",
    "us = (t1-t0) / append_count * 1e6 # microseconds (there are 1 second has 1000000 microseconds)\n",
    "print(\"microseconds:\", us)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Example 1: the `in` operator\n",
    "\n",
    "The `in` operator can be used to check whether a value is in a list or a set, but it's much faster on a set.  If your code needs to perform the `in` operation a lot, this is a good reason to use a set rather than a list.  Let's review how `in` works on each:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "L = [\"A\", \"B\", \"C\"]\n",
    "S = {\"A\", \"B\", \"C\"}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(True, False, True, False)"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"A\" in L, \"D\" in L, \"A\" in S, \"D\" in S"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see how fast `in` is if we are checking over 1 million numbers in a list or a set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0.03719329833984375, 0.03743171691894531)"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "seq_size = 1000000\n",
    "L = list(range(seq_size))\n",
    "S = set(range(seq_size))\n",
    "\n",
    "# return average microseconds to perform lookup\n",
    "def time_lookup(data, search):\n",
    "    trials = 1000\n",
    "    t0 = time.time()\n",
    "    for i in range(trials):\n",
    "        found = search in data\n",
    "    t1 = time.time()\n",
    "    return (t1-t0)*1e6/trials\n",
    "\n",
    "time_lookup(L, 0), time_lookup(S, 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ok, looks like looking up `0` (the first number) is about equally fast in either data structure.\n",
    "\n",
    "What if we lookup a number that's not stored?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(10068.64070892334, 0.0438690185546875)"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time_lookup(L, -1), time_lookup(S, -1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Woah, now the list is >10K times slower!  What if we lookup the last item in the list?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(11480.518341064453, 0.0591278076171875)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time_lookup(L, 999999), time_lookup(S, 999999)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The set is fast again, but the list is still really slow (about as slow as looking up something that doesn't exist).  What if we lookup a number in the middle?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(5739.615678787231, 0.05888938903808594)"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time_lookup(L, 500000), time_lookup(S, 500000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Well, checking for something in the middle of a list is about twice as fast as checking for the last item.  Can you guess why?\n",
    "\n",
    "It turns out that while sets are designed around making `in` fast, running `in` on a list amounts to looping over ever item, much like a call to the following function."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_in(L, search):\n",
    "    for item in L:\n",
    "        if search == L: # if this is True early in the list, the search is fast\n",
    "            return True\n",
    "    return False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "How does the list size factor in when we perform an `in` and we don't find anything?  Let's do an experiment to find out."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1000      9.510994\n",
       "2000     18.847942\n",
       "5000     47.323465\n",
       "10000    95.795155\n",
       "dtype: float64"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from pandas import Series\n",
    "\n",
    "times = Series()\n",
    "\n",
    "for size in [1000, 2000, 5000, 10000]:\n",
    "    L = list(range(size))\n",
    "    microseconds = time_lookup(L, -1)\n",
    "    times.loc[size] = microseconds\n",
    "times"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "ax = times.plot.line(color=\"r\")\n",
    "\n",
    "# following makes plot look better (only necessary if we plan to share it with others)\n",
    "ax.spines[\"right\"].set_visible(False)\n",
    "ax.spines[\"top\"].set_visible(False)\n",
    "ax.set_xlabel(\"List Size\")\n",
    "ax.set_ylabel(\"Lookup Miss Time (μs)\")\n",
    "None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Looking at the above, we would say that the `in` operator scales *linearly*.  In otherwords, doubling the list size doubles the time it takes to perform the operation.\n",
    "\n",
    "### Example 2: Ratio Search\n",
    "\n",
    "Not all functions we'll encounter will scale linearly.  For example, consider this one, which checks whether the ratio of any two numbers in a list matches the ratio we're searching for:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def ratio_search(L, ratio):\n",
    "    for numerator in L:\n",
    "        for denominator in L:\n",
    "            if numerator / denominator == ratio:\n",
    "                return True\n",
    "    return False\n",
    "\n",
    "ratio_search([1, 2, 3, 4], 0.75)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ratio_search([1, 2, 3, 4], 0.2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's see how it scales when we search for a ratio we know we won't find."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0       0.000003\n",
       "1000    0.056291\n",
       "2000    0.222333\n",
       "3000    0.499056\n",
       "4000    0.890178\n",
       "5000    1.397182\n",
       "dtype: float64"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import random, string\n",
    "\n",
    "times = Series()\n",
    "\n",
    "for i in range(6):\n",
    "    size = i * 1000\n",
    "    L = list(range(1, size+1)) # don't include 0, because we need to divide\n",
    "\n",
    "    t0 = time.time()\n",
    "    found = ratio_search(L, -1)\n",
    "    t1 = time.time()\n",
    "\n",
    "    times.loc[size] = t1-t0\n",
    "times"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "ax = times.plot.line(color=\"r\")\n",
    "\n",
    "# following makes plot look better (only necessary if we plan to share it with others)\n",
    "ax.spines[\"right\"].set_visible(False)\n",
    "ax.spines[\"top\"].set_visible(False)\n",
    "ax.set_xlabel(\"List Size\")\n",
    "ax.set_ylabel(\"Lookup Miss Time (μs)\")\n",
    "None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The above is an example of quadratic scaling: doubling the list size quadruples the time it takes to run!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Conclusion\n",
    "\n",
    "In this notebook, we've learned how to automatically run programs and time code.  Together, these skills provide the empirical basis for exploring performance and scalability.  Soon, we'll be learning a bit of theory (complexity analysis) and notation (big-O) for thinking about what happens to performance as we add more data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
