[pointprocesses] updated some figures

This commit is contained in:
Jan Benda 2021-01-09 23:23:47 +01:00
parent 10f71d5661
commit e5fd1ecb32
5 changed files with 101 additions and 85 deletions

View File

@ -55,11 +55,11 @@ def plotisih( ax, isis, binwidth=None ) :
binwidth = 5e-4
h, b = np.histogram(isis, np.arange(0.0, np.max(isis)+binwidth, binwidth), density=True)
ax.text(0.9, 0.85, 'rate={:.0f}Hz'.format(1.0/np.mean(isis)), ha='right', transform=ax.transAxes)
ax.text(0.9, 0.75, 'mean={:.0f}ms'.format(1000.0*np.mean(isis)), ha='right', transform=ax.transAxes)
ax.text(0.9, 0.65, 'CV={:.2f}'.format(np.std(isis)/np.mean(isis)), ha='right', transform=ax.transAxes)
ax.text(0.9, 0.7, 'mean={:.0f}ms'.format(1000.0*np.mean(isis)), ha='right', transform=ax.transAxes)
ax.text(0.9, 0.55, 'CV={:.2f}'.format(np.std(isis)/np.mean(isis)), ha='right', transform=ax.transAxes)
ax.set_xlabel('ISI', 'ms')
ax.set_ylabel('p(ISI)', '1/s')
ax.bar( 1000.0*b[:-1], h, bar_fac*1000.0*np.diff(b), facecolor=colors['blue'])
ax.bar( 1000.0*b[:-1], h, bar_fac*1000.0*np.diff(b), **fsA)
# parameter:
rate = 20.0
@ -85,16 +85,18 @@ x[x<0.0] = 0.0
inhspikes = pifspikes(x, trials, dt, D=0.3)
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.subplots_adjust(**adjust_fs(fig, top=1.5))
ax1.set_title('stationary')
ax1.set_xlim(0.0, 200.0)
ax1.set_ylim(0.0, 40.0)
plotisih(ax1, isis(homspikes))
fig.subplots_adjust(**adjust_fs(fig, top=0.5, right=1.5))
ax1.set_xlim(0.0, 150.0)
ax1.set_ylim(0.0, 31.0)
ax1.set_xticks(np.arange(0.0, 151.0, 50.0))
ax1.set_yticks(np.arange(0.0, 31.0, 10.0))
plotisih(ax1, isis(homspikes), 0.005)
ax2.set_title('non-stationary')
ax2.set_xlim(0.0, 200.0)
ax2.set_ylim(0.0, 40.0)
plotisih(ax2, isis(inhspikes))
ax2.set_xlim(0.0, 150.0)
ax2.set_ylim(0.0, 31.0)
ax2.set_xticks(np.arange(0.0, 151.0, 50.0))
ax2.set_yticks(np.arange(0.0, 31.0, 10.0))
plotisih(ax2, isis(inhspikes), 0.005)
plt.savefig('isihexamples.pdf')
plt.close()

View File

@ -1,36 +1,41 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Spiketrain analysis}
\chapter{Spike-train analysis}
\label{pointprocesseschapter}
\exercisechapter{Spiketrain analysis}
\exercisechapter{Spike-train analysis}
\entermde[action potential]{Aktionspotential}{Action potentials}
(\enterm[spike|seealso{action potential}]{spikes}) are the carriers of
information in the nervous system. Thereby it is the time at which the
spikes are generated that is of importance for information
transmission. The waveform of the action potential is largely
stereotyped and therefore does not carry information.
The result of the pre-processing of electrophysiological recordings are
series of spike times, which are termed \enterm{spiketrains}. If
measurements are repeated we get several \enterm{trials} of
spiketrains (\figref{rasterexamplesfig}).
Spiketrains are times of events, the action potentials. Analyzing
spike trains leads into the realm of the so called \entermde[point
process]{Punktprozess}{point processes}.
\begin{figure}[ht]
(\enterm[spike|seealso{action potential}]{spikes}) carry information
within neural systems. More precisely, the times at which action
potentials are generated contain the information. The waveform of the
action potential is largely stereotyped and therefore conveys no
information. Analyzing the statistics of spike times and their
relation to sensory stimuli or motor actions is central to
neuroscientific research. With multi-electrode arrays it is nowadays
possible to record from hundreds or even thousands of neurons
simultaneously. The open challenge is how to analyze such data sets in
order to understand how neural systems work. Let's start with the
basics in this chapter.
The result of the pre-processing of electrophysiological recordings
are series of spike times, which are termed \enterm[spike train]{spike
trains}. If measurements are repeated we get several \enterm{trials}
of spike trains (\figref{rasterexamplesfig}). Spike trains are lists
of times of events, the action potentials. Analyzing spike trains
leads into the realm of the statistics of so called \entermde[point
process]{Punktprozess}{point processes}.
\begin{figure}[bt]
\includegraphics[width=1\textwidth]{rasterexamples}
\titlecaption{\label{rasterexamplesfig}Raster-plot.}{Raster-plots of
ten trials of data illustrating the times of the action
potentials. Each vertical dash illustrates the time at which an
action potential was observed. Each line displays the events of
one trial. Shown is a stationary point process (homogeneous point
\titlecaption{\label{rasterexamplesfig}Raster plot.}{Raster plots of
ten trials of data illustrating the times of action
potentials. Each vertical stroke illustrates the time at which an
action potential was observed. Each row displays the events of one
trial. Shown is a stationary point process (homogeneous point
process with a rate $\lambda=20$\;Hz, left) and an non-stationary
point process (perfect integrate-and-fire neuron driven by
Ohrnstein-Uhlenbeck noise with a time-constant $\tau=100$\,ms,
right).}
point process with a rate that varies in time (noisy perfect
integrate-and-fire neuron driven by Ohrnstein-Uhlenbeck noise with
a time-constant $\tau=100$\,ms, right).}
\end{figure}
@ -43,7 +48,7 @@ spike trains leads into the realm of the so called \entermde[point
crosses some threshold. For example:\vspace{-1ex}
\begin{itemize}
\item Action potentials/heart beat: created by the dynamics of the
neuron/sinoatrial node
neuron/sinoatrial node.
\item Earthquake: defined by the dynamics of the pressure between
tectonical plates.
\item Communication calls in crickets/frogs/birds: shaped by
@ -59,21 +64,21 @@ spike trains leads into the realm of the so called \entermde[point
$T_i=t_{i+1}-t_i$ and the number of events $n_i$. }
\end{figure}
\noindent
A temporal \entermde{Punktprozess}{point process} is a stochastic
process that generates a sequence of events at times $\{t_i\}$, $t_i
\in \reZ$. In the neurosciences, the statistics of point processes is
of importance since the timing of neuronal events (action potentials,
post-synaptic potentials, events in EEG or local-field recordings,
etc.) is crucial for information transmission and can be treated as
such a process.
process that generates a sequence of events at times $\{t_i\}$. In
the neurosciences, the statistics of point processes is of importance
since the timing of neuronal events (action potentials, post-synaptic
potentials, events in EEG or local-field recordings, etc.) is crucial
for information transmission and can be treated as such a process.
The events of a point process can be illustrated by means of a raster
plot in which each vertical line indicates the time of an event. The
event from two different point processes are shown in
\figref{rasterexamplesfig}. Point processes can be described using
the intervals between successive events $T_i=t_{i+1}-t_i$ and the
number of observed events within a certain time window $n_i$
(\figref{pointprocessscetchfig}).
\figref{rasterexamplesfig}. In addition to the event times, point
processes can be described using the intervals $T_i=t_{i+1}-t_i$
between successive events or the number of observed events within a
certain time window $n_i$ (\figref{pointprocessscetchfig}).
\begin{exercise}{rasterplot.m}{}
Implement a function \varcode{rasterplot()} that displays the times of
@ -94,7 +99,7 @@ real-valued variables:
\begin{figure}[t]
\includegraphics[width=0.96\textwidth]{isihexamples}\vspace{-2ex}
\titlecaption{\label{isihexamplesfig}Interspike interval
\titlecaption{\label{isihexamplesfig}Interspike-interval
histograms}{of the spike trains shown in \figref{rasterexamplesfig}.}
\end{figure}
@ -144,7 +149,7 @@ the interval $T_i$. The parameter $k$ is called the \enterm{lag}
(\determ{Verz\"ogerung}) $k$. Stationary and non-stationary return
maps are distinctly different \figref{returnmapfig}.
\begin{figure}[t]
\begin{figure}[tp]
\includegraphics[width=1\textwidth]{returnmapexamples}
\includegraphics[width=1\textwidth]{serialcorrexamples}
\titlecaption{\label{returnmapfig}Interspike interval
@ -314,7 +319,7 @@ The homogeneous Poisson process has the following properties:
\includegraphics[width=0.48\textwidth]{poissoncounthistdist100hz10ms}\hfill
\includegraphics[width=0.48\textwidth]{poissoncounthistdist100hz100ms}
\titlecaption{\label{hompoissoncountfig}Distribution of counts of a
Poisson spiketrain.}{The count statistics was generated for two
Poisson spike train.}{The count statistics was generated for two
different windows of width $W=10$\,ms (left) and width $W=100$\,ms
(right). The red line illustrates the corresponding Poisson
distribution \eqnref{poissoncounts}.}
@ -324,7 +329,7 @@ The homogeneous Poisson process has the following properties:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\section{Time-dependent firing rate}
So far we have discussed stationary spiketrains. The statistical properties
So far we have discussed stationary spike trains. The statistical properties
of these did not change within the observation time (stationary point
processes). Most commonly, however, this is not the case. A sensory
neuron, for example, might respond to a stimulus by modulating its
@ -351,7 +356,7 @@ justifications, their pros- and cons.
\begin{figure}[tp]
\includegraphics[width=\columnwidth]{isimethod}
\titlecaption{Instantaneous firing rate.}{The recorded spiketrain
\titlecaption{Instantaneous firing rate.}{The recorded spike train
(top). Arrows illustrate the interspike intervals and numbers
give the intervals in milliseconds. The inverse of the interspike
intervals is the \emph{instantaneous firing rate}
@ -412,7 +417,7 @@ methods make an assumption about the relevant observation time-scale
\begin{figure}[tp]
\includegraphics[width=\columnwidth]{binmethod}
\titlecaption{Estimating the PSTH using the binning method.}{The
same spiketrain as shown in \figref{instratefig} (top). Vertical
same spike train as shown in \figref{instratefig} (top). Vertical
gray lines indicate the borders between adjacent bins in which the
number of action potentials is counted (red numbers). The firing
rate is then the histogram normalized to the binwidth
@ -448,8 +453,8 @@ time-scale.
\begin{figure}[tp]
\includegraphics[width=\columnwidth]{convmethod}
\titlecaption{Estimating the firing rate using the convolution
method.}{The same spiketrain as in \figref{instratefig} (top). The
convolution of the spiketrain with a kernel replaces each spike
method.}{The same spike train as in \figref{instratefig} (top). The
convolution of the spike train with a kernel replaces each spike
event with the kernel (red). A Gaussian kernel is used here, but
other kernels are also possible. If the kernel is properly
normalized the firing rate results directly form the superposition

View File

@ -1,5 +1,6 @@
import numpy as np
import matplotlib.pyplot as plt
from plotstyle import *
def hompoisson(rate, trials, duration) :
spikes = []
@ -8,8 +9,8 @@ def hompoisson(rate, trials, duration) :
t = 0.0
while t < duration :
t += np.random.exponential(1/rate)
times.append( t )
spikes.append( times )
times.append(t)
spikes.append(times)
return spikes
def inhompoisson(rate, trials, dt) :
@ -18,7 +19,7 @@ def inhompoisson(rate, trials, dt) :
for k in range(trials) :
x = np.random.rand(len(rate))
times = dt*np.nonzero(x<p)[0]
spikes.append( times )
spikes.append(times)
return spikes
@ -36,7 +37,7 @@ def pifspikes(input, trials, dt, D=0.1) :
if v >= vthresh :
v = vreset
times.append(k*dt)
spikes.append( times )
spikes.append(times)
return spikes
# parameter:
@ -64,23 +65,22 @@ x[x<0.0] = 0.0
# pif spike trains:
inhspikes = pifspikes(x, trials, dt, D=0.3)
fig = plt.figure( figsize=(9,4) )
ax = fig.add_subplot(1, 2, 1)
ax.set_title('stationary')
ax.set_xlim(0.0, duration)
ax.set_ylim(-0.5, trials-0.5)
ax.set_xlabel('Time [s]')
ax.set_ylabel('Trials')
ax.eventplot(homspikes, colors=[[0, 0, 0]], linelength=0.8)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=cm_size(figure_width, 0.5*figure_width))
fig.subplots_adjust(**adjust_fs(fig, left=4.0, right=1.0, top=1.2))
ax = fig.add_subplot(1, 2, 2)
ax.set_title('non-stationary')
ax.set_xlim(0.0, duration)
ax.set_ylim(-0.5, trials-0.5)
ax.set_xlabel('Time [s]')
ax.set_ylabel('Trials')
ax.eventplot(inhspikes, colors=[[0, 0, 0]], linelength=0.8)
ax1.set_title('stationary')
ax1.set_xlim(0.0, duration)
ax1.set_ylim(-0.5, trials-0.5)
ax1.set_xlabel('Time [s]')
ax1.set_ylabel('Trial')
ax1.eventplot(homspikes, colors=[lsA['color']], linelength=0.8, lw=1)
ax2.set_title('non-stationary')
ax2.set_xlim(0.0, duration)
ax2.set_ylim(-0.5, trials-0.5)
ax2.set_xlabel('Time [s]')
ax2.set_ylabel('Trial')
ax2.eventplot(inhspikes, colors=[lsA['color']], linelength=0.8, lw=1)
plt.tight_layout()
plt.savefig('rasterexamples.pdf')
plt.close()

View File

@ -40,19 +40,21 @@ def pifspikes(input, trials, dt, D=0.1) :
spikes.append( times )
return spikes
def isis( spikes ) :
isi = []
for k in range(len(spikes)) :
isi.extend(np.diff(spikes[k]))
return np.array( isi )
def plotreturnmap(ax, isis, lag=1, max=None) :
def plotreturnmap(ax, isis, lag=1, max=1.0) :
ax.set_xlabel(r'ISI$_i$', 'ms')
ax.set_ylabel(r'ISI$_{i+1}$', 'ms')
if max != None :
ax.set_xlim(0.0, 1000.0*max)
ax.set_ylim(0.0, 1000.0*max)
ax.scatter(1000.0*isis[:-lag], 1000.0*isis[lag:], c=colors['blue'])
ax.set_xlim(0.0, 1000.0*max)
ax.set_ylim(0.0, 1000.0*max)
isiss = isis[isis<max]
ax.plot(1000.0*isiss[:-lag], 1000.0*isiss[lag:], clip_on=False, **psAm)
# parameter:
rate = 20.0
@ -79,11 +81,14 @@ inhspikes = pifspikes(x, trials, dt, D=0.3)
fig, (ax1, ax2) = plt.subplots(1, 2)
fig.subplots_adjust(**adjust_fs(fig, left=6.5, top=1.5))
ax1.set_title('stationary')
plotreturnmap(ax1, isis(homspikes), 1, 0.3)
ax1.set_xticks(np.arange(0.0, 301.0, 100.0))
ax1.set_yticks(np.arange(0.0, 301.0, 100.0))
ax2.set_title('non-stationary')
plotreturnmap(ax2, isis(inhspikes), 1, 0.3)
ax2.set_ylabel('')
ax2.set_xticks(np.arange(0.0, 301.0, 100.0))
ax2.set_yticks(np.arange(0.0, 301.0, 100.0))
plt.savefig('returnmapexamples.pdf')
plt.close()

View File

@ -13,6 +13,7 @@ def hompoisson(rate, trials, duration) :
spikes.append( times )
return spikes
def inhompoisson(rate, trials, dt) :
spikes = []
p = rate*dt
@ -55,8 +56,10 @@ def plotserialcorr(ax, isis, maxlag=10) :
ax.set_ylabel(r'ISI correlation $\rho_k$')
ax.set_xlim(0.0, maxlag)
ax.set_ylim(-1.0, 1.0)
ax.plot(lags, corr, '.-', markersize=15, c=colors['blue'])
ax.plot([0, 10], [0.0, 0.0], **lsGrid)
ax.plot(lags, corr, clip_on=False, zorder=100, **lpsAm)
# parameter:
rate = 20.0
drate = 50.0
@ -87,6 +90,7 @@ plotserialcorr(ax1, isis(homspikes))
ax1.set_ylim(-0.2, 1.0)
plotserialcorr(ax2, isis(inhspikes))
ax2.set_ylabel('')
ax2.set_ylim(-0.2, 1.0)
plt.savefig('serialcorrexamples.pdf')