{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZX6M7xdN4B0e"
      },
      "source": [
        "# CS 124 Tutorial: `Jupyter Notebooks`\n",
        "\n",
        "Based on the `CS 124: Jupyter and Python Tutorial` created by \n",
        "`Krishna Patel (Winter 2020)`, and updated by `Bryan Kim (Winter 2021)` and \n",
        "`Dilara Soylu (Fall 2021)`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_mygv6OHty4i"
      },
      "source": [
        "<a id='overview'></a>\n",
        "## Overview\n",
        "\n",
        "This tutorial is prepared to help you get set up with `Jupyter Notebooks`.\n",
        "Even if you have prior experience working with `Jupyter Notebooks`, we still \n",
        "recommend skimming through this tutorial.\n",
        "You can complete this tutorial without completing the setup instructions shared \n",
        "in the [PA 0 repository](https://github.com/cs124/pa0-python-jupyter-tutorial) \n",
        "for your machine, but we assume that you have completed it."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3BAddkVL8wRR"
      },
      "source": [
        "<a id='contents'></a>\n",
        "## Contents\n",
        "\n",
        "1. [Cells](#cells)\n",
        "2. [Notebook Kernel](#notebook_kernel)\n",
        "3. [Environment Check](#environment_check)\n",
        "4. [Next Steps](#next_steps)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OlvVUIMLtsMq",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "<a id='cells'></a>\n",
        "## Cells\n",
        "\n",
        "`Jupyter Notebooks` are similar to `Python` scripts, except that they are \n",
        "comprised of cells of `Python` code or text that can be run and modified \n",
        "separately and out-of-order.\n",
        "They provide an easy way to modify and test code snippets, or to provide \n",
        "explanations and visualizations to accompany your code.\n",
        "`Jupyter Notebooks` contain two types of cells:\n",
        "\n",
        "* `Markdown` Cells\n",
        "* `Code` Cells"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YgXTj6GItsMr"
      },
      "source": [
        "__Editing Markdown Cells__ \n",
        "You can edit `Markdown` cells by double clicking them or hitting the `Enter` \n",
        "key while they are selected.\n",
        "In general, you shouldn't need to do this on any of the assignments, since we \n",
        "will only grade your code."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WADMiDEytsMr"
      },
      "source": [
        "This cell is an example `Markdown` cell. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "y-OMMv3jtsMs"
      },
      "source": [
        "__Running Code Cells__ You can run `Code` cells by selecting them and clicking \n",
        "the run button (`▶ Run`) in the top toolbar.\n",
        "You can also run `Code` cells by hitting `CTRL + Enter` or `Command + Enter` \n",
        "if you are on a `Mac`.\n",
        "If you also want your cursor to advance to the next cell, you can use \n",
        "`Shift + Enter`.\n",
        "The output of the code, such as `print` statements, will be shown below the \n",
        "cell after it is run. You can use the arrow keys to navigate between cells."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TqLguDiutsMs",
        "scrolled": true
      },
      "outputs": [],
      "source": [
        "# This is cell is an example Code cell\n",
        "print(\"I can run code!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uICBMrO5tsMt",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "Alternatively, if the last line of a cell is a variable, the value of the \n",
        "variable will be printed as the output. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0HQlSmTftsMu",
        "pycharm": {
          "name": "#%%\n"
        }
      },
      "outputs": [],
      "source": [
        "var = \"I am a string.\"\n",
        "var"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m1cmpF4vtsMv",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "__Adding New Cells__ To add new cells, you can hit the `+` button in the top \n",
        "toolbar, or select `Insert Cell Above` or `Below` options in the `Insert` menu \n",
        "item.\n",
        "You can also use the shortcuts `A` to insert a cell above the current cell, and \n",
        "`B` to insert a cell below. By default, a newly created cell will be a code \n",
        "cell.\n",
        "You can change the type of a cell via the dropdown in the toolbar or by \n",
        "selecting it and hitting `Y` for `Code`, and `M` for `Markdown`.\n",
        "You can also quickly delete cells by hitting `D` twice (`D + D`). "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vrzDRVK5xTom"
      },
      "source": [
        "<a id='notebook_kernel'></a>\n",
        "## Notebook Kernel\n",
        "\n",
        "Notebook `Kernel` is the piece of program that executes the code in your \n",
        "notebook.\n",
        "You can see the current `Kernel` on the top right of the notebook, which should \n",
        "say `Python [conda env:cs124]` if you started `Jupyter` after you activated the \n",
        "`cs124 conda` environment in your terminal.\n",
        "This means that the notebook is using the `Python` installation in our `conda` \n",
        "environment, which is the correct version of the `Python` (`Python 3.10`) we \n",
        "expect you to use in the assignments.\n",
        "This also ensures that the versions of the external libraries used in the \n",
        "assignments, such as `NumPy`, are the same for everyone in the class.\n",
        "\n",
        "One of the common mistakes students run into is forgetting to activate our \n",
        "`conda` environment before starting to work on the assignments.\n",
        "In such cases, you may see `Python` complaining about not finding a module, \n",
        "or a specific method from a specific version of a module.\n",
        "It is always a good idea to ensure that your notebook is running the correct \n",
        "`Kernel` such cases."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eqUZeFAStsMw"
      },
      "source": [
        "__Interrupting the Kernel__ You may want to interrupt the execution of your \n",
        "code in some cases, like the example below. To stop the `Kernel`, you can click \n",
        "on the interrupt button (`■`) in the toolbar or select the `Interrupt` option \n",
        "in the `Kernel` menu item. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7XeNN_bhtsMx"
      },
      "outputs": [],
      "source": [
        "# Code that will run forever\n",
        "while True:\n",
        "    pass"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4IWldeC1tsMy"
      },
      "source": [
        "__Restarting the Kernel__ Because you can execute cells in any order you want \n",
        "in a notebook, you may find that some cells work differently when you run them \n",
        "after running other cells.\n",
        "It is good to restart your `Kernel` in such cases to start with a clean state.\n",
        "You can restart your `Kernel` by clicking on the restart button (`⟳`) in the \n",
        "toolbar or by selecting the `Restart` option in the `Kernel` menu item.\n",
        "Once you are done with your assignments, we recommend restarting your `Kernel` \n",
        "and running your cells in sequential order to make sure your code works as you \n",
        "intended. \n",
        "\n",
        "You can restart the kernel and run all the cells in-order in one go by using \n",
        "the fast-forward button on the toolbar, or selecting the `Restart & Run All` \n",
        "option in the `Kernel` menu item."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GxRk1ugn2WE2"
      },
      "source": [
        "__Notebook State__ Below is an example showing the side effects of running \n",
        "`Jupyter Notebook` cells out-of-order.\n",
        "When you run the cell immediately below, you will likely get the following \n",
        "error:\n",
        "```\n",
        "NameError: name 'var' is not defined\n",
        "```"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "w7I9YfBs2x-A",
        "outputId": "9f8cff8a-7e7c-425a-9a80-598bd1de95ad"
      },
      "outputs": [],
      "source": [
        "var"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9Wc0BF3v1WLe"
      },
      "source": [
        "Now, run the cell immediately below this one.\n",
        "This will initialize `var`.\n",
        "Now, go back and run the cell that produced an error earlier.\n",
        "You won't get an error this time around."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 26,
      "metadata": {
        "id": "mqjPQ-cbtsMy"
      },
      "outputs": [],
      "source": [
        "# Initialize var\n",
        "# Run the cell above again. You won't get an error time around.\n",
        "var = 0"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GZ-Thh5j3R3b"
      },
      "source": [
        "How did this happen?\n",
        "Running the cell initializing the `var` variable changed the state of the \n",
        "notebook, creating the new variable.\n",
        "Once created, the new variable becomes accessible from all the cells in the \n",
        "notebook.\n",
        "This applies to any future cell you run anywhere in the notebook, whether it be \n",
        "physically `above` or `below` the current cell.\n",
        "The notebook's state is determined by the order in which the cells are run \n",
        "rather than the physical order of the cells in the notebook.\n",
        "This is something important to keep in mind as your notebooks become longer and \n",
        "more complex, with lots of cells.\n",
        "If you run into weird or unexpected behavior in your notebook, it probably has \n",
        "something to do with the order in which you executed your cells!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "QVbYO_1ctsMz",
        "outputId": "80e3c981-51b3-4ad9-e2c2-983ecf348243"
      },
      "outputs": [],
      "source": [
        "# Perform an operation on the variable assuming it exists in the memory\n",
        "# Run this cell multiple times to see how the value of var changes\n",
        "var += 1\n",
        "var"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eblgJe2Z4mLO"
      },
      "source": [
        "Shared above is another example on how the order in which cells are run \n",
        "determine the notebook state.\n",
        "Once `var` is intialized, run the cell above a few times and observe how the \n",
        "values printed change.\n",
        "You will see the value increment every time you run the cell.\n",
        "This may or may not surprise you. \n",
        "Often students who haven't worked with `Jupyter Notebooks` before can find this \n",
        "counter-intuitive, as it seems natural to expect that the same part of your \n",
        "code should produce the same output every time. \n",
        "The reason why that isn't true here is because of the global state issue that \n",
        "we showed above.\n",
        "Every time you run a cell, it's not just redoing the same calculation from the \n",
        "same starting point.\n",
        "It's also updating the global state of the notebook!\n",
        "Any changes you make to variables persist, and will affect every future cell \n",
        "that you run."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 21,
      "metadata": {
        "id": "NwTbSLfatsMz"
      },
      "outputs": [],
      "source": [
        "# Delete the variable and execute the cell that caused a NameError\n",
        "# You will get the NameError again!\n",
        "del var"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "85iJ9aHr7rO_"
      },
      "source": [
        "As a result, a good tip when working with `Jupyter Notebooks` is to try to avoid\n",
        "making the side effects of your cells too complicated.\n",
        "Obviously it's impossible to totally avoid cross-cell side effects, because if\n",
        "you did it would defeat the purpose of using a notebook at all!\n",
        "You would have to have one giant cell with all of your code, or have each cell \n",
        "only do self-contained work, which wouldn't be very interesting or useful!\n",
        "The global state maintained by notebooks is what makes them useful and \n",
        "powerful, but it can also be a major point of pain and confusion if you're not \n",
        "careful.\n",
        "\n",
        "If your notebook state gets too confusing, you can always `Restart` your \n",
        "`Kernel`, as described earlier."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "faOF834ctsM0",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "__Saving Your Work__ `Jupyter Notebook` automatically saves your changes \n",
        "once every `120 seconds`, but to be safe we recommend saving frequently as you \n",
        "make changes.\n",
        "You can save with the save button in the top toolbar or the usual shortcut\n",
        "(`CTRL + S` or `Command + S`)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ORBfRrHQtsM0",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "__Reference__ You can find the list of all shortcuts by hitting `H` if you ever \n",
        "need a reference!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RyJNj6dDtsM0"
      },
      "source": [
        "<a id='environment_check'></a>\n",
        "## Environment Check\n",
        "\n",
        "You will see an environment check at the beginning of your assignment notebooks. \n",
        "This is important to ensure that you are running the correct version of \n",
        "`Python` in the right environment!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jw6sS9SHtsM1"
      },
      "outputs": [],
      "source": [
        "# Check the name of the conda environment\n",
        "import os\n",
        "assert os.environ['CONDA_DEFAULT_ENV'] == \"cs124\"\n",
        "\n",
        "# Check that the Python version is 3.10\n",
        "import sys\n",
        "assert sys.version_info.major == 3 and sys.version_info.minor == 10"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A3c-AC3gtsM1",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "If the above cell causes an error, it means that you're using the wrong \n",
        "environment or `Python` version!\n",
        "If you get an error, go to the terminal from which you ran the \n",
        "`jupyter notebook` command, and kill notebook server by hitting `CTRL + C` or \n",
        "`Command + C`. \n",
        "You will be asked whether you want to shutdown the notebook server, to which \n",
        "you should respond with a `y`. \n",
        "\n",
        "You can then activate the correct environment by running the below command in \n",
        "your terminal.\n",
        "\n",
        "`$ conda activate cs124`\n",
        "\n",
        "Once the you are in the correct environment, you can start the notebook again \n",
        "with the below command. \n",
        "\n",
        "`$ jupyter notebook`\n",
        "\n",
        "If you get the same error, you should go back and follow the setup and \n",
        "installation instructions in the `README.md` file that came with this notebook."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wW5qOSSvtsM1"
      },
      "source": [
        "__which command__ Another way to check whether `Jupyter` is running your intended installation of `Python` is through the `which` terminal command, which helps us find the program ran by our terminal given a keyboard. Note that `Jupyter Notebook` cells are intended to contain `Python` code. We can tell `Jupyter` that we want run our command outside of the notebook by using the exclamation mark (`!`). The output of the below cell shows us the location of the `Python` installation used to run the cells in the notebook. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d3M94UTbtsM2",
        "outputId": "9be0d450-c28c-49e7-a724-18f0d45f0857",
        "scrolled": false
      },
      "outputs": [],
      "source": [
        "!which python"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tzyTGjmStsM3"
      },
      "source": [
        "The expected output of the above cell will be different based on your username and your `miniconda` install location, but it will contain a substring similar to `/miniconda3/envs/cs124/bin/python`. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lB5v_kZ3tsNB",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "<a id='next_steps'></a>\n",
        "## Next Steps\n",
        "\n",
        "`Jupyter Notebooks` are awesome tools for visualization, working with data, \n",
        "and doing quick prototyping. \n",
        "We hope they can become a useful tool in your toolbox if they haven't already!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_gGbV2eHtsNB",
        "pycharm": {
          "name": "#%% md\n"
        }
      },
      "source": [
        "If you are interested in learning a little more `Jupyter-foo`, check out some of\n",
        "the links below. \n",
        "Even if you are relatively experienced with `Jupyter Notebooks`, it's likely \n",
        "that many of the tips below will be new to you!\n",
        "\n",
        "* [28 Jupyter Notebook Tips, Tricks, and Shortcuts](https://www.dataquest.io/blog/jupyter-notebook-tips-tricks-shortcuts/)\n",
        "* [Optimizing Jupyter Notebook: Tips, Tricks, and nbextensions](https://towardsdatascience.com/optimizing-jupyter-notebook-tips-tricks-and-nbextensions-26d75d502663)\n",
        "* [15 Tips and Tricks to Use Jupyter Notebook More Efficiently](https://towardsdatascience.com/15-tips-and-tricks-to-use-jupyter-notebook-more-efficiently-ef05ede4e4b9)\n"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "jupyter_tutorial.ipynb",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python [conda env:cs124] *",
      "language": "python",
      "name": "conda-env-cs124-py"
    },
    "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.8.5"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
