def preprocess_raw_data(block_path, config): """ Takes raw data and runs: 1) CAR 2) notch filters 3) Downsampling Parameters ---------- block_path : str subject file path config : dictionary 'CAR' - Number of channels to use in CAR (default=16) 'Notch' - Main frequency (Hz) for notch filters (default=60) 'Downsample' - Downsampling frequency (Hz, default= 400) Returns ------- Saves preprocessed signals (LFP) in the current NWB file. Only if containers for these data do not exist in the current file. """ subj_path, block_name = os.path.split(block_path) block_name = os.path.splitext(block_path)[0] start = time.time() with NWBHDF5IO(block_path, 'r+', load_namespaces=True) as io: nwb = io.read() # Storage of processed signals on NWB file ----------------------------- try: # if ecephys module already exists ecephys_module = nwb.processing['ecephys'] except: # creates ecephys ProcessingModule ecephys_module = ProcessingModule( name='ecephys', description='Extracellular electrophysiology data.') # Add module to NWB file nwb.add_processing_module(ecephys_module) print('Created ecephys') # LFP: Downsampled and power line signal removed ----------------------- if 'LFP' in nwb.processing[ 'ecephys'].data_interfaces: # if LFP already exists lfp = nwb.processing['ecephys'].data_interfaces['LFP'] lfp_ts = nwb.processing['ecephys'].data_interfaces[ 'LFP'].electrical_series['preprocessed'] else: # creates LFP data interface container lfp = LFP() # Data source lis = list(nwb.acquisition.keys()) for i in lis: # Check if there is ElectricalSeries in acquisition group if type(nwb.acquisition[i]).__name__ == 'ElectricalSeries': source = nwb.acquisition[i] nChannels = source.data.shape[1] # Downsampling extraBins0 = 0 fs = source.rate if config['Downsample'] is not None: print("Downsampling signals to " + str(config['Downsample']) + " Hz.") print("Please wait, this might take around 30 minutes.") start = time.time() #zeros to pad to make signal lenght a power of 2 nBins = source.data.shape[0] extraBins0 = 2**(np.ceil(np.log2(nBins)).astype('int')) - nBins extraZeros = np.zeros(extraBins0) rate = config['Downsample'] #One channel at a time, to improve memory usage for long signals for ch in np.arange(nChannels): #1e6 scaling helps with numerical accuracy Xch = source.data[:, ch] * 1e6 #Make lenght a power of 2, improves performance Xch = np.append(Xch, extraZeros) Xch = resample(Xch, rate, fs) if ch == 0: X = Xch.reshape(1, -1) else: X = np.append(X, Xch.reshape(1, -1), axis=0) print( 'Downsampling finished in {} seconds'.format(time.time() - start)) else: # No downsample rate = fs X = source.data[:, :].T * 1e6 # Subtract CAR if config['CAR'] is not None: print( "Computing and subtracting Common Average Reference in " + str(config['CAR']) + " channel blocks.") start = time.time() X = subtract_CAR(X, b_size=config['CAR']) print('CAR subtract time for {}: {} seconds'.format( block_name, time.time() - start)) # Apply Notch filters if config['Notch'] is not None: print("Applying Notch filtering of " + str(config['Notch']) + " Hz") #zeros to pad to make signal lenght a power of 2 nBins = X.shape[1] extraBins1 = 2**(np.ceil(np.log2(nBins)).astype('int')) - nBins extraZeros = np.zeros(extraBins1) start = time.time() for ch in np.arange(nChannels): Xch = np.append(X[ch, :], extraZeros).reshape(1, -1) Xch = linenoise_notch(Xch, rate, notch_freq=config['Notch']) if ch == 0: X2 = Xch.reshape(1, -1) else: X2 = np.append(X2, Xch.reshape(1, -1), axis=0) print('Notch filter time for {}: {} seconds'.format( block_name, time.time() - start)) X = np.copy(X2) del X2 #Remove excess bins (because of zero padding on previous steps) excessBins = int(np.ceil(extraBins0 * rate / fs) + extraBins1) X = X[:, 0:-excessBins] X = X.astype('float32') # signal (nChannels,nSamples) X /= 1e6 # Scales signals back to Volt # Add preprocessed downsampled signals as an electrical_series if config['CAR'] is None: car = 'None' else: car = str(config['CAR']) if config['Notch'] is None: notch = 'None' else: notch = str(config['Notch']) if config['Downsample'] is None: downs = 'No' else: downs = 'Yes' config_comment = 'CAR:' + car + ', Notch:' + notch + ', Downsampled:' + downs lfp_ts = lfp.create_electrical_series(name='preprocessed', data=X.T, electrodes=source.electrodes, rate=rate, description='', comments=config_comment) ecephys_module.add_data_interface(lfp) # Write LFP to NWB file io.write(nwb) print('LFP saved in ' + block_path)
def copy_obj(obj_old, nwb_old, nwb_new): """ Creates a copy of obj_old. """ # ElectricalSeries -------------------------------------------------------- if type(obj_old) is ElectricalSeries: nChannels = obj_old.electrodes.table['x'].data.shape[0] elecs_region = nwb_new.electrodes.create_region( name='electrodes', region=np.arange(nChannels).tolist(), description='' ) return ElectricalSeries( name=obj_old.name, data=obj_old.data[:], electrodes=elecs_region, rate=obj_old.rate, description=obj_old.description ) # DynamicTable ------------------------------------------------------------ if type(obj_old) is DynamicTable: return DynamicTable( name=obj_old.name, description=obj_old.description, colnames=obj_old.colnames, columns=obj_old.columns, ) # LFP --------------------------------------------------------------------- if type(obj_old) is LFP: obj = LFP(name=obj_old.name) assert len(obj_old.electrical_series) == 1, ( 'Expected precisely one electrical series, got %i!' % len(obj_old.electrical_series)) els = list(obj_old.electrical_series.values())[0] nChannels = els.data.shape[1] #### # first check for a table among the new file's data_interfaces if els.electrodes.table.name in nwb_new.processing[ 'ecephys'].data_interfaces: LFP_dynamic_table = nwb_new.processing['ecephys'].data_interfaces[ els.electrodes.table.name] else: # othewise use the electrodes as the table LFP_dynamic_table = nwb_new.electrodes #### elecs_region = LFP_dynamic_table.create_region( name='electrodes', region=[i for i in range(nChannels)], description=els.electrodes.description ) obj_ts = obj.create_electrical_series( name=els.name, comments=els.comments, conversion=els.conversion, data=els.data[:], description=els.description, electrodes=elecs_region, rate=els.rate, resolution=els.resolution, starting_time=els.starting_time ) return obj # TimeSeries -------------------------------------------------------------- if type(obj_old) is TimeSeries: return TimeSeries( name=obj_old.name, description=obj_old.description, data=obj_old.data[:], rate=obj_old.rate, resolution=obj_old.resolution, conversion=obj_old.conversion, starting_time=obj_old.starting_time, unit=obj_old.unit ) # DecompositionSeries ----------------------------------------------------- if type(obj_old) is DecompositionSeries: list_columns = [] for item in obj_old.bands.columns: bp = VectorData( name=item.name, description=item.description, data=item.data[:] ) list_columns.append(bp) bandsTable = DynamicTable( name=obj_old.bands.name, description=obj_old.bands.description, columns=list_columns, colnames=obj_old.bands.colnames ) return DecompositionSeries( name=obj_old.name, data=obj_old.data[:], description=obj_old.description, metric=obj_old.metric, unit=obj_old.unit, rate=obj_old.rate, # source_timeseries=lfp, bands=bandsTable, ) # Spectrum ---------------------------------------------------------------- if type(obj_old) is Spectrum: file_elecs = nwb_new.electrodes nChannels = len(file_elecs['x'].data[:]) elecs_region = file_elecs.create_region( name='electrodes', region=np.arange(nChannels).tolist(), description='' ) return Spectrum( name=obj_old.name, frequencies=obj_old.frequencies[:], power=obj_old.power, electrodes=elecs_region )
def preprocess_raw_data(block_path, config): """ Takes raw data and runs: 1) CAR 2) notch filters 3) Downsampling Parameters ---------- block_path : str subject file path config : dictionary 'referencing' - tuple specifying electrode referencing (type, options) ('CAR', N_channels_per_group) ('CMR', N_channels_per_group) ('bipolar', INCLUDE_OBLIQUE_NBHD) 'Notch' - Main frequency (Hz) for notch filters (default=60) 'Downsample' - Downsampling frequency (Hz, default= 400) Returns ------- Saves preprocessed signals (LFP) in the current NWB file. Only if containers for these data do not exist in the current file. """ subj_path, block_name = os.path.split(block_path) block_name = os.path.splitext(block_path)[0] start = time.time() with NWBHDF5IO(block_path, 'r+', load_namespaces=True) as io: nwb = io.read() # Storage of processed signals on NWB file ---------------------------- if 'ecephys' in nwb.processing: ecephys_module = nwb.processing['ecephys'] else: # creates ecephys ProcessingModule ecephys_module = ProcessingModule( name='ecephys', description='Extracellular electrophysiology data.') # Add module to NWB file nwb.add_processing_module(ecephys_module) print('Created ecephys') # LFP: Downsampled and power line signal removed ---------------------- if 'LFP' in nwb.processing['ecephys'].data_interfaces: warnings.warn( 'LFP data already exists in the nwb file. Skipping preprocessing.' ) else: # creates LFP data interface container lfp = LFP() # Data source source_list = [ acq for acq in nwb.acquisition.values() if type(acq) == ElectricalSeries ] assert len(source_list) == 1, ( 'Not precisely one ElectricalSeries in acquisition!') source = source_list[0] nChannels = source.data.shape[1] # Downsampling if config['Downsample'] is not None: print("Downsampling signals to " + str(config['Downsample']) + " Hz.") print("Please wait...") start = time.time() # Note: zero padding the signal to make the length # a power of 2 won't help, since resample will further pad it # (breaking the power of 2) nBins = source.data.shape[0] rate = config['Downsample'] # malloc T = int(np.ceil(nBins * rate / source.rate)) X = np.zeros((source.data.shape[1], T)) # One channel at a time, to improve memory usage for long signals for ch in np.arange(nChannels): # 1e6 scaling helps with numerical accuracy Xch = source.data[:, ch] * 1e6 X[ch, :] = resample(Xch, rate, source.rate) print( 'Downsampling finished in {} seconds'.format(time.time() - start)) else: # No downsample rate = source.rate X = source.data[()].T * 1e6 # re-reference the (scaled by 1e6!) data electrodes = source.electrodes if config['referencing'] is not None: if config['referencing'][0] == 'CAR': print( "Computing and subtracting Common Average Reference in " + str(config['referencing'][1]) + " channel blocks.") start = time.time() X = subtract_CAR(X, b_size=config['referencing'][1]) print('CAR subtract time for {}: {} seconds'.format( block_name, time.time() - start)) elif config['referencing'][0] == 'bipolar': X, bipolarTable, electrodes = get_bipolar_referenced_electrodes( X, electrodes, rate, grid_step=1) # add data interface for the metadata for saving ecephys_module.add_data_interface(bipolarTable) print('bipolarElectrodes stored for saving in ' + block_path) else: print('UNRECOGNIZED REFERENCING SCHEME; ', end='') print('SKIPPING REFERENCING!') # Apply Notch filters if config['Notch'] is not None: print("Applying notch filtering of " + str(config['Notch']) + " Hz") # Note: zero padding the signal to make the length a power # of 2 won't help, since notch filtering will further pad it start = time.time() for ch in np.arange(nChannels): # NOTE: apply_linenoise_notch takes a signal that is # (n_timePoints, n_channels). The documentation may be wrong Xch = X[ch, :].reshape(-1, 1) Xch = apply_linenoise_notch(Xch, rate) X[ch, :] = Xch[:, 0] print('Notch filter time for {}: {} seconds'.format( block_name, time.time() - start)) X = X.astype('float32') # signal (nChannels,nSamples) X /= 1e6 # Scales signals back to volts # Add preprocessed downsampled signals as an electrical_series referencing = 'None' if config['referencing'] is None else config[ 'referencing'][0] notch = 'None' if config['Notch'] is None else str(config['Notch']) downs = 'No' if config['Downsample'] is None else 'Yes' config_comment = ('referencing:' + referencing + ', Notch:' + notch + ', Downsampled:' + downs) # create an electrical series for the LFP and store it in lfp lfp.create_electrical_series(name='preprocessed', data=X.T, electrodes=electrodes, rate=rate, description='', comments=config_comment) ecephys_module.add_data_interface(lfp) # Write LFP to NWB file io.write(nwb) print('LFP saved in ' + block_path)
def preprocess_raw_data(block_path, config): """ Takes raw data and runs: 1) CAR 2) notch filters 3) Downsampling Parameters ---------- block_path : str subject file path config : dictionary 'referencing' - tuple specifying electrode referencing (type, options) ('CAR', N_channels_per_group) ('CMR', N_channels_per_group) ('bipolar', INCLUDE_OBLIQUE_NBHD) 'Notch' - Main frequency (Hz) for notch filters (default=60) 'Downsample' - Downsampling frequency (Hz, default= 400) Returns ------- Saves preprocessed signals (LFP) in the current NWB file. Only if containers for these data do not exist in the current file. """ subj_path, block_name = os.path.split(block_path) block_name = os.path.splitext(block_path)[0] start = time.time() with NWBHDF5IO(block_path, 'r+', load_namespaces=True) as io: nwb = io.read() # Storage of processed signals on NWB file ---------------------------- if 'ecephys' in nwb.processing: ecephys_module = nwb.processing['ecephys'] else: # creates ecephys ProcessingModule ecephys_module = ProcessingModule( name='ecephys', description='Extracellular electrophysiology data.') # Add module to NWB file nwb.add_processing_module(ecephys_module) print('Created ecephys') # LFP: Downsampled and power line signal removed ---------------------- if 'LFP' in nwb.processing['ecephys'].data_interfaces: ###### # What's the point of this? Nothing is done with these vars... lfp = nwb.processing['ecephys'].data_interfaces['LFP'] lfp_ts = nwb.processing['ecephys'].data_interfaces[ 'LFP'].electrical_series['preprocessed'] ###### else: # creates LFP data interface container lfp = LFP() # Data source source_list = [ acq for acq in nwb.acquisition.values() if type(acq) == ElectricalSeries ] assert len(source_list) == 1, ( 'Not precisely one ElectricalSeries in acquisition!') source = source_list[0] nChannels = source.data.shape[1] # Downsampling if config['Downsample'] is not None: print("Downsampling signals to " + str(config['Downsample']) + " Hz.") print("Please wait, this might take around 30 minutes.") start = time.time() # zeros to pad to make signal length a power of 2 nBins = source.data.shape[0] extraBins0 = 2**(np.ceil(np.log2(nBins)).astype('int')) - nBins extraZeros = np.zeros(extraBins0) rate = config['Downsample'] # malloc T = int(np.ceil((nBins + extraBins0) * rate / source.rate)) X = np.zeros((source.data.shape[1], T)) # One channel at a time, to improve memory usage for long signals for ch in np.arange(nChannels): # 1e6 scaling helps with numerical accuracy Xch = source.data[:, ch] * 1e6 # Make length a power of 2, improves performance Xch = np.append(Xch, extraZeros) X[ch, :] = resample(Xch, rate, source.rate) print( 'Downsampling finished in {} seconds'.format(time.time() - start)) else: # No downsample extraBins0 = 0 rate = source.rate X = source.data[()].T * 1e6 # re-reference the (scaled by 1e6!) data electrodes = source.electrodes if config['referencing'] is not None: if config['referencing'][0] == 'CAR': print( "Computing and subtracting Common Average Reference in " + str(config['referencing'][1]) + " channel blocks.") start = time.time() X = subtract_CAR(X, b_size=config['referencing'][1]) print('CAR subtract time for {}: {} seconds'.format( block_name, time.time() - start)) elif config['referencing'][0] == 'bipolar': X, bipolarTable, electrodes = get_bipolar_referenced_electrodes( X, electrodes, rate, grid_step=1) # add data interface for the metadata for saving ecephys_module.add_data_interface(bipolarTable) print('bipolarElectrodes stored for saving in ' + block_path) else: print('UNRECOGNIZED REFERENCING SCHEME; ', end='') print('SKIPPING REFERENCING!') # Apply Notch filters if config['Notch'] is not None: print("Applying notch filtering of " + str(config['Notch']) + " Hz") # zeros to pad to make signal lenght a power of 2 nBins = X.shape[1] extraBins1 = 2**(np.ceil(np.log2(nBins)).astype('int')) - nBins extraZeros = np.zeros(extraBins1) start = time.time() for ch in np.arange(nChannels): Xch = np.append(X[ch, :], extraZeros).reshape(1, -1) Xch = linenoise_notch(Xch, rate, notch_freq=config['Notch']) if ch == 0: X2 = Xch.reshape(1, -1) else: X2 = np.append(X2, Xch.reshape(1, -1), axis=0) print('Notch filter time for {}: {} seconds'.format( block_name, time.time() - start)) X = np.copy(X2) del X2 else: extraBins1 = 0 # Remove excess bins (because of zero padding on previous steps) excessBins = int( np.ceil(extraBins0 * rate / source.rate) + extraBins1) X = X[:, 0:-excessBins] X = X.astype('float32') # signal (nChannels,nSamples) X /= 1e6 # Scales signals back to volts # Add preprocessed downsampled signals as an electrical_series referencing = 'None' if config['referencing'] is None else config[ 'referencing'][0] notch = 'None' if config['Notch'] is None else str(config['Notch']) downs = 'No' if config['Downsample'] is None else 'Yes' config_comment = ('referencing:' + referencing + ',Notch:' + notch + ', Downsampled:' + downs) # create an electrical series for the LFP and store it in lfp lfp_ts = lfp.create_electrical_series(name='preprocessed', data=X.T, electrodes=electrodes, rate=rate, description='', comments=config_comment) ecephys_module.add_data_interface(lfp) # Write LFP to NWB file io.write(nwb) print('LFP saved in ' + block_path)
def transform(block_path, filter='default', bands_vals=None): """ Takes raw LFP data and does the standard Hilbert algorithm: 1) CAR 2) notch filters 3) Hilbert transform on different bands Takes about 20 minutes to run on 1 10-min block. Parameters ---------- block_path : str subject file path filter: str, optional Frequency bands to filter the signal. 'default' for Chang lab default values (Gaussian filters) 'custom' for user defined (Gaussian filters) bands_vals: 2D array, necessary only if filter='custom' [2,nBands] numpy array with Gaussian filter parameters, where: bands_vals[0,:] = filter centers [Hz] bands_vals[1,:] = filter sigmas [Hz] Returns ------- Saves preprocessed signals (LFP) and spectral power (DecompositionSeries) in the current NWB file. Only if containers for these data do not exist in the file. """ write_file = 1 rate = 400. # Define filter parameters if filter == 'default': band_param_0 = bands.chang_lab['cfs'] band_param_1 = bands.chang_lab['sds'] elif filter == 'high_gamma': band_param_0 = bands.chang_lab['cfs'][(bands.chang_lab['cfs'] > 70) & (bands.chang_lab['cfs'] < 150)] band_param_1 = bands.chang_lab['sds'][(bands.chang_lab['cfs'] > 70) & (bands.chang_lab['cfs'] < 150)] #band_param_0 = [ bands.neuro['min_freqs'][-1] ] #for hamming window filter #band_param_1 = [ bands.neuro['max_freqs'][-1] ] #band_param_0 = bands.chang_lab['cfs'][29:37] #for average of gaussian filters #band_param_1 = bands.chang_lab['sds'][29:37] elif filter == 'custom': band_param_0 = bands_vals[0, :] band_param_1 = bands_vals[1, :] block_name = os.path.splitext(block_path)[0] start = time.time() with NWBHDF5IO(block_path, 'a') as io: nwb = io.read() # Storage of processed signals on NWB file ----------------------------- if 'ecephys' not in nwb.modules: # Add module to NWB file nwb.create_processing_module( name='ecephys', description='Extracellular electrophysiology data.') ecephys_module = nwb.modules['ecephys'] # LFP: Downsampled and power line signal removed if 'LFP' in nwb.modules['ecephys'].data_interfaces: lfp_ts = nwb.modules['ecephys'].data_interfaces[ 'LFP'].electrical_series['preprocessed'] X = lfp_ts.data[:].T rate = lfp_ts.rate else: # 1e6 scaling helps with numerical accuracy X = nwb.acquisition['ECoG'].data[:].T * 1e6 fs = nwb.acquisition['ECoG'].rate bad_elects = load_bad_electrodes(nwb) print('Load time for h5 {}: {} seconds'.format( block_name, time.time() - start)) print('rates {}: {} {}'.format(block_name, rate, fs)) if not np.allclose(rate, fs): assert rate < fs start = time.time() X = resample(X, rate, fs) print('resample time for {}: {} seconds'.format( block_name, time.time() - start)) if bad_elects.sum() > 0: X[bad_elects] = np.nan # Subtract CAR start = time.time() X = subtract_CAR(X) print('CAR subtract time for {}: {} seconds'.format( block_name, time.time() - start)) # Apply Notch filters start = time.time() X = linenoise_notch(X, rate) print('Notch filter time for {}: {} seconds'.format( block_name, time.time() - start)) lfp = LFP() # Add preprocessed downsampled signals as an electrical_series lfp_ts = lfp.create_electrical_series( name='preprocessed', data=X.T, electrodes=nwb.acquisition['ECoG'].electrodes, rate=rate, description='') ecephys_module.add_data_interface(lfp) # Spectral band power if 'Bandpower_' + filter not in nwb.modules['ecephys'].data_interfaces: # Apply Hilbert transform X = X.astype('float32') # signal (nChannels,nSamples) nChannels = X.shape[0] nSamples = X.shape[1] nBands = len(band_param_0) Xp = np.zeros((nBands, nChannels, nSamples)) # power (nBands,nChannels,nSamples) X_fft_h = None for ii, (bp0, bp1) in enumerate(zip(band_param_0, band_param_1)): # if filter=='high_gamma': # kernel = hamming(X, rate, bp0, bp1) # else: kernel = gaussian(X, rate, bp0, bp1) X_analytic, X_fft_h = hilbert_transform(X, rate, kernel, phase=None, X_fft_h=X_fft_h) Xp[ii] = abs(X_analytic).astype('float32') # Scales signals back to Volt X /= 1e6 band_param_0V = VectorData( name='filter_param_0', description='frequencies for bandpass filters', data=band_param_0) band_param_1V = VectorData( name='filter_param_1', description='frequencies for bandpass filters', data=band_param_1) bandsTable = DynamicTable( name='bands', description='Series of filters used for Hilbert transform.', columns=[band_param_0V, band_param_1V], colnames=['filter_param_0', 'filter_param_1']) # data: (ndarray) dims: num_times * num_channels * num_bands Xp = np.swapaxes(Xp, 0, 2) decs = DecompositionSeries( name='Bandpower_' + filter, data=Xp, description='Band power estimated with Hilbert transform.', metric='power', unit='V**2/Hz', bands=bandsTable, rate=rate, source_timeseries=lfp_ts) ecephys_module.add_data_interface(decs) io.write(nwb) print('done', flush=True)
def copy_obj(obj_old, nwb_old, nwb_new): """ Creates a copy of obj_old. """ # ElectricalSeries -------------------------------------------------------- if type(obj_old) is ElectricalSeries: # If reference electrodes table is bipolar scheme if isinstance(obj_old.electrodes.table, BipolarSchemeTable): bst_old = obj_old.electrodes.table bst_old_df = bst_old.to_dataframe() bst_new = nwb_new.lab_meta_data['ecephys_ext'].bipolar_scheme_table for id, row in bst_old_df.iterrows(): index_anodes = row['anodes'].index.tolist() index_cathodes = row['cathodes'].index.tolist() bst_new.add_row(anodes=index_anodes, cathodes=index_cathodes) bst_new.anodes.table = nwb_new.electrodes bst_new.cathodes.table = nwb_new.electrodes # if there are custom columns new_cols = list(bst_old_df.columns) default_cols = ['anodes', 'cathodes'] [new_cols.remove(col) for col in default_cols] for col in new_cols: col_data = list(bst_old[col].data[:]) bst_new.add_column(name=str(col), description=str(bst_old[col].description), data=col_data) elecs_region = DynamicTableRegion(name='electrodes', data=bst_old_df.index.tolist(), description='desc', table=bst_new) else: region = np.array(obj_old.electrodes.table.id[:])[ obj_old.electrodes.data[:]].tolist() elecs_region = nwb_new.create_electrode_table_region( name='electrodes', region=region, description='') els = ElectricalSeries(name=obj_old.name, data=obj_old.data[:], electrodes=elecs_region, rate=obj_old.rate, description=obj_old.description) return els # DynamicTable ------------------------------------------------------------ if type(obj_old) is DynamicTable: return DynamicTable( name=obj_old.name, description=obj_old.description, colnames=obj_old.colnames, columns=obj_old.columns, ) # LFP --------------------------------------------------------------------- if type(obj_old) is LFP: obj = LFP(name=obj_old.name) assert len(obj_old.electrical_series) == 1, ( 'Expected precisely one electrical series, got %i!' % len(obj_old.electrical_series)) els = list(obj_old.electrical_series.values())[0] #### # first check for a table among the new file's data_interfaces if els.electrodes.table.name in nwb_new.processing[ 'ecephys'].data_interfaces: LFP_dynamic_table = nwb_new.processing['ecephys'].data_interfaces[ els.electrodes.table.name] else: # othewise use the electrodes as the table LFP_dynamic_table = nwb_new.electrodes #### region = np.array( els.electrodes.table.id[:])[els.electrodes.data[:]].tolist() elecs_region = LFP_dynamic_table.create_region( name='electrodes', region=region, description=els.electrodes.description) obj.create_electrical_series(name=els.name, comments=els.comments, conversion=els.conversion, data=els.data[:], description=els.description, electrodes=elecs_region, rate=els.rate, resolution=els.resolution, starting_time=els.starting_time) return obj # TimeSeries -------------------------------------------------------------- if type(obj_old) is TimeSeries: return TimeSeries(name=obj_old.name, description=obj_old.description, data=obj_old.data[:], rate=obj_old.rate, resolution=obj_old.resolution, conversion=obj_old.conversion, starting_time=obj_old.starting_time, unit=obj_old.unit) # DecompositionSeries ----------------------------------------------------- if type(obj_old) is DecompositionSeries: list_columns = [] for item in obj_old.bands.columns: bp = VectorData(name=item.name, description=item.description, data=item.data[:]) list_columns.append(bp) bandsTable = DynamicTable(name=obj_old.bands.name, description=obj_old.bands.description, columns=list_columns, colnames=obj_old.bands.colnames) return DecompositionSeries( name=obj_old.name, data=obj_old.data[:], description=obj_old.description, metric=obj_old.metric, unit=obj_old.unit, rate=obj_old.rate, # source_timeseries=lfp, bands=bandsTable, ) # Spectrum ---------------------------------------------------------------- if type(obj_old) is Spectrum: file_elecs = nwb_new.electrodes nChannels = len(file_elecs['x'].data[:]) elecs_region = file_elecs.create_region( name='electrodes', region=np.arange(nChannels).tolist(), description='') return Spectrum(name=obj_old.name, frequencies=obj_old.frequencies[:], power=obj_old.power, electrodes=elecs_region) # Survey tables ------------------------------------------------------------ if obj_old.neurodata_type == 'SurveyTable': if obj_old.name == 'nrs_survey_table': n_rows = len(obj_old['nrs_pain_intensity_rating'].data) for i in range(n_rows): nrs_survey_table.add_row( **{c: obj_old[c][i] for c in obj_old.colnames}) return nrs_survey_table elif obj_old.name == 'vas_survey_table': n_rows = len(obj_old['vas_pain_intensity_rating'].data) for i in range(n_rows): vas_survey_table.add_row( **{c: obj_old[c][i] for c in obj_old.colnames}) return vas_survey_table elif obj_old.name == 'mpq_survey_table': n_rows = len(obj_old['throbbing'].data) for i in range(n_rows): mpq_survey_table.add_row( **{c: obj_old[c][i] for c in obj_old.colnames}) return mpq_survey_table