Lists#
Spike detection with python#
Present data in code (individual voltage values, manipulate them and store the results) - variables
Compare variables (voltage to threshold) - boolean values
Perform different actions based on the value of a variable (only keep the position if the voltage exceeds the threshold) - if-else statements
Present and access data in a time series of voltage values - lists
Perform an action for each element in a sequence of values (inspect voltage values one-by-one) - for loops
Separate data and logic so we can use the same code for new recordings - functions
Apply this to multi data files
Plot and save the results
The core computation of the spike detection problem is solved!!
Now we need to learn how to process a whole time series of voltage values!
We could print the numbers from the text file to paper, read them, and then manually enter different values of the voltage
variable. But this would be tedious.
So far all variables hold single values - numbers or strings. How do we present sequences of numbers? And how do we work through a sequence and apply the spike detection to each individual value in the sequence? This is were lists and loops come into play…
Present and access data in a time series - lists#
Making lists#
Lists hold an ordered sequence of values. The individual elements of a list are called items.
Lists are constructed by enclosing a comma-separated sequence of items - values or variable names - with square brackets:
my_list = [item1, item2, item3]
a = [-10, -12, -23, -45, 10, -12, -23]
print(a)
[-10, -12, -23, -45, 10, -12, -23]
You can store, or “collect”, multiple variables in a list. Do you understand what is happening here?
x = 10
y = 20
outlier = -1_000
b = [x, outlier, y]
print(b)
[10, -1000, 20]
You can mix variables of different types, like numbers and text, in the same list:
b = [1, 2, 3.14, 'pi']
print(b)
[1, 2, 3.14, 'pi']
Lists can even contain other lists as items - this will results in a list of lists, or a so-called nested list:
elements = ['zinc', 'gold', 'radium']
atomic_numbers = [30,79,88]
nested_list = [elements, atomic_numbers]
print('elements:', nested_list[0])
print('atomic numbers:', nested_list[1])
print('nested_list:', nested_list)
elements: ['zinc', 'gold', 'radium']
atomic numbers: [30, 79, 88]
nested_list: [['zinc', 'gold', 'radium'], [30, 79, 88]]
You can think of a nested list like of a table, with the nested list containing to columns (in the example above: elements, atomic numbers).
You can create empty lists (for adding items to it later) in two ways:
c = []
d = list()
Accessing individual elements of a list#
You can access the values of different elements of the list by enclosing an integer “index”, which is the position of a list element, in square brackets following the name of the list variable.
The index (position) of the first element is 0
, not 1
!
a = [-10, -12, -23, -45, 10, -12, -23]
print('the full list:', a)
print('the first element (index 0):', a[0])
print('the second element (index 1):', a[1])
print('the fifth element (index 5):', a[4])
print('the last element (index -1):', a[-1])
the full list: [-10, -12, -23, -45, 10, -12, -23]
the first element (index 0): -10
the second element (index 1): -12
the fifth element (index 5): 10
the last element (index -1): -23
Note: The index must be a positive or negative integer value! Indexing with a float throws an error:
a = [1235, 31354, 235]
a[1.0]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[7], line 2
1 a = [1235, 31354, 235]
----> 2 a[1.0]
TypeError: list indices must be integers or slices, not float
Index arithmetic#
We can use variables for indexing!! This allows us to perform computations on indices.
For instance, given an index, we can get the list preceeding or the following item:
a = [1, 12, 235, 424, 1234, 14456]
idx = 4
print('Value at index', idx, a[idx])
print('Value following index', idx, a[idx+1])
print('Value preceeding index', idx, a[idx-1])
Value at index 4 1234
Value following index 4 14456
Value preceeding index 4 424
Accessing parts of a list - slice indexing#
General form list[start_index:stop_index:step]
.
You can omit start_index
, stop_index
, or step
and python will fill in default values:
default for
start_index
is 0 (first index)default for
stop_index
is the last element.default for
step
is 1 (get every element)
Important: When specifying stop_index
the element at the stop_index
itself is not included.
a = [1, 12, 235, 424, 1234, 14456]
print(a[:4])
print(a[4:])
print(a[::2])
print(a[1::2])
print(a[1:4:2])
print(a[::-2])
[1, 12, 235, 424]
[1234, 14456]
[1, 235, 1234]
[12, 424, 14456]
[12, 424]
[14456, 424, 12]
[1, 12, 235, 424, 1234, 14456]
Clicker question “lists indexing”(Click me!)
Given the list a = [10, 20, 30, 40, 50]
,
Which of the following outputs is correct?
a[1] -> 10
a[-1] -> 40
a[::2] -> [10, 20]
a[3:] -> [30, 40, 50]
b = 5; a[b-2] -> 40
Getting the number of elements in a list#
The len
function gives us the number of elements in the list, its “length”. You use the len
function like the print
function - you “call” it by it’s name “len” followed by its “argument” in parentheses: len(name_of_list_variable)
.
a = [-10, -12, -23, -45, 10, -12, -23]
print(a)
print("A has", len(a), "elements.")
[-10, -12, -23, -45, 10, -12, -23]
A has 7 elements.
However, while the print
function did not “return” a result - it simply printed the input - len
does return a result - the number of elements in the list - and we can store this number in a new variable for further computations.
length_of_a = len(a)
print(length_of_a)
7
List manipulations#
Adding elements to a list#
To build up a list of spike times, we need to be able to add elements to a list as they are computed.
This is done using the append
method, which will add its argument to the end of the list.
The append
method is like a function. But while functions (print
, len
) are independent bocks of code, methods are attached to a variable.
The append
method is attached to each list variable and is used like so: name_of_list_variable.append(new_element)
.
There are many more list methods which we will not discuss - see the bonus section below.
spike_times = [] # intialize an empty list
print(spike_times)
time_of_first_spike = 10.3
spike_times.append(time_of_first_spike)
print(spike_times)
time_of_second_spike = 50.3
spike_times.append(time_of_second_spike)
print(spike_times)
[]
[10.3]
[10.3, 50.3]
Bonus: Adding multiple elements to a list#
# `append` will append the list [1,2,3] as a a single element to the original list and create a nested list
my_list = ['a','b']
print(my_list)
my_list.append([1, 2, 3])
print(my_list)
# `extend` will add the elements in the argument as individual elements of the list:
my_list.extend([5, 6, 7])
print(my_list)
['a', 'b']
['a', 'b', [1, 2, 3]]
['a', 'b', [1, 2, 3], 5, 6, 7]
Deleting list elements#
We can remove elements using the del
function with the list element we want to delete as an argument:
my_list = [10, 20, 30, 40]
print(my_list)
del(my_list[1])
print(my_list)
[10, 20, 30, 40]
[10, 30, 40]
Clicker question “lists manipulations 1”(Click me!)
What is the length of the list names at the end of this code?
names = ['Toby', 'Goby', 'Moby']
names.append('Roby')
del(names[1])
Clicker question “lists manipulations 2”(Click me!)
What will be printed at the end of this code?
names = ['Toby', 'Goby', 'Moby']
names.append('Roby')
del(names[1])
print(names[1])
Bonus: More list functions#
https://docs.python.org/3/tutorial/datastructures.html
pop(index) # return and remove indexed or if arg is omitted, the last element
append(value) # add single value to list
extend([val1, val2]) # add elements of a list as individual elements to a list
insert(index, value) # insert value at index
remove(value) # remove item by value
del(list[index]) # remove item by index
index(value) # get first index of value
sort(list, reverse=False) # sort the list in-place - returns None
sorted(list) # return sorted copy of the list without changing the original one
value in list # value if item is in list
Spike detection with python#
Present data in code (individual voltage values, manipulate them and store the results) - variables
Compare variables (voltage to threshold) - boolean values
Perform different actions based on the value of a variable (only keep the position if the voltage exceeds the threshold) - if-else statements
Present and access data in a time series of voltage values - lists
Perform an action for each element in a sequence of values (inspect voltage values one-by-one) - for loops
Separate data and logic so we can use the same code for new recordings - functions
Apply this to multi data files
Plot and save the results