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()


Cluster phase method

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 cluster phase method across subjects for each frequency band.


In [5]:
def disco_cpm(indata,intype,outdir,subjects):
    ''' Cluster phase method 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_cpm'
    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)
    
    levels = indata.drop(['id','t'],axis=1).shape[1]  # Number of frequency bands
    
    CPM = {} # Group rho timeseries 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)
    
        # Create table of subjects x samples for current level
        SUBJ = pd.DataFrame({})
        for S in subjects:
            temp = indata[indata.id==S]['L'+str(L).zfill(2)]
            SUBJ = pd.concat([SUBJ,temp],axis=1,ignore_index=True)
        SUBJ = pd.DataFrame.transpose(SUBJ)

        # ADAPTED FROM CLUSTERPHASE_DO.M
        
        # Compute phase for each timeseries using Hilbert transform
        hilbert = sig.hilbert(SUBJ)
        arctan2 = np.arctan2(np.real(hilbert),np.imag(hilbert))
        TSphase = np.unwrap(arctan2)
        
        # Compute mean running or cluster phase
        znumber = np.exp(1j*TSphase)
        ztotal = np.mean(znumber,axis=0)
        zangle = np.angle(ztotal)
        clusterphase = np.unwrap(zangle)

        # Compute relative phases between timeseries phase and cluster phase
        znumber = np.exp(1j*(TSphase-clusterphase))
        ztotal = np.mean(znumber,axis=1)
        TSRPM = np.angle(ztotal)
        TSRPM = np.tile(TSRPM,(len(clusterphase),1)).transpose() # So valid dimensions
        
        # Compute cluster amplitute in rotation frame                
        znumber = np.exp(1j*(TSphase-clusterphase-TSRPM))
        ztotal = np.mean(znumber,axis=0)
        TSrhoGRP = np.absolute(ztotal)
                         
        CPM['L'+str(L).zfill(2)] = TSrhoGRP
        
    CPM = pd.DataFrame(CPM)
    T = pd.DataFrame({'t':indata[indata.id==subjects[0]].t})
    timeseries = pd.concat([T,CPM],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 [6]:
cpm_cf1_avg_lin_zal = disco_cpm(cf1_avg_lin_zal,'coif1_average_linear_zalign','',['1b','2b','3b','4b','5b','6b'])


11/12/2016 23:14:06 Running disco_cpm
11/12/2016 23:14:06 Subjects = ['1b', '2b', '3b', '4b', '5b', '6b']
11/12/2016 23:14:06 Level = 0
11/12/2016 23:14:08 Level = 1
11/12/2016 23:14:09 Level = 2
11/12/2016 23:14:11 Level = 3
11/12/2016 23:14:12 Level = 4
11/12/2016 23:14:13 Level = 5
11/12/2016 23:14:15 Level = 6
11/12/2016 23:14:16 Level = 7
11/12/2016 23:14:17 Level = 8
11/12/2016 23:14:18 Level = 9
11/12/2016 23:14:20 Level = 10
11/12/2016 23:14:21 Level = 11
11/12/2016 23:14:22 Level = 12
11/12/2016 23:14:24 Level = 13
11/12/2016 23:14:25 Level = 14
11/12/2016 23:14:26 Level = 15
11/12/2016 23:14:28 Level = 16
11/12/2016 23:14:29 Saving disco_cpm_coif1_average_linear_zalign.pkl
11/12/2016 23:14:29 Done

In [7]:
cpm_cf1_avg_lin_zal.head()


Out[7]:
t L00 L01 L02 L03 L04 L05 L06 L07 L08 L09 L10 L11 L12 L13 L14 L15 L16
0 55544587.5 0.336933 0.508069 0.614726 0.607057 0.628867 0.634337 0.618694 0.616964 0.612939 0.537518 0.629720 0.646974 0.657050 0.338884 0.914695 0.989085 1.0
1 55544603.5 0.456023 0.593784 0.606154 0.610561 0.633510 0.635833 0.621102 0.618068 0.614161 0.535608 0.629446 0.646911 0.657006 0.338940 0.914708 0.989086 1.0
2 55544619.5 0.623966 0.596071 0.596884 0.613451 0.637380 0.637149 0.623482 0.619132 0.615354 0.533757 0.629167 0.646848 0.656962 0.338998 0.914720 0.989086 1.0
3 55544635.5 0.608524 0.582409 0.578821 0.611326 0.639681 0.638225 0.625684 0.620149 0.616540 0.532006 0.628891 0.646787 0.656919 0.339058 0.914732 0.989086 1.0
4 55544651.5 0.581289 0.582980 0.563335 0.612482 0.642358 0.639362 0.627938 0.621190 0.617739 0.530406 0.628618 0.646727 0.656876 0.339116 0.914744 0.989086 1.0

Heat map of cluster phase method at each frequency band.


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

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 = 'Cluster Phase Synchronization (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)