Skip to content

Commit

Permalink
Improvements to spike train basics after course
Browse files Browse the repository at this point in the history
Added explanation of lists of arrays and exercise about using np.histogram by specifying the bin edges.
  • Loading branch information
stnitsche committed Jun 16, 2021
1 parent 6ac20d2 commit 4ff3364
Showing 1 changed file with 140 additions and 19 deletions.
159 changes: 140 additions & 19 deletions day1_2_spike_train_basics.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise**\n",
"**Exercise:**\n",
"\n",
"Print the shape of `example_spike_times`. What does the result mean? Print the time of the 10th spike in milliseconds."
]
Expand All @@ -120,7 +120,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Expected output**\n",
"**Expected output:**\n",
"```\n",
"(5391,)\n",
"1634.5\n",
Expand Down Expand Up @@ -186,6 +186,76 @@
"plt.title(\"Raster plot\");"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Intermezzo: Lists and arrays"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we want to work with multiple neurons, we need data structures that can hold all that data, e.g. all spike trains. We could create one variable for each spike train, but that will get very tedious if we have many neurons. Instead, we want one variable for all spike trains."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's first remind ourselves of the pros and cons of lists and arrays:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"|Lists|Arrays|\n",
"|--|--|\n",
"|can contain multiple datatypes|can only contain one datatype|\n",
"|indexing by slicing|indexing by slicing and boolean arrays|\n",
"|only few methods/functions|fast and powerful computations using numpy|\n",
"| |numpy functions work on/return arrays anyway|\n",
"|only 1-dimensional|multiple dimensions possible|"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"2-dimensional arrays are a great choice for e.g. parameters (mean firing rate etc.)! The first dimension (rows) can denote the cell, the second dimension (columns) can denote its parameter.\n",
"\n",
"To optimize memory allocation we often want to initialize an empty array before we begin our analysis. Let's say we have 20 cells and we want to calculate 3 different parameters for each cell."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"parameter_storage = np.empty((20, 3))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"During our analysis, we can store the results in this 2D array."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For spike trains, however, 2D arrays are not suited. This is because 2D arrays must be rectangular, i.e. each row has the same number of columns. Not all cells have the same number of spikes in their spike train, though.\n",
"\n",
"Instead, we could use arrays of arrays, lists of lists, or lists of arrays. All are fine, but we recommend lists of arrays.\n",
"\n",
"This means: All spike train data is stored in a list. The elements of the list are numpy arrays, one for each cell. Each array contains the spike train of that cell. "
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down Expand Up @@ -242,7 +312,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise**\n",
"**Exercise:**\n",
"\n",
"Write a function called `load_spike_trains_to_list`. As an argument, this function should take a list of filepaths called `list_of_paths`. It should return a list containing each neuron's spike times called `list_of_spikes`.\n",
"\n",
Expand Down Expand Up @@ -293,7 +363,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Expected output:\n",
"**Expected output:**\n",
"```\n",
"[ 0.5766 2.8239 4.5523 ... 481.387 482.4371 482.4677]\n",
"```"
Expand Down Expand Up @@ -365,9 +435,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise**\n",
"**Exercise:**\n",
"\n",
"Let's focus on some neurons that responded similarly. Specifically, plot the first 32 seconds of the spike trains of the 1st, 12th, 13th, 14th, and 19th neurons in `all_spike_trains`, but not the rest."
"Let's focus on some neurons that have similar spike trains. Specifically, plot the first 32 seconds of the spike trains of the 1st, 12th, 13th, 14th, and 19th neurons in `all_spike_trains`, but not the rest."
]
},
{
Expand Down Expand Up @@ -428,7 +498,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Numpy provides the function `histogram` to calculate histograms."
"Numpy provides the function `histogram` to calculate histograms. We'll start by analyzing the first of the five neurons."
]
},
{
Expand Down Expand Up @@ -510,7 +580,21 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise**\n",
"Compared to the eventplot, we can now see the dynamics of the spike train much better."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the next three exercises, your goal will be to create a plot that shows the firing rates of all five neurons, so that we can compare them better."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise:**\n",
"\n",
"Write a function called `firing_rate_histogram` that calculates the firing rate histogram from a spike train. As an argument, this function should take a spike train called `spike_train`. It should return two variables: First, the firing rate in each bin of the histogram, called `hist_firing_rate`. Second, the centers of the corresponding bins, called `hist_bin_centers`. The histogram should have 50 bins in the range from 0 to 8.\n",
"\n",
Expand Down Expand Up @@ -542,7 +626,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Expected output:\n",
"**Expected output:**\n",
"\n",
"```93.75 4.88```"
]
Expand All @@ -551,11 +635,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise**\n",
"**Exercise:**\n",
"\n",
"Write another function called `multi_frate_histograms` that calculates a histogram for each of multiple spike trains. As an argument, this function should take a list of spike trains called `list_of_spike_trains`. It should return two variables: First, a list called `multi_hist_firing_rate` that contains for each given spike train the corresponding firing rates in a histogram. Second, the bin centers of these histograms, called `hist_bin_centers`.\n",
"\n",
"_Hint:_ Make use of a for-loop and the function you wrote above. Remember that the bin centers of all the histograms are the same, so you don't have to create a list for them."
"_Hint:_ Make use of a for-loop and the function you wrote above. Remember that the bin centers of all the histograms are the same, so you don't have to create a list for them. A single 1D array will suffice."
]
},
{
Expand Down Expand Up @@ -583,7 +667,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Expected output:\n",
"**Expected output:**\n",
"\n",
"```56.25 4.88```"
]
Expand All @@ -592,7 +676,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise**\n",
"**Exercise:**\n",
"\n",
"Finally, create one plot that shows the histograms of the five neurons from the end of the last chapter (use `short_spike_trains`).\n",
"\n",
Expand Down Expand Up @@ -642,7 +726,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise**\n",
"**Exercise:**\n",
"\n",
"Calculate the ISI histogram for the spike train `example_spike_times` that we loaded in the beginning. Choose a reasonable number of bins and focus on ISIs below 30ms. Then plot the histogram.\n",
"\n",
Expand Down Expand Up @@ -672,7 +756,25 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"_Followup exercise:_ If you're done early, try plotting the histogram using matplotlib's `hist` function."
"What does this mean? Why are there so few intervals below ~3ms?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So far, when using 'np.histogram', we have specified the number of bins of the histogram. This is the easiest way of using it, but we might also want to directly control the size of the bins. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Exercise:**\n",
"\n",
"Create the same plot as above, but now explicitly set the size of the bins to 0.1 ms. You can do so by creating the bin edges manually and passing them as the parameter `bins` to `np.histogram`. Take a look at the documentation!\n",
"\n",
"_Hint:_ To create the bin edges, you can use `np.arange` with the `step` parameter."
]
},
{
Expand All @@ -681,9 +783,12 @@
"metadata": {},
"outputs": [],
"source": [
"# Start your code here\n",
"# FIXME\n",
"plt.hist(isi, bins=50, range=(0, 0.03))\n",
"bin_size = 0.0001\n",
"bin_edges = np.arange(0, 0.03 + bin_size, bin_size)\n",
"bin_centers = bin_edges[:-1] + bin_size/2\n",
"isi_hist, bin_edges = np.histogram(isi, bins=bin_edges)\n",
"\n",
"plt.plot(bin_centers, isi_hist)\n",
"plt.title(\"Interspike interval histogram\")\n",
"plt.xlabel(\"Interspike interval [s]\")\n",
"plt.ylabel(\"Number of occurences\");"
Expand All @@ -693,7 +798,23 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"What does this mean? Why are there so few intervals below ~3ms?"
"**Exercise:**\n",
"\n",
"Try plotting a 'real' histogram using matplotlib's `hist` function. Whether you specify the number of bins or the bin edges is up to you."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Start your code here\n",
"# FIXME\n",
"plt.hist(isi, bins=50, range=(0, 0.03))\n",
"plt.title(\"Interspike interval histogram\")\n",
"plt.xlabel(\"Interspike interval [s]\")\n",
"plt.ylabel(\"Number of occurences\");"
]
}
],
Expand Down

0 comments on commit 4ff3364

Please sign in to comment.