{ "cells": [ { "cell_type": "markdown", "id": "32647951-7dcf-4553-b42a-5d8508d95cf9", "metadata": {}, "source": [ "\"Open   " ] }, { "cell_type": "markdown", "id": "28726d42-c8d7-4143-b4ac-43e068540136", "metadata": {}, "source": [ "# Data Explorer" ] }, { "cell_type": "markdown", "id": "f07451ff-cf56-4763-b4ac-bd099ba1f145", "metadata": {}, "source": [ "\n", "# Table of Contents\n", "\n", "- [Introduction](#intro)\n", "- [Setup](#setup)\n", "- [Part I. Process Data](#one)\n", "- [Part II. Spike-Triggered Voltage](#two)\n", "- [Part III. PSP amplitudes](#three)\n" ] }, { "cell_type": "markdown", "id": "38b445ff-7cf7-442e-bb25-83afe6d5a3fb", "metadata": {}, "source": [ "\n", "# Synaptic Plasticity\n", "\n", "How does the timing between spikes effect the post-synaptic potential (PSP)? \n", "\n", "You will be using a lot of the same tools to analyze the data as you used to analyze spontaneous spiking and psp events. " ] }, { "cell_type": "markdown", "id": "488d476b-9387-43d7-b4bf-0528d9f4950a", "metadata": {}, "source": [ "\n", "# Setup\n", "\n", "[toc](#toc)" ] }, { "cell_type": "markdown", "id": "b94f344a-8c2a-4080-b972-8e7a30c91e66", "metadata": {}, "source": [ "Import and define functions" ] }, { "cell_type": "code", "execution_count": null, "id": "be70dacf-b862-4afa-8fc0-dce8c363fdf9", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode: \"form\"}\n", "\n", "#@markdown Run this code cell to import packages and define functions \n", "from pathlib import Path\n", "import random\n", "import numpy as np\n", "import pandas as pd\n", "import plotly.express as px\n", "import plotly.graph_objects as go\n", "from plotly.subplots import make_subplots\n", "from scipy import ndimage\n", "from scipy.signal import hilbert,medfilt,resample, find_peaks\n", "import seaborn as sns\n", "import matplotlib.pyplot as plt\n", "from sklearn.decomposition import PCA\n", "from sklearn.cluster import KMeans\n", "from datetime import datetime,timezone,timedelta\n", "pal = sns.color_palette(n_colors=15)\n", "pal = pal.as_hex()\n", "\n", "from ipywidgets import interactive, HBox, VBox, widgets, interact\n", "\n", "print('Task completed at ' + str(datetime.now(timezone(-timedelta(hours=5)))))" ] }, { "cell_type": "markdown", "id": "f91a09e1-c305-4809-8302-c1fad4140efa", "metadata": {}, "source": [ "Mount Google Drive" ] }, { "cell_type": "code", "execution_count": null, "id": "2b3a4500-470b-44e3-8572-a0d55f3bc1cb", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode: \"form\"}\n", "\n", "#@markdown Run this cell to mount your Google Drive.\n", "\n", "from google.colab import drive\n", "drive.mount('/content/drive')\n", "\n", "print('Task completed at ' + str(datetime.now(timezone(-timedelta(hours=5)))))" ] }, { "cell_type": "markdown", "id": "61aa1776-ad44-4487-ad14-9dfe050de305", "metadata": {}, "source": [ "Import data digitized with *Nidaq USB6211* and recorded using *Bonsai-rx* as a *.bin* file" ] }, { "cell_type": "code", "execution_count": null, "id": "b4e462b0-3e79-4f68-ac93-4a5ed2a83696", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode: \"form\"}\n", "\n", "#@markdown Specify the file path \n", "#@markdown to your recorded data on Drive (find the filepath in the colab file manager:\n", "\n", "filepath = \"full filepath goes here\" #@param \n", "filepath = '/Users/kperks/mnt/OneDrive - wesleyan.edu/Teaching/Neurophysiology_FA21/Data/CrayfishNerve3/nerve_Muscle_TelsonStim2021-07-16T14_34_57.bin'\n", "\n", "#@markdown Specify the sampling rate and number of channels recorded.\n", "\n", "sampling_rate = None #@param\n", "number_channels = None #@param\n", "muscle_channel = None #@param\n", "nerve_channel = None #@param\n", "\n", "downsample = False #@param\n", "newfs = 2500 #@param\n", "\n", "#@markdown After you have filled out all form fields, \n", "#@markdown run this code cell to load the data. \n", "\n", "filepath = Path(filepath)\n", "\n", "# No need to edit below this line\n", "#################################\n", "data = np.fromfile(Path(filepath), dtype = np.float64)\n", "if number_channels>1:\n", " data = data.reshape(-1,number_channels)\n", "dur = np.shape(data)[0]/sampling_rate\n", "print('duration of recording was %0.2f seconds' %dur)\n", "\n", "fs = sampling_rate\n", "if downsample:\n", " # newfs = 2500 #downsample data\n", " chunksize = int(sampling_rate/newfs)\n", " if number_channels>1:\n", " data = data[0::chunksize,:]\n", " if number_channels==1:\n", " data = data[0::chunksize]\n", " fs = int(np.shape(data)[0]/dur)\n", "\n", "time = np.linspace(0,dur,np.shape(data)[0])\n", "pre = data[:,nerve_channel]\n", "post = data[:,muscle_channel]\n", "\n", "print('Now be a bit patient while it plots.')\n", "\n", "f = go.FigureWidget(make_subplots(rows=2, cols=1, shared_xaxes= True)) #,layout=go.Layout(height=500, width=800))\n", "f.add_trace(go.Scatter(x = time[0:fs], y = pre[0:fs],\n", " name='pre synaptic',opacity=1),row=1,col=1)\n", "f.add_trace(go.Scatter(x = time[0:fs], y = post[0:fs],\n", " name='post synaptic',opacity=1),row=2,col=1)\n", "f.update_layout(height=600, width=800,\n", " showlegend=False,\n", " xaxis2_title=\"time(seconds)\", \n", " yaxis_title='pre-synaptic voltage', yaxis2_title='post-synaptic voltage')\n", "\n", "slider = widgets.FloatRangeSlider(\n", " min=0,\n", " max=dur,\n", " value=(0,1),\n", " step= 1,\n", " readout=False,\n", " description='Time')\n", "slider.layout.width = '600px'\n", "\n", "# our function that will modify the xaxis range\n", "def response(x):\n", " with f.batch_update():\n", " starti = int(x[0]*fs)\n", " stopi = int(x[1]*fs)\n", " f.data[0].x = time[starti:stopi]\n", " f.data[0].y = pre[starti:stopi]\n", " f.data[1].x = time[starti:stopi]\n", " f.data[1].y = post[starti:stopi]\n", "\n", "vb = VBox((f, interactive(response, x=slider)))\n", "vb.layout.align_items = 'center'\n", "vb\n" ] }, { "cell_type": "markdown", "id": "b7b40cda-55dd-4604-afb7-89e5d0731983", "metadata": {}, "source": [ "\n", "# Part I. Process Data\n", "\n", "[toc](#toc)" ] }, { "cell_type": "code", "execution_count": null, "id": "142b84be-c0ba-43ae-a16b-03fcdf54dca1", "metadata": { "cellView": "form", "id": "iE2MylaxTGpL", "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title { display-mode: \"form\" }\n", "\n", "#@markdown Type in the start and stop time (in seconds) \n", "#@markdown that specifies the section of your recording you want to focus on for analysis.\n", "start_time = None #@param {type: \"number\"}\n", "stop_time = None #@param {type: \"number\"}\n", "#@markdown Also type in an appropriate threshold amplitude for event detection.\n", "threshold = None #@param {type: \"number\"}\n", "#@markdown Then from the dropdown, select a polarity (whether peaks are up or down)\n", "peaks = \"select peak direction\" #@param ['select peak direction','up', 'down']\n", "#@markdown Finally, run this cell to set these values and plot a histogram of peak amplitudes.\n", "\n", "spike_detection_threshold = threshold\n", "\n", "if peaks=='up': polarity = 1\n", "if peaks=='down': polarity=-1\n", "\n", "min_isi = 0.001 #seconds\n", "\n", "peaks,props = find_peaks(polarity * pre,height=spike_detection_threshold, \n", " prominence = spike_detection_threshold, distance=int(min_isi*fs))\n", "peaks_t = peaks/fs\n", "inwin_inds = ((peaks_t>start_time) & (peaks_t\n", "\n", "The histogram plot can give you a sense for how many distinct motor neurons might be in your recording. \n", "\n", "We can cluster events based on peak height and waveform shape using [\"Kmeans\"](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html) clustering. \n", "This will provide us with \"putative single units\" for further analysis." ] }, { "cell_type": "code", "execution_count": null, "id": "f3a1f5d0-54ab-4cab-9076-5b2d872580b4", "metadata": { "cellView": "form", "id": "4e574ce9-d314-4a20-918b-f2496260c9a8", "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title Cluster Detected Events { display-mode: \"form\" }\n", "\n", "#@markdown Choose the number of clusters you want to split the event-based data into and type that number below.
\n", "#@markdown >Note: It can sometimes help to \"over-split\" the events into more clusters \n", "#@markdown than you think will be necessary. You can try both strategies and assess the results.\n", "number_of_clusters = None #@param {type: \"number\"}\n", "#@markdown Then run this cell to run the Kmeans algorithm. \n", "\n", "# No need to edit below this line\n", "#################################\n", "\n", "kmeans = KMeans(n_clusters=number_of_clusters).fit(df_data)\n", "# df_props['peaks_t'] = peaks_t\n", "df_props['cluster'] = kmeans.labels_" ] }, { "cell_type": "markdown", "id": "29851d8d-403c-46b4-884d-45b923686fa1", "metadata": {}, "source": [ "\n", "\n", "Now that the events are clustered, you can visualize the mean spike waveform associated with each cluster (putative motor neuron)." ] }, { "cell_type": "code", "execution_count": null, "id": "4f188f71-cf6c-4fc4-ad24-b43b9ec5544c", "metadata": { "cellView": "form", "id": "4e574ce9-d314-4a20-918b-f2496260c9a8", "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode:'form'}\n", "\n", "#@markdown Run this cell to display the mean (and std) waveform for each cluster.\n", "\n", "windur = 0.001\n", "winsamps = int(windur * fs)\n", "x = np.linspace(-windur,windur,winsamps*2)*1000\n", "hfig,ax = plt.subplots(1,figsize=(8,6))\n", "ax.set_ylabel('Volts recorded',fontsize=14)\n", "ax.set_xlabel('milliseconds',fontsize=14)\n", "plt.xticks(fontsize=14)\n", "plt.yticks(fontsize=14)\n", "\n", "for k in np.unique(df_props['cluster']):\n", " spkt = df_props.loc[df_props['cluster']==k]['spikeT'].values #['peaks_t'].values\n", " spkt = spkt[(spkt>windur) & (spkt<(len((pre)/fs)-windur))]\n", " print(str(len(spkt)) + \" spikes in cluster number \" + str(k))\n", " spkwav = np.asarray([pre[(int(t*fs)-winsamps):(int(t*fs)+winsamps)] for t in spkt])\n", " wav_u = np.mean(spkwav,0)\n", " wav_std = np.std(spkwav,0)\n", " ax.plot(x,wav_u,linewidth = 3,label='cluster '+ str(k),color=pal[k])\n", " ax.fill_between(x, wav_u-wav_std, wav_u+wav_std, alpha = 0.25,color=pal[k])\n", "plt.legend(bbox_to_anchor=[1.25,1],fontsize=14);\n", "\n", "print('Tasks completed at ' + str(datetime.now(timezone(-timedelta(hours=5)))))" ] }, { "cell_type": "markdown", "id": "0a37aa64-ee1b-4248-8901-982f326e0cb0", "metadata": { "id": "9iyWsThmXdI_" }, "source": [ "\n", "If there are multiple spike clusters you want to merge into a single cell class, *edit and run* the cell below.\n", "\n", "> **merge_cluster_list** = a list of the clusters (identified by numbers associated with the colors specified in the legend above).\n", " - **For example**, the folowing list would merge clusters 0 and 2 together and 1, 4, and 3 together:
\n", " **merge_cluster_list = [[0,2],[1,4,3]]**\n", " - For each merge group, the first cluster number listed will be the re-asigned cluster number for that group (for example, in this case you would end up with a cluster number 0 and a cluster number 1). \n", " " ] }, { "cell_type": "code", "execution_count": null, "id": "e7ae4811-90b0-4c5d-8f7b-39d48fb2590b", "metadata": { "cellView": "form", "id": "EDJgd8DAXRba", "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title Merge Clusters { display-mode: \"form\" }\n", "\n", "#@markdown ONLY USE THIS CODE CELL IF YOU WANT TO MERGE CLUSTERS. \n", "#@markdown OTHERWISE, MOVE ON. \n", "#@markdown
Below, create your list (of sublists) of clusters to merge.\n", "#@markdown >Just leave out from the list any clusters that you want unmerged.\n", "merge_cluster_list = [[0,3,4],[1,2]] #@param\n", "#@markdown Then, run this cell to merge clusters as specified.\n", "\n", "for k_group in merge_cluster_list:\n", " for k in k_group:\n", " df_props.loc[df_props['cluster']==k,'cluster'] = k_group[0]\n", "print('you now have the following clusters: ' + str(np.unique(df_props['cluster'])))\n", "\n", "print('Tasks completed at ' + str(datetime.now(timezone(-timedelta(hours=5)))))\n" ] }, { "cell_type": "markdown", "id": "27ba23b1-7643-4138-9b70-8478910de0c4", "metadata": {}, "source": [ "After merging, return to the [display clusters](#display-clusters) code cell to plot the mean waveform of each new cluster (and determine if you need to [merge more](#merge-clusters))." ] }, { "cell_type": "markdown", "id": "bc5a51f2-a02c-4e03-a227-6079e348bce6", "metadata": {}, "source": [ "\n", "\n", "Once you are happy with the clustering results based on the waveform shapes, check back with the raw data. " ] }, { "cell_type": "code", "execution_count": null, "id": "c68ccb8b-9d2b-4c66-8939-59c0b6f51df1", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode:\"form\"}\n", "\n", "#@markdown Run this cell to overlay spike times by cluster identity on the raw signal\n", "\n", "f = go.FigureWidget()\n", "f.add_trace(go.Scatter(x = time[0:fs], y = pre[0:fs],\n", " name='pre synaptic',opacity=1,line_color='black'))\n", "for k in np.unique(df_props['cluster']):\n", " start = 0 \n", " stop = 1\n", " inwin_inds = np.asarray([(df_props['spikeT'].values>start) & (df_props['spikeT'].valuesx[0]) & (df_props['spikeT'].values\n", "# Part II. Spike-triggered voltage\n", "\n", "[toc](#toc)\n", "\n", "You can use the event times (spike times) to extract the pre-synaptic and/or post-synaptic voltage signal following each event. This is a helpful way to determine if you have recorded any synaptic pairs (a connected pair of pre and post-synaptic cells). " ] }, { "cell_type": "code", "execution_count": null, "id": "e2fb9c5b-5f47-4bfc-b088-7d1af2eddb22", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode:\"form\"}\n", "\n", "#@markdown Type in the window duration that you want to analyze following each spiking event. \n", "#@markdown Then run this cell to plot the average spike-triggered post-synaptic potential for each cluster\n", "\n", "window = 0.1 #@param\n", "\n", "# No need to edit below this line\n", "#################################\n", "windur = window\n", "winsamps = int(windur * fs)\n", "x = np.linspace(0,windur,winsamps)*1000 #transform time to milliseconds\n", "hfig,ax = plt.subplots(1)\n", "ax.set_ylabel('volts recorded',fontsize=14)\n", "ax.set_xlabel('milliseconds',fontsize=14)\n", "plt.xticks(fontsize=14)\n", "plt.yticks(fontsize=14)\n", "for k in np.unique(df_props['cluster']):\n", " spkt = df_props.loc[df_props['cluster']==k]['spikeT'].values\n", " spkt = spkt[(spkt<((len(post)/fs)-windur))]\n", " synwav = np.asarray([post[(int(t*sampling_rate)):(int(t*sampling_rate)+winsamps)] for t in spkt])\n", " wav_u = np.mean(synwav,0)\n", " wav_std = np.std(synwav,0)\n", " ax.plot(x,wav_u,linewidth = 3,color = pal[k],label='cluster '+str(k))\n", " # ax.fill_between(x, wav_u-wav_std, wav_u+wav_std, alpha = 0.25, color = pal[k])\n", "plt.legend(bbox_to_anchor=[1,1], fontsize=14);" ] }, { "cell_type": "markdown", "id": "bf5c4ebd-1796-4ed9-a4d4-0d93a7f08497", "metadata": {}, "source": [ "It is helpful to look at individual trials (events) to get a sense of the variance/reliability in the pre and post-synaptic signal associated with each spike time." ] }, { "cell_type": "code", "execution_count": null, "id": "e8815ce9-b00a-4237-90ce-03096e0fa5ff", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode:\"form\"}\n", "\n", "#@markdown Type in the window duration that you want to analyze following each spiking event. \n", "\n", "window = 0.1 #@param\n", "\n", "#@markdown Then, run this code cell to plot a random set of 10 spike time triggered voltage signals\n", "#@markdown (pre and post synaptic) for each cluster (or maximum number of trials for that cluster).\n", "#@markdown Every time you select a new cluster, a new random sample of trials from that cluster will be plotted.\n", "#@markdown
The average waveform is plotted overlaid in black.\n", "windur = window\n", "winoffset = 0.002 # in milliseconds\n", "winsamps = int(windur * fs)\n", "xtime = ((np.linspace(0,windur,winsamps))- winoffset)*1000 #subtract pre-spike offset\n", "\n", "k = df_props['cluster'][0] #seed it to start\n", "\n", "f = go.FigureWidget(make_subplots(rows=2,cols=1,shared_xaxes=True))\n", "\n", "spkt = df_props.loc[df_props['cluster']==k]['spikeT'].values\n", "spkt = spkt[(spkt>winoffset) & (spkt<(len(post)/fs)-windur)] - winoffset\n", "\n", "spkt_ = spkt[random.sample(range(0,len(spkt)),np.min([10,len(spkt)]))]\n", " \n", "spkwav = np.asarray([pre[(int(t*fs)):(int(t*fs)+winsamps)] - pre[int(t*fs)] for t in spkt_]).T\n", "spk_u = np.mean(spkwav,1)\n", "spk_std = np.std(spkwav,1)\n", "\n", "for i in spkwav.T:\n", " f.add_trace(go.Scatter(x = xtime, y = i, opacity = 0.5,line_color = pal[k]),row=1,col=1);\n", "f.add_trace(go.Scatter(x=xtime,y = spk_u,line_color = 'black'),row=1,col=1)\n", "\n", "synwav = np.asarray([post[(int(t*fs)):(int(t*fs)+winsamps)] - post[int(t*fs)] for t in spkt_]).T\n", "syn_u = np.mean(synwav,1)\n", "syn_std = np.std(synwav,1)\n", "for i in synwav.T:\n", " f.add_trace(go.Scatter(x = xtime, y = i, opacity = 0.5,line_color = pal[k]),row=2,col=1);\n", "f.add_trace(go.Scatter(x=xtime,y = syn_u,line_color = 'black'),row=2,col=1)\n", "\n", " \n", "f.update_layout(height=600, width=800,\n", " showlegend=False,\n", " xaxis2_title=\"time(milliseconds)\", \n", " yaxis_title='amplitude (volts)',yaxis2_title='amplitude (volts)')\n", "\n", "cluster_select = widgets.Dropdown(\n", " options=np.unique(df_props['cluster']),\n", " value=k,\n", " description='Cluster ID:',\n", " disabled=False,\n", " )\n", "\n", "\n", "# our function that will modify the xaxis range\n", "def response(k):\n", " with f.batch_update():\n", " spkt = df_props.loc[df_props['cluster']==k]['spikeT'].values\n", " spkt = spkt[(spkt>winoffset) & (spkt<(len(post)/fs)-windur)] - winoffset\n", " \n", " spkt_ = spkt[random.sample(range(0,len(spkt)),np.min([10,len(spkt)]))]\n", " \n", " spkwav = np.asarray([pre[(int(t*fs)):(int(t*fs)+winsamps)] - pre[int(t*fs)] for t in spkt_]).T\n", " spk_u = np.mean(spkwav,1)\n", " spk_std = np.std(spkwav,1)\n", "\n", " synwav = np.asarray([post[(int(t*fs)):(int(t*fs)+winsamps)] - post[int(t*fs)] for t in spkt_]).T\n", " syn_u = np.mean(synwav,1)\n", " syn_std = np.std(synwav,1)\n", "\n", " trace_ = 0\n", "\n", " for i in spkwav.T:\n", " f.data[trace_].y = i\n", " trace_+=1\n", " f.data[trace_].y = spk_u\n", " trace_+=1\n", "\n", " for i in synwav.T:\n", " f.data[trace_].y = i\n", " trace_+=1\n", " f.data[trace_].y = syn_u\n", " trace_+=1\n", "\n", "\n", "vb = VBox((f, interactive(response, k=cluster_select)))\n", "vb.layout.align_items = 'center'\n", "vb" ] }, { "cell_type": "markdown", "id": "dab050ce-1e4c-48a2-8e02-4cf1d76dea42", "metadata": {}, "source": [ "Finally, you can plot the pre and post synaptic signal associated with each individual event time in each cluster. This visualization enables you to extract more exact quantitative measurements from the signals associated with each event." ] }, { "cell_type": "code", "execution_count": null, "id": "d686d1b0-3723-41ae-8aa7-8647e83fe65f", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode:\"form\"}\n", "\n", "#@markdown Type in the window duration that you want to analyze following each spiking event. \n", "\n", "window = 0.1 #@param\n", "\n", "#@markdown Then, run this code cell to plot individual spike-triggered voltage signals\n", "#@markdown (pre and post synaptic) for each cluster. Select the cluster from the dropdown menu.\n", "#@markdown Select the spike event number using the slider.\n", "\n", "windur=window\n", "\n", "winoffset = 2 # in milliseconds\n", "winsamps = int(windur * fs)\n", "xtime = ((np.linspace(0,windur,winsamps))*1000)- winoffset #subtract pre-spike offset\n", "\n", "k = df_props['cluster'][0] #seed it to start\n", "\n", "f = go.FigureWidget(make_subplots(rows=2,cols=1,shared_xaxes=True))\n", "\n", "spkt = df_props.loc[df_props['cluster']==k]['spikeT'].values\n", "spkt = spkt[(spkt>winoffset) & (spkt<(len(post)/fs)-windur)] - winoffset/1000\n", "\n", "spkt_ = spkt[0]\n", " \n", "spkwav = pre[(int(spkt_*fs)):(int(spkt_*fs)+winsamps)] - pre[int(spkt_*fs)]\n", "f.add_trace(go.Scatter(x=xtime,y = spkwav,line_color = 'black',name='pre synaptic'),row=1,col=1)\n", "\n", "synwav = post[(int(spkt_*fs)):(int(spkt_*fs)+winsamps)]# - post[int(spkt_*fs)]\n", "f.add_trace(go.Scatter(x=xtime,y = synwav,line_color = 'black',name='post synaptic'),row=2,col=1)\n", "\n", "f.update_layout(height=600, width=800,\n", " showlegend=False,\n", " xaxis2_title=\"time(milliseconds)\", \n", " yaxis_title='pre-synaptic voltage',yaxis2_title='post-synaptic voltage')\n", "\n", "cluster_select = widgets.Dropdown(\n", " options=np.unique(df_props['cluster']),\n", " value=k,\n", " description='Cluster ID:',\n", " disabled=False,\n", ")\n", "\n", "event_select = widgets.IntSlider(\n", " value=0,\n", " min=0,\n", " max=len(spkt),\n", " step=1,\n", " description='Spike Event Number:',\n", " disabled=False,\n", " continuous_update=False,\n", " orientation='horizontal',\n", " readout=True,\n", " readout_format='d'\n", ")\n", "event_select.layout.width = '600px'\n", "\n", "# our function that will modify the xaxis range\n", "def response(k,t):\n", " with f.batch_update():\n", " spkt = df_props.loc[df_props['cluster']==k]['spikeT'].values\n", " spkt = spkt[(spkt>winoffset) & (spkt<(len(post)/fs)-windur)] - winoffset/1000\n", " \n", " event_select.max=len(spkt)-1\n", "\n", " spkt_ = spkt[event_select.value] # shoulod be able to use \"t\"\n", " spkwav = pre[(int(spkt_*fs)):(int(spkt_*fs)+winsamps)] - pre[int(spkt_*fs)]\n", " synwav = post[(int(spkt_*fs)):(int(spkt_*fs)+winsamps)]# - post[int(spkt_*fs)]\n", " \n", " f.data[0].y = spkwav\n", " f.data[1].y = synwav\n", " \n", " f.update_layout(yaxis1_range=[np.min(pre),np.max(pre)])\n", "\n", "\n", "vb = VBox((f, interactive(response, k=cluster_select, t=event_select)))\n", "vb.layout.align_items = 'center'\n", "vb\n", "\n" ] }, { "cell_type": "markdown", "id": "c224f763-fc10-4dc7-8a2f-8b6be3ce0dba", "metadata": {}, "source": [ "\n", "# Part III. PSP amplitudes\n", "\n", "[toc](#toc)\n", "\n", "To detect post-synaptic potentials (psps), you can use the same method you used to find events (signal peaks) in the pre-synaptic signal. Did you record distinct classes of PSPs or was the distribution of PSPs continuous?" ] }, { "cell_type": "code", "execution_count": null, "id": "6406021c-d2b7-401a-9601-cf9eb3e3d5cc", "metadata": { "tags": [ "hide-input" ] }, "outputs": [], "source": [ "#@title {display-mode:'form'}\n", "\n", "#@markdown Type in an appropriate event threshold amplitude for detection of psps.\n", "threshold = 0.02 #@param {type: \"number\"}\n", "\n", "#@markdown Then, run this cell to detect psp peaks and calculate their height.\n", "\n", "#@markdown You will see a scatter plot of peaks (red) and bases (green) overlaid on the raw trace\n", "#@markdown and a histogram of event peak amplitudes.\n", "\n", "min_isi = 0.002 #seconds\n", "\n", "# samples_inwin = samples[int(start_time/sample_rate):int(stop_time/sample_rate)]\n", "peaks,props = find_peaks(post,prominence = threshold, distance=int(min_isi*fs))\n", "peaks_,props_ = find_peaks(-post,prominence = threshold, distance=int(min_isi*fs))\n", "\n", "plt.figure(figsize=(15,3))\n", "plt.plot(post)\n", "plt.scatter(peaks_,post[peaks_],color='green')\n", "plt.scatter(peaks,post[peaks],color='red')\n", "plt.xlim(0,2*fs)\n", "plt.ylim(-0.8,-0.5)\n", "\n", "psp_amp = []\n", "for p in peaks:\n", " b = np.max(peaks_[peaks_ \n", "Written by Dr. Krista Perks for courses taught at Wesleyan University." ] }, { "cell_type": "code", "execution_count": null, "id": "5c707588-d5f6-4142-8289-da7ba6a97dbc", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "id": "57a8a68c-055e-4af0-ba4d-67d0d67148f1", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "a350712e-e145-4475-9588-e3f19469b5ce", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "86fd2b4a-b890-465f-bf33-c2057738789e", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "b05de192-2baf-4d46-8848-6db1e3b50bff", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "e6519277-fc86-44fd-a75b-f74cad0efcf1", "metadata": {}, "source": [ "" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.13" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 5 }