Skip to content

Commit 4b95a20

Browse files
authored
Merge branch 'gh-pages' into henryiii/fix/anumpy
2 parents fc5ed62 + 4e1980e commit 4b95a20

17 files changed

+210
-140
lines changed

.github/workflows/template.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,14 @@ jobs:
127127
id: check-rmd
128128
working-directory: lesson
129129
run: |
130-
echo "::set-output name=count::$(shopt -s nullglob; files=($(find . -iname '*.Rmd')); echo ${#files[@]})"
130+
echo "count=$(shopt -s nullglob; files=($(find . -iname '*.Rmd')); echo ${#files[@]})" >> $GITHUB_OUTPUT
131131
132132
- name: Set up R
133133
if: steps.check-rmd.outputs.count != 0
134-
uses: r-lib/actions/setup-r@master
134+
uses: r-lib/actions/setup-r@v2
135135
with:
136-
r-version: 'release'
136+
use-public-rspm: true
137+
install-r: false
137138

138139
- name: Install needed packages
139140
if: steps.check-rmd.outputs.count != 0

.github/workflows/website.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,14 @@ jobs:
4444
- name: Look for R-markdown files
4545
id: check-rmd
4646
run: |
47-
echo "::set-output name=count::$(shopt -s nullglob; files=($(find . -iname '*.Rmd')); echo ${#files[@]})"
47+
echo "count=$(shopt -s nullglob; files=($(find . -iname '*.Rmd')); echo ${#files[@]})" >> $GITHUB_OUTPUT
4848
4949
- name: Set up R
5050
if: steps.check-rmd.outputs.count != 0
51-
uses: r-lib/actions/setup-r@master
51+
uses: r-lib/actions/setup-r@v2
5252
with:
53-
r-version: 'release'
53+
use-public-rspm: true
54+
install-r: false
5455

5556
- name: Restore R Cache
5657
if: steps.check-rmd.outputs.count != 0

_episodes/01-intro.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ keypoints:
1414
- "Use `variable = value` to assign a value to a variable in order to record it in memory."
1515
- "Variables are created on demand whenever a value is assigned to them."
1616
- "Use `print(something)` to display the value of `something`."
17+
- "Use `# some kind of explanation` to add comments to programs."
1718
- "Built-in functions are always available to use."
19+
1820
---
1921

2022
## Variables
@@ -42,7 +44,7 @@ weight_kg = 60
4244
{: .language-python}
4345

4446
From now on, whenever we use `weight_kg`, Python will substitute the value we assigned to
45-
it. In layman's terms, **a variable is a name for a value**.
47+
it. In layperson's terms, **a variable is a name for a value**.
4648

4749
In Python, variable names:
4850

@@ -209,8 +211,12 @@ weight in kilograms is now: 65.0
209211
> ~~~
210212
> {: .output}
211213
>
212-
> ![Value of 65.0 with weight_kg label stuck on it, and value of 143.0 with weight_lb label
213-
stuck on it](../fig/python-sticky-note-variables-02.svg)
214+
> Everything in a line of code following the '#' symbol is a
215+
> [comment]({{ page.root }}/reference/#comment) that is ignored by Python.
216+
> Comments allow programmers to leave explanatory notes for other
217+
> programmers or their future selves.
218+
>
219+
> ![Value of 65.0 with weight_kg label stuck on it, and value of 143.0 with weight_lb label stuck on it](../fig/python-sticky-note-variables-02.svg)
214220
>
215221
> Similar to above, the expression `2.2 * weight_kg` is evaluated to `143.0`,
216222
> and then this value is assigned to the variable `weight_lb` (i.e. the sticky

_episodes/02-numpy.md

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ that can be called upon when needed.
3232

3333
To begin processing the clinical trial inflammation data, we need to load it into Python.
3434
We can do that using a library called
35-
[NumPy](http://docs.scipy.org/doc/numpy/ "NumPy Documentation"), which stands for Numerical Python.
35+
[NumPy](https://numpy.org/doc/stable "NumPy Documentation"), which stands for Numerical Python.
3636
In general, you should use this library when you want to do fancy things with lots of numbers,
3737
especially if you have matrices or arrays. To tell Python that we'd like to start using NumPy,
3838
we need to [import]({{ page.root }}/reference.html#import) it:
@@ -70,9 +70,8 @@ The expression `numpy.loadtxt(...)` is a
7070
[function call]({{ page.root }}/reference.html#function-call)
7171
that asks Python to run the [function]({{ page.root }}/reference.html#function) `loadtxt` which
7272
belongs to the `numpy` library.
73-
This [dotted notation]({{ page.root }}/reference.html#dotted-notation)
74-
is used everywhere in Python: the thing that appears before the dot contains the thing that
75-
appears after.
73+
The dot notation in Python is used most of all as an object attribute/property specifier or for invoking its method. `object.property` will give you the object.property value,
74+
`object_name.method()` will invoke on object_name method.
7675

7776
As an example, John Smith is the John that belongs to the Smith family.
7877
We could use the dot notation to write his name `smith.john`,
@@ -205,16 +204,16 @@ first value in data: 0.0
205204
{: .output}
206205
207206
~~~
208-
print('middle value in data:', data[30, 20])
207+
print('middle value in data:', data[29, 19])
209208
~~~
210209
{: .language-python}
211210
212211
~~~
213-
middle value in data: 13.0
212+
middle value in data: 16.0
214213
~~~
215214
{: .output}
216215
217-
The expression `data[30, 20]` accesses the element at row 30, column 20. While this expression may
216+
The expression `data[29, 19]` accesses the element at row 30, column 20. While this expression may
218217
not surprise you,
219218
`data[0, 0]` might.
220219
Programming languages like Fortran, MATLAB and R start counting at 1
@@ -411,11 +410,6 @@ maximum inflammation for patient 0: 18.0
411410
~~~
412411
{: .output}
413412
414-
Everything in a line of code following the '#' symbol is a
415-
[comment]({{ page.root }}/reference.html#comment) that is ignored by Python.
416-
Comments allow programmers to leave explanatory notes for other
417-
programmers or their future selves.
418-
419413
We don't actually need to store the row in a variable of its own.
420414
Instead, we can combine the selection and the function call:
421415

_episodes/04-lists.md

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -166,57 +166,80 @@ does not.
166166
> ## Nested Lists
167167
> Since a list can contain any Python variables, it can even contain other lists.
168168
>
169-
> For example, we could represent the products in the shelves of a small grocery shop:
169+
> For example, you could represent the products on the shelves of a small grocery shop
170+
> as a nested list called `veg`:
171+
>
172+
> ![`veg` is represented as a shelf full of produce. There are three rows of vegetables
173+
> on the shelf, and each row contains three baskets of vegetables. We can label
174+
> each basket according to the type of vegetable it contains, so the top row
175+
> contains (from left to right) lettuce, lettuce, and peppers.](../fig/04_groceries_veg.png)
176+
>
177+
> To store the contents of the shelf in a nested list, you write it this way:
170178
>
171179
> ~~~
172-
> x = [['pepper', 'zucchini', 'onion'],
173-
> ['cabbage', 'lettuce', 'garlic'],
174-
> ['apple', 'pear', 'banana']]
180+
> veg = [['lettuce', 'lettuce', 'peppers', 'zucchini'],
181+
> ['lettuce', 'lettuce', 'peppers', 'zucchini'],
182+
> ['lettuce', 'cilantro', 'peppers', 'zucchini']]
175183
> ~~~
176184
> {: .language-python}
177185
>
178-
> Here is a visual example of how indexing a list of lists `x` works:
186+
> Here are some visual examples of how indexing a list of lists `veg` works. First,
187+
> you can reference each row on the shelf as a separate list. For example, `veg[2]`
188+
> represents the bottom row, which is a list of the baskets in that row.
179189
>
180-
> [![x is represented as a pepper shaker containing several packets of pepper. [x[0]] is represented
181-
> as a pepper shaker containing a single packet of pepper. x[0] is represented as a single packet of
182-
> pepper. x[0][0] is represented as single grain of pepper. Adapted
183-
> from @hadleywickham.](../fig/indexing_lists_python.png)][hadleywickham-tweet]
190+
> ![`veg` is now shown as a list of three rows, with `veg[0]` representing the top row of
191+
> three baskets, `veg[1]` representing the second row, and `veg[2]` representing the bottom row.](../fig/04_groceries_veg0.png)
184192
>
185-
> Using the previously declared list `x`, these would be the results of the
186-
> index operations shown in the image:
193+
> Index operations using the image would work like this:
187194
>
188195
> ~~~
189-
> print([x[0]])
196+
> print(veg[2])
190197
> ~~~
191198
> {: .language-python}
192199
>
193200
> ~~~
194-
> [['pepper', 'zucchini', 'onion']]
201+
> ['lettuce', 'cilantro', 'peppers', 'zucchini']
195202
> ~~~
196203
> {: .output}
197204
>
198205
> ~~~
199-
> print(x[0])
206+
> print(veg[0])
200207
> ~~~
201208
> {: .language-python}
202209
>
203210
> ~~~
204-
> ['pepper', 'zucchini', 'onion']
211+
> ['lettuce', 'lettuce', 'peppers', 'zucchini']
205212
> ~~~
206213
> {: .output}
207214
>
215+
> To reference a specific basket on a specific shelf, you use two indexes. The first
216+
> index represents the row (from top to bottom) and the second index represents
217+
> the specific basket (from left to right).
218+
> ![`veg` is now shown as a two-dimensional grid, with each basket labeled according to
219+
> its index in the nested list. The first index is the row number and the second
220+
> index is the basket number, so `veg[1][3]` represents the basket on the far right
221+
> side of the second row (basket 4 on row 2): zucchini](../fig/04_groceries_veg00.png)
222+
>
208223
> ~~~
209-
> print(x[0][0])
224+
> print(veg[0][0])
210225
> ~~~
211226
> {: .language-python}
212227
>
213228
> ~~~
214-
> 'pepper'
229+
> 'lettuce'
230+
> ~~~
231+
> {: .output}
232+
>
233+
> ~~~
234+
> print(veg[1][2])
235+
> ~~~
236+
> {: .language-python}
237+
>
238+
> ~~~
239+
> 'peppers'
215240
> ~~~
216241
> {: .output}
217242
>
218-
> Thanks to [Hadley Wickham][hadleywickham-tweet]
219-
> for the image above.
220243
{: .callout}
221244
222245
> ## Heterogeneous Lists
@@ -273,7 +296,7 @@ copy it and then modify this list, we can cause all sorts of trouble. This also
273296
the list using the above functions:
274297
275298
~~~
276-
odds = [1, 3, 5, 7]
299+
odds = [3, 5, 7]
277300
primes = odds
278301
primes.append(2)
279302
print('primes:', primes)
@@ -282,8 +305,8 @@ print('odds:', odds)
282305
{: .language-python}
283306
284307
~~~
285-
primes: [1, 3, 5, 7, 2]
286-
odds: [1, 3, 5, 7, 2]
308+
primes: [3, 5, 7, 2]
309+
odds: [3, 5, 7, 2]
287310
~~~
288311
{: .output}
289312
@@ -292,7 +315,7 @@ same list. If all we want to do is copy a (simple) list, we can again use the `l
292315
do not modify a list we did not mean to:
293316
294317
~~~
295-
odds = [1, 3, 5, 7]
318+
odds = [3, 5, 7]
296319
primes = list(odds)
297320
primes.append(2)
298321
print('primes:', primes)
@@ -301,8 +324,8 @@ print('odds:', odds)
301324
{: .language-python}
302325
303326
~~~
304-
primes: [1, 3, 5, 7, 2]
305-
odds: [1, 3, 5, 7]
327+
primes: [3, 5, 7, 2]
328+
odds: [3, 5, 7]
306329
~~~
307330
{: .output}
308331

_episodes/05-loop.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,8 @@ so we should always use it when we can.
307307
> Given the following loop:
308308
> ~~~
309309
> word = 'oxygen'
310-
> for char in word:
311-
> print(char)
310+
> for letter in word:
311+
> print(letter)
312312
> ~~~
313313
> {: .language-python}
314314
>

_episodes/07-cond.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,14 @@ freeing us from having to manually examine every plot for features we've seen be
268268
> > ## Solution
269269
> > C gets printed because the first two conditions, `4 > 5` and `4 == 5`, are not true,
270270
> > but `4 < 5` is true.
271+
> > In this case only one of these conditions can be true for at a time, but in other
272+
> > scenarios multiple `elif` conditions could be met. In these scenarios only the action
273+
> > associated with the first true `elif` condition will occur, starting from the top of the
274+
> > conditional section.
275+
> > ![A flowchart diagram of a conditional section with multiple `elif` conditions and some possible outcomes.](../fig/python-else-if.png)
276+
> > This contrasts with the case of multiple `if` statements, where every action can occur
277+
> > as long as their condition is met.
278+
> > ![A flowchart diagram of a conditional section with multiple `if` statements and some possible outcomes.](../fig/python-multi-if.png)
271279
> {: .solution}
272280
{: .challenge}
273281

_episodes/08-func.md

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,45 @@ keypoints:
3131
then call it with different parameter values to customize its behavior."
3232
---
3333

34-
At this point,
35-
we've written code to draw some interesting features in our inflammation data,
36-
loop over all our data files to quickly draw these plots for each of them,
37-
and have Python make decisions based on what it sees in our data.
38-
But, our code is getting pretty long and complicated;
39-
what if we had thousands of datasets,
40-
and didn't want to generate a figure for every single one?
41-
Commenting out the figure-drawing code is a nuisance.
42-
Also, what if we want to use that code again,
43-
on a different dataset or at a different point in our program?
34+
At this point, we've seen that code can have Python make decisions about what it sees in our data. What if we want to convert some of our data, like taking a temperature in Fahrenheit and converting it to Celsius. We could write something like this for converting a single number
35+
36+
~~~
37+
fahrenheit_val = 99
38+
celsius_val = ((fahrenheit_val - 32) * (5/9))
39+
~~~
40+
{: .language-python}
41+
42+
and for a second number we could just copy the line and rename the variables
43+
44+
~~~
45+
fahrenheit_val = 99
46+
celsius_val = ((fahrenheit_val - 32) * (5/9))
47+
48+
fahrenheit_val2 = 43
49+
celsius_val2 = ((fahrenheit_val2 - 32) * (5/9))
50+
~~~
51+
{: .language-python}
52+
53+
But we would be in trouble as soon as we had to do this more than a couple times.
4454
Cutting and pasting it is going to make our code get very long and very repetitive,
4555
very quickly.
4656
We'd like a way to package our code so that it is easier to reuse,
47-
and Python provides for this by letting us define things called 'functions' ---
48-
a shorthand way of re-executing longer pieces of code.
57+
a shorthand way of re-executing longer pieces of code. In Python we can use 'functions'.
4958
Let's start by defining a function `fahr_to_celsius` that converts temperatures
5059
from Fahrenheit to Celsius:
5160

5261
~~~
62+
def explicit_fahr_to_celsius(temp):
63+
# Assign the converted value to a variable
64+
converted = ((temp - 32) * (5/9))
65+
# Return the value of the new variable
66+
return converted
67+
5368
def fahr_to_celsius(temp):
69+
# Return converted value more efficiently using the return
70+
# function without creating a new variable. This code does
71+
# the same thing as the previous function but it is more explicit
72+
# in explaining how the return command works.
5473
return ((temp - 32) * (5/9))
5574
~~~
5675
{: .language-python}
@@ -897,7 +916,7 @@ readable code!
897916
> > and does not alter `k` outside of its local copy.
898917
> > Therefore the original value of `k` remains unchanged.
899918
> > Beware that a local `k` is created because `f2k` internal statements
900-
> > *affect* a new value to it. If `k` was only `read`, it would simply retreive the
919+
> > *affect* a new value to it. If `k` was only `read`, it would simply retrieve the
901920
> > global `k` value.
902921
> {: .solution}
903922
{: .challenge}

0 commit comments

Comments
 (0)