From a1c97f14d14a0de970403e5e679731592921022e Mon Sep 17 00:00:00 2001
From: Michiel Cottaar <MichielCottaar@gmail.com>
Date: Thu, 15 Feb 2018 12:41:41 +0000
Subject: [PATCH] Implemented MJ's comments

---
 getting_started/02_text_io.ipynb | 10 ++---
 getting_started/02_text_io.md    | 10 ++---
 getting_started/07_jupyter.ipynb | 66 +++++++++++++++++++++++++++++---
 getting_started/07_jupyter.md    |  7 +++-
 4 files changed, 75 insertions(+), 18 deletions(-)

diff --git a/getting_started/02_text_io.ipynb b/getting_started/02_text_io.ipynb
index d329bea..a6333b9 100644
--- a/getting_started/02_text_io.ipynb
+++ b/getting_started/02_text_io.ipynb
@@ -110,7 +110,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "> Any lines starting with `!` will be interpreted as shell commands by ipython. It is great when playing around in the ipython notebook or in the ipython terminal, however it is an ipython-only feature and hence is not available when writing python scripts. How to call shell commands from python will be discusses in the `scripts` practical.\n",
+    "> Any lines starting with `!` will be interpreted as shell commands by ipython. It is great when playing around in the ipython notebook or in the ipython terminal, however it is an ipython-only feature and hence is not available when writing python scripts. How to call shell commands from python will be discussed in the `scripts` practical.\n",
     "\n",
     "If we want to add to the existing file we can open it in the append mode:"
    ]
@@ -375,8 +375,8 @@
    "outputs": [],
    "source": [
     "from datetime import datetime\n",
-    "print(str(datetime.now())\n",
-    "print(repr(datetime.now())"
+    "print('str(): ', str(datetime.now()))\n",
+    "print('repr(): ', repr(datetime.now()))"
    ]
   },
   {
@@ -492,7 +492,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "Note that the variable `:` delimiter separates the variable identifies on the left from the formatting rules on the right.\n",
+    "Note that the variable `:` delimiter separates the variable identifiers on the left from the formatting rules on the right.\n",
     "\n",
     "Finally the new, fancy formatted string literals (only available in python 3.6+).\n",
     "This new format is very similar to the recommended style, except that all placeholders are automatically evaluated in the local environment at the time the template is defined.\n",
@@ -596,7 +596,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "> We use the syntax `[<expr> for <element> in <sequence>]` here which applies the `expr` to each `element` in the `sequence` and returns the resulting list. This is a convenient form in python to create a new list from the old one.\n",
+    "> We use the syntax `[<expr> for <element> in <sequence>]` here which applies the `expr` to each `element` in the `sequence` and returns the resulting list. This is a list comprehension - a convenient form in python to create a new list from the old one.\n",
     "\n",
     "<a class=\"anchor\" id=\"converting-strings-to-numbers\"></a>\n",
     "### Converting strings to numbers\n",
diff --git a/getting_started/02_text_io.md b/getting_started/02_text_io.md
index da04b17..efc40b9 100644
--- a/getting_started/02_text_io.md
+++ b/getting_started/02_text_io.md
@@ -52,7 +52,7 @@ Note that no new line characters get added automatically. We can investigate the
 ```
 !cat 02_text_io/my_file
 ```
-> Any lines starting with `!` will be interpreted as shell commands by ipython. It is great when playing around in the ipython notebook or in the ipython terminal, however it is an ipython-only feature and hence is not available when writing python scripts. How to call shell commands from python will be discusses in the `scripts` practical.
+> Any lines starting with `!` will be interpreted as shell commands by ipython. It is great when playing around in the ipython notebook or in the ipython terminal, however it is an ipython-only feature and hence is not available when writing python scripts. How to call shell commands from python will be discussed in the `scripts` practical.
 
 If we want to add to the existing file we can open it in the append mode:
 ```
@@ -166,8 +166,8 @@ The `datetime` module contains various classes and functions to work with dates
 Here we will look at the alternative string representations of the `datetime` object itself:
 ```
 from datetime import datetime
-print(str(datetime.now())
-print(repr(datetime.now())
+print('str(): ', str(datetime.now()))
+print('repr(): ', repr(datetime.now()))
 ```
 Note that the result from `str()` is human-readable as a date, while the result from `repr()` is more useful if you wanted to recreate the `datetime` object.
 
@@ -222,7 +222,7 @@ b = 1 / 3
 print('{:.3f} = {} + {:.3f}'.format(a + b, a, b))
 print('{total:.3f} = {a} + {b:.3f}'.format(a=a, b=b, total=a+b))
 ```
-Note that the variable `:` delimiter separates the variable identifies on the left from the formatting rules on the right.
+Note that the variable `:` delimiter separates the variable identifiers on the left from the formatting rules on the right.
 
 Finally the new, fancy formatted string literals (only available in python 3.6+).
 This new format is very similar to the recommended style, except that all placeholders are automatically evaluated in the local environment at the time the template is defined.
@@ -269,7 +269,7 @@ print(list_with_whitespace)
 list_without_whitespace = [individual_string.strip() for individual_string in list_with_whitespace]
 print(list_without_whitespace)
 ```
-> We use the syntax `[<expr> for <element> in <sequence>]` here which applies the `expr` to each `element` in the `sequence` and returns the resulting list. This is a convenient form in python to create a new list from the old one.
+> We use the syntax `[<expr> for <element> in <sequence>]` here which applies the `expr` to each `element` in the `sequence` and returns the resulting list. This is a list comprehension - a convenient form in python to create a new list from the old one.
 
 <a class="anchor" id="converting-strings-to-numbers"></a>
 ### Converting strings to numbers
diff --git a/getting_started/07_jupyter.ipynb b/getting_started/07_jupyter.ipynb
index bed1e2d..d80ba60 100644
--- a/getting_started/07_jupyter.ipynb
+++ b/getting_started/07_jupyter.ipynb
@@ -38,6 +38,22 @@
     "string.capwords?"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "This also works for any of the magic commands discussed below"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "%run?"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -91,13 +107,25 @@
    "source": [
     "r = !fslstats ${FSLDIR}/data/standard/FMRIB58_FA_1mm.nii.gz -r\n",
     "r_lower, r_upper = [float(element) for element in r[0].split()]\n",
-    "print('Bounds are ({:d}, {:d})'.format(r_lower, r_upper"
+    "print('Bounds are ({:.0f}, {:.0f})'.format(r_lower, r_upper))"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "---\n",
+    "\n",
+    "## Running python scripts\n",
+    "We could run a python script as a shell command above. However, it will often be more convenient to use `%run` instead.\n",
+    "> ```\n",
+    "> %run <python script> <arguments...>\n",
+    "> ```\n",
+    "Arguments are provided in exactly the same way as if you called `python` in the shell. The main advantages are:\n",
+    "- Any top-level variables will be made available to you after the script finishes\n",
+    "- All the debugging/timing/profiling tools discussed below will be available to you\n",
+    "A common workflow, when writing a python script is to have an Ipython terminal open next to your text editor and regularly use %run to test the script\n",
+    "\n",
     "---\n",
     "\n",
     "## Running other programming languages\n",
@@ -122,7 +150,7 @@
    "source": [
     "---\n",
     "\n",
-    "## Timing code\n",
+    "## Timing/profiling code\n",
     "We can time a line of code with `%time` or a whole code block using `%%time`.\n",
     "To get the time needed to calculate the sine of a million random numbers:"
    ]
@@ -156,6 +184,24 @@
     "%timeit np.sin(numbers)  # this will take a few seconds to run"
    ]
   },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "Finally, if you want to figure out what part of the code is actually slowing you down you can use `%prun`, which gives you an overview of how long the interpreter spent in each method:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import nibabel as nib\n",
+    "import os.path as op\n",
+    "%prun nib.load(op.expandvars('${FSLDIR}/data/standard/FMRIB58_FA_1mm.nii.gz'))"
+   ]
+  },
   {
    "cell_type": "markdown",
    "metadata": {},
@@ -174,6 +220,10 @@
    "source": [
     "import numpy as np\n",
     "def total(a_list):\n",
+    "    \"\"\"Calculate the total of a list.\n",
+    "\n",
+    "    This is a very naive (not recommended) and bugged implementation\n",
+    "    \"\"\"\n",
     "    # create local copy befor changing the input\n",
     "    local_list = list(a_list)\n",
     "    total = 0.\n",
@@ -208,7 +258,7 @@
     "\n",
     "> WARNING: you need to quit the debugger before any further commands will run (type `q` into the prompt)!\n",
     "\n",
-    "If you always want to enter the debugger when an error is raised you can call `%pdb on` at any time (call `%pdf off` to rever this)\n",
+    "If you always want to enter the debugger when an error is raised you can call `%pdb on` at any time (call `%pdf off` to reverse this)\n",
     "\n",
     "---\n",
     "\n",
@@ -233,7 +283,7 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "> Keep in mind that as soon as you have started plotting you can no longer change your backend without restarting python.\n",
+    "> Keep in mind that as soon as you have started plotting you can no longer change your backend without exiting the python interpreter and restarting `python` (note that in the jupyter notebook you can just press `Restart` in the `Kernel` menu).\n",
     "\n",
     "To do the equivalent in a python script would look like\n",
     "> ```\n",
@@ -264,6 +314,7 @@
     "> mpl.use(<backend>)\n",
     "> from matplotlib.pylab import *\n",
     "> ```\n",
+    "> The last line imports everything from the matplotlib.pylab module into the namespace.\n",
     "\n",
     "I start most of my notebooks or terminals with the `%pylab` command, because afterwards I can just do stuff like:"
    ]
@@ -283,6 +334,9 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
+    "The main disadvantage is that it will not be obvious to the naive reader of this code, whether functions like `linspace`, `sin`, or `plot` are originate from numpy, matplotlib, or are built-in.\n",
+    "This is why we dont recommend `from <module> import *` statements in any longer code or code you intend to share.\n",
+    "\n",
     "---\n",
     "\n",
     "## Exporting code from the Jupyter notebook\n",
@@ -333,7 +387,7 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "!python script_from_notebook.py"
+    "%run script_from_notebook.py"
    ]
   },
   {
@@ -344,7 +398,7 @@
     "\n",
     "## Exporting code from the Ipython terminal\n",
     "You can access the full history of your session using `%history`.\n",
-    "To save the history to a file use `%history -f <filename>`\n",
+    "To save the history to a file use `%history -f <filename>`.\n",
     "You will probably have to clean a lot of erroneous commands you typed from that file before you are able to run it as a script."
    ]
   }
diff --git a/getting_started/07_jupyter.md b/getting_started/07_jupyter.md
index 990f4fe..d5e9de6 100644
--- a/getting_started/07_jupyter.md
+++ b/getting_started/07_jupyter.md
@@ -130,7 +130,7 @@ Try to check the value of `a_list` and `local_list` from within the debugger.
 
 > WARNING: you need to quit the debugger before any further commands will run (type `q` into the prompt)!
 
-If you always want to enter the debugger when an error is raised you can call `%pdb on` at any time (call `%pdf off` to rever this)
+If you always want to enter the debugger when an error is raised you can call `%pdb on` at any time (call `%pdf off` to reverse this)
 
 ---
 
@@ -143,7 +143,7 @@ When failing to provide a backend it will simply use the default (which is usual
 ```
 %matplotlib nbagg
 ```
-> Keep in mind that as soon as you have started plotting you can no longer change your backend without restarting python.
+> Keep in mind that as soon as you have started plotting you can no longer change your backend without exiting the python interpreter and restarting `python` (note that in the jupyter notebook you can just press `Restart` in the `Kernel` menu).
 
 To do the equivalent in a python script would look like
 > ```
@@ -163,6 +163,7 @@ This is equivalent in python code to:
 > mpl.use(<backend>)
 > from matplotlib.pylab import *
 > ```
+> The last line imports everything from the matplotlib.pylab module into the namespace.
 
 I start most of my notebooks or terminals with the `%pylab` command, because afterwards I can just do stuff like:
 ```
@@ -170,6 +171,8 @@ x = linspace(0, pi, 301)
 y = sin(x)
 plot(x, y, 'r-')
 ```
+The main disadvantage is that it will not be obvious to the naive reader of this code, whether functions like `linspace`, `sin`, or `plot` are originate from numpy, matplotlib, or are built-in.
+This is why we dont recommend `from <module> import *` statements in any longer code or code you intend to share.
 
 ---
 
-- 
GitLab