Skip to content
Snippets Groups Projects
intro.ipynb 38.3 KiB
Newer Older
Paul McCarthy's avatar
Paul McCarthy committed
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Welcome to the WIN Virtual Mini PyTreat 2020!\n",
    "\n",
    "\n",
Paul McCarthy's avatar
Paul McCarthy committed
    "This notebook is available at:\n",
Paul McCarthy's avatar
Paul McCarthy committed
    "\n",
    "\n",
Paul McCarthy's avatar
Paul McCarthy committed
    "https://git.fmrib.ox.ac.uk/fsl/pytreat-practicals-2020/-/tree/master/talks%2Fvirtual_intro/intro.ipynb\n",
    "\n",
    "\n",
    "If you have FSL installed and you'd like to follow along *interactively*,\n",
    "follow the instructions for attendees in the `README.md` file of the above\n",
    "repository, and then open the `talks/virtual_intro/intro.ipynb` notebook.\n",
    "\n",
    "\n",
    "# Contents\n",
Paul McCarthy's avatar
Paul McCarthy committed
    "\n",
    "\n",
    "* [Introduction](#introduction)\n",
    "  * [Python in a nutshell](#python-in-a-nutshell)\n",
    "  * [Different ways of running Python](#different-ways-of-running-python)\n",
    "* [Variables and basic types](#variables-and-basic-types)\n",
    "  * [Integer and floating point scalars](#integer-and-floating-point-scalars)\n",
    "  * [Strings](#strings)\n",
    "  * [Lists and tuples](#lists-and-tuples)\n",
    "  * [Dictionaries](#dictionaries)\n",
    "  * [A note on mutablility](#a-note-on-mutablility)\n",
    "* [Flow control](#flow-control)\n",
    "  * [List comprehensions](#list-comprehensions)\n",
    "* [Reading and writing text files](#reading-and-writing-text-files)\n",
    "  * [Example: processing lesion counts](#example-processing-lesion-counts)\n",
    "* [Functions](#functions)\n",
    "* [Working with `numpy`](#working-with-numpy)\n",
    "  * [The Python list versus the `numpy` array](#the-python-list-versus-the-numpy-array)\n",
    "  * [Creating arrays](#creating-arrays)\n",
    "  * [Example: reading arrays from text files](#example-reading-arrays-from-text-files)\n",
    "\n",
    "\n",
    "<a class=\"anchor\" id=\"introduction\"></a>\n",
    "# Introduction\n",
    "\n",
    "\n",
    "This talk is an attempt to give a whirlwind overview of the Python programming\n",
    "language.  It is assumed that you have experience with another programming\n",
    "language (e.g. MATLAB).\n",
    "\n",
    "\n",
    "This talk is presented as an interactive [Jupyter\n",
    "Notebook](https://jupyter.org/) - you can run all of the code on your own\n",
    "machine - click on a code block, and press **SHIFT+ENTER**. You can also \"run\"\n",
    "the text sections, so you can just move down the document by pressing\n",
    "**SHIFT+ENTER**.\n",
    "\n",
    "\n",
    "It is also possible to *change* the contents of each code block (these pages\n",
    "are completely interactive) so do experiment with the code you see and try\n",
    "some variations!\n",
    "\n",
    "\n",
    "You can get help on any Python object, function, or method by putting a `?`\n",
    "before or after the thing you want help on:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'hello!'\n",
    "?a.upper"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And you can explore the available methods on a Python object by using the\n",
    "**TAB** key:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Put the cursor after the dot, and press the TAB key...\n",
    "a."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\"python-in-a-nutshell\"></a>\n",
    "## Python in a nutshell\n",
    "\n",
    "\n",
    "**Pros**\n",
    "\n",
    "\n",
    "* _Flexible_ Feel free to use functions, classes, objects, modules and\n",
    "  packages. Or don't - it's up to you!\n",
    "\n",
    "* _Fast_ If you do things right (in other words, if you use `numpy`)\n",
    "\n",
    "* _Dynamically typed_ No need to declare your variables, or specify their\n",
    "  types.\n",
    "\n",
    "* _Intuitive syntax_ How do I run some code for each of the elements in my\n",
    "  list?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mylist = [1, 2, 3, 4, 5]\n",
Paul McCarthy's avatar
Paul McCarthy committed
    "\n",
    "for element in mylist:\n",
    "    print(element)"
Paul McCarthy's avatar
Paul McCarthy committed
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Cons**\n",
    "\n",
    "\n",
    "* _Dynamically typed_ Easier to make mistakes, harder to catch them\n",
    "\n",
    "* _No compiler_ See above\n",
    "\n",
    "* _Slow_ if you don't do things the right way\n",
    "\n",
    "* _Python 2 is not the same as Python 3_ But there's an easy solution: Forget\n",
    "  that Python 2 exists.\n",
    "\n",
    "* _Hard to manage different versions of python_ But we have a solution for\n",
    "  you: `fslpython`.\n",
    "\n",
    "\n",
    "Python is a widely used language, so you can get lots of help through google\n",
    "and [stackoverflow](https://stackoverflow.com). But make sure that the\n",
    "information you find is for **Python 3**, and **not** for **Python 2**!\n",
    "Python 2 is obsolete, but is still used by many organisations, so you will\n",
    "inevitably come across many Python 2 resources.\n",
    "\n",
    "\n",
    "The differences between Python 2 and 3 are small, but important. The most\n",
    "visible difference is in the `print` function: in Python 3, we write\n",
    "`print('hello!')`, but in Python 2, we would write `print 'hello!'`.\n",
    "\n",
    "\n",
    "FSL 5.0.10 and newer comes with its own version of Python, bundled with nearly\n",
    "all of the scientific libraries that you are likely to need.\n",
    "\n",
    "\n",
    "So if you use `fslpython` for all of your development, you can be sure that it\n",
    "will work in FSL!\n",
    "\n",
    "\n",
    "<a class=\"anchor\" id=\"different-ways-of-running-python\"></a>\n",
    "## Different ways of running Python\n",
    "\n",
    "\n",
    "Many of the Pytreat talks and practicals are presented as *Jupyter notebooks*,\n",
    "which is a way of running python code in a web browser.\n",
    "\n",
    "\n",
    "Jupyter notebooks are good for presentations and practicals, and some people\n",
    "find them very useful for exploratory data analysis. But they're not the only\n",
    "way of running Python code.\n",
    "\n",
    "\n",
    "**Run Python from a file**\n",
    "\n",
    "\n",
    "This works just like it does in MATLAB:\n",
    "\n",
    "\n",
    "1. Put your code in a `.py` file (e.g. `mycode.py`).\n",
    "2. Run `fslpython mycode.py` in a terminal.\n",
    "3. ??\n",
    "4. Profit.\n",
    "\n",
    "\n",
    "**Run python in an interpreter**\n",
    "\n",
    "\n",
    "Python is an [*interpreted\n",
    "language*](https://en.wikipedia.org/wiki/Interpreted_language), like MATLAB.\n",
    "So you can either write your code into a file, and then run that file, or you\n",
    "can type code directly into a Python interpreter.\n",
    "\n",
    "\n",
    "Python has a standard interpreter built-in - run `fslpython` in a terminal,\n",
    "and see what happens (use CTRL+D to exit).\n",
    "\n",
    "\n",
    "**But** there is another interpreter called [IPython](https://ipython.org/)\n",
    "which is vastly superior to the standard Python interpreter. Use IPython\n",
    "instead! It is already installed in `fslpython`, so if you want to do some\n",
    "interactive work, you can use `fslipython` in a terminal.\n",
    "\n",
    "\n",
    "<a class=\"anchor\" id=\"variables-and-basic-types\"></a>\n",
    "# Variables and basic types\n",
    "\n",
    "\n",
    "There are many different types of values in Python. Python *variables* do not\n",
    "have a type though - a variable can refer to values of any type, and a\n",
    "variable can be updated to refer to different values (of different\n",
    "types). This is just like how things work in MATLAB.\n",
    "\n",
    "\n",
    "<a class=\"anchor\" id=\"integer-and-floating-point-scalars\"></a>\n",
    "## Integer and floating point scalars"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 7\n",
    "b = 1 / 3\n",
    "c = a + b\n",
    "print('a:    ', a)\n",
    "print('b:    ', b)\n",
    "print('c:    ', c)\n",
    "print('b:     {:0.4f}'.format(b))\n",
    "print('a + b:', a + b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\"strings)\"></a>\n",
    "## Strings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'Hello'\n",
    "b = \"Kitty\"\n",
    "c = '''\n",
    "Magic\n",
    "multi-line\n",
    "strings!\n",
    "'''\n",
    "\n",
    "print(a, b)\n",
    "print(a + b)\n",
    "print('{}, {}!'.format(a, b))\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "String objects have a number of useful methods:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = 'This is a Test String'\n",
    "print(s.upper())\n",
    "print(s.lower())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another useful method is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = 'This is a Test String'\n",
    "s2 = s.replace('Test', 'Better')\n",
    "print(s2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Two common and convenient string methods are `strip()` and `split()`.  The\n",
    "first will remove any whitespace at the beginning and end of a string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s2 = '   A very    spacy   string       '\n",
    "print('*' + s2 + '*')\n",
    "print('*' + s2.strip() + '*')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With `split()` we can tokenize a string (to turn it into a list of strings)\n",
    "like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(s.split())\n",
    "print(s2.split())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also use the `join` method to re-construct a new string. Imagine that\n",
    "we need to reformat some data from being comma-separated to being\n",
    "space-separated:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = ' 1,2,3,4,5,6,7  '"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`strip`, `split` and `join` makes this job trivial:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('Original:               {}'.format(data))\n",
    "print('Strip, split, and join: {}'.format(' '.join(data.strip().split(','))))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\"lists-and-tuples\"></a>\n",
    "## Lists and tuples\n",
    "\n",
    "\n",
    "Both tuples and lists are built-in Python types and are like cell-arrays in\n",
    "MATLAB. For numerical vectors and arrays it is much better to use *numpy*\n",
    "arrays, which are covered later.\n",
    "\n",
    "\n",
    "Tuples are defined using round brackets and lists are defined using square\n",
    "brackets. For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "t = (3, 7.6, 'str')\n",
    "l = [1, 'mj', -5.4]\n",
    "print(t)\n",
    "print(l)\n",
    "\n",
    "t2 = (t, l)\n",
    "l2 = [t, l]\n",
    "print('t2 is: ', t2)\n",
Paul McCarthy's avatar
Paul McCarthy committed
    "print('l3 is: ', l2)\n",
    "print(len(t2))\n",
    "print(len(l2))"
Paul McCarthy's avatar
Paul McCarthy committed
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The key difference between lists and tuples is that tuples are *immutable*\n",
    "(once created, they cannot be changed), whereas lists are *mutable*:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [10, 20, 30]\n",
Paul McCarthy's avatar
Paul McCarthy committed
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Square brackets are used to index tuples, lists, strings, dictionaries, etc.\n",
    "For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = [10, 20, 30]\n",
    "print(d[1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **MATLAB pitfall:** Python uses zero-based indexing, unlike MATLAB, where\n",
    "> indices start from 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [10, 20, 30, 40, 50, 60]\n",
    "print(a[0])\n",
    "print(a[2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A range of values for the indices can be specified to extract values from a\n",
    "list or tuple using the `:` character.  For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(a[0:3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **MATLAB pitfall:** Note that Python's slicing syntax is different from\n",
    "> MATLAB in that the second number is *exclusive*, i.e. `a[0:3]` gives us the\n",
    "> elements of `a` at positions `0`, `1` and `2` , but *not* at position `3`.\n",
    "\n",
    "\n",
    "When slicing a list or tuple, you can leave the start and end values out -\n",
    "when you do this, Python will assume that you want to start slicing from the\n",
    "beginning or the end of the list.  For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(a[:3])\n",
    "print(a[1:])\n",
    "print(a[:])\n",
    "print(a[:-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also change the step size, which is specified by the third value (not\n",
    "the second one, as in MATLAB).  For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(a[0:4:2])\n",
    "print(a[::2])\n",
    "print(a[::-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some methods are available on `list` objects for adding and removing items:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(d)\n",
    "d.append(40)\n",
    "print(d)\n",
    "d.extend([50, 60])\n",
    "print(d)\n",
    "d = d + [70, 80]\n",
    "print(d)\n",
    "d.remove(20)\n",
    "print(d)\n",
    "d.pop(0)\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What will `d.append([50,60])` do, and how is it different from\n",
    "`d.extend([50,60])`?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "d.append([50, 60])\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\"dictionaries\"></a>\n",
    "## Dictionaries\n",
    "\n",
    "\n",
    "Dictionaries (or *dicts*) can be used to store key-value pairs. Almost\n",
    "anything can used as a key, and anything can be stored as a value; it is\n",
    "common to use strings as keys:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e = {'a' : 10, 'b': 20}\n",
    "print(len(e))\n",
    "print(e.keys())\n",
    "print(e.values())\n",
    "print(e['a'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Like lists (and unlike tuples), dicts are mutable, and have a number of\n",
    "methods for manipulating them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e['c'] = 30\n",
    "e.pop('a')\n",
    "e.update({'a' : 100, 'd' : 400})\n",
    "print(e)\n",
    "e.clear()\n",
    "print(e)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\"a-note-on-mutability\"></a>\n",
    "## A note on mutablility\n",
    "\n",
    "\n",
    "Python variables can refer to values which are either mutable, or\n",
    "immutable. Examples of immutable values are strings, tuples, and integer and\n",
    "floating point scalars. Examples of mutable values are lists, dicts, and most\n",
    "user-defined types.\n",
    "\n",
    "\n",
    "When you pass an immutable value around (e.g. into a function, or to another\n",
    "variable), it works the same as if you were to copy the value and pass in the\n",
    "copy - the original value is not changed:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'abcde'\n",
    "b = a\n",
    "b = b.upper()\n",
    "print('a:', a)\n",
    "print('b:', b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In contrast, when you pass a mutable value around, you are passing a\n",
    "*reference* to that value - there is only ever one value in existence, but\n",
    "multiple variables refer to it. You can manipulate the value through any of\n",
    "the variables that refer to it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [1, 2, 3, 4, 5]\n",
    "b = a\n",
    "\n",
    "a[3] = 999\n",
    "b.append(6)\n",
    "\n",
    "print('a', a)\n",
    "print('b', b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\"flow-control\"></a>\n",
    "# Flow control\n",
    "\n",
    "\n",
    "Python also has a boolean type which can be either `True` or `False`. Most\n",
    "Python types can be implicitly converted into booleans when used in a\n",
    "conditional expression.\n",
    "\n",
    "\n",
    "Relevant boolean and comparison operators include: `not`, `and`, `or`, `==`\n",
    "and `!=`\n",
    "\n",
    "\n",
    "For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = True\n",
    "b = False\n",
    "print('Not a is:', not a)\n",
    "print('a or b is:', a or b)\n",
    "print('a and b is:', a and b)\n",
    "print('Not 1 is:', not 1)\n",
    "print('Not 0 is:', not 0)\n",
    "print('Not {} is:', not {})\n",
    "print('{}==0 is:', {}==0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is also the `in` test for strings, lists, etc:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('the' in 'a number of words')\n",
    "print('of' in 'a number of words')\n",
    "print(3 in [1, 2, 3, 4])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use boolean values in `if`-`else` conditional expressions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [1, 2, 3, 4]\n",
    "val = 3\n",
    "if val in a:\n",
    "    print('Found {}!'.format(val))\n",
    "else:\n",
    "    print('{} not found :('.format(val))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that the indentation in the `if`-`else` statement is **crucial**.\n",
    "**All** python control blocks are delineated purely by indentation. We\n",
    "recommend using **four spaces** and no tabs, as this is a standard practice\n",
    "and will help a lot when collaborating with others.\n",
    "\n",
    "\n",
    "You can use the `for` statement to loop over elements in a list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = [10, 20, 30]\n",
    "for x in d:\n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also loop over the key-value pairs in a dict:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = {'a' : 10, 'b' : 20, 'c' : 30}\n",
    "print('a.items()')\n",
    "for key, val in a.items():\n",
    "    print(key, val)\n",
    "print('a.keys()')\n",
    "for key in a.keys():\n",
    "    print(key, a[key])\n",
    "print('a.values()')\n",
    "for val in a.values():\n",
    "    print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> In older versions of Python 3, there was no guarantee of ordering when using dictionaries.\n",
    "> However, a of Python 3.7, dictionaries will remember the order in which items are inserted,\n",
    "> and the `keys()`, `values()`, and `items()` methods will return elements in that order.\n",
    ">\n",
    "\n",
    "> If you want a dictionary with ordering, *and* you want your code to work with\n",
    "> Python versions older than 3.7, you can use the\n",
    "> [`OrderedDict`](https://docs.python.org/3/library/collections.html#collections.OrderedDict)\n",
    "> class.\n",
    "\n",
    "\n",
    "There are some handy built-in functions that you can use with `for` loops:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = [10, 20, 30]\n",
    "print('Using the range function')\n",
    "for i in range(len(d)):\n",
    "    print('element at position {}: {}'.format(i, d[i]))\n",
    "\n",
    "print('Using the enumerate function')\n",
    "for i, elem in enumerate(d):\n",
    "    print('element at position {}: {}'.format(i, elem))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\" list-comprehensions\"></a>\n",
    "## List comprehensions\n",
    "\n",
    "\n",
    "Python has a really neat way to create lists (and dicts), called\n",
    "*comprehensions*. Let's say we have some strings, and we want to count the\n",
    "number of characters in each of them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "strings = ['hello', 'howdy', 'hi', 'hey']\n",
    "nchars = [len(s) for s in strings]\n",
    "for s, c in zip(strings, nchars):\n",
    "    print('{}: {}'.format(s, c))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> The `zip` function \"zips\" two or more sequences, so you can loop over them\n",
    "> together.\n",
    "\n",
    "\n",
    "Or we could store the character counts in a dict:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "nchars = { s : len(s) for s in strings }\n",
    "\n",
    "for s, c in nchars.items():\n",
    "    print('{}: {}'.format(s, c))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
Paul McCarthy's avatar
Paul McCarthy committed
    "<a class=\"anchor\" id=\"reading-and-writing-text-files\"></a>\n",
Paul McCarthy's avatar
Paul McCarthy committed
    "# Reading and writing text files\n",
    "\n",
    "\n",
    "The syntax to open a file in python is\n",
    "`with open(<filename>, <mode>) as <file_object>: <block of code>`, where\n",
    "\n",
    "\n",
    "* `filename` is a string with the name of the file\n",
    "* `mode` is one of 'r' (for read-only access), 'w' (for writing a file, this\n",
    "  wipes out any existing content), 'a' (for appending to an existing file).\n",
    "* `file_object` is a variable name which will be used within the `block of\n",
    "  code` to access the opened file.\n",
    "\n",
    "\n",
    "For example the following will read all the text in `data/file.txt` and print\n",
    "it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('data/file.txt', 'r') as f:\n",
    "    print(f.read())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A very similar syntax is used to write files:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('new_file.txt', 'w') as f:\n",
    "    f.write('This is my first line\\n')\n",
    "    f.writelines(['Second line\\n', 'and the third\\n'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a class=\"anchor\" id=\"example-processing-lesion-counts\"></a>\n",
    "## Example: processing lesion counts\n",
    "\n",
    "\n",
    "Imagine that we have written an amazing algorithm in Python which\n",
    "automatically counts the number of lesions in an individual's structural MRI\n",
    "image."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "subject_ids   = ['01', '07', '21', '32']\n",
    "lesion_counts = [  4,    9,   13,    2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We may wish to process this data in another application (e.g. Excel or SPSS).\n",
    "Let's save the results out to a CSV (comma-separated value) file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open('lesion_counts.csv', 'w') as f:\n",
    "    f.write('Subject ID, Lesion count\\n')\n",
    "    for subj_id, count in zip(subject_ids, lesion_counts):\n",
    "        f.write('{}, {}\\n'.format(subj_id, count))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can now load the `lesion_counts.csv` file into our analysis software of\n",
    "choice. Or we could load it back into another Python session, and store\n",
    "the data in a dict:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],