import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import pearsonr, spearmanr, kstest, rankdata
from scipy.io import loadmat
from scipy.fft import fft, ifft
from scipy.signal import correlate, correlation_lags
Chapter 27
Chapter 27
Analyzing Neural Time Series Data
Python code for Chapter 27 – converted from original Matlab by AE Studio (and ChatGPT)
Original Matlab code by Mike X Cohen
This code accompanies the book, titled “Analyzing Neural Time Series Data” (MIT Press).
Using the code without following the book may lead to confusion, incorrect data analyses, and misinterpretations of results.
Mike X Cohen and AE Studio assume no responsibility for inappropriate or incorrect use of this code.
Import necessary libraries
An aside on covariance and correlation
= np.random.randn(100)
a = np.random.randn(100)
b
= np.corrcoef(a, b)[0, 1]
corr1
= a - np.mean(a)
a1 = b - np.mean(b)
b1 = (a1 @ b1.T) / np.sqrt((a1 @ a1.T) * (b1 @ b1.T))
corr2
= np.vstack((a1, b1))
c = c @ c.T
covmat
# notice the following:
print(covmat[0, 0] == a1 @ a1.T)
print(covmat[1, 1] == b1 @ b1.T)
print(covmat[1, 0] == a1 @ b1.T)
# actually, some of these might not be exactly equal due to very small computer rounding errors.
# try this instead:
print((covmat[1, 0] - a1 @ b1.T) < 1e-14)
= covmat[0, 1] / np.sqrt(covmat[0, 0] * covmat[1, 1])
corr3
print(f"\nPython numpy.corrcoef function: {corr1}")
print(f"covariance scaled by variances: {corr2}")
print(f"covariance computed as matrix: {corr3}\n")
False
False
False
True
Python numpy.corrcoef function: -0.18111792542261373
covariance scaled by variances: -0.18111792542261368
covariance computed as matrix: -0.18111792542261373
Figure 27.1
= np.array([
anscombe # series 1 series 2 series 3 series 4
10, 8.04, 10, 9.14, 10, 7.46, 8, 6.58],
[8, 6.95, 8, 8.14, 8, 6.77, 8, 5.76],
[13, 7.58, 13, 8.76, 13, 12.74, 8, 7.71],
[9, 8.81, 9, 8.77, 9, 7.11, 8, 8.84],
[11, 8.33, 11, 9.26, 11, 7.81, 8, 8.47],
[14, 9.96, 14, 8.10, 14, 8.84, 8, 7.04],
[6, 7.24, 6, 6.13, 6, 6.08, 8, 5.25],
[4, 4.26, 4, 3.10, 4, 5.39, 8, 5.56],
[12, 10.84, 12, 9.13, 12, 8.15, 8, 7.91],
[7, 4.82, 7, 7.26, 7, 6.42, 8, 6.89],
[5, 5.68, 5, 4.74, 5, 5.73, 19, 12.50],
[
])
# plot and compute correlations
=(10, 10))
plt.figure(figsizefor i in range(1, 5):
2, 2, i)
plt.subplot(= anscombe[:, (i - 1) * 2]
x = anscombe[:, (i - 1) * 2 + 1]
y '.')
plt.plot(x, y, 1))(np.unique(x)), color='red')
plt.plot(np.unique(x), np.poly1d(np.polyfit(x, y, = pearsonr(x, y)
corr_p, _ = spearmanr(x, y)
corr_s, _ f'r_p={round(corr_p, 3)}; r_s={round(corr_s, 3)}')
plt.title( plt.show()
Figure 27.2
# Load EEG data
= loadmat('../data/sampleEEGdata.mat')['EEG'][0, 0]
EEG
= 'Fz'
sensor2use = 10 # in Hz
centerfreq
# setup wavelet convolution and outputs
= np.arange(-1, 1 + 1/EEG['srate'][0, 0], 1/EEG['srate'][0, 0])
time = (len(time) - 1) // 2
half_of_wavelet_size
# FFT parameters
= len(time)
n_wavelet = EEG['pnts'][0, 0] * EEG['trials'][0, 0]
n_data = n_wavelet + n_data - 1
n_convolution = 4.5
wavelet_cycles
# FFT of data (note: this doesn't change on frequency iteration)
= fft(EEG['data'][EEG['chanlocs'][0]['labels']==sensor2use, :, :].flatten('F'), n_convolution)
fft_data
# create wavelet and run convolution
= fft(np.exp(2 * 1j * np.pi * centerfreq * time) * np.exp(-time ** 2 / (2 * (wavelet_cycles / (2 * np.pi * centerfreq)) ** 2)), n_convolution)
fft_wavelet = ifft(fft_wavelet * fft_data, n_convolution) * np.sqrt(wavelet_cycles / (2 * np.pi * centerfreq))
convolution_result_fft = convolution_result_fft[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft = np.abs(np.reshape(convolution_result_fft, (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
convolution_result_fft
# trim edges so the distribution is not driven by edge artifact outliers
= convolution_result_fft[99:-100, :]
convolution_result_fft
# plot distribution of power data
=(12, 6))
plt.figure(figsize121)
plt.subplot('F'), bins=500)
plt.hist(convolution_result_fft.flatten(0, 5000])
plt.xlim(['Distribution of power values')
plt.title(
122)
plt.subplot('F')), bins=500)
plt.hist(np.log10(convolution_result_fft.flatten('Distribution of log10 power values')
plt.title(
plt.show()
# test for normal distribution, if you have the stats toolbox
if 'kstest' in dir():
= kstest(convolution_result_fft.flatten('F'), 'norm')[1]
p1 = kstest(np.log10(convolution_result_fft.flatten('F')), 'norm')[1]
p2 = kstest(np.random.randn(convolution_result_fft.size), 'norm')[1]
p3 print(f'KS test for normality of power: {p1} (>.05 means normal distribution)')
print(f'KS test for normality of log10(power): {p2} (>.05 means normal distribution)')
print(f'KS test for normality of random data: {p3} (>.05 means normal distribution)')
KS test for normality of power: 0.0 (>.05 means normal distribution)
KS test for normality of log10(power): 0.0 (>.05 means normal distribution)
KS test for normality of random data: 0.6439599564317877 (>.05 means normal distribution)
Figure 27.3
# Fisher Z transformation
= np.random.rand(1000) * 2 - 1
lots_of_corr_coefs = 0.5 * np.log((1 + lots_of_corr_coefs) / (1 - lots_of_corr_coefs))
fisher_z_coefs
=(12, 12))
plt.figure(figsize
# Histogram of correlation coefficients
221)
plt.subplot(50)
plt.hist(lots_of_corr_coefs, 'Correlation coefficient')
plt.xlabel('Count')
plt.ylabel(-1, 1])
plt.xlim([-1, 1.5, 0.5))
plt.xticks(np.arange(
# Histogram of Fisher-Z transformed coefficients
222)
plt.subplot(50)
plt.hist(fisher_z_coefs, 'Fisher-Z transformed coefficients')
plt.xlabel('Count')
plt.ylabel(-5, 5])
plt.xlim([-4, 5, 2))
plt.xticks(np.arange(
# Scatter plot of correlation coefficients vs. Fisher-Z transformed coefficients
223)
plt.subplot('.')
plt.plot(lots_of_corr_coefs, fisher_z_coefs, 'Correlation coefficient')
plt.xlabel('Fisher-Z transformed coefficients')
plt.ylabel(-1, 1])
plt.xlim([-1, 1.5, 0.5))
plt.xticks(np.arange(
# Scatter plot of atanh (inverse Fisher-Z) vs. Fisher-Z
224)
plt.subplot('.')
plt.plot(np.arctanh(lots_of_corr_coefs), fisher_z_coefs, 'atanh')
plt.xlabel('Fisher-Z')
plt.ylabel(= np.corrcoef(np.arctanh(lots_of_corr_coefs), fisher_z_coefs)[0, 1]
r f'Correlation = {r}'])
plt.legend([-4, 5, 2))
plt.xticks(np.arange(-4, 5, 2))
plt.yticks(np.arange(-4, 4, -4, 4])
plt.axis([ plt.show()
Figure 27.4
# Define sensors and frequencies
= 'Fz'
sensor1 = 'P5'
sensor2
= 6 # in Hz
centerfreq = 10 - 1 # subtract 1 because Python is 0-indexed
trial2plot
# Keep only requested time regions
= np.array([np.argmin(np.abs(EEG['times'][0] - t)) for t in [-300, 1200]])
times2plot_idx
# FFT of data for both sensors
= fft(EEG['data'][EEG['chanlocs'][0]['labels']==sensor1, :, :].flatten('F'), n_convolution)
fft_data1 = fft(EEG['data'][EEG['chanlocs'][0]['labels']==sensor2, :, :].flatten('F'), n_convolution)
fft_data2
# Create wavelet and run convolution for both sensors
= fft(np.exp(2 * 1j * np.pi * centerfreq * time) * np.exp(-time ** 2 / (2 * (wavelet_cycles / (2 * np.pi * centerfreq)) ** 2)), n_convolution)
fft_wavelet
# Convolution for sensor 1
= ifft(fft_wavelet * fft_data1, n_convolution) * np.sqrt(wavelet_cycles / (2 * np.pi * centerfreq))
convolution_result_fft1 = convolution_result_fft1[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft1 = np.abs(np.reshape(convolution_result_fft1, (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
convolution_result_fft1
# Convolution for sensor 2
= ifft(fft_wavelet * fft_data2, n_convolution) * np.sqrt(wavelet_cycles / (2 * np.pi * centerfreq))
convolution_result_fft2 = convolution_result_fft2[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft2 = np.abs(np.reshape(convolution_result_fft2, (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
convolution_result_fft2
= convolution_result_fft1[times2plot_idx[0]:times2plot_idx[1] + 1, :]
convolution_result_fft1 = convolution_result_fft2[times2plot_idx[0]:times2plot_idx[1] + 1, :]
convolution_result_fft2
# Plotting the power values and their relationship
=(12, 12))
plt.figure(figsize211)
plt.subplot('times'][0][times2plot_idx[0]:times2plot_idx[1] + 1], convolution_result_fft1[:, trial2plot])
plt.plot(EEG['times'][0][times2plot_idx[0]:times2plot_idx[1] + 1], convolution_result_fft2[:, trial2plot], 'r')
plt.plot(EEG['Time (ms)')
plt.xlabel('times'][0][times2plot_idx])
plt.xlim(EEG[
plt.legend([sensor1, sensor2])
223)
plt.subplot('.')
plt.plot(convolution_result_fft1[:, trial2plot], convolution_result_fft2[:, trial2plot], 'Power relationship')
plt.title(f'{sensor1} {centerfreq}Hz power')
plt.xlabel(f'{sensor2} {centerfreq}Hz power')
plt.ylabel(= np.corrcoef(convolution_result_fft1[:, trial2plot], convolution_result_fft2[:, trial2plot])[0, 1]
r f'Pearson R = {r}'])
plt.legend([
224)
plt.subplot('.')
plt.plot(rankdata(convolution_result_fft1[:, trial2plot]), rankdata(convolution_result_fft2[:, trial2plot]), 'Rank-power relationship')
plt.title(f'{sensor1} {centerfreq}Hz rank-power')
plt.xlabel(f'{sensor2} {centerfreq}Hz rank-power')
plt.ylabel(= spearmanr(convolution_result_fft1[:, trial2plot], convolution_result_fft2[:, trial2plot])[0]
r_spearman f'Spearman Rho = {r_spearman}'])
plt.legend([
plt.ylim(plt.xlim()) plt.show()
Figure 27.5
# Compute how many time points are in one cycle, and limit xcov to this lag
= round(EEG['srate'][0][0] / centerfreq)
nlags
# Rank transform the power values
= rankdata(np.abs(convolution_result_fft1[:, trial2plot]) ** 2)
rank_power1 = rankdata(np.abs(convolution_result_fft2[:, trial2plot]) ** 2)
rank_power2
# Compute cross-correlation
= correlate(rank_power1 - np.mean(rank_power1),
corrvals - np.mean(rank_power2),
rank_power2 ='full')
mode
# Normalize the cross-correlation values to get correlation coefficients
/= np.sqrt(np.sum((rank_power1 - np.mean(rank_power1)) ** 2) * np.sum((rank_power2 - np.mean(rank_power2)) ** 2))
corrvals
# Get lags and convert to milliseconds
= correlation_lags(len(rank_power1), len(rank_power2), mode='full')
lags = lags / EEG['srate'][0][0] * 1000
corrlags
# Find the center index corresponding to zero lag
= np.where(lags == 0)[0][0]
center_idx
# Plot the cross-correlation
=(10, 5))
plt.figure(figsize- nlags:center_idx + nlags + 1],
plt.plot(corrlags[center_idx - nlags:center_idx + nlags + 1], '-o', markerfacecolor='w')
corrvals[center_idx 0, color='k', linestyle='--')
plt.axvline(f'{sensor1} leads --- Time lag (ms) --- {sensor2} leads')
plt.xlabel('Correlation coefficient')
plt.ylabel('Cross-correlation between sensors')
plt.title( plt.show()
Figure 27.6
# Define sensors and frequencies
= 'POz'
sensor1 = 'Fz'
sensor2
# Define time windows and frequencies
= [-300, -100] # in ms relative to stim onset
timewin1 = [200, 400]
timewin2
= 6 # in Hz
centerfreq1 = 6
centerfreq2
# Convert time from ms to index
= [np.argmin(np.abs(EEG['times'][0] - t)) for t in timewin1]
timeidx1 = [np.argmin(np.abs(EEG['times'][0] - t)) for t in timewin2]
timeidx2
# FFT parameters
= len(time)
n_wavelet = EEG['pnts'][0, 0] * EEG['trials'][0, 0]
n_data = n_wavelet + n_data - 1
n_convolution = 4.5
wavelet_cycles
# FFT of data for both sensors
= fft(EEG['data'][EEG['chanlocs'][0]['labels']==sensor1, :, :].flatten('F'), n_convolution)
fft_data1 = fft(EEG['data'][EEG['chanlocs'][0]['labels']==sensor2, :, :].flatten('F'), n_convolution)
fft_data2
# Create wavelet and run convolution for both sensors
= fft(np.exp(2 * 1j * np.pi * centerfreq1 * time) * np.exp(-time ** 2 / (2 * (wavelet_cycles / (2 * np.pi * centerfreq1)) ** 2)), n_convolution)
fft_wavelet1 = ifft(fft_wavelet1 * fft_data1, n_convolution) * np.sqrt(wavelet_cycles / (2 * np.pi * centerfreq1))
convolution_result_fft1 = convolution_result_fft1[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft1 = np.abs(np.reshape(convolution_result_fft1, (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
analyticsignal1
= fft(np.exp(2 * 1j * np.pi * centerfreq2 * time) * np.exp(-time ** 2 / (2 * (wavelet_cycles / (2 * np.pi * centerfreq2)) ** 2)), n_convolution)
fft_wavelet2 = ifft(fft_wavelet2 * fft_data2, n_convolution) * np.sqrt(wavelet_cycles / (2 * np.pi * centerfreq2))
convolution_result_fft2 = convolution_result_fft2[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft2 = np.abs(np.reshape(convolution_result_fft2, (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
analyticsignal2
# Panel A: correlation in a specified window
= np.mean(analyticsignal1[timeidx1[0]:timeidx1[1] + 1, :], axis=0)
tfwindowdata1 = np.mean(analyticsignal2[timeidx2[0]:timeidx2[1] + 1, :], axis=0)
tfwindowdata2
=(12, 6))
plt.figure(figsize121)
plt.subplot('.')
plt.plot(tfwindowdata1, tfwindowdata2, f'TF window correlation, r_p={pearsonr(tfwindowdata1, tfwindowdata2)[0]:.4f}')
plt.title(f'{sensor1}: {timewin1[0]}-{timewin1[1]}; {centerfreq1} Hz')
plt.xlabel(f'{sensor2}: {timewin2[0]}-{timewin2[1]}; {centerfreq2} Hz')
plt.ylabel(
# Also plot rank-transformed data
122)
plt.subplot('.')
plt.plot(rankdata(tfwindowdata1), rankdata(tfwindowdata2), f'{sensor1}: {timewin1[0]}-{timewin1[1]}; {centerfreq1} Hz')
plt.xlabel(f'{sensor2}: {timewin2[0]}-{timewin2[1]}; {centerfreq2} Hz')
plt.ylabel(f'TF window correlation, r_p={spearmanr(tfwindowdata1, tfwindowdata2)[0]:.5f}')
plt.title(
plt.tight_layout()
plt.show()
# Panel B: correlation over time
= np.array([spearmanr(analyticsignal1[ti, :], analyticsignal2[ti, :])[0] for ti in range(EEG['pnts'][0, 0])])
corr_ts
plt.figure()'times'][0], corr_ts)
plt.plot(EEG[-200, 1200])
plt.xlim(['Time (ms)')
plt.xlabel("Spearman's rho")
plt.ylabel(
plt.show()
# Panel C: exploratory time-frequency power correlations
# Define times and frequencies for exploration
= np.arange(-200, 1225, 25) # in ms
times2save = np.logspace(np.log10(2), np.log10(40), 20)
frex
# Convert times to indices
= np.array([np.argmin(np.abs(EEG['times'][0] - t)) for t in times2save])
times2save_idx
# Rank-transforming the data can happen outside the frequency loop
= rankdata(tfwindowdata2)
seeddata_rank
# Initialize output correlation matrix
= np.zeros((len(frex), len(times2save)))
expl_corrs
for fi, freq in enumerate(frex):
# Get power (via wavelet convolution) from signal1
= fft(np.exp(2 * 1j * np.pi * freq * time) * np.exp(-time ** 2 / (2 * (wavelet_cycles / (2 * np.pi * freq)) ** 2)), n_convolution)
fft_wavelet = ifft(fft_wavelet * fft_data1, n_convolution) * np.sqrt(wavelet_cycles / (2 * np.pi * freq))
convolution_result_fft = convolution_result_fft[half_of_wavelet_size: -half_of_wavelet_size]
convolution_result_fft = np.abs(np.reshape(convolution_result_fft, (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
analyticsignal1
for ti, time_idx in enumerate(times2save_idx):
= 1 - 6 * np.sum((seeddata_rank - rankdata(analyticsignal1[time_idx, :])) ** 2) / (EEG['trials'][0, 0] * (EEG['trials'][0, 0] ** 2 - 1))
expl_corrs[fi, ti]
# Plot the exploratory time-frequency power correlations
plt.figure()40, cmap='viridis', extend='both')
plt.contourf(times2save, frex, expl_corrs, 'log')
plt.yscale(round(np.logspace(np.log10(frex[0]), np.log10(frex[-1]), 8)), np.round(np.logspace(np.log10(frex[0]), np.log10(frex[-1]), 8)))
plt.yticks(np.'Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel(f'Correlation over trials from seed {sensor2}, {centerfreq2} Hz and {timewin2[0]}-{timewin2[1]} ms')
plt.title(
plt.colorbar() plt.show()
Figure 27.7
# Define channels and parameters
= 'Fz'
seed_chan = 'F6'
target_chan = 'F1'
control_chan
= [0, 0.6]
clim
# Wavelet parameters
= 2
min_freq = 40
max_freq = 15
num_frex
# Downsampled times
= np.arange(-200, 850, 50)
times2save # times2save = EEG['times'][0]
# Other wavelet parameters
= np.logspace(np.log10(min_freq), np.log10(max_freq), num_frex)
frequencies = np.arange(-1, 1 + 1/EEG['srate'][0, 0], 1/EEG['srate'][0, 0])
time = (len(time) - 1) // 2
half_of_wavelet_size
# FFT parameters
= len(time)
n_wavelet = EEG['pnts'][0, 0] * EEG['trials'][0, 0]
n_data = n_wavelet + n_data - 1
n_convolution = 4.5
wavelet_cycles
= np.array([np.argmin(np.abs(EEG['times'][0] - t)) for t in times2save])
times2saveidx
# FFT of data for seed, target, and control channels
= fft(EEG['data'][EEG['chanlocs'][0]['labels']==seed_chan, :, :].flatten('F'), n_convolution)
fft_data_seed = fft(EEG['data'][EEG['chanlocs'][0]['labels']==target_chan, :, :].flatten('F'), n_convolution)
fft_data_trgt = fft(EEG['data'][EEG['chanlocs'][0]['labels']==control_chan, :, :].flatten('F'), n_convolution)
fft_data_ctrl
# Initialize output time-frequency data
= np.zeros((len(frequencies), len(times2save), 2))
tf_corrdata
for fi, freq in enumerate(frequencies):
# Create wavelet and get its FFT
= fft(np.exp(2 * 1j * np.pi * freq * time) * np.exp(-time ** 2 / (2 * (wavelet_cycles / (2 * np.pi * freq)) ** 2)) / freq, n_convolution)
fft_wavelet
# Convolution for seed, target, and control sites (save only power)
= np.abs(np.reshape(ifft(fft_wavelet * fft_data_seed, n_convolution)[half_of_wavelet_size: -half_of_wavelet_size], (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
conv_result_seed = np.abs(np.reshape(ifft(fft_wavelet * fft_data_trgt, n_convolution)[half_of_wavelet_size: -half_of_wavelet_size], (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
conv_result_trgt = np.abs(np.reshape(ifft(fft_wavelet * fft_data_ctrl, n_convolution)[half_of_wavelet_size: -half_of_wavelet_size], (EEG['pnts'][0, 0], EEG['trials'][0, 0]), 'F')) ** 2
conv_result_ctrl
# Downsample and rank transform all data
= rankdata(conv_result_seed[times2saveidx, :], axis=1)
conv_result_seed = rankdata(conv_result_trgt[times2saveidx, :], axis=1)
conv_result_trgt = rankdata(conv_result_ctrl[times2saveidx, :], axis=1)
conv_result_ctrl
for ti, time_idx in enumerate(times2saveidx):
# Compute bivariate correlations
= 1 - 6 * np.sum((conv_result_seed[ti, :] - conv_result_trgt[ti, :]) ** 2) / (EEG['trials'][0, 0] * (EEG['trials'][0, 0] ** 2 - 1))
r_st = 1 - 6 * np.sum((conv_result_seed[ti, :] - conv_result_ctrl[ti, :]) ** 2) / (EEG['trials'][0, 0] * (EEG['trials'][0, 0] ** 2 - 1))
r_sc = 1 - 6 * np.sum((conv_result_ctrl[ti, :] - conv_result_trgt[ti, :]) ** 2) / (EEG['trials'][0, 0] * (EEG['trials'][0, 0] ** 2 - 1))
r_tc
# Bivariate correlation for comparison
0] = r_st
tf_corrdata[fi, ti,
# Compute partial correlation and store in results matrix
1] = (r_st - r_sc * r_tc) / (np.sqrt(1 - r_sc ** 2) * np.sqrt(1 - r_tc ** 2))
tf_corrdata[fi, ti,
# Plot
=(12, 6))
plt.figure(figsizefor i in range(2):
1, 2, i + 1)
plt.subplot(40, cmap='viridis', extend='both')
plt.contourf(times2save, frequencies, tf_corrdata[:, :, i],
plt.clim(clim)-200, 800])
plt.xlim(['log')
plt.yscale(round(np.logspace(np.log10(frequencies[0]), np.log10(frequencies[-1]), 6), 1), np.round(np.logspace(np.log10(frequencies[0]), np.log10(frequencies[-1]), 6), 1))
plt.yticks(np.if i == 0:
f'Correlation between {seed_chan} and {target_chan}')
plt.title(else:
f'Partial correlation between {seed_chan} and {target_chan}')
plt.title('Time (ms)')
plt.xlabel('Frequency (Hz)')
plt.ylabel(
plt.tight_layout() plt.show()
Figure 27.8
Re-run the code for the previous figure but comment out the following line towards the top:
times2save = EEG['times'][0] # uncomment this line for figure 27.8
Then run this section of code.
# Downsample the time series
= np.array([np.argmin(np.abs(times2save - t)) for t in np.arange(-200, 850, 50)]) # Downsampled times
ds_timesidx = np.argmin(np.abs(frequencies - 4.7))
lofreq = np.argmin(np.abs(frequencies - 32))
hifreq
=(12, 12))
plt.figure(figsize
# Original (256 Hz) time-frequency plot
221)
plt.subplot(1], 40, cmap='viridis', extend='both')
plt.contourf(times2save, frequencies, tf_corrdata[:, :, * len(times2save), 'k--')
plt.plot(times2save, [frequencies[lofreq]] * len(times2save), 'k--')
plt.plot(times2save, [frequencies[hifreq]]
plt.clim(clim)-200, 800])
plt.xlim(['log')
plt.yscale(round(np.logspace(np.log10(frequencies[0]), np.log10(frequencies[-1]), 6)), np.round(np.logspace(np.log10(frequencies[0]), np.log10(frequencies[-1]), 6)))
plt.yticks(np.'Original (256 Hz)')
plt.title(
# Downsampled (20 Hz) time-frequency plot
222)
plt.subplot(1], 40, cmap='viridis', extend='both')
plt.contourf(times2save[ds_timesidx], frequencies, tf_corrdata[:, ds_timesidx, * len(times2save[ds_timesidx]), 'k--')
plt.plot(times2save[ds_timesidx], [frequencies[lofreq]] * len(times2save[ds_timesidx]), 'k--')
plt.plot(times2save[ds_timesidx], [frequencies[hifreq]]
plt.clim(clim)-200, 800])
plt.xlim(['log')
plt.yscale(round(np.logspace(np.log10(frequencies[0]), np.log10(frequencies[-1]), 6)), np.round(np.logspace(np.log10(frequencies[0]), np.log10(frequencies[-1]), 6)))
plt.yticks(np.'Down-sampled (20 Hz)')
plt.title(
# Effect of downsampling on low-frequency activity
223)
plt.subplot(1])
plt.plot(times2save, tf_corrdata[lofreq, :, 1], 'ro-', markerfacecolor='w')
plt.plot(times2save[ds_timesidx], tf_corrdata[lofreq, ds_timesidx, -200, 800])
plt.xlim([0.25, 0.65])
plt.ylim(['Effect of downsampling on low-frequency activity')
plt.title(
# Effect of downsampling on high-frequency activity
224)
plt.subplot(1])
plt.plot(times2save, tf_corrdata[hifreq, :, 1], 'ro-', markerfacecolor='w')
plt.plot(times2save[ds_timesidx], tf_corrdata[hifreq, ds_timesidx, -200, 800])
plt.xlim([-0.1, 0.6])
plt.ylim(['Effect of downsampling on high-frequency activity')
plt.title('Original (256 Hz)', 'Down-sampled (20 Hz)'])
plt.legend([
plt.tight_layout() plt.show()