Synchrony


In [1]:
import time
import os

import sqlite3

import pandas as pd
import numpy as np
import scipy as sp

import scipy.io as sio
import scipy.signal as sig

import plotly
plotly.offline.init_notebook_mode()


Intersubject phase synchronization

Load decomposed timeseries.


In [2]:
cf1_avg_lin_zal = pd.read_pickle('disco_decompose_coif1_average_linear_zalign.pkl')
cf1_avg_lin_zal.head()


Out[2]:
id t L00 L01 L02 L03 L04 L05 L06 L07 L08 L09 L10 L11 L12 L13 L14 L15 L16
0 1a 55544587.5 0.437819 0.363623 0.750461 0.706682 0.595032 1.382487 1.856779 -1.264673 -1.554573 -0.832260 0.025133 1.238817 3.034769 -6.937689 1.216199 3.843380 -3.213427
1 1a 55544603.5 0.456833 0.755834 1.077211 0.763299 0.679155 1.311234 1.873680 -1.247859 -1.545647 -0.847035 0.015576 1.231296 3.022003 -6.938942 1.215734 3.843811 -3.213433
2 1a 55544619.5 0.847117 1.148380 1.277645 0.878457 0.779679 1.218174 1.890706 -1.227848 -1.536669 -0.861238 0.006042 1.223817 3.009260 -6.940178 1.215276 3.844243 -3.213430
3 1a 55544635.5 0.977855 1.293980 1.357916 0.956800 0.835278 1.108216 1.900371 -1.208144 -1.530187 -0.876722 -0.004249 1.216065 2.996350 -6.941457 1.214779 3.844666 -3.213433
4 1a 55544651.5 0.922416 1.334348 1.350304 0.956692 0.856806 0.981870 1.905511 -1.189794 -1.525169 -0.892329 -0.014608 1.208243 2.983409 -6.942738 1.214269 3.845101 -3.213432

Compute intersubject phase synchronization across subjects for each frequency band.


In [77]:
def disco_ips(indata,intype,outdir,subjects):
    ''' Intersubject phase synchronization for group synchrony measure
    indata = Input data table (id,t,v0,v1...vn)
    intype = ('coif','db','sym') x ('ave','dec') x ('lin','nea','cub') x ('vec','xal','yal','zal')
    outdir = Output data directory
    subjects = List of subjects to include in analysis
    Returns: timeseries = Group synchrony values (id,t,v) '''
    
    function = 'disco_ips'
    print(time.strftime("%m/%d/%Y"),time.strftime("%H:%M:%S"),'Running',function)
    print(time.strftime("%m/%d/%Y"),time.strftime("%H:%M:%S"),'Subjects =',subjects)
    
    pairs = len(subjects) * (len(subjects)-1) / 2  # Number of subject pairs  
    levels = indata.drop(['id','t'],axis=1).shape[1]  # Number of frequency bands
    
    IPS = {} # Intersubject phase synchronization for each frequency band (samples x levels)
    for L in range(levels):
        
        print(time.strftime("%m/%d/%Y"),time.strftime("%H:%M:%S"),'Level =',L)
        
        # ADAPTED FROM CALCULATEPHASESYNCH.M (ISC TOOLBOX)        
        AD = [] # Angular distance at each time point for each subject pair
        for s1 in range(len(subjects)):            
            # Hilbert transform to obtain corresponding analytic signal
            t1 = sig.hilbert(indata[indata.id==subjects[s1]]['L'+str(L).zfill(2)])            
            for s2 in range(len(subjects)):
                if s2 > s1:
                    # print(time.strftime("%m/%d/%Y"),time.strftime("%H:%M:%S"),subjects[s1],subjects[s2])
                    t2 = sig.hilbert(indata[indata.id==subjects[s2]]['L'+str(L).zfill(2)])
                    AD.append(np.angle(t1)-np.angle(t2))
        
        if pairs == 1:
            absAD = np.absolute(AD)  # Absolute angular distance (Dissimilarity measure)
        else:
            absAD = np.sum(np.absolute(AD),0) / pairs  # Average of all subject-pairwise absolute angular distances
        
        IPS['L'+str(L).zfill(2)] = 1 - absAD / np.pi # Normalized version of (average) absolute angular distance(s)
        
    IPS = pd.DataFrame(IPS)
    T = pd.DataFrame({'t':indata[indata.id==subjects[s1]].t})
    timeseries = pd.concat([T,IPS],axis=1)
    
    outfile = function+'_'+intype+'.pkl'
    print(time.strftime("%m/%d/%Y"),time.strftime("%H:%M:%S"),'Saving',outfile)
    timeseries.to_pickle(os.path.join('.',outdir,outfile))
    
    print(time.strftime("%m/%d/%Y"),time.strftime("%H:%M:%S"),'Done') 
    return timeseries

In [78]:
ips_cf1_avg_lin_zal = disco_ips(cf1_avg_lin_zal,'coif1_average_linear_zalign','',['1b','2b','3b','4b','5b','6b'])


11/09/2016 03:30:08 Running disco_ips
11/09/2016 03:30:08 Subjects = ['1b', '2b', '3b', '4b', '5b', '6b']
11/09/2016 03:30:08 Level = 0
11/09/2016 03:30:12 Level = 1
11/09/2016 03:30:15 Level = 2
11/09/2016 03:30:18 Level = 3
11/09/2016 03:30:21 Level = 4
11/09/2016 03:30:24 Level = 5
11/09/2016 03:30:28 Level = 6
11/09/2016 03:30:31 Level = 7
11/09/2016 03:30:34 Level = 8
11/09/2016 03:30:37 Level = 9
11/09/2016 03:30:41 Level = 10
11/09/2016 03:30:44 Level = 11
11/09/2016 03:30:47 Level = 12
11/09/2016 03:30:50 Level = 13
11/09/2016 03:30:54 Level = 14
11/09/2016 03:30:57 Level = 15
11/09/2016 03:31:00 Level = 16
11/09/2016 03:31:03 Saving disco_ips_coif1_average_linear_zalign.pkl
11/09/2016 03:31:04 Done

In [80]:
ips_cf1_avg_lin_zal.head()


Out[80]:
t L00 L01 L02 L03 L04 L05 L06 L07 L08 L09 L10 L11 L12 L13 L14 L15 L16
0 55544587.5 0.481281 0.551853 0.628094 0.621870 0.633336 0.658082 0.663451 0.705617 0.717665 0.405483 0.724852 0.663643 0.525291 0.320369 0.680073 0.509882 -0.066665
1 55544603.5 0.509474 0.611329 0.615529 0.628370 0.643237 0.660562 0.666971 0.706839 0.718561 0.406814 0.724636 0.663621 0.525199 0.320339 0.680063 0.509876 -0.066667
2 55544619.5 0.621533 0.606133 0.604124 0.629953 0.651227 0.662885 0.670502 0.708015 0.719441 0.408094 0.724417 0.663598 0.525107 0.320308 0.680054 0.509871 -0.200000
3 55544635.5 0.610648 0.586856 0.586084 0.625281 0.655246 0.664850 0.673921 0.709166 0.720272 0.409320 0.724199 0.663578 0.525013 0.320278 0.680045 0.509865 -0.200000
4 55544651.5 0.581055 0.583297 0.572111 0.623581 0.659862 0.666910 0.677499 0.710354 0.721071 0.410456 0.723983 0.663556 0.524919 0.320247 0.680036 0.509859 -0.066666

Heat map of intersubject phase synchronization at each frequency band.


In [2]:
# Load synchrony timeseries
df = sio.loadmat('matlabfiles/disco_ips_coif1_mean_linear_zalign.mat',variable_names='IPS')
df = pd.DataFrame.transpose(pd.DataFrame(df['IPS']))

In [3]:
# Load condition times and names
timedb = sqlite3.connect('disco_millisecond_conditions.db')
query = "SELECT * FROM conditions;"
timedf = pd.read_sql_query(query,timedb)
timedb.close()

In [ ]:
samplingrate = 62.50 # Sampling rate in HZ (1000ms / 16ms)
minutes = np.arange(0,df.shape[0])/samplingrate/60 # Time in minutes (X)
frequency = [str('%.3f' %i) for i in samplingrate/2**np.arange(0,df.shape[1])] # Frequencies of levels (Y)

# Condition lines
conditions = []
for t in range(0+1,len(timedf)-1): # Not including first and last time points 
    X = (timedf['msec'][t]-timedf['msec'][0])/1000/60 # Convert to minutes from first time point   
    L = dict(x0=X,x1=X,y0=0-.5,y1=len(frequency)-.5,type='line',line=dict(width=1.5,dash='dot'))
    conditions.append(L)

# Synchrony values (Z)
values = []
for f in range(len(frequency)):
    values.append(df[f].tolist())

data = [plotly.graph_objs.Heatmap(
            z = values,
            x = minutes,
            y = frequency,
            colorscale = 'Viridis')]

layout = plotly.graph_objs.Layout(
            title = 'Intersubject Phase Sychrony (Pipeline: C=Z-align, I=Linear, D=Average, W=Coiflet/Short)',
            xaxis = dict(title='Time (minutes)',hoverformat='.3f',ticks='',zeroline=False),
            yaxis = dict(title='Frequency (Hz)',hoverformat='.3f',ticks='',autorange='reversed',type='category'),
            shapes = conditions)

print(''); print(timedf['name'][0:len(timedf)-1].tolist()) # Condition names

fig = plotly.graph_objs.Figure(data=data,layout=layout)
plotly.offline.iplot(fig)