diff --git a/getting_started/02_text_io.ipynb b/getting_started/02_text_io.ipynb index b6181731bbe95856547422cd6ed7b54f1ce36b70..d329bea024fe9a39be253b979e2bc1f6c9a53f0a 100644 --- a/getting_started/02_text_io.ipynb +++ b/getting_started/02_text_io.ipynb @@ -36,16 +36,16 @@ "metadata": {}, "source": [ "* [Reading/writing files](#reading-writing-files)\n", - "* [Creating neew strings](#creating-new-strings)\n", - "** [String syntax](#string-syntax)\n", - "*** [Unicode versus bytes](#unicode-versus-bytes)\n", - "** [Converting objects into strings](#converting-objects-into-strings)\n", - "** [Combining strings](#combining-strings)\n", - "** [String formattings](#string-formatting)\n", + "* [Creating new strings](#creating-new-strings)\n", + " * [String syntax](#string-syntax)\n", + " * [Unicode versus bytes](#unicode-versus-bytes)\n", + " * [Converting objects into strings](#converting-objects-into-strings)\n", + " * [Combining strings](#combining-strings)\n", + " * [String formattings](#string-formatting)\n", "* [Extracting information from strings](#extracting-information-from-strings)\n", - "** [Splitting strings](#splitting-strings)\n", - "** [Converting strings to numbers](#converting-strings-to-numbers)\n", - "** [Regular expressions](#regular-expressions)\n", + " * [Splitting strings](#splitting-strings)\n", + " * [Converting strings to numbers](#converting-strings-to-numbers)\n", + " * [Regular expressions](#regular-expressions)\n", "* [Exercises](#exercises)\n", "\n", "<a class=\"anchor\" id=\"reading-writing-files\"></a>\n", @@ -311,7 +311,8 @@ "metadata": {}, "outputs": [], "source": [ - "with open('/usr/local/fsl/data/standard/MNI152_T1_1mm.nii.gz', 'rb') as gzipped_nifti:\n", + "import os.path as op\n", + "with open(op.expandvars('${FSLDIR}/data/standard/MNI152_T1_1mm.nii.gz'), 'rb') as gzipped_nifti:\n", " print('First few bytes of gzipped NIFTI file:', gzipped_nifti.read(10))" ] }, @@ -319,6 +320,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "> We use the `expandvars()` function here to insert the FSLDIR environmental variable into our string. This function will be presented in the file management practical.\n", + "\n", "<a class=\"anchor\" id=\"converting-objects-into-strings\"></a>\n", "### converting objects into strings\n", "There are two functions to convert python objects into strings, `repr()` and `str()`.\n", @@ -360,6 +363,28 @@ "source": [ "In both cases you get the value of the object (3), but only the `repr` returns enough information to actually know the type of the object.\n", "\n", + "Perhaps the difference is clearer with a more advanced object.\n", + "The `datetime` module contains various classes and functions to work with dates (there is also a `time` module).\n", + "Here we will look at the alternative string representations of the `datetime` object itself:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import datetime\n", + "print(str(datetime.now())\n", + "print(repr(datetime.now())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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.\n", + "\n", "<a class=\"anchor\" id=\"combining-strings\"></a>\n", "### Combining strings\n", "The simplest way to concatenate strings is to simply add them together:" @@ -467,9 +492,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that the variable `:` delimeter separates the variable identifies on the left from the formatting rules on the right.\n", + "Note that the variable `:` delimiter separates the variable identifies 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+). 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. This means that we do not have to explicitly provide the parameters (and we can evaluate the sum inside the string!), although it does mean we also can not re-use the template." + "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", + "This means that we do not have to explicitly provide the parameters (and we can evaluate the sum inside the string!), although it does mean we also can not re-use the template." ] }, { @@ -488,6 +515,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "This code block will fail in fslpython, since it uses python 3.5.\n", + "\n", + "\n", "<a class=\"anchor\" id=\"extracting-information-from-strings\"></a>\n", "## Extracting information from strings\n", "<a class=\"anchor\" id=\"splitting-strings\"></a>\n", @@ -556,7 +586,7 @@ "outputs": [], "source": [ "scientific_packages_string = \"numpy, scipy, pandas, matplotlib, nibabel\"\n", - "list_with_whitespace = scientific_packages_string.split()\n", + "list_with_whitespace = scientific_packages_string.split(',')\n", "print(list_with_whitespace)\n", "list_without_whitespace = [individual_string.strip() for individual_string in list_with_whitespace]\n", "print(list_without_whitespace)" diff --git a/getting_started/02_text_io.md b/getting_started/02_text_io.md index 0c00651c3afd011823348b5cc5f7eadcb5344c04..da04b174b793b297d31ad2932b95d615d682a571 100644 --- a/getting_started/02_text_io.md +++ b/getting_started/02_text_io.md @@ -14,16 +14,16 @@ empty_string. # after running the code block above, put your cursor behind th ``` * [Reading/writing files](#reading-writing-files) -* [Creating neew strings](#creating-new-strings) -** [String syntax](#string-syntax) -*** [Unicode versus bytes](#unicode-versus-bytes) -** [Converting objects into strings](#converting-objects-into-strings) -** [Combining strings](#combining-strings) -** [String formattings](#string-formatting) +* [Creating new strings](#creating-new-strings) + * [String syntax](#string-syntax) + * [Unicode versus bytes](#unicode-versus-bytes) + * [Converting objects into strings](#converting-objects-into-strings) + * [Combining strings](#combining-strings) + * [String formattings](#string-formatting) * [Extracting information from strings](#extracting-information-from-strings) -** [Splitting strings](#splitting-strings) -** [Converting strings to numbers](#converting-strings-to-numbers) -** [Regular expressions](#regular-expressions) + * [Splitting strings](#splitting-strings) + * [Converting strings to numbers](#converting-strings-to-numbers) + * [Regular expressions](#regular-expressions) * [Exercises](#exercises) <a class="anchor" id="reading-writing-files"></a> @@ -137,9 +137,12 @@ Especially in code dealing with strings (e.g., reading/writing of files) many of By default any file opened in python will be interpreted as unicode. If you want to treat a file as raw bytes, you have to include a 'b' in the `mode` when calling the `open()` function: ``` -with open('/usr/local/fsl/data/standard/MNI152_T1_1mm.nii.gz', 'rb') as gzipped_nifti: +import os.path as op +with open(op.expandvars('${FSLDIR}/data/standard/MNI152_T1_1mm.nii.gz'), 'rb') as gzipped_nifti: print('First few bytes of gzipped NIFTI file:', gzipped_nifti.read(10)) ``` +> We use the `expandvars()` function here to insert the FSLDIR environmental variable into our string. This function will be presented in the file management practical. + <a class="anchor" id="converting-objects-into-strings"></a> ### converting objects into strings There are two functions to convert python objects into strings, `repr()` and `str()`. @@ -158,6 +161,16 @@ print(repr(3)) ``` In both cases you get the value of the object (3), but only the `repr` returns enough information to actually know the type of the object. +Perhaps the difference is clearer with a more advanced object. +The `datetime` module contains various classes and functions to work with dates (there is also a `time` module). +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()) +``` +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. + <a class="anchor" id="combining-strings"></a> ### Combining strings The simplest way to concatenate strings is to simply add them together: @@ -209,15 +222,18 @@ 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 `:` delimeter separates the variable identifies on the left from the formatting rules on the right. +Note that the variable `:` delimiter separates the variable identifies 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. This means that we do not have to explicitly provide the parameters (and we can evaluate the sum inside the string!), although it does mean we also can not re-use the template. +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. +This means that we do not have to explicitly provide the parameters (and we can evaluate the sum inside the string!), although it does mean we also can not re-use the template. ``` a = 3 b = 1/3 print(f'{a + b:.3f} = {a} + {b:.3f}') ``` +This code block will fail in fslpython, since it uses python 3.5. <a class="anchor" id="extracting-information-from-strings"></a> @@ -248,7 +264,7 @@ print('The split() method\trecognizes a wide variety\nof white space'.split()) To separate a comma separated list we will need to supply the delimiter to the `split()` method. We can then use the `strip()` method to remove any whitespace at the beginning or end of the string: ``` scientific_packages_string = "numpy, scipy, pandas, matplotlib, nibabel" -list_with_whitespace = scientific_packages_string.split() +list_with_whitespace = scientific_packages_string.split(',') print(list_with_whitespace) list_without_whitespace = [individual_string.strip() for individual_string in list_with_whitespace] print(list_without_whitespace) diff --git a/getting_started/07_jupyter.ipynb b/getting_started/07_jupyter.ipynb index 77c8df4c0500f3792a1ae02f225e89351ba8d79c..6d743be8f5f8c69db2ba2dc12a8e315e3dc13f10 100644 --- a/getting_started/07_jupyter.ipynb +++ b/getting_started/07_jupyter.ipynb @@ -12,7 +12,7 @@ "This makes them more useful for analysis that needs to be reproducible, but does not need to be replicated on different datasets (e.g., making a plot for a paper).\n", "\n", "For more ad-hoc analysis it can be useful to just use the command line (i.e., a REPL).\n", - "We strongly recommend to use the IPython (available as `ipython` in the terminal after you install `ipython` using `pip` or `conda`) rather than default python REPL (available through `python` or `fslpython`)\n", + "We strongly recommend to use the IPython (available as `ipython` or `fslipython`) rather than default python REPL (available through `python` or `fslpython`)\n", "\n", "Both Ipython and the jupyter notebook offer a whole range of magic commands, which all start with a `%` sign.\n", "* A magic command starting with a single `%` sign will only affect the single line.\n", @@ -59,7 +59,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Both Ipython and Jupyter also come with autocomplete, which is available at any time by pressing <tab>\n", + "Both Ipython and Jupyter also come with autocomplete, which is available at any time by pressing the tab key\n", "\n", "---\n", "\n", @@ -76,6 +76,24 @@ "!fslstats ${FSLDIR}/data/standard/FMRIB58_FA_1mm.nii.gz -r" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can even capture the output from the shell command in a variable:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "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 ({:.0f}, {:.0f})'.format(r_lower, r_upper))" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -135,7 +153,7 @@ "source": [ "import numpy as np\n", "numbers = np.random.rand(10)\n", - "%timeit np.sin(numbers)" + "%timeit np.sin(numbers) # this will take a few seconds to run" ] }, { @@ -156,6 +174,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", @@ -188,6 +210,8 @@ "source": [ "Try to check the value of `a_list` and `local_list` from within the debugger.\n", "\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", "\n", "---\n", @@ -215,23 +239,12 @@ "source": [ "> Keep in mind that as soon as you have started plotting you can no longer change your backend without restarting python.\n", "\n", - "To do the equivalent in a python script would look like" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib as mpl\n", - "mpl.use(<backend>)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ + "To do the equivalent in a python script would look like\n", + "> ```\n", + "> import matplotlib as mpl\n", + "> mpl.use(<backend>)\n", + "> ```\n", + "\n", "For interactive use it can be handy to have all the `numpy` numeric functions and `matplotlib` plotting functions directly available without importing them explicitly.\n", "This can be achieved using the `%pylab <backend>` magic command." ] @@ -249,24 +262,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This is equivalent in python code to:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib as mpl\n", - "mpl.use(<backend>)\n", - "from matplotlib.pylab import *" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ + "This is equivalent in python code to:\n", + "> ```\n", + "> import matplotlib as mpl\n", + "> mpl.use(<backend>)\n", + "> from matplotlib.pylab import *\n", + "> ```\n", + "\n", "I start most of my notebooks or terminals with the `%pylab` command, because afterwards I can just do stuff like:" ] }, @@ -346,7 +348,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 1a9090a254fda5ce3d0da46bf6e44301f09536e5..9924b38fad0c17c98e38062a0fe6d0a3a7e7dffa 100644 --- a/getting_started/07_jupyter.md +++ b/getting_started/07_jupyter.md @@ -6,7 +6,7 @@ However, they can not be called as scripts on the command line or be imported fr This makes them more useful for analysis that needs to be reproducible, but does not need to be replicated on different datasets (e.g., making a plot for a paper). For more ad-hoc analysis it can be useful to just use the command line (i.e., a REPL). -We strongly recommend to use the IPython (available as `ipython` in the terminal after you install `ipython` using `pip` or `conda`) rather than default python REPL (available through `python` or `fslpython`) +We strongly recommend to use the IPython (available as `ipython` or `fslipython`) rather than default python REPL (available through `python` or `fslpython`) Both Ipython and the jupyter notebook offer a whole range of magic commands, which all start with a `%` sign. * A magic command starting with a single `%` sign will only affect the single line. @@ -31,7 +31,7 @@ import string string.capwords?? ``` -Both Ipython and Jupyter also come with autocomplete, which is available at any time by pressing <tab> +Both Ipython and Jupyter also come with autocomplete, which is available at any time by pressing the tab key --- @@ -41,6 +41,13 @@ Commands starting with a `!` will be sent to the shell rather than the python in !fslstats ${FSLDIR}/data/standard/FMRIB58_FA_1mm.nii.gz -r ``` +You can even capture the output from the shell command in a variable: +``` +r = !fslstats ${FSLDIR}/data/standard/FMRIB58_FA_1mm.nii.gz -r +r_lower, r_upper = [float(element) for element in r[0].split()] +print('Bounds are ({:.0f}, {:.0f})'.format(r_lower, r_upper)) +``` + --- ## Running other programming languages @@ -67,7 +74,7 @@ For very fast evaluation, you might need to run it multiple times to get an accu ``` import numpy as np numbers = np.random.rand(10) -%timeit np.sin(numbers) +%timeit np.sin(numbers) # this will take a few seconds to run ``` --- @@ -77,6 +84,10 @@ Despite your best efforts in many cases some error will crop up ``` import numpy as np def total(a_list): + """Calculate the total of a list. + + This is a very naive (not recommended) and bugged implementation + """ # create local copy befor changing the input local_list = list(a_list) total = 0. @@ -93,6 +104,8 @@ You can always open a debugger at the location of the last error by using the `% ``` 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) --- @@ -109,10 +122,10 @@ When failing to provide a backend it will simply use the default (which is usual > Keep in mind that as soon as you have started plotting you can no longer change your backend without restarting python. To do the equivalent in a python script would look like -``` -import matplotlib as mpl -mpl.use(<backend>) -``` +> ``` +> import matplotlib as mpl +> mpl.use(<backend>) +> ``` For interactive use it can be handy to have all the `numpy` numeric functions and `matplotlib` plotting functions directly available without importing them explicitly. This can be achieved using the `%pylab <backend>` magic command. @@ -121,11 +134,11 @@ This can be achieved using the `%pylab <backend>` magic command. ``` This is equivalent in python code to: -``` -import matplotlib as mpl -mpl.use(<backend>) -from matplotlib.pylab import * -``` +> ``` +> import matplotlib as mpl +> mpl.use(<backend>) +> from matplotlib.pylab import * +> ``` I start most of my notebooks or terminals with the `%pylab` command, because afterwards I can just do stuff like: ``` @@ -164,6 +177,6 @@ We can now run this script ## Exporting code from the Ipython terminal You can access the full history of your session using `%history`. -To save the history to a file use `%history -f <filename>` +To save the history to a file use `%history -f <filename>`. 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.