diff --git a/_episodes/02_fundamentals.md b/_episodes/02_fundamentals.md index 7883132..427d41f 100644 --- a/_episodes/02_fundamentals.md +++ b/_episodes/02_fundamentals.md @@ -39,8 +39,7 @@ Any Python interpreter can be used as a calculator: This is great but not very interesting. To do anything useful with data, we need to assign its value to a _variable_. -In Python, we can [assign]({{ page.root }}/reference.html#assign) a value to a -[variable]({{ page.root }}/reference.html#variable), using the equals sign `=`. +In Python, we can assign a value to a variable, using the equals sign `=`. For example, we can track the weight of a patient who weighs 60 kilograms by assigning the value `60` to a variable `weight_kg`: @@ -56,7 +55,7 @@ In Python, variable names: - can include letters, digits, and underscores - cannot start with a digit - - are [case sensitive]({{ page.root }}/reference.html#case-sensitive). + - are case-sensitive. This means that, for example: - `weight0` is a valid variable name, whereas `0weight` is not @@ -107,7 +106,7 @@ patient_id = 'inflam_' + patient_id ## Built-in Python functions To carry out common tasks with data and variables in Python, -the language provides us with several built-in [functions]({{ page.root }}/reference.html#function). +the language provides us with several built-in functions. To display information to the screen, we use the `print` function: ~~~ @@ -142,8 +141,7 @@ inflam_001 weight in kilograms: 60.3 {: .output} We can also call a function inside of another -[function call]({{ page.root }}/reference.html#function-call). -For example, Python has a built-in function called `type` that tells you a value's data type: +function call. For example, Python has a built-in function called `type` that tells you a value's data type: ~~~ print(type(60.3)) @@ -194,8 +192,8 @@ weight in kilograms is now: 65.0 ~~~ {: .output} -> ## Variables as Sticky Notes -> +## Variables as Sticky Notes + > A variable in Python is analogous to a sticky note with a name written on it: > assigning a value to a variable is like putting that sticky note on a particular value. > @@ -246,8 +244,8 @@ stuck on it](../fig/python-sticky-note-variables-03.svg) {: .callout} -> ## Check Your Understanding -> +## Check Your Understanding + > What values do the variables `mass` and `age` have after each of the following statements? > Test your answer by executing the lines. > @@ -270,8 +268,8 @@ stuck on it](../fig/python-sticky-note-variables-03.svg) > {: .solution} {: .challenge} -> ## Sorting Out References -> +## Sorting Out References + > Python allows you to assign multiple values to multiple variables in one line by separating > the variables and values with commas. What does the following program print out? > @@ -290,8 +288,8 @@ stuck on it](../fig/python-sticky-note-variables-03.svg) > {: .solution} {: .challenge} -> ## Seeing Data Types -> +## Seeing Data Types + > What are the data types of the following variables? > > ~~~ diff --git a/_episodes/03_lists.md b/_episodes/03_lists.md index 54780d8..b8de99c 100644 --- a/_episodes/03_lists.md +++ b/_episodes/03_lists.md @@ -17,7 +17,7 @@ At the end of this lesson you will be able to: - Append values to an existing list - Create and manipulate nested lists -## Keypoints +## Key points - "`[value1, value2, value3, ...]` creates a list." - "Lists can contain any Python object, including lists (i.e., list of lists)." @@ -26,25 +26,10 @@ list[2:9]), in the same way as strings and arrays." - "Lists are mutable (i.e., their values can be changed in place)." - "Strings are immutable (i.e., the characters in them cannot be changed)." -## Introduction - -In the previous episode, we analyzed a single file of clinical trial inflammation data. However, -after finding some peculiar and potentially suspicious trends in the trial data we ask -Dr. Maverick if they have performed any other clinical trials. Surprisingly, they say that they -have and provide us with 11 more CSV files for a further 11 clinical trials they have undertaken -since the initial trial. - -Our goal now is to process all the inflammation data we have, which means that we still have -eleven more files to go! - -The natural first step is to collect the names of all the files that we have to process. In Python, -a list is a way to store multiple values together. In this episode, we will learn how to store -multiple values in a list as well as how to work with lists. - ## Python lists -Unlike NumPy arrays, lists are built into the language so we do not have to load a library -to use them. +Lists are a data structure in Python that can contain a changeable (or mutable) sequence of elements. These elements can be values or other variables. + We create a list by putting values inside square brackets and separating the values with commas: ~~~ @@ -119,11 +104,11 @@ TypeError: 'str' object does not support item assignment does not. -> ## Ch-Ch-Ch-Ch-Changes -> -> Data which can be modified in place is called [mutable]({{ page.root }}/reference.html#mutable), +## Ch-Ch-Ch-Ch-Changes + +> Data which can be modified in place is called mutable, > while data which cannot be modified is called -> [immutable]({{ page.root }}/reference.html#immutable). +> immutable. > Strings and numbers are immutable. This does not mean that variables with string or number values > are constants, but when we want to change the value of a string or number variable, we can only > replace the old value with a completely new value. diff --git a/_episodes/05_control_flow.md b/_episodes/05_control_flow.md index aa61567..8186a5f 100644 --- a/_episodes/05_control_flow.md +++ b/_episodes/05_control_flow.md @@ -16,11 +16,7 @@ At the end of this lesson you will be able to: - Explain the basic conditional statements, such as `if`, `else`, `and`, `not`, and `or` - Write some simple expressions using these statements -## Representing a problem computationally - - - -## Keypoints +## Key points - "Use `if condition` to start a conditional statement, `elif condition` to provide additional tests, and `else` to provide a default." - "The bodies of the branches of conditional statements must be indented." @@ -104,8 +100,8 @@ else: Note that to test for equality we use a double equals sign `==` rather than a single equals sign `=` which is used to assign values. -> ## Comparing in Python -> +## Comparing in Python + > Along with the `>` and `==` operators we have already used for comparing values in our > conditionals, there are a few more options to know about: > @@ -249,8 +245,8 @@ but we could also imagine not using the `else` catch-all so that messages are only printed when something is wrong, freeing us from having to manually examine every plot for features we've seen before. -> ## How Many Paths? -> +## How Many Paths? + > Consider this code: > > ~~~ @@ -277,8 +273,8 @@ freeing us from having to manually examine every plot for features we've seen be > {: .solution} {: .challenge} -> ## What Is Truth? -> +## What Is Truth? + > `True` and `False` booleans are not the only values in Python that are true and false. > In fact, *any* value can be used in an `if` or `elif`. > After reading and running the code below, @@ -301,8 +297,8 @@ freeing us from having to manually examine every plot for features we've seen be > {: .language-python} {: .challenge} -> ## That's Not Not What I Meant -> +## That's Not Not What I Meant + > Sometimes it is useful to check whether some condition is not true. > The Boolean operator `not` can do this explicitly. > After reading and running the code below, @@ -320,8 +316,8 @@ freeing us from having to manually examine every plot for features we've seen be > {: .language-python} {: .challenge} -> ## Close Enough -> +## Close Enough + > Write some conditions that print `True` if the variable `a` is within 10% of the variable `b` > and `False` otherwise. > Compare your implementation with your partner's: @@ -363,148 +359,3 @@ freeing us from having to manually examine every plot for features we've seen be > > have string representations which can be printed. > {: .solution} {: .challenge} - -> ## In-Place Operators -> -> Python (and most other languages in the C family) provides -> [in-place operators]({{ page.root }}/reference.html#in-place-operators) -> that work like this: -> -> ~~~ -> x = 1 # original value -> x += 1 # add one to x, assigning result back to x -> x *= 3 # multiply x by 3 -> print(x) -> ~~~ -> {: .language-python} -> -> ~~~ -> 6 -> ~~~ -> {: .output} -> -> Write some code that sums the positive and negative numbers in a list separately, -> using in-place operators. -> Do you think the result is more or less readable -> than writing the same without in-place operators? -> -> > ## Solution -> > ~~~ -> > positive_sum = 0 -> > negative_sum = 0 -> > test_list = [3, 4, 6, 1, -1, -5, 0, 7, -8] -> > for num in test_list: -> > if num > 0: -> > positive_sum += num -> > elif num == 0: -> > pass -> > else: -> > negative_sum += num -> > print(positive_sum, negative_sum) -> > ~~~ -> > {: .language-python} -> > -> > Here `pass` means "don't do anything". -> In this particular case, it's not actually needed, since if `num == 0` neither -> > sum needs to change, but it illustrates the use of `elif` and `pass`. -> {: .solution} -{: .challenge} - -> ## Sorting a List Into Buckets -> -> In our `data` folder, large data sets are stored in files whose names start with -> "inflammation-" and small data sets -- in files whose names start with "small-". We -> also have some other files that we do not care about at this point. We'd like to break all -> these files into three lists called `large_files`, `small_files`, and `other_files`, -> respectively. -> -> Add code to the template below to do this. Note that the string method -> [`startswith`](https://docs.python.org/3/library/stdtypes.html#str.startswith) -> returns `True` if and only if the string it is called on starts with the string -> passed as an argument, that is: -> -> ~~~ -> 'String'.startswith('Str') -> ~~~ -> {: .language-python} -> ~~~ -> True -> ~~~ -> {: .output} -> But -> ~~~ -> 'String'.startswith('str') -> ~~~ -> {: .language-python} -> ~~~ -> False -> ~~~ -> {: .output} ->Use the following Python code as your starting point: -> ~~~ -> filenames = ['inflammation-01.csv', -> 'myscript.py', -> 'inflammation-02.csv', -> 'small-01.csv', -> 'small-02.csv'] -> large_files = [] -> small_files = [] -> other_files = [] -> ~~~ -> {: .language-python} -> -> Your solution should: -> -> 1. loop over the names of the files -> 2. figure out which group each filename belongs in -> 3. append the filename to that list -> -> In the end the three lists should be: -> -> ~~~ -> large_files = ['inflammation-01.csv', 'inflammation-02.csv'] -> small_files = ['small-01.csv', 'small-02.csv'] -> other_files = ['myscript.py'] -> ~~~ -> {: .language-python} -> -> > ## Solution -> > ~~~ -> > for filename in filenames: -> > if filename.startswith('inflammation-'): -> > large_files.append(filename) -> > elif filename.startswith('small-'): -> > small_files.append(filename) -> > else: -> > other_files.append(filename) -> > -> > print('large_files:', large_files) -> > print('small_files:', small_files) -> > print('other_files:', other_files) -> > ~~~ -> > {: .language-python} -> {: .solution} -{: .challenge} - -> ## Counting Vowels -> -> 1. Write a loop that counts the number of vowels in a character string. -> 2. Test it on a few individual words and full sentences. -> 3. Once you are done, compare your solution to your neighbor's. -> Did you make the same decisions about how to handle the letter 'y' -> (which some people think is a vowel, and some do not)? -> -> > ## Solution -> > ~~~ -> > vowels = 'aeiouAEIOU' -> > sentence = 'Mary had a little lamb.' -> > count = 0 -> > for char in sentence: -> > if char in vowels: -> > count += 1 -> > -> > print('The number of vowels in this string is ' + str(count)) -> > ~~~ -> > {: .language-python} -> {: .solution} -{: .challenge} diff --git a/_episodes/06_loops.md b/_episodes/06_loops.md index 2013371..188e378 100644 --- a/_episodes/06_loops.md +++ b/_episodes/06_loops.md @@ -16,15 +16,13 @@ At the end of this lesson you will be able to: - Write some simple loops to perform repeat calculations - Investigate what is happening to variables as a `for` loop progresses -## Introduction to variables +## Key points - -## Keypoints - "Use `for variable in sequence` to process the elements of a sequence one at a time." - "The body of a `for` loop must be indented." - "Use `len(thing)` to determine the length of something that contains other values." - +## Introduction to loops ~~~ odds = [1, 3, 5, 7] @@ -96,7 +94,7 @@ IndexError: list index out of range ~~~ {: .error} -Here's a better approach: a [for loop]({{ page.root }}/reference.html#for-loop) +Here's a better approach: a `for` loop ~~~ odds = [1, 3, 5, 7] @@ -133,7 +131,7 @@ for num in odds: ~~~ {: .output} -The improved version uses a [for loop]({{ page.root }}/reference.html#for-loop) +The improved version uses a `for` loop to repeat an operation --- in this case, printing --- once for each thing in a sequence. The general form of a loop is: @@ -152,15 +150,14 @@ where each number (`num`) in the variable `odds` is looped through and printed o another. The other numbers in the diagram denote which loop cycle the number was printed in (1 being the first loop cycle, and 6 being the final loop cycle). -We can call the [loop variable]({{ page.root }}/reference.html#loop-variable) anything we like, but +We can call the loop variable anything we like, but there must be a colon at the end of the line starting the loop, and we must indent anything we want to run inside the loop. Unlike many other languages, there is no command to signify the end of the loop body (e.g. `end for`); what is indented after the `for` statement belongs to the loop. -> ## What's in a name? -> -> +## What's in a name? + > In the example above, the loop variable was given the name `num` as a mnemonic; > it is short for 'number'. > We can choose any name we want for variables. We might just as easily have chosen the name @@ -260,8 +257,8 @@ and much easier to read than a two-line loop; it will also give us the length of many other things that we haven't met yet, so we should always use it when we can. -> ## From 1 to N -> +## From 1 to N + > Python has a built-in function called `range` that generates a sequence of numbers. `range` can > accept 1, 2, or 3 parameters. > @@ -294,11 +291,8 @@ so we should always use it when we can. > {: .solution} {: .challenge} + ## Understanding the loops - - -> ## Understanding the loops -> > Given the following loop: > ~~~ > word = 'oxygen' @@ -321,10 +315,8 @@ so we should always use it when we can. > {: .solution} {: .challenge} +## Computing Powers With Loops - -> ## Computing Powers With Loops -> > Exponentiation is built into Python: > > ~~~ @@ -351,8 +343,8 @@ so we should always use it when we can. > {: .solution} {: .challenge} -> ## Summing a list -> +## Summing a list + > Write a loop that calculates the sum of elements in a list > by adding each element and printing the final value, > so `[124, 402, 36]` prints 562 @@ -369,9 +361,9 @@ so we should always use it when we can. > {: .solution} {: .challenge} -> ## Computing the Value of a Polynomial -> -> The built-in function `enumerate` takes a sequence (e.g. a [list]({{ page.root }}/04-lists/)) and +## Computing the Value of a Polynomial + +> The built-in function `enumerate` takes a sequence (e.g. a list and > generates a new sequence of the same length. Each element of the new sequence is a pair composed > of the index (0, 1, 2,...) and the value from the original sequence: > @@ -413,3 +405,26 @@ so we should always use it when we can. > > {: .language-python} > {: .solution} {: .challenge} + +## Counting Vowels + +> 1. Write a loop that counts the number of vowels in a character string. +> 2. Test it on a few individual words and full sentences. +> 3. Once you are done, compare your solution to your neighbor's. +> Did you make the same decisions about how to handle the letter 'y' +> (which some people think is a vowel, and some do not)? +> +> > ## Solution +> > ~~~ +> > vowels = 'aeiouAEIOU' +> > sentence = 'Mary had a little lamb.' +> > count = 0 +> > for char in sentence: +> > if char in vowels: +> > count += 1 +> > +> > print('The number of vowels in this string is ' + str(count)) +> > ~~~ +> > {: .language-python} +> {: .solution} +{: .challenge} diff --git a/_episodes/07_additional_exercises.md.md b/_episodes/07_additional_exercises.md.md index e857231..9904058 100644 --- a/_episodes/07_additional_exercises.md.md +++ b/_episodes/07_additional_exercises.md.md @@ -51,6 +51,52 @@ toc: true > {: .solution} {: .challenge} +## In-Place Operators + +> Python (and most other languages in the C family) provides +> in-place operators +> that work like this: +> +> ~~~ +> x = 1 # original value +> x += 1 # add one to x, assigning result back to x +> x *= 3 # multiply x by 3 +> print(x) +> ~~~ +> {: .language-python} +> +> ~~~ +> 6 +> ~~~ +> {: .output} +> +> Write some code that sums the positive and negative numbers in a list separately, +> using in-place operators. +> Do you think the result is more or less readable +> than writing the same without in-place operators? +> +> > ## Solution +> > ~~~ +> > positive_sum = 0 +> > negative_sum = 0 +> > test_list = [3, 4, 6, 1, -1, -5, 0, 7, -8] +> > for num in test_list: +> > if num > 0: +> > positive_sum += num +> > elif num == 0: +> > pass +> > else: +> > negative_sum += num +> > print(positive_sum, negative_sum) +> > ~~~ +> > {: .language-python} +> > +> > Here `pass` means "don't do anything". +> In this particular case, it's not actually needed, since if `num == 0` neither +> > sum needs to change, but it illustrates the use of `elif` and `pass`. +> {: .solution} +{: .challenge} + ## Turn a String into a List > Use a for-loop to convert the string "hello" into a list of letters: @@ -96,26 +142,3 @@ toc: true > > {: .language-python} > {: .solution} {: .challenge} - -## Fixing and Testing - -> Fix `range_overlap`. Re-run `test_range_overlap` after each change you make. -> -> > ## Solution -> > ~~~ -> > def range_overlap(ranges): -> > '''Return common overlap among a set of [left, right] ranges.''' -> > if not ranges: -> > # ranges is None or an empty list -> > return None -> > max_left, min_right = ranges[0] -> > for (left, right) in ranges[1:]: -> > max_left = max(max_left, left) -> > min_right = min(min_right, right) -> > if max_left >= min_right: # no overlap -> > return None -> > return (max_left, min_right) -> > ~~~ -> > {: .language-python} -> {: .solution} -{: .challenge} diff --git a/fig/generate_figures.py b/fig/generate_figures.py deleted file mode 100755 index 0ec35fa..0000000 --- a/fig/generate_figures.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate figures used in the lesson episodes. -Usage: ./generate_figures.py -""" - -try: - import numpy - import matplotlib.pyplot -except ImportError: - print("Failed to load NumPy and/or Matplotlib", file=sys.stderr) - exit(1) - -# Configure Matplotlib to not convert text to outlines -# All settings: matplotlib.rcParams or matplotlib.pyplot.rcParams -matplotlib.pyplot.rcParams['svg.fonttype'] = 'none' - -# Load data -data = numpy.loadtxt(fname="../data/inflammation-01.csv", delimiter=",") - -# Episode 1 -## Visualizing data - -matplotlib.pyplot.imshow(data) -matplotlib.pyplot.savefig("inflammation-01-imshow.svg") -matplotlib.pyplot.close() - -matplotlib.pyplot.plot(numpy.mean(data, axis=0)) -matplotlib.pyplot.savefig("inflammation-01-average.svg") -matplotlib.pyplot.close() - -matplotlib.pyplot.plot(numpy.max(data, axis=0)) -matplotlib.pyplot.savefig("inflammation-01-maximum.svg") -matplotlib.pyplot.close() - -matplotlib.pyplot.plot(numpy.min(data, axis=0)) -matplotlib.pyplot.savefig("inflammation-01-minimum.svg") -matplotlib.pyplot.close() - -## Grouping plots -fig = matplotlib.pyplot.figure(figsize=(10.0, 3.0)) - -axes1 = fig.add_subplot(1, 3, 1) -axes2 = fig.add_subplot(1, 3, 2) -axes3 = fig.add_subplot(1, 3, 3) - -axes1.set_ylabel('average') -axes1.plot(numpy.mean(data, axis=0)) - -axes2.set_ylabel('max') -axes2.plot(numpy.max(data, axis=0)) - -axes3.set_ylabel('min') -axes3.plot(numpy.min(data, axis=0)) - -fig.tight_layout() -matplotlib.pyplot.savefig("inflammation-01-group-plot.svg") -matplotlib.pyplot.close(fig) - - -## Exercise: Drawing Straight Lines -fig = matplotlib.pyplot.figure(figsize=(10.0, 3.0)) - -axes1 = fig.add_subplot(1, 3, 1) -axes2 = fig.add_subplot(1, 3, 2) -axes3 = fig.add_subplot(1, 3, 3) - -axes1.set_ylabel('average') -axes1.plot(numpy.mean(data, axis=0), drawstyle='steps-mid') - -axes2.set_ylabel('max') -axes2.plot(numpy.max(data, axis=0), drawstyle='steps-mid') - -axes3.set_ylabel('min') -axes3.plot(numpy.min(data, axis=0), drawstyle='steps-mid') - -fig.tight_layout() -matplotlib.pyplot.savefig("inflammation-01-line-styles.svg") -matplotlib.pyplot.close(fig) diff --git a/index.md b/index.md index 395d794..dc44fab 100644 --- a/index.md +++ b/index.md @@ -6,7 +6,9 @@ title: Course Information ## Overview -Welcome to Intro to Python! Python is one of the most popular general-purpose programming languages around. It is used in a huge range of applications, from building systems incorporating cutting-edge machine learning, such as in self-driving cars, to building web applications with hundreds of millions of users, as seen in Instagram. +Welcome to Intro to Python! + +Python is one of the most popular general-purpose programming languages around. It is used in a huge range of applications, from building systems incorporating cutting-edge machine learning, such as in self-driving cars, to building web applications with hundreds of millions of users, as seen in Instagram. As researchers, we use Python for all manner of tasks, from data analysis, to automation, to prototyping software, to creating engaging visuals for websites and publications. Like you, we started our journey into Python learning the basics, building a strong foundation for achieving these more complex tasks. This introductory course will teach you these basics, and get you up to speed on your own programming journeys. @@ -24,7 +26,7 @@ This course will enable you to: ## Pre-requisite knowledge -No pre-requisite knowledge needed. However, course attendees will need to follow our setup guide to install Python and JupyterLab, which we will use for the course. Don't worry, we will help you with this! +No pre-requisite knowledge needed. However, course attendees will need to follow our setup guide to install Python and JupyterLab, which we will use for the course. ## Workshop format