Skip to content

Commit

Permalink
Converting existing material to new format
Browse files Browse the repository at this point in the history
  • Loading branch information
gvwilson committed Jun 23, 2016
1 parent 6e0ab1d commit 344cb7d
Show file tree
Hide file tree
Showing 22 changed files with 1,429 additions and 775 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
python-novice-inflammation
==========================

Introduction to Python for non-programmers using inflammation data.
An introduction to Python for non-programmers using inflammation data.

> Please see [https://github.com/swcarpentry/lesson-example](https://github.com/swcarpentry/lesson-example)
> for instructions on formatting, building, and submitting lessons,
> or run `make` in this directory for a list of helpful commands.
See [the lesson template documentation][lesson-example]
for instructions on formatting, building, and submitting material,
or run `make` in this directory for a list of helpful commands.

Maintainers:

* [Trevor Bekolay](http://software-carpentry.org/team/#jackson_m)
* [Valentina Staneva](http://software-carpentry.org/team/#staneva_valentina)
* [Trevor Bekolay][bekolay_trevor]
* [Valentina Staneva][staneva_valentina]

[bekolay_trevor]: http://software-carpentry.org/team/#bekolay_trevor
[staneva_valentina]: http://software-carpentry.org/team/#staneva_valentina
121 changes: 78 additions & 43 deletions _extras/discuss.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
layout: page
title: Programming with Python
subtitle: Discussion
title: Discussion
permalink: /discuss/
---
## Rules of Debugging

Expand All @@ -25,14 +25,15 @@ To make things clearer,
we'll start by putting the initial value 32.0 in a variable
and store the final result in one as well:

~~~ {.python}
~~~
original = 32.0
final = fahr_to_celsius(original)
~~~
{: .python}

The diagram below shows what memory looks like after the first line has been executed:

![Call Stack (Initial State)](fig/python-call-stack-01.svg)\
![Call Stack (Initial State)]({{ site.github.url }}/fig/python-call-stack-01.svg)

When we call `fahr_to_celsius`,
Python *doesn't* create the variable `temp` right away.
Expand All @@ -42,12 +43,12 @@ to keep track of the variables defined by `fahr_to_kelvin`.
Initially,
this stack frame only holds the value of `temp`:

![Call Stack Immediately After First Function Call](fig/python-call-stack-02.svg)\
![Call Stack Immediately After First Function Call]({{ site.github.url }}/fig/python-call-stack-02.svg)

When we call `fahr_to_kelvin` inside `fahr_to_celsius`,
Python creates another stack frame to hold `fahr_to_kelvin`'s variables:

![Call Stack During First Nested Function Call](fig/python-call-stack-03.svg)\
![Call Stack During First Nested Function Call]({{ site.github.url }}/fig/python-call-stack-03.svg)

It does this because there are now two variables in play called `temp`:
the parameter to `fahr_to_celsius`,
Expand All @@ -60,54 +61,59 @@ When the call to `fahr_to_kelvin` returns a value,
Python throws away `fahr_to_kelvin`'s stack frame
and creates a new variable in the stack frame for `fahr_to_celsius` to hold the temperature in Kelvin:

![Call Stack After Return From First Nested Function Call](fig/python-call-stack-04.svg)\
![Call Stack After Return From First Nested Function Call]({{ site.github.url }}/fig/python-call-stack-04.svg)

It then calls `kelvin_to_celsius`,
which means it creates a stack frame to hold that function's variables:

![Call Stack During Call to Second Nested Function](fig/python-call-stack-05.svg)\
![Call Stack During Call to Second Nested Function]({{ site.github.url }}/fig/python-call-stack-05.svg)

Once again,
Python throws away that stack frame when `kelvin_to_celsius` is done
and creates the variable `result` in the stack frame for `fahr_to_celsius`:

![Call Stack After Second Nested Function Returns](fig/python-call-stack-06.svg)\
![Call Stack After Second Nested Function Returns]({{ site.github.url }}/fig/python-call-stack-06.svg)

Finally,
when `fahr_to_celsius` is done,
Python throws away *its* stack frame
and puts its result in a new variable called `final`
that lives in the stack frame we started with:

![Call Stack After All Functions Have Finished](fig/python-call-stack-07.svg)\
![Call Stack After All Functions Have Finished]({{ site.github.url }}/fig/python-call-stack-07.svg)

This final stack frame is always there;
it holds the variables we defined outside the functions in our code.
What it *doesn't* hold is the variables that were in the various stack frames.
If we try to get the value of `temp` after our functions have finished running,
Python tells us that there's no such thing:

~~~ {.python}
~~~
print('final value of temp after all function calls:', temp)
~~~
~~~ {.error}
{: .python}

~~~
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-ffd9b4dbd5f1> in <module>()
----> 1 print('final value of temp after all function calls:', temp)
NameError: name 'temp' is not defined
~~~
~~~ {.output}
{: .error}

~~~
final value of temp after all function calls:
~~~
{: .output}

Why go to all this trouble?
Well,
here's a function called `span` that calculates the difference between
the mininum and maximum values in an array:

~~~ {.python}
~~~
import numpy
def span(a):
Expand All @@ -117,20 +123,26 @@ def span(a):
data = numpy.loadtxt(fname='inflammation-01.csv', delimiter=',')
print('span of data:', span(data))
~~~
~~~ {.output}
{: .python}

~~~
span of data: 20.0
~~~
{: .output}

Notice that `span` assigns a value to a variable called `diff`.
We might very well use a variable with the same name to hold data:

~~~ {.python}
~~~
diff = numpy.loadtxt(fname='inflammation-01.csv', delimiter=',')
print('span of data:', span(diff))
~~~
~~~ {.output}
{: .python}

~~~
span of data: 20.0
~~~
{: .output}

We don't expect `diff` to have the value 20.0 after this function call,
so the name `diff` cannot refer to the same thing inside `span` as it does in the main body of our program.
Expand All @@ -151,24 +163,27 @@ if they do,
we have to pay attention to the details once again,
which quickly overloads our short-term memory.

> ## Following the call stack {.challenge}
> ## Following the Call Stack
>
> We previously wrote functions called `fence` and `outer`.
> Draw a diagram showing how the call stack changes when we run the following:
>
> ~~~ {.python}
> ~~~
> print(outer(fence('carbon', '+')))
> ~~~
> {: .python}
{: .challenge}
## Image Grids
Let's start by creating some simple heat maps of our own
using a library called `ipythonblocks`.
The first step is to create our own "image":
~~~ {.python}
~~~
from ipythonblocks import ImageGrid
~~~
{: .python}
Unlike the `import` statements we have seen earlier,
this one doesn't load the entire `ipythonblocks` library.
Expand All @@ -179,26 +194,30 @@ since that's the only thing we need (for now).
Once we have `ImageGrid` loaded,
we can use it to create a very simple grid of colored cells:
~~~ {.python}
~~~
grid = ImageGrid(5, 3)
grid.show()
~~~
{: .python}
![](img/grid-01.png)
![]({{ site.github.url }}/fig/grid-01.png)
Just like a NumPy array,
an `ImageGrid` has some properties that hold information about it:
~~~ {.python}
~~~
print('grid width:', grid.width)
print('grid height:', grid.height)
print('grid lines on:', grid.lines_on)
~~~
~~~ {.output}
{: .python}
~~~
grid width: 5
grid height: 3
grid lines on: True
~~~
{: .output}
The obvious thing to do with a grid like this is color in its cells,
but in order to do that,
Expand All @@ -209,47 +228,53 @@ RGB is an [additive color model](reference.html#additive-color-model):
every shade is some combination of red, green, and blue intensities.
We can think of these three values as being the axes in a cube:
![RGB Color Cube](fig/color-cube.png)
![RGB Color Cube]({{ site.github.url }}/fig/color-cube.png)
An RGB color is an example of a multi-part value:
like a Cartesian coordinate,
it is one thing with several parts.
We can represent such a value in Python using a [tuple](reference.html#tuple),
which we write using parentheses instead of the square brackets used for a list:
~~~ {.python}
~~~
position = (12.3, 45.6)
print('position is:', position)
color = (10, 20, 30)
print('color is:', color)
~~~
{: .python}
~~~ {.output}
~~~
position is: (12.3, 45.6)
color is: (10, 20, 30)
~~~
{: .output}
We can select elements from tuples using indexing,
just as we do with lists and arrays:
~~~ {.python}
~~~
print('first element of color is:', color[0])
~~~
{: .python}
~~~ {.output}
~~~
first element of color is: 10
~~~
{: .output}
Unlike lists and arrays,
though,
tuples cannot be changed after they are created --- in technical terms,
they are [immutable](reference.html#immutable):
~~~ {.python}
~~~
color[0] = 40
print('first element of color after change:', color[0])
~~~
~~~ {.error}
{: .python}
~~~
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-11-9c3dd30a4e52> in <module>()
Expand All @@ -258,6 +283,7 @@ TypeError Traceback (most recent call last)

TypeError: 'tuple' object does not support item assignment
~~~
{: .error}
If a tuple represents an RGB color,
its red, green, and blue components can take on values between 0 and 255.
Expand All @@ -270,7 +296,7 @@ most of the time.
Let's see what a few RGB colors actually look like:
~~~ {.python}
~~~
row = ImageGrid(8, 1)
row[0, 0] = (0, 0, 0) # no color => black
row[1, 0] = (255, 255, 255) # all colors => white
Expand All @@ -282,24 +308,26 @@ row[6, 0] = (255, 0, 255) # red and blue
row[7, 0] = (0, 255, 255) # green and blue
row.show()
~~~
{: .python}
![](img/grid-02.png)
![]({{ site.github.url }}/fig/grid-02.png)
Simple color values like `(0,255,0)` are easy enough to decipher with a bit of practice,
but what color is `(214,90,127)`?
To help us,
`ipythonblocks` provides a function called `show_color`:
~~~ {.python}
~~~
from ipythonblocks import show_color
show_color(214, 90, 127)
~~~
{: .python}
![](fig/ipythonblocks_show_color_example.png)
![]({{ site.github.url }}/fig/ipythonblocks_show_color_example.png)
It also provides a table of standard colors:
~~~ {.python}
~~~
from ipythonblocks import colors
c = ImageGrid(3, 2)
c[0, 0] = colors['Fuchsia']
Expand All @@ -310,36 +338,43 @@ c[2, 0] = colors['LimeGreen']
c[2, 1] = colors['HotPink']
c.show()
~~~
{: .python}
![](img/grid-03.png)
![]({{ site.github.url }}/fig/grid-03.png)
> ## Making a colorbar {.challenge}
> ## Making a Colorbar
>
> Fill in the `____` in the code below to create a bar that changes color from dark blue to black.
>
> ~~~ {.python}
> ~~~
> bar = ImageGrid(10, 1)
> for x in range(10):
> bar[x, 0] = (0, 0, ____)
> bar.show()
> ~~~
> {: .python}
{: .challenge}
> ## Why RGB? {.challenge}
> ## Why RGB?
>
> Why do computers use red, green, and blue as their primary colors?
{: .challenge}
> ## Nested loops {.challenge}
> ## Nested Loops
>
> Will changing the nesting of the loops in the code above --- i.e.,
> wrapping the Y-axis loop around the X-axis loop --- change the final image?
> Why or why not?
{: .challenge}
> ## Where to change data {.challenge}
> ## Where to Change Data
>
> Why did we transpose our data outside our heat map function?
> Why not have the function perform the transpose?
{: .challenge}
> ## Design choice: return versus display {.challenge}
> ## Return Versus Display
>
> Why does the heat map function return the grid rather than displaying it immediately?
> Do you think this is a good or bad design choice?
{: .challenge}
Loading

0 comments on commit 344cb7d

Please sign in to comment.