def test_access_group_after_io(self): """ Motivated by #739 """ nwbfile = NWBFile('a', 'b', datetime.now(tzlocal())) device = nwbfile.create_device('a') elecgrp = nwbfile.create_electrode_group('a', 'b', device=device, location='a') nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'a', 'a', elecgrp, id=0) with NWBHDF5IO('electrodes_mwe.nwb', 'w') as io: io.write(nwbfile) with NWBHDF5IO('electrodes_mwe.nwb', 'a') as io: nwbfile_i = io.read() for aa, bb in zip(nwbfile_i.electrodes['group'][:], nwbfile.electrodes['group'][:]): self.assertEqual(aa.name, bb.name) for i in range(4): nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'a', 'a', elecgrp, id=i + 1) with NWBHDF5IO('electrodes_mwe.nwb', 'w') as io: io.write(nwbfile) with NWBHDF5IO('electrodes_mwe.nwb', 'a') as io: nwbfile_i = io.read() for aa, bb in zip(nwbfile_i.electrodes['group'][:], nwbfile.electrodes['group'][:]): self.assertEqual(aa.name, bb.name) remove_test_file("electrodes_mwe.nwb")
def test_create_electrode_group_invalid_index(self): """ Test the case where the user creates an electrode table region with indexes that are out of range of the amount of electrodes added. """ nwbfile = NWBFile('a', 'b', 'c', datetime.now()) device = nwbfile.create_device('a', 'b') elecgrp = nwbfile.create_electrode_group('a', 'b', 'c', device=device, location='a') for i in range(4): nwbfile.add_electrode(i, np.nan, np.nan, np.nan, np.nan, group=elecgrp, location='a', filtering='a', description='a') with self.assertRaises(IndexError) as err: nwbfile.create_electrode_table_region(list(range(6)), 'test') self.assertTrue('out of range' in str(err.exception))
def setUp(self): nwbfile = NWBFile( 'my first synthetic recording', 'EXAMPLE_ID', datetime.now(tzlocal()), experimenter='Dr. Matthew Douglass', lab='Vision Neuroscience Laboratory', institution='University of Middle Earth at the Shire', experiment_description= 'We recorded from macaque monkeys during memory-guided saccade task', session_id='LONELYMTL') device = nwbfile.create_device(name='trodes_rig123') electrode_group = nwbfile.create_electrode_group( name='tetrode1', description='an example tetrode', location='somewhere in the hippocampus', device=device) for idx in [1, 2, 3, 4]: nwbfile.add_electrode(id=idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location='CA1', filtering='none', group=electrode_group) electrode_table_region = nwbfile.create_electrode_table_region( [0, 2], 'the first and third electrodes') self.electrodes = electrode_table_region
def test_io(): nwbfile = NWBFile('description', 'id', datetime.now().astimezone()) device = nwbfile.create_device('device_test') group = nwbfile.create_electrode_group(name='electrodes', description='label', device=device, location='brain') for i in range(4): nwbfile.add_electrode(x=float(i), y=float(i), z=float(i), imp=np.nan, location='', filtering='', group=group) bipolar_scheme_table = BipolarSchemeTable(name='bipolar_scheme_table', description='desc') bipolar_scheme_table.anodes.table = nwbfile.electrodes bipolar_scheme_table.cathodes.table = nwbfile.electrodes bipolar_scheme_table.add_row(anodes=[0], cathodes=[1]) bipolar_scheme_table.add_row(anodes=[0, 1], cathodes=[2, 3]) ecephys_ext = EcephysExt(name='ecephys_ext') ecephys_ext.bipolar_scheme_table = bipolar_scheme_table nwbfile.add_lab_meta_data(ecephys_ext) st = StimTable( name='stimtable', description='stimulation parameters', # bipolar_table=bipolar_scheme_table ) # calling this before `add_run` obviates bipolar_table=bipolar_scheme_table above. # You can add it to the NWBFile later, but you'll need to specify bipolar_table manually nwbfile.add_time_intervals(st) frequencies = [10., 10.] amplitudes = [5., 5.] pulse_widths = [2., 3.] for i in range(2): st.add_run(start_time=np.nan, stop_time=np.nan, frequency=frequencies[i], amplitude=amplitudes[i], pulse_width=pulse_widths[i], bipolar_pair=i) with NWBHDF5IO('test_file.nwb', 'w') as io: io.write(nwbfile) # Make a 300 timepoint waveform time series for 2 electrodes (one # cathode, and one anode). current_data = np.random.randn(300, 2)
def write_recording(recording, save_path, acquisition_name='ElectricalSeries'): assert HAVE_NWB, "To use the Nwb extractors, install pynwb: \n\n pip install pynwb\n\n" M = recording.get_num_channels() nwbfile = NWBFile( session_description='', identifier='', session_start_time=datetime.now(), ) device = nwbfile.create_device(name='device_name') eg_name = 'electrode_group_name' eg_description = "electrode_group_description" eg_location = "electrode_group_location" electrode_group = nwbfile.create_electrode_group( name=eg_name, location=eg_location, device=device, description=eg_description ) for m in range(M): location = recording.get_channel_property(m, 'location') impedence = -1.0 while len(location) < 3: location = np.append(location, [0]) nwbfile.add_electrode( id=m, x=float(location[0]), y=float(location[1]), z=float(location[2]), imp=impedence, location='electrode_location', filtering='none', group=electrode_group, ) electrode_table_region = nwbfile.create_electrode_table_region( list(range(M)), 'electrode_table_region' ) rate = recording.get_sampling_frequency() ephys_data = recording.get_traces().T ephys_ts = ElectricalSeries( name=acquisition_name, data=ephys_data, electrodes=electrode_table_region, starting_time=recording.frame_to_time(0), rate=rate, resolution=1e-6, comments='Generated from SpikeInterface::NwbRecordingExtractor', description='acquisition_description' ) nwbfile.add_acquisition(ephys_ts) if os.path.exists(save_path): os.remove(save_path) with NWBHDF5IO(save_path, 'w') as io: io.write(nwbfile)
def setUp(self): nwbfile = NWBFile( "my first synthetic recording", "EXAMPLE_ID", datetime.now(tzlocal()), experimenter="Dr. Matthew Douglass", lab="Vision Neuroscience Laboratory", institution="University of Middle Earth at the Shire", experiment_description= "We recorded from macaque monkeys during memory-guided saccade task", session_id="LONELYMTL", ) device = nwbfile.create_device(name="trodes_rig123") electrode_group = nwbfile.create_electrode_group( name="tetrode1", description="an example tetrode", location="somewhere in the hippocampus", device=device, ) for idx in [1, 2, 3, 4]: nwbfile.add_electrode( id=idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location="CA1", filtering="none", group=electrode_group, ) electrode_table_region = nwbfile.create_electrode_table_region( [0, 2], "the first and third electrodes") self.electrodes = electrode_table_region rate = 10.0 np.random.seed(1234) data_len = 1000 ephys_data = np.random.rand(data_len * 2).reshape((data_len, 2)) ephys_timestamps = np.arange(data_len) / rate self.ephys_ts = ElectricalSeries( "test_ephys_data", ephys_data, self.electrodes, timestamps=ephys_timestamps, resolution=0.001, description="Random numbers generated with numpy.random.rand", ) self.lfp = LFP(electrical_series=self.ephys_ts, name="LFP data")
def test_ext(): nwbfile = NWBFile('description', 'id', datetime.now().astimezone()) device = nwbfile.create_device('device_name') electrode_group = nwbfile.create_electrode_group('electrode_group', 'desc', 'loc', device=device) for i in np.arange(20.): nwbfile.add_electrode(i, i, i, np.nan, 'loc', 'filt', electrode_group) bipolar_scheme = DynamicTable(name='bipolar_scheme', description='desc') bipolar_scheme.add_column(name='anode', description='desc', index=True, table=nwbfile.electrodes) bipolar_scheme.add_column(name='cathode', description='desc', index=True, table=nwbfile.electrodes) bipolar_scheme.add_row(anode=[0], cathode=[1]) bipolar_scheme.add_row(anode=[0, 1], cathode=[2, 3]) bipolar_scheme.add_row(anode=[0, 1], cathode=[2]) ecephys_ext = EcephysExt(bipolar_scheme=bipolar_scheme) nwbfile.add_lab_meta_data(ecephys_ext) bipolar_scheme_region = DynamicTableRegion( name='electrodes', data=np.arange(0, 3), description='desc', table=nwbfile.lab_meta_data['extracellular_ephys_extensions']. bipolar_scheme) ec_series = ElectricalSeries(name='test_ec_series', description='desc', data=np.random.rand(100, 3), rate=1000., electrodes=bipolar_scheme_region) nwbfile.add_acquisition(ec_series) with NWBHDF5IO('test_nwb.nwb', 'w') as io: io.write(nwbfile) with NWBHDF5IO('test_nwb.nwb', 'r', load_namespaces=True) as io: nwbfile = io.read() assert_array_equal( nwbfile.acquisition['test_ec_series'].electrodes.table['anode'][2] ['x'], [0., 1.]) os.remove('test_nwb.nwb')
def test_append(self): FILENAME = 'test_append.nwb' nwb = NWBFile(session_description='hi', identifier='hi', session_start_time=datetime(1970, 1, 1, 12, tzinfo=tzutc())) proc_mod = nwb.create_processing_module(name='test_proc_mod', description='') proc_inter = LFP(name='test_proc_dset') proc_mod.add_data_interface(proc_inter) device = nwb.create_device(name='test_device') e_group = nwb.create_electrode_group(name='test_electrode_group', description='', location='', device=device) nwb.add_electrode(x=0.0, y=0.0, z=0.0, imp=np.nan, location='', filtering='', group=e_group) electrodes = nwb.create_electrode_table_region(region=[0], description='') e_series = ElectricalSeries( name='test_device', electrodes=electrodes, data=np.ones(shape=(100, )), rate=10000.0, ) proc_inter.add_electrical_series(e_series) with NWBHDF5IO(FILENAME, mode='w') as io: io.write(nwb) with NWBHDF5IO(FILENAME, mode='a') as io: nwb = io.read() elec = nwb.modules['test_proc_mod']['LFP'].electrical_series[ 'test_device'].electrodes ts2 = ElectricalSeries(name='timeseries2', data=[4, 5, 6], rate=1.0, electrodes=elec) nwb.add_acquisition(ts2) io.write(nwb) with NWBHDF5IO(FILENAME, mode='r') as io: nwb = io.read() np.testing.assert_equal(nwb.acquisition['timeseries2'].data[:], ts2.data)
def create(cls, nwb_content: NWBFile, fl_electrode: FlElectrode): validate_parameters_not_none(__name__, fl_electrode.electrode_group, fl_electrode.electrode_id) nwb_content.add_electrode(x=0.0, y=0.0, z=0.0, imp=0.0, location='None', filtering='None', group=fl_electrode.electrode_group, id=fl_electrode.electrode_id)
def test_create_electrode_group_invalid_index(self): """ Test the case where the user creates an electrode table region with indexes that are out of range of the amount of electrodes added. """ nwbfile = NWBFile('a', 'b', datetime.now(tzlocal())) device = nwbfile.create_device('a') elecgrp = nwbfile.create_electrode_group('a', 'b', device=device, location='a') for i in range(4): nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'a', 'a', elecgrp, id=i) with self.assertRaises(IndexError): nwbfile.create_electrode_table_region(list(range(6)), 'test')
class TestAppend(TestCase): def setUp(self): self.nwbfile = NWBFile(session_description='hi', identifier='hi', session_start_time=datetime(1970, 1, 1, 12, tzinfo=tzutc())) self.path = "test_append.nwb" def tearDown(self): remove_test_file(self.path) def test_append(self): proc_mod = self.nwbfile.create_processing_module(name='test_proc_mod', description='') proc_inter = LFP(name='LFP') proc_mod.add(proc_inter) device = self.nwbfile.create_device(name='test_device') e_group = self.nwbfile.create_electrode_group( name='test_electrode_group', description='', location='', device=device ) self.nwbfile.add_electrode(x=0.0, y=0.0, z=0.0, imp=np.nan, location='', filtering='', group=e_group) electrodes = self.nwbfile.create_electrode_table_region(region=[0], description='') e_series = ElectricalSeries( name='test_es', electrodes=electrodes, data=np.ones(shape=(100,)), rate=10000.0, ) proc_inter.add_electrical_series(e_series) with NWBHDF5IO(self.path, mode='w') as io: io.write(self.nwbfile, cache_spec=False) with NWBHDF5IO(self.path, mode='a') as io: nwb = io.read() link_electrodes = nwb.processing['test_proc_mod']['LFP'].electrical_series['test_es'].electrodes ts2 = ElectricalSeries(name='timeseries2', data=[4., 5., 6.], rate=1.0, electrodes=link_electrodes) nwb.add_acquisition(ts2) io.write(nwb) # also attempt to write same spec again self.assertIs(nwb.processing['test_proc_mod']['LFP'].electrical_series['test_es'].electrodes, nwb.acquisition['timeseries2'].electrodes) with NWBHDF5IO(self.path, mode='r') as io: nwb = io.read() np.testing.assert_equal(nwb.acquisition['timeseries2'].data[:], ts2.data) self.assertIs(nwb.processing['test_proc_mod']['LFP'].electrical_series['test_es'].electrodes, nwb.acquisition['timeseries2'].electrodes) errors = validate(io) for e in errors: print('ERROR', e)
class My_NWB_Writer: def __init__(self, filename, name, description, session_id='MyHome'): self.io = NWBHDF5IO(filename, 'w') self.nwbfile = NWBFile(name, name.replace(' ', '_'), datetime.now(tzlocal()), experimenter='Francesco Cavarretta', lab='Jaeger lab', institution='Emory University', experiment_description=description, session_id=session_id) self.device = self.nwbfile.create_device(name='ThalamicRelayCell') self.electrode_group = self.nwbfile.create_electrode_group( 'ThalamicRelayCell_000', description= "Thalamic Relay Cell somatic traces, Mouselight Morphologies", location="VM Thalamus", device=self.device) self.nwbfile.add_electrode(id=1, imp=-1.0, x=0.0, y=0.0, z=0.0, location="VM Thalamus", filtering='none', group=self.electrode_group) self.electrode_table_region = self.nwbfile.create_electrode_table_region( [0], 'an electrode') def write(self, name, t, v, description, comments=""): self.nwbfile.add_acquisition( ElectricalSeries(name, v, self.electrode_table_region, timestamps=t, resolution=0.001, comments=comments, description=description)) def close(self): self.io.write(self.nwbfile) self.io.close()
def setUp(self): nwbfile = NWBFile( "my first synthetic recording", "EXAMPLE_ID", datetime.now(tzlocal()), experimenter="Dr. Matthew Douglass", lab="Vision Neuroscience Laboratory", institution="University of Middle Earth at the Shire", experiment_description= "We recorded from macaque monkeys during memory-guided saccade task", session_id="LONELYMTL", ) device = nwbfile.create_device(name="trodes_rig123") electrode_group = nwbfile.create_electrode_group( name="tetrode1", description="an example tetrode", location="somewhere in the hippocampus", device=device, ) for idx in [1, 2, 3, 4]: nwbfile.add_electrode( id=idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location="CA1", filtering="none", group=electrode_group, ) electrode_table_region = nwbfile.create_electrode_table_region( [0, 2], "the first and third electrodes") self.electrodes = electrode_table_region
def set_up_nwbfile(): nwbfile = NWBFile(session_description='session_description', identifier='identifier', session_start_time=datetime.datetime.now( datetime.timezone.utc)) device = nwbfile.create_device(name='device_name') electrode_group = nwbfile.create_electrode_group(name='electrode_group', description='description', location='location', device=device) for i in np.arange(10.): nwbfile.add_electrode(x=i, y=i, z=i, imp=np.nan, location='location', filtering='filtering', group=electrode_group) return nwbfile
def generate_nwbfile(nchannels=4): """Generate an `NWBFile` object that an `ElectricalSeries` can be added to. Returns ------- nwbfile : NWBFile NWBFile object Device : Device Device for the ElectricalSeries electrode_group : ElectrodeGroup ElectrodeGroup for the ElectricalSeries electrodes : Electrodes Electrodes for the ElectricalSeries """ start_time = datetime(2020, 12, 31, 11, 28, tzinfo=tzlocal()) nwbfile = NWBFile( session_description='Demonstrate `process_nwb` on an NWBFile', identifier='NWB123', session_start_time=start_time) device = nwbfile.create_device(name='ECoG_grid') electrode_group = nwbfile.create_electrode_group('Grid', description='Grid', location='cortex', device=device) for idx in range(nchannels): nwbfile.add_electrode(id=idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location='cortex', filtering='none', group=electrode_group) electrodes = nwbfile.create_electrode_table_region(list(range(nchannels)), 'Electrodes') return nwbfile, device, electrode_group, electrodes
def export_to_nwb(session_key, nwb_output_dir=default_nwb_output_dir, save=False, overwrite=True): this_session = (acquisition.Session & session_key).fetch1() # =============================================================================== # ============================== META INFORMATION =============================== # =============================================================================== # -- NWB file - a NWB2.0 file for each session experimenter = (acquisition.Session.Experimenter & session_key).fetch1('experimenter') nwbfile = NWBFile(identifier='_'.join( [this_session['subject'], this_session['session_time'].strftime('%Y-%m-%d %H:%M:%S')]), related_publications='https://www.nature.com/articles/s41586-018-0633-x', experiment_description='Extracelluar recording in ALM', session_description='', session_start_time=this_session['session_time'], file_create_date=datetime.now(tzlocal()), experimenter=experimenter, institution=institution, keywords=['motor planning', 'anterior lateral cortex', 'ALM', 'Extracellular recording', 'optogenetics']) # -- subject subj = (subject.Subject & session_key).fetch1() nwbfile.subject = pynwb.file.Subject( subject_id=str(this_session['subject']), genotype=' x '.join((subject.Zygosity & subj).fetch('allele')) \ if len(subject.Zygosity & subj) else 'unknown', sex=subj['sex'], species=subj['species'], date_of_birth=datetime.combine(subj['date_of_birth'], zero_zero_time) if subj['date_of_birth'] else None) # -- virus nwbfile.virus = json.dumps([{k: str(v) for k, v in virus_injection.items() if k not in subj} for virus_injection in action.VirusInjection * reference.Virus & session_key]) # =============================================================================== # ======================== EXTRACELLULAR & CLUSTERING =========================== # =============================================================================== """ In the event of multiple probe recording (i.e. multiple probe insertions), the clustering results (and the associated units) are associated with the corresponding probe. Each probe insertion is associated with one ElectrodeConfiguration (which may define multiple electrode groups) """ dj_insert_location = ephys.ProbeInsertion for probe_insertion in ephys.ProbeInsertion & session_key: probe = (reference.Probe & probe_insertion).fetch1() electrode_group = nwbfile.create_electrode_group( name=probe['probe_type'] + '_g1', description='N/A', device=nwbfile.create_device(name=probe['probe_type']), location=json.dumps({k: str(v) for k, v in (dj_insert_location & session_key).fetch1().items() if k not in dj_insert_location.primary_key})) for chn in (reference.Probe.Channel & probe).fetch(as_dict=True): nwbfile.add_electrode( id=chn['channel_id']-1, group=electrode_group, filtering=hardware_filter, imp=-1., x=np.nan, y=np.nan, z=np.nan, location=(dj_insert_location & session_key).fetch1('brain_location')) # --- unit spike times --- nwbfile.add_unit_column(name='cell_type', description='cell type (e.g. fast spiking or pyramidal)') nwbfile.add_unit_column(name='sampling_rate', description='sampling rate of the waveform, Hz') spk_times_all = np.hstack((ephys.UnitSpikeTimes & probe_insertion).fetch('spike_times')) obs_min = np.min(spk_times_all) obs_max = np.max(spk_times_all) for unit in (ephys.UnitSpikeTimes & probe_insertion).fetch(as_dict=True): nwbfile.add_unit(id=unit['unit_id'], electrodes=[unit['channel']-1], electrode_group=electrode_group, cell_type=unit['unit_cell_type'], spike_times=unit['spike_times'], obs_intervals=np.array([[obs_min - 0.001, obs_max + 0.001]]), waveform_mean=np.mean(unit['spike_waveform'], axis=0), waveform_sd=np.std(unit['spike_waveform'], axis=0), sampling_rate=20000) # =============================================================================== # ============================= PHOTO-STIMULATION =============================== # =============================================================================== stim_sites = {} for photostim in acquisition.PhotoStim * reference.BrainLocation & session_key: stim_device = (nwbfile.get_device(photostim['photo_stim_method']) if photostim['photo_stim_method'] in nwbfile.devices else nwbfile.create_device(name=photostim['photo_stim_method'])) stim_site = pynwb.ogen.OptogeneticStimulusSite( name=photostim['brain_location'], device=stim_device, excitation_lambda=float(photostim['photo_stim_wavelength']), location=json.dumps({k: str(v) for k, v in photostim.items() if k in acquisition.PhotoStim.heading.names and k not in acquisition.PhotoStim.primary_key + ['photo_stim_method', 'photo_stim_wavelength']}), description='') nwbfile.add_ogen_site(stim_site) # =============================================================================== # =============================== BEHAVIOR TRIALS =============================== # =============================================================================== # =============== TrialSet ==================== # NWB 'trial' (of type dynamic table) by default comes with three mandatory attributes: 'start_time' and 'stop_time' # Other trial-related information needs to be added in to the trial-table as additional columns (with column name # and column description) dj_trial = acquisition.Session * behavior.TrialSet.Trial skip_adding_columns = acquisition.Session.primary_key + \ ['trial_id', 'trial_start_idx', 'trial_end_idx', 'trial_start_time', 'session_note'] if behavior.TrialSet.Trial & session_key: # Get trial descriptors from TrialSet.Trial and TrialStimInfo trial_columns = [{'name': tag.replace('trial_', ''), 'description': re.sub('\s+:|\s+', ' ', re.search( f'(?<={tag})(.*)', str(dj_trial.heading)).group()).strip()} for tag in dj_trial.heading.names if tag not in skip_adding_columns] # Add new table columns to nwb trial-table for trial-label for c in trial_columns: nwbfile.add_trial_column(**c) # Add entry to the trial-table for trial in (dj_trial & session_key).fetch(as_dict=True): trial['start_time'] = float(trial['trial_start_time']) trial['stop_time'] = float(trial['trial_start_time']) + 5.0 trial['trial_pole_in_time'] = trial['start_time'] + trial['trial_pole_in_time'] trial['trial_pole_out_time'] = trial['start_time'] + trial['trial_pole_out_time'] trial['trial_cue_time'] = trial['start_time'] + trial['trial_cue_time'] [trial.pop(k) for k in skip_adding_columns] for k in trial.keys(): if 'trial_' in k: trial[k.replace('trial_', '')] = trial.pop(k) nwbfile.add_trial(**trial) # =============== Write NWB 2.0 file =============== if save: save_file_name = ''.join([nwbfile.identifier, '.nwb']) if not os.path.exists(nwb_output_dir): os.makedirs(nwb_output_dir) if not overwrite and os.path.exists(os.path.join(nwb_output_dir, save_file_name)): return nwbfile with NWBHDF5IO(os.path.join(nwb_output_dir, save_file_name), mode='w') as io: io.write(nwbfile) print(f'Write NWB 2.0 file: {save_file_name}') return nwbfile
def main(): import os.path # prerequisites: start import numpy as np rate = 10.0 np.random.seed(1234) data_len = 1000 ephys_data = np.random.rand(data_len) ephys_timestamps = np.arange(data_len) / rate spatial_timestamps = ephys_timestamps[::10] spatial_data = np.cumsum(np.random.normal(size=(2, len(spatial_timestamps))), axis=-1).T # prerequisites: end # create-nwbfile: start from datetime import datetime from dateutil.tz import tzlocal from pynwb import NWBFile f = NWBFile( 'the PyNWB tutorial', 'my first synthetic recording', 'EXAMPLE_ID', datetime.now(tzlocal()), experimenter='Dr. Bilbo Baggins', lab='Bag End Laboratory', institution='University of Middle Earth at the Shire', experiment_description= 'I went on an adventure with thirteen dwarves to reclaim vast treasures.', session_id='LONELYMTN') # create-nwbfile: end # save-nwbfile: start from pynwb import NWBHDF5IO filename = "example.h5" io = NWBHDF5IO(filename, mode='w') io.write(f) io.close() # save-nwbfile: end os.remove(filename) # create-device: start device = f.create_device(name='trodes_rig123', source="a source") # create-device: end # create-electrode-groups: start electrode_name = 'tetrode1' source = "an hypothetical source" description = "an example tetrode" location = "somewhere in the hippocampus" electrode_group = f.create_electrode_group(electrode_name, source=source, description=description, location=location, device=device) # create-electrode-groups: end # create-electrode-table-region: start for idx in [1, 2, 3, 4]: f.add_electrode(idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location='CA1', filtering='none', description='channel %s' % idx, group=electrode_group) electrode_table_region = f.create_electrode_table_region( [0, 2], 'the first and third electrodes') # create-electrode-table-region: end # create-timeseries: start from pynwb.ecephys import ElectricalSeries from pynwb.behavior import SpatialSeries ephys_ts = ElectricalSeries( 'test_ephys_data', 'an hypothetical source', ephys_data, electrode_table_region, timestamps=ephys_timestamps, # Alternatively, could specify starting_time and rate as follows # starting_time=ephys_timestamps[0], # rate=rate, resolution=0.001, comments= "This data was randomly generated with numpy, using 1234 as the seed", description="Random numbers generated with numpy.random.rand") f.add_acquisition(ephys_ts) spatial_ts = SpatialSeries( 'test_spatial_timeseries', 'a stumbling rat', spatial_data, 'origin on x,y-plane', timestamps=spatial_timestamps, resolution=0.1, comments="This data was generated with numpy, using 1234 as the seed", description="This 2D Brownian process generated with " "np.cumsum(np.random.normal(size=(2, len(spatial_timestamps))), axis=-1).T" ) f.add_acquisition(spatial_ts) # create-timeseries: end # create-data-interface: start from pynwb.ecephys import LFP from pynwb.behavior import Position lfp = f.add_acquisition(LFP('a hypothetical source')) ephys_ts = lfp.create_electrical_series( 'test_ephys_data', 'an hypothetical source', ephys_data, electrode_table_region, timestamps=ephys_timestamps, resolution=0.001, comments= "This data was randomly generated with numpy, using 1234 as the seed", # noqa: E501 description="Random numbers generated with numpy.random.rand") pos = f.add_acquisition(Position('a hypothetical source')) spatial_ts = pos.create_spatial_series( 'test_spatial_timeseries', 'a stumbling rat', spatial_data, 'origin on x,y-plane', timestamps=spatial_timestamps, resolution=0.1, comments="This data was generated with numpy, using 1234 as the seed", description="This 2D Brownian process generated with " "np.cumsum(np.random.normal(size=(2, len(spatial_timestamps))), axis=-1).T" ) # noqa: E501 # create-data-interface: end # create-epochs: start epoch_tags = ('example_epoch', ) f.add_epoch(name='epoch1', start_time=0.0, stop_time=1.0, tags=epoch_tags, description="the first test epoch", timeseries=[ephys_ts, spatial_ts]) f.add_epoch(name='epoch2', start_time=0.0, stop_time=1.0, tags=epoch_tags, description="the second test epoch", timeseries=[ephys_ts, spatial_ts]) # create-epochs: end # create-compressed-timeseries: start from pynwb.ecephys import ElectricalSeries from pynwb.behavior import SpatialSeries from pynwb.form.backends.hdf5 import H5DataIO ephys_ts = ElectricalSeries( 'test_compressed_ephys_data', 'an hypothetical source', H5DataIO(ephys_data, compress=True), electrode_table_region, timestamps=H5DataIO(ephys_timestamps, compress=True), resolution=0.001, comments= "This data was randomly generated with numpy, using 1234 as the seed", description="Random numbers generated with numpy.random.rand") f.add_acquisition(ephys_ts) spatial_ts = SpatialSeries( 'test_compressed_spatial_timeseries', 'a stumbling rat', H5DataIO(spatial_data, compress=True), 'origin on x,y-plane', timestamps=H5DataIO(spatial_timestamps, compress=True), resolution=0.1, comments="This data was generated with numpy, using 1234 as the seed", description="This 2D Brownian process generated with " "np.cumsum(np.random.normal(size=(2, len(spatial_timestamps))), axis=-1).T" ) f.add_acquisition(spatial_ts)
def write_multiple_nwb_files(root_dir='/tmp'): rec_datetime = date_parser.parse('03/22/2018 15:35:22') block = 'Site1' recording_name = '{}_{}'.format('bird', block) nwb_file = os.path.join(root_dir, '{}.nwb'.format(recording_name)) session_desc = "A single recording session" exp_desc = "An experiment." nf = NWBFile(recording_name, session_desc, 'bird', rec_datetime, experimenter='Experi Menter', lab='The Lab', institution='University of Shaz', experiment_description=exp_desc, session_id='bird') hemi = 'L' electrode_array_name = '16 electrode microwire array on {} hemisphere'.format( hemi) electrode_array = nf.create_device(name=electrode_array_name, source='') # create an electrode group egrp_desc = """ The (x,y) locations of the electrodes refer to the distance from region midline and distance from L2A, respectively, in mm. """ electrode_group = nf.create_electrode_group( hemi, source=electrode_array_name, description=egrp_desc, location='{} Hemisphere, Field L, CM, NCM'.format(hemi), device=electrode_array) # add electrodes to electrode group electrode_start = 0 if hemi == 'R': electrode_start = 16 electrode_numbers = list(np.arange(electrode_start, electrode_start + 16)) for electrode_number in electrode_numbers: nf.add_electrode(electrode_number - 1, x=np.random.randn(), y=np.random.randn(), z=0.0, imp=0.0, location='cortex', filtering='none', description='An electrode', group=electrode_group) # create an electrode table region etable = nf.create_electrode_table_region( electrode_numbers, 'All electrodes in array for hemisphere {} with LFP'.format(hemi)) lfp_data = np.random.randn(len(electrode_numbers), 1000) sr = 1000. t = np.arange(lfp_data.shape[1]) / sr # add the raw LFP lfp_series_name = 'Multi-electrode LFP on {} hemisphere from block {}'.format( hemi, block) lfp = ElectricalSeries( lfp_series_name, electrode_array_name, lfp_data, etable, timestamps=t, resolution=1e-12, comments='', description='Low-passed LFP recorded from microwire array') # add the spikes and their waveforms electrode_number = 0 spike_times = [0.5, 1.5, 3.5] waveforms = np.random.randn(3, 18) sort_type = 'Multi-unit' full_unit_name = '{} on electrode {}'.format(sort_type, electrode_number) spikes = SpikeEventSeries( full_unit_name, lfp_series_name, waveforms, spike_times, etable, resolution=1e-12, conversion=1e6, comments='', description='', ) print('\tAdding spikes acquisition: {} ({}), waveforms.shape={}'.format( full_unit_name, sort_type, str(waveforms.shape))) # adding the LFP is fine nf.add_acquisition(lfp) ######################################################## # adding even a single spike event series causes the error ######################################################## nf.add_acquisition(spikes) print('Writing to {}'.format(nwb_file)) with NWBHDF5IO(nwb_file, mode='w') as io: io.write(nf) del nf
location=location, device=device) ####################### # After setting up electrode group metadata, you should add metadata about the individual electrodes comprising # each electrode group. This is done with :py:func:`~pynwb.file.NWBFile.add_electrode`. # # The first argument to :py:class:`~pynwb.file.NWBFile.add_electrode` is a unique identifier that the user should # assign. For details on the rest of the arguments, please see the # :py:func:`API documentation <pynwb.file.NWBFile.add_electrode>`. for idx in [1, 2, 3, 4]: nwbfile.add_electrode(idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location='CA1', filtering='none', description='channel %s' % idx, group=electrode_group) ####################### # .. note: :py:class:`~pynwb.file.NWBFile.add_electrode` returns the index of the electrode you just added. # This can come in handy when creating with an :py:class:`~pynwb.ecephys.ElectrodeTableRegion` # :py:class:`~pynwb.file.NWBFile.create_electrode_table_region` (See :ref:`ec_recordings`). ####################### # .. _ec_recordings: # # Extracellular recordings # ^^^^^^^^^^^^^^^^^^^^^^^^ #
class Alyx2NWBConverter: def __init__(self, saveloc=None, nwb_metadata_file=None, metadata_obj: Alyx2NWBMetadata = None, one_object: ONE = None, save_raw=False, save_camera_raw=False, complevel=4, shuffle=False, buffer_size=1): """ Retrieve all Alyx session, subject metadata, raw data for eid using the one apis load method Map that to nwb supported datatypes and create an nwb file. Parameters ---------- saveloc: str, Path save location of nwbfile nwb_metadata_file: [dict, str] output of Alyx2NWBMetadata as a dict/json location str metadata_obj: Alyx2NWBMetadata one_object: ONE() save_raw: bool will load and save large raw files: ecephys.raw.ap/lf.cbin to nwb save_camera_raw: bool will load and save mice camera movie .mp4: _iblrig_Camera.raw complevel: int level of compression to apply to raw datasets (0-9)>(low,high). https://docs.h5py.org/en/latest/high/dataset.html shuffle: bool Enable shuffle I/O filter. http://docs.h5py.org/en/latest/high/dataset.html#dataset-shuffle """ self.buffer_size = buffer_size self.complevel = complevel self.shuffle = shuffle if nwb_metadata_file is not None: if isinstance(nwb_metadata_file, dict): self.nwb_metadata = nwb_metadata_file elif isinstance(nwb_metadata_file, str): with open(nwb_metadata_file, 'r') as f: self.nwb_metadata = json.load(f) elif metadata_obj is not None: self.nwb_metadata = metadata_obj.complete_metadata else: raise Exception( 'required one of argument: nwb_metadata_file OR metadata_obj') if one_object is not None: self.one_object = one_object elif metadata_obj is not None: self.one_object = metadata_obj.one_obj else: Warning('creating a ONE object and continuing') self.one_object = ONE() if saveloc is None: Warning('saving nwb file in current working directory') self.saveloc = str(Path.cwd()) else: self.saveloc = str(saveloc) self.eid = self.nwb_metadata["eid"] if not isinstance(self.nwb_metadata['NWBFile']['session_start_time'], datetime): self.nwb_metadata['NWBFile']['session_start_time'] = \ datetime.strptime(self.nwb_metadata['NWBFile']['session_start_time'], '%Y-%m-%dT%X').replace( tzinfo=pytz.utc) self.nwb_metadata['IBLSubject']['date_of_birth'] = \ datetime.strptime(self.nwb_metadata['IBLSubject']['date_of_birth'], '%Y-%m-%dT%X').replace( tzinfo=pytz.utc) # create nwbfile: self.initialize_nwbfile() self.no_probes = len(self.nwb_metadata['Probes']) if self.no_probes == 0: warnings.warn( 'could not find probe information, will create trials, behavior, acquisition' ) self.electrode_table_exist = False self._one_data = _OneData(self.one_object, self.eid, self.no_probes, self.nwb_metadata, save_raw=save_raw, save_camera_raw=save_camera_raw) def initialize_nwbfile(self): """ Creates self.nwbfile, devices and electrode group of nwb file. """ nwbfile_args = dict(identifier=str(uuid.uuid4()), ) nwbfile_args.update(**self.nwb_metadata['NWBFile']) self.nwbfile = NWBFile(**nwbfile_args) # create devices [ self.nwbfile.create_device(**idevice_meta) for idevice_meta in self.nwb_metadata['Ecephys']['Device'] ] if 'ElectrodeGroup' in self.nwb_metadata['Ecephys']: self.create_electrode_groups(self.nwb_metadata['Ecephys']) def create_electrode_groups(self, metadata_ecephys): """ This method is called at __init__. Use metadata to create ElectrodeGroup object(s) in the NWBFile Parameters ---------- metadata_ecephys : dict Dict with key:value pairs for defining the Ecephys group from where this ElectrodeGroup belongs. This should contain keys for required groups such as 'Device', 'ElectrodeGroup', etc. """ for metadata_elec_group in metadata_ecephys['ElectrodeGroup']: eg_name = metadata_elec_group['name'] # Tests if ElectrodeGroup already exists aux = [i.name == eg_name for i in self.nwbfile.children] if any(aux): print(eg_name + ' already exists in current NWBFile.') else: device_name = metadata_elec_group['device'] if device_name in self.nwbfile.devices: device = self.nwbfile.devices[device_name] else: print('Device ', device_name, ' for ElectrodeGroup ', eg_name, ' does not exist.') print('Make sure ', device_name, ' is defined in metadata.') eg_description = metadata_elec_group['description'] eg_location = metadata_elec_group['location'] self.nwbfile.create_electrode_group(name=eg_name, location=eg_location, device=device, description=eg_description) def check_module(self, name, description=None): """ Check if processing module exists. If not, create it. Then return module Parameters ---------- name: str description: str | None (optional) Returns ------- pynwb.module """ if name in self.nwbfile.processing: return self.nwbfile.processing[name] else: if description is None: description = name return self.nwbfile.create_processing_module(name, description) def create_stimulus(self): """ Creates stimulus data in nwbfile """ stimulus_list = self._get_data( self.nwb_metadata['Stimulus'].get('time_series')) for i in stimulus_list: self.nwbfile.add_stimulus(pynwb.TimeSeries(**i)) def create_units(self): """ Units table in nwbfile """ if self.no_probes == 0: return if not self.electrode_table_exist: self.create_electrode_table_ecephys() unit_table_list = self._get_data(self.nwb_metadata['Units']) # no required arguments for units table. Below are default columns in the table. default_args = [ 'id', 'waveform_mean', 'electrodes', 'electrode_group', 'spike_times', 'obs_intervals' ] default_ids = _get_default_column_ids( default_args, [i['name'] for i in unit_table_list]) if len(default_ids) != len(default_args): warnings.warn(f'could not find all of {default_args} clusters') non_default_ids = list( set(range(len(unit_table_list))).difference(set(default_ids))) default_dict = { unit_table_list[id]['name']: unit_table_list[id]['data'] for id in default_ids } for cluster_no in range(len(unit_table_list[0]['data'])): add_dict = dict() for ibl_dataset_name in default_dict: if ibl_dataset_name == 'electrodes': add_dict.update({ ibl_dataset_name: [default_dict[ibl_dataset_name][cluster_no]] }) if ibl_dataset_name == 'spike_times': add_dict.update({ ibl_dataset_name: default_dict[ibl_dataset_name][cluster_no] }) elif ibl_dataset_name == 'obs_intervals': # common across all clusters add_dict.update( {ibl_dataset_name: default_dict[ibl_dataset_name]}) elif ibl_dataset_name == 'electrode_group': add_dict.update({ ibl_dataset_name: self.nwbfile.electrode_groups[self.nwb_metadata[ 'Probes'][default_dict[ibl_dataset_name] [cluster_no]]['name']] }) elif ibl_dataset_name == 'id': if cluster_no >= self._one_data.data_attrs_dump[ 'unit_table_length'][0]: add_dict.update({ ibl_dataset_name: default_dict[ibl_dataset_name][cluster_no] + self._one_data.data_attrs_dump['unit_table_length'] [0] }) else: add_dict.update({ ibl_dataset_name: default_dict[ibl_dataset_name][cluster_no] }) elif ibl_dataset_name == 'waveform_mean': add_dict.update({ ibl_dataset_name: np.mean(default_dict[ibl_dataset_name][cluster_no], axis=1) }) # finding the mean along all the channels of the sluter self.nwbfile.add_unit(**add_dict) for id in non_default_ids: if isinstance(unit_table_list[id]['data'], object): unit_table_list[id]['data'] = unit_table_list[id][ 'data'].tolist() # convert string numpy self.nwbfile.add_unit_column( name=unit_table_list[id]['name'], description=unit_table_list[id]['description'], data=unit_table_list[id]['data']) def create_electrode_table_ecephys(self): """ Creates electrode table """ if self.no_probes == 0: return if self.electrode_table_exist: pass electrode_table_list = self._get_data( self.nwb_metadata['ElectrodeTable']) # electrode table has required arguments: required_args = ['group', 'x', 'y'] default_ids = _get_default_column_ids( required_args, [i['name'] for i in electrode_table_list]) non_default_ids = list( set(range(len(electrode_table_list))).difference(set(default_ids))) default_dict = { electrode_table_list[id]['name']: electrode_table_list[id]['data'] for id in default_ids } if 'group' in default_dict: group_labels = default_dict['group'] else: # else fill with probe zero data. group_labels = np.concatenate([ np.ones(self._one_data. data_attrs_dump['electrode_table_length'][i], dtype=int) * i for i in range(self.no_probes) ]) for electrode_no in range(len(electrode_table_list[0]['data'])): if 'x' in default_dict: x = default_dict['x'][electrode_no][0] y = default_dict['y'][electrode_no][1] else: x = float('NaN') y = float('NaN') group_data = self.nwbfile.electrode_groups[self.nwb_metadata[ 'Probes'][group_labels[electrode_no]]['name']] self.nwbfile.add_electrode(x=x, y=y, z=float('NaN'), imp=float('NaN'), location='None', group=group_data, filtering='none') for id in non_default_ids: self.nwbfile.add_electrode_column( name=electrode_table_list[id]['name'], description=electrode_table_list[id]['description'], data=electrode_table_list[id]['data']) # create probes specific DynamicTableRegion: self.probe_dt_region = [ self.nwbfile.create_electrode_table_region(region=list( range(self._one_data.data_attrs_dump['electrode_table_length'] [j])), description=i['name']) for j, i in enumerate(self.nwb_metadata['Probes']) ] self.probe_dt_region_all = self.nwbfile.create_electrode_table_region( region=list( range( sum(self._one_data. data_attrs_dump['electrode_table_length']))), description='AllProbes') self.electrode_table_exist = True def create_timeseries_ecephys(self): """ create SpikeEventSeries, ElectricalSeries, Spectrum datatypes within nwbfile>processing>ecephys """ if self.no_probes == 0: return if not self.electrode_table_exist: self.create_electrode_table_ecephys() if 'ecephys' not in self.nwbfile.processing: mod = self.nwbfile.create_processing_module( 'ecephys', 'Processed electrophysiology data of IBL') else: mod = self.nwbfile.get_processing_module('ecephys') for neurodata_type_name, neurodata_type_args_list in self.nwb_metadata[ 'Ecephys']['Ecephys'].items(): data_retrieved_args_list = self._get_data( neurodata_type_args_list ) # list of dicts with keys as argument names for no, neurodata_type_args in enumerate(data_retrieved_args_list): ibl_dataset_name = neurodata_type_args_list[no]['data'] if 'ElectricalSeries' in neurodata_type_name: timestamps_names = self._one_data.data_attrs_dump[ '_iblqc_ephysTimeRms.timestamps'] data_names = self._one_data.data_attrs_dump[ '_iblqc_ephysTimeRms.rms'] for data_idx, data in enumerate( neurodata_type_args['data']): probe_no = [ j for j in range(self.no_probes) if self.nwb_metadata['Probes'][j]['name'] in data_names[data_idx] ][0] if data.shape[1] > self._one_data.data_attrs_dump[ 'electrode_table_length'][probe_no]: if 'channels.rawInd' in self._one_data.loaded_datasets: channel_idx = self._one_data.loaded_datasets[ 'channels.rawInd'][probe_no].data.astype( 'int') else: warnings.warn('could not find channels.rawInd') break else: channel_idx = slice(None) mod.add( ElectricalSeries( name=data_names[data_idx], description=neurodata_type_args['description'], timestamps=neurodata_type_args['timestamps'] [timestamps_names.index(data_names[data_idx])], data=data[:, channel_idx], electrodes=self.probe_dt_region[probe_no])) elif 'Spectrum' in neurodata_type_name: if ibl_dataset_name in '_iblqc_ephysSpectralDensity.power': freqs_names = self._one_data.data_attrs_dump[ '_iblqc_ephysSpectralDensity.freqs'] data_names = self._one_data.data_attrs_dump[ '_iblqc_ephysSpectralDensity.power'] for data_idx, data in enumerate( neurodata_type_args['data']): mod.add( Spectrum(name=data_names[data_idx], frequencies=neurodata_type_args[ 'frequencies'][freqs_names.index( data_names[data_idx])], power=data)) elif 'SpikeEventSeries' in neurodata_type_name: neurodata_type_args.update( dict(electrodes=self.probe_dt_region_all)) mod.add( pynwb.ecephys.SpikeEventSeries(**neurodata_type_args)) def create_behavior(self): """ Create behavior processing module """ self.check_module('behavior') for behavior_datatype in self.nwb_metadata['Behavior']: if behavior_datatype == 'Position': position_cont = pynwb.behavior.Position() time_series_list_details = self._get_data( self.nwb_metadata['Behavior'][behavior_datatype] ['spatial_series']) if len(time_series_list_details) == 0: continue # rate_list = [150.0,60.0,60.0] # based on the google doc for _iblrig_body/left/rightCamera.raw, dataname_list = self._one_data.data_attrs_dump['camera.dlc'] data_list = time_series_list_details[0]['data'] timestamps_list = time_series_list_details[0]['timestamps'] for dataname, data, timestamps in zip(dataname_list, data_list, timestamps_list): colnames = data.columns data_np = data.to_numpy() x_column_ids = [ n for n, k in enumerate(colnames) if 'x' in k ] for x_column_id in x_column_ids: data_loop = data_np[:, x_column_id:x_column_id + 2] position_cont.create_spatial_series( name=dataname + colnames[x_column_id][:-2], data=data_loop, reference_frame='none', timestamps=timestamps, conversion=1e-3) self.nwbfile.processing['behavior'].add(position_cont) elif not (behavior_datatype == 'BehavioralEpochs'): time_series_func = pynwb.TimeSeries time_series_list_details = self._get_data( self.nwb_metadata['Behavior'][behavior_datatype] ['time_series']) if len(time_series_list_details) == 0: continue time_series_list_obj = [] for i in time_series_list_details: unit = 'radians/sec' if 'velocity' in i[ 'name'] else 'radians' time_series_list_obj.append( time_series_func(**i, unit=unit)) func = getattr(pynwb.behavior, behavior_datatype) self.nwbfile.processing['behavior'].add( func(time_series=time_series_list_obj)) else: time_series_func = pynwb.epoch.TimeIntervals time_series_list_details = self._get_data( self.nwb_metadata['Behavior'][behavior_datatype] ['time_intervals']) if len(time_series_list_details) == 0: continue for k in time_series_list_details: time_intervals = time_series_func('BehavioralEpochs') for time_interval in k['timestamps']: time_intervals.add_interval( start_time=time_interval[0], stop_time=time_interval[1]) time_intervals.add_column(k['name'], k['description'], data=k['data']) self.nwbfile.processing['behavior'].add(time_intervals) def create_acquisition(self): """ Acquisition data like audiospectrogram(raw beh data), nidq(raw ephys data), raw camera data. These are independent of probe type. """ for neurodata_type_name, neurodata_type_args_list in self.nwb_metadata[ 'Acquisition'].items(): data_retrieved_args_list = self._get_data(neurodata_type_args_list) for neurodata_type_args in data_retrieved_args_list: if neurodata_type_name == 'ImageSeries': for types, times in zip(neurodata_type_args['data'], neurodata_type_args['timestamps']): customargs = dict(name='camera_raw', external_file=[str(types)], format='external', timestamps=times, unit='n.a.') self.nwbfile.add_acquisition(ImageSeries(**customargs)) elif neurodata_type_name == 'DecompositionSeries': neurodata_type_args['bands'] = np.squeeze( neurodata_type_args['bands']) freqs = DynamicTable( 'bands', 'spectogram frequencies', id=np.arange(neurodata_type_args['bands'].shape[0])) freqs.add_column('freq', 'frequency value', data=neurodata_type_args['bands']) neurodata_type_args.update(dict(bands=freqs)) temp = neurodata_type_args['data'][:, :, np.newaxis] neurodata_type_args['data'] = np.moveaxis( temp, [0, 1, 2], [0, 2, 1]) ts = neurodata_type_args.pop('timestamps') starting_time = ts[0][0] if isinstance( ts[0], np.ndarray) else ts[0] neurodata_type_args.update( dict(starting_time=np.float64(starting_time), rate=1 / np.mean(np.diff(ts.squeeze())), unit='sec')) self.nwbfile.add_acquisition( DecompositionSeries(**neurodata_type_args)) elif neurodata_type_name == 'ElectricalSeries': if not self.electrode_table_exist: self.create_electrode_table_ecephys() if neurodata_type_args['name'] in ['raw.lf', 'raw.ap']: for probe_no in range(self.no_probes): if neurodata_type_args['data'][probe_no].shape[ 1] > self._one_data.data_attrs_dump[ 'electrode_table_length'][probe_no]: if 'channels.rawInd' in self._one_data.loaded_datasets: channel_idx = self._one_data.loaded_datasets[ 'channels.rawInd'][ probe_no].data.astype('int') else: warnings.warn( 'could not find channels.rawInd') break else: channel_idx = slice(None) self.nwbfile.add_acquisition( ElectricalSeries( name=neurodata_type_args['name'] + '_' + self.nwb_metadata['Probes'][probe_no] ['name'], starting_time=np.abs( np.round( neurodata_type_args['timestamps'] [probe_no][0, 1], 2) ), # round starting times of the order of 1e-5 rate=neurodata_type_args['data'] [probe_no].fs, data=H5DataIO( DataChunkIterator( _iter_datasetview( neurodata_type_args['data'] [probe_no], channel_ids=channel_idx), buffer_size=self.buffer_size), compression=True, shuffle=self.shuffle, compression_opts=self.complevel), electrodes=self.probe_dt_region[probe_no], channel_conversion=neurodata_type_args[ 'data'] [probe_no].channel_conversion_sample2v[ neurodata_type_args['data'] [probe_no].type][channel_idx])) elif neurodata_type_args['name'] in ['raw.nidq']: self.nwbfile.add_acquisition( ElectricalSeries(**neurodata_type_args)) def create_probes(self): """ Fills in all the probes metadata into the custom NeuroPixels extension. """ for i in self.nwb_metadata['Probes']: self.nwbfile.add_device(IblProbes(**i)) def create_iblsubject(self): """ Populates the custom subject extension for IBL mice daata """ self.nwbfile.subject = IblSubject(**self.nwb_metadata['IBLSubject']) def create_lab_meta_data(self): """ Populates the custom lab_meta_data extension for IBL sessions data """ self.nwbfile.add_lab_meta_data( IblSessionData(**self.nwb_metadata['IBLSessionsData'])) def create_trials(self): table_data = self._get_data(self.nwb_metadata['Trials']) required_fields = ['start_time', 'stop_time'] required_data = [i for i in table_data if i['name'] in required_fields] optional_data = [ i for i in table_data if i['name'] not in required_fields ] if len(required_fields) != len(required_data): warnings.warn( 'could not find required datasets: trials.start_time, trials.stop_time, ' 'skipping trials table') return for start_time, stop_time in zip(required_data[0]['data'][:, 0], required_data[1]['data'][:, 1]): self.nwbfile.add_trial(start_time=start_time, stop_time=stop_time) for op_data in optional_data: if op_data['data'].shape[0] == required_data[0]['data'].shape[0]: self.nwbfile.add_trial_column( name=op_data['name'], description=op_data['description'], data=op_data['data']) else: warnings.warn( f'shape of trials.{op_data["name"]} does not match other trials.* datasets' ) def _get_data(self, sub_metadata): """ Uses OneData class to query ONE datasets on server and download them locally Parameters ---------- sub_metadata: [list, dict] list of metadata dicts containing a data key with a dataset type string as value to retrieve data from(npy, tsv etc) Returns ------- out_dict: dict dictionary with actual data loaded in the data field """ include_idx = [] out_dict_trim = [] alt_datatypes = ['bands', 'power', 'frequencies', 'timestamps'] if isinstance(sub_metadata, list): out_dict = deepcopy(sub_metadata) elif isinstance(sub_metadata, dict): out_dict = deepcopy(list(sub_metadata)) else: return [] req_datatypes = ['data'] for count, neurodata_type_args in enumerate(out_dict): for alt_names in alt_datatypes: if neurodata_type_args.get( alt_names ): # in case of Decomposotion series, Spectrum neurodata_type_args[ alt_names] = self._one_data.download_dataset( neurodata_type_args[alt_names], neurodata_type_args['name']) req_datatypes.append(alt_names) if neurodata_type_args[ 'name'] == 'id': # valid in case of units table. neurodata_type_args['data'] = self._one_data.download_dataset( neurodata_type_args['data'], 'cluster_id') else: out_dict[count]['data'] = self._one_data.download_dataset( neurodata_type_args['data'], neurodata_type_args['name']) if all([out_dict[count][i] is not None for i in req_datatypes]): include_idx.extend([count]) out_dict_trim.extend([out_dict[j0] for j0 in include_idx]) return out_dict_trim def run_conversion(self): """ Single method to create all datasets and metadata in nwbfile in one go Returns ------- """ execute_list = [ self.create_stimulus, self.create_trials, self.create_electrode_table_ecephys, self.create_timeseries_ecephys, self.create_units, self.create_behavior, self.create_probes, self.create_iblsubject, self.create_lab_meta_data, self.create_acquisition ] t = tqdm(execute_list) for i in t: t.set_postfix(current=f'creating nwb ' + i.__name__.split('_')[-1]) i() print('done converting') def write_nwb(self, read_check=True): """ After run_conversion(), write nwbfile to disk with the loaded nwbfile Parameters ---------- read_check: bool Round trip verification """ print('Saving to file, please wait...') with NWBHDF5IO(self.saveloc, 'w') as io: io.write(self.nwbfile) print('File successfully saved at: ', str(self.saveloc)) if read_check: with NWBHDF5IO(self.saveloc, 'r') as io: io.read() print('Read check: OK')
location=location, device=device) ####################### # After setting up electrode group metadata, you should add metadata about the individual electrodes comprising # each electrode group. This is done with :py:func:`~pynwb.file.NWBFile.add_electrode`. # # The first argument to :py:class:`~pynwb.file.NWBFile.add_electrode` is a unique identifier that the user should # assign. For details on the rest of the arguments, please see the # :py:func:`API documentation <pynwb.file.NWBFile.add_electrode>`. for idx in [1, 2, 3, 4]: nwbfile.add_electrode(id=idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location='CA1', filtering='none', group=electrode_group) ####################### # .. note: :py:class:`~pynwb.file.NWBFile.add_electrode` returns the index of the electrode you just added. # This can come in handy when creating with an :py:class:`~pynwb.core.DynamicTableRegion` # :py:class:`~pynwb.file.NWBFile.create_electrode_table_region` (See :ref:`ec_recordings`). ####################### # .. _ec_recordings: # # Extracellular recordings # ^^^^^^^^^^^^^^^^^^^^^^^^ #
def nwb_copy_file(old_file, new_file, cp_objs={}): """ Copy fields defined in 'obj', from existing NWB file to new NWB file. Parameters ---------- old_file : str, path String such as '/path/to/old_file.nwb'. new_file : str, path String such as '/path/to/new_file.nwb'. cp_objs : dict Name:Value pairs (Group:Children) listing the groups and respective children from the current NWB file to be copied. Children can be: - Boolean, indicating an attribute (e.g. for institution, lab) - List of strings, containing several children names Example: {'institution':True, 'lab':True, 'acquisition':['microphone'], 'ecephys':['LFP','DecompositionSeries']} """ manager = get_manager() # Open original signal file with NWBHDF5IO(old_file, 'r', manager=manager, load_namespaces=True) as io1: nwb_old = io1.read() # Creates new file nwb_new = NWBFile(session_description=str(nwb_old.session_description), identifier='', session_start_time=datetime.now(tzlocal())) with NWBHDF5IO(new_file, mode='w', manager=manager, load_namespaces=False) as io2: # Institution name ------------------------------------------------ if 'institution' in cp_objs: nwb_new.institution = str(nwb_old.institution) # Lab name -------------------------------------------------------- if 'lab' in cp_objs: nwb_new.lab = str(nwb_old.lab) # Session id ------------------------------------------------------ if 'session' in cp_objs: nwb_new.session_id = nwb_old.session_id # Devices --------------------------------------------------------- if 'devices' in cp_objs: for aux in list(nwb_old.devices.keys()): dev = Device(nwb_old.devices[aux].name) nwb_new.add_device(dev) # Electrode groups ------------------------------------------------ if 'electrode_groups' in cp_objs: for aux in list(nwb_old.electrode_groups.keys()): nwb_new.create_electrode_group( name=str(nwb_old.electrode_groups[aux].name), description=str(nwb_old.electrode_groups[ aux].description), location=str(nwb_old.electrode_groups[aux].location), device=nwb_new.get_device( nwb_old.electrode_groups[aux].device.name) ) # Electrodes ------------------------------------------------------ if 'electrodes' in cp_objs: nElec = len(nwb_old.electrodes['x'].data[:]) for aux in np.arange(nElec): nwb_new.add_electrode( x=nwb_old.electrodes['x'][aux], y=nwb_old.electrodes['y'][aux], z=nwb_old.electrodes['z'][aux], imp=nwb_old.electrodes['imp'][aux], location=str(nwb_old.electrodes['location'][aux]), filtering=str(nwb_old.electrodes['filtering'][aux]), group=nwb_new.get_electrode_group( nwb_old.electrodes['group'][aux].name), group_name=str(nwb_old.electrodes['group_name'][aux]) ) # if there are custom variables new_vars = list(nwb_old.electrodes.colnames) default_vars = ['x', 'y', 'z', 'imp', 'location', 'filtering', 'group', 'group_name'] [new_vars.remove(var) for var in default_vars] for var in new_vars: if var == 'label': var_data = [str(elem) for elem in nwb_old.electrodes[ var].data[:]] else: var_data = np.array(nwb_old.electrodes[var].data[:]) nwb_new.add_electrode_column(name=str(var), description= str(nwb_old.electrodes[ var].description), data=var_data) # Epochs ---------------------------------------------------------- if 'epochs' in cp_objs: nEpochs = len(nwb_old.epochs['start_time'].data[:]) for i in np.arange(nEpochs): nwb_new.add_epoch( start_time=nwb_old.epochs['start_time'].data[i], stop_time=nwb_old.epochs['stop_time'].data[i]) # if there are custom variables new_vars = list(nwb_old.epochs.colnames) default_vars = ['start_time', 'stop_time', 'tags', 'timeseries'] [new_vars.remove(var) for var in default_vars if var in new_vars] for var in new_vars: nwb_new.add_epoch_column(name=var, description=nwb_old.epochs[ var].description, data=nwb_old.epochs[var].data[:]) # Invalid times --------------------------------------------------- if 'invalid_times' in cp_objs: nInvalid = len(nwb_old.invalid_times['start_time'][:]) for aux in np.arange(nInvalid): nwb_new.add_invalid_time_interval( start_time=nwb_old.invalid_times['start_time'][aux], stop_time=nwb_old.invalid_times['stop_time'][aux]) # Trials ---------------------------------------------------------- if 'trials' in cp_objs: nTrials = len(nwb_old.trials['start_time']) for aux in np.arange(nTrials): nwb_new.add_trial( start_time=nwb_old.trials['start_time'][aux], stop_time=nwb_old.trials['stop_time'][aux]) # if there are custom variables new_vars = list(nwb_old.trials.colnames) default_vars = ['start_time', 'stop_time'] [new_vars.remove(var) for var in default_vars] for var in new_vars: nwb_new.add_trial_column(name=var, description=nwb_old.trials[ var].description, data=nwb_old.trials[var].data[:]) # Intervals ------------------------------------------------------- if 'intervals' in cp_objs: all_objs_names = list(nwb_old.intervals.keys()) for obj_name in all_objs_names: obj_old = nwb_old.intervals[obj_name] # create and add TimeIntervals obj = TimeIntervals(name=obj_old.name, description=obj_old.description) nInt = len(obj_old['start_time']) for ind in np.arange(nInt): obj.add_interval(start_time=obj_old['start_time'][ind], stop_time=obj_old['stop_time'][ind]) # Add to file nwb_new.add_time_intervals(obj) # Stimulus -------------------------------------------------------- if 'stimulus' in cp_objs: all_objs_names = list(nwb_old.stimulus.keys()) for obj_name in all_objs_names: obj_old = nwb_old.stimulus[obj_name] obj = 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) nwb_new.add_stimulus(obj) # Processing modules ---------------------------------------------- if 'ecephys' in cp_objs: if cp_objs['ecephys'] is True: interfaces = nwb_old.processing[ 'ecephys'].data_interfaces.keys() else: # list of items interfaces = [ nwb_old.processing['ecephys'].data_interfaces[key] for key in cp_objs['ecephys'] ] # Add ecephys module to NWB file ecephys_module = ProcessingModule( name='ecephys', description='Extracellular electrophysiology data.' ) nwb_new.add_processing_module(ecephys_module) for interface_old in interfaces: obj = copy_obj(interface_old, nwb_old, nwb_new) if obj is not None: ecephys_module.add_data_interface(obj) # Acquisition ----------------------------------------------------- if 'acquisition' in cp_objs: if cp_objs['acquisition'] is True: all_acq_names = list(nwb_old.acquisition.keys()) else: # list of items all_acq_names = cp_objs['acquisition'] for acq_name in all_acq_names: obj_old = nwb_old.acquisition[acq_name] obj = copy_obj(obj_old, nwb_old, nwb_new) if obj is not None: nwb_new.add_acquisition(obj) # Subject --------------------------------------------------------- if 'subject' in cp_objs: try: cortical_surfaces = CorticalSurfaces() surfaces = nwb_old.subject.cortical_surfaces.surfaces for sfc in list(surfaces.keys()): cortical_surfaces.create_surface( name=surfaces[sfc].name, faces=surfaces[sfc].faces, vertices=surfaces[sfc].vertices) nwb_new.subject = ECoGSubject( cortical_surfaces=cortical_surfaces, subject_id=nwb_old.subject.subject_id, age=nwb_old.subject.age, description=nwb_old.subject.description, genotype=nwb_old.subject.genotype, sex=nwb_old.subject.sex, species=nwb_old.subject.species, weight=nwb_old.subject.weight, date_of_birth=nwb_old.subject.date_of_birth) except: nwb_new.subject = Subject(age=nwb_old.subject.age, description=nwb_old.subject.description, genotype=nwb_old.subject.genotype, sex=nwb_old.subject.sex, species=nwb_old.subject.species, subject_id=nwb_old.subject.subject_id, weight=nwb_old.subject.weight, date_of_birth=nwb_old.subject.date_of_birth) # Write new file with copied fields io2.write(nwb_new, link_data=False)
def no2nwb(NOData, session_use, subjects_ini, path_to_data): ''' Purpose: Import the data and associated meta-data from the new/old recognition dataset into an NWB file. Each of the features of the dataset, such as the events (i.e., TTLs) or mean waveform, are compartmentalized to the appropriate component of the NWB file. ''' # Time scaling (covert uS -----> S for NWB file) TIME_SCALING = 10**6 # Prepare the NO data that will be coverted to the NWB format session = NOData.sessions[session_use] events = NOData._get_event_data(session_use, experiment_type='All') cell_ids = NOData.ls_cells(session_use) experiment_id_learn = session['experiment_id_learn'] experiment_id_recog = session['experiment_id_recog'] task_descr = session['task_descr'] # Get the metadata for the subject # ============ Read Config File () # load config file (subjects == config file) # Check config file path filename = subjects_ini if not os.path.exists(filename): print('This file does not exist: {}'.format(filename)) print("Check filename/and or directory") # Read the config file try: # initialze the ConfigParser() class config = configparser.ConfigParser() # read .ini file config.read(filename) except: print('Failed to read the config file..') print('Does this file exist: {}'.format(os.path.exists(filename))) # Read Meta-data from INI file. for section in config.sections(): if session_use == int(section): session_id = int(section) # The New/Old ID for the session #Get the session ID for value in config[section]: if value.lower() == 'nosessions.age': age = int(config[section][value]) if value.lower() == 'nosessions.diagnosiscode': epilepsyDxCode = config[section][value] epilepsyDx = getEpilepsyDx(int(epilepsyDxCode)) if value.lower() == 'nosessions.sex': sex = config[section][value].strip("'") if value.lower() == 'nosessions.id': ID = config[section][value].strip("'") if value.lower() == 'nosessions.session': pt_session = config[section][value].strip("'") if value.lower() == 'nosessions.date': unformattedDate = config[section][value].strip("'") date = datetime.strptime(unformattedDate, '%Y-%m-%d') finaldate = date.replace(hour=0, minute=0) if value.lower() == 'nosessions.institution': institution = config[section][value].strip("'") if value.lower() == 'nosessions.la': LA = config[section][value].strip("'").split(',') if LA[0] == 'NaN': LA_x = np.nan LA_y = np.nan LA_z = np.nan else: LA_x = float(LA[0]) LA_y = float(LA[1]) LA_z = float(LA[2]) if value.lower() == 'nosessions.ra': RA = config[section][value].strip("'").split(',') if RA[0] == 'NaN': RA_x = np.nan RA_y = np.nan RA_z = np.nan else: RA_x = float(RA[0]) RA_y = float(RA[1]) RA_z = float(RA[2]) if value.lower() == 'nosessions.lh': LH = config[section][value].strip("'").split(',') if LH[0] == 'NaN': LH_x = np.nan LH_y = np.nan LH_z = np.nan else: LH_x = float(LH[0]) LH_y = float(LH[1]) LH_z = float(LH[2]) if value.lower() == 'nosessions.rh': RH = config[section][value].strip("'").split(',') if RH[0] == 'NaN': RH_x = np.nan RH_y = np.nan RH_z = np.nan else: RH_x = float(RH[0]) RH_y = float(RH[1]) RH_z = float(RH[2]) if value.lower() == 'nosessions.system': signalSystem = config[section][value].strip("'") # ================================================================= print( '=======================================================================' ) print('session use: {}'.format(session_id)) print('age: {}'.format(age)) print('epilepsy_diagnosis: {}'.format(epilepsyDx)) nwb_subject = Subject(age=str(age), description=epilepsyDx, sex=sex, species='Human', subject_id=pt_session[:pt_session.find('_')]) # Create the NWB file nwbfile = NWBFile( #source='https://datadryad.org/bitstream/handle/10255/dryad.163179/RecogMemory_MTL_release_v2.zip', session_description='New/Old recognition task for ID: {}. '.format( session_id), identifier='{}_{}'.format(ID, session_use), session_start_time=finaldate, #default session start time file_create_date=datetime.now(), experiment_description= 'The data contained within this file describes a new/old recogntion task performed in ' 'patients with intractable epilepsy implanted with depth electrodes and Behnke-Fried ' 'microwires in the human Medical Temporal Lobe (MTL).', institution=institution, keywords=[ 'Intracranial Recordings', 'Intractable Epilepsy', 'Single-Unit Recordings', 'Cognitive Neuroscience', 'Learning', 'Memory', 'Neurosurgery' ], related_publications= 'Faraut et al. 2018, Scientific Data; Rutishauser et al. 2015, Nat Neurosci;', lab='Rutishauser', subject=nwb_subject, data_collection='learning: {}, recognition: {}'.format( session['experiment_id_learn'], session['experiment_id_recog'])) # Add events and experiment_id acquisition events_description = ( """ The events coorespond to the TTL markers for each trial. For the learning trials, the TTL markers are the following: 55 = start of the experiment, 1 = stimulus ON, 2 = stimulus OFF, 3 = Question Screen Onset [“Is this an animal?”], 20 = Yes (21 = NO) during learning, 6 = End of Delay after Response, 66 = End of Experiment. For the recognition trials, the TTL markers are the following: 55 = start of experiment, 1 = stimulus ON, 2 = stimulus OFF, 3 = Question Screen Onset [“Have you seen this image before?”], 31:36 = Confidence (Yes vs. No) response [31 (new, confident), 32 (new, probably), 33 (new, guess), 34 (old, guess), 35 (old, probably), 36 (old, confident)], 66 = End of Experiment""" ) event_ts = AnnotationSeries(name='events', data=np.asarray(events[1].values).astype(str), timestamps=np.asarray(events[0].values) / TIME_SCALING, description=events_description) experiment_ids_description = ( """The experiment_ids coorespond to the encoding (i.e., learning) or recogniton trials. The learning trials are demarcated by: {}. The recognition trials are demarcated by: {}. """ .format(experiment_id_learn, experiment_id_recog)) experiment_ids = TimeSeries(name='experiment_ids', unit='NA', data=np.asarray(events[2]), timestamps=np.asarray(events[0].values) / TIME_SCALING, description=experiment_ids_description) nwbfile.add_acquisition(event_ts) nwbfile.add_acquisition(experiment_ids) # Add stimuli to the NWB file # Get the first cell from the cell list cell = NOData.pop_cell(session_use, NOData.ls_cells(session_use)[0], path_to_data) trials = cell.trials stimuli_recog_path = [trial.file_path_recog for trial in trials] stimuli_learn_path = [trial.file_path_learn for trial in trials] # Add epochs and trials: storing start and end times for a stimulus # First extract the category ids and names that we need # The metadata for each trials will be store in a trial table cat_id_recog = [trial.category_recog for trial in trials] cat_name_recog = [trial.category_name_recog for trial in trials] cat_id_learn = [trial.category_learn for trial in trials] cat_name_learn = [trial.category_name_learn for trial in trials] # Extract the event timestamps events_learn_stim_on = events[(events[2] == experiment_id_learn) & (events[1] == NOData.markers['stimulus_on'])] events_learn_stim_off = events[(events[2] == experiment_id_learn) & ( events[1] == NOData.markers['stimulus_off'])] events_learn_delay1_off = events[(events[2] == experiment_id_learn) & ( events[1] == NOData.markers['delay1_off'])] events_learn_delay2_off = events[(events[2] == experiment_id_learn) & ( events[1] == NOData.markers['delay2_off'])] events_learn = events[(events[2] == experiment_id_learn)] events_learn_response = [] events_learn_response_time = [] for i in range(len(events_learn[0])): if (events_learn.iloc[i, 1] == NOData.markers['response_learning_animal']) or ( events_learn.iloc[i, 1] == NOData.markers['response_learning_non_animal']): events_learn_response.append(events_learn.iloc[i, 1] - 20) events_learn_response_time.append(events_learn.iloc[i, 0]) events_recog_stim_on = events[(events[2] == experiment_id_recog) & (events[1] == NOData.markers['stimulus_on'])] events_recog_stim_off = events[(events[2] == experiment_id_recog) & ( events[1] == NOData.markers['stimulus_off'])] events_recog_delay1_off = events[(events[2] == experiment_id_recog) & ( events[1] == NOData.markers['delay1_off'])] events_recog_delay2_off = events[(events[2] == experiment_id_recog) & ( events[1] == NOData.markers['delay2_off'])] events_recog = events[(events[2] == experiment_id_recog)] events_recog_response = [] events_recog_response_time = [] for i in range(len(events_recog[0])): if ((events_recog.iloc[i, 1] == NOData.markers['response_1']) or (events_recog.iloc[i, 1] == NOData.markers['response_2']) or (events_recog.iloc[i, 1] == NOData.markers['response_3']) or (events_recog.iloc[i, 1] == NOData.markers['response_4']) or (events_recog.iloc[i, 1] == NOData.markers['response_5']) or (events_recog.iloc[i, 1] == NOData.markers['response_6'])): events_recog_response.append(events_recog.iloc[i, 1]) events_recog_response_time.append(events_recog.iloc[i, 0]) # Extract new_old label new_old_recog = [trial.new_old_recog for trial in trials] # Create the trial tables nwbfile.add_trial_column('stim_on_time', 'The Time when the Stimulus is Shown') nwbfile.add_trial_column('stim_off_time', 'The Time when the Stimulus is Off') nwbfile.add_trial_column('delay1_time', 'The Time when Delay1 is Off') nwbfile.add_trial_column('delay2_time', 'The Time when Delay2 is Off') nwbfile.add_trial_column('stim_phase', 'Learning/Recognition Phase During the Trial') nwbfile.add_trial_column('stimCategory', 'The Category ID of the Stimulus') nwbfile.add_trial_column('category_name', 'The Category Name of the Stimulus') nwbfile.add_trial_column('external_image_file', 'The File Path to the Stimulus') nwbfile.add_trial_column( 'new_old_labels_recog', '''The Ground truth Labels for New or Old Stimulus. 0 == Old Stimuli (presented during the learning phase), 1 = New Stimuli (not seen )'during learning phase''' ) nwbfile.add_trial_column('response_value', 'The Response for Each Stimulus') nwbfile.add_trial_column('response_time', 'The Response Time for each Stimulus') range_recog = np.amin([ len(events_recog_stim_on), len(events_recog_stim_off), len(events_recog_delay1_off), len(events_recog_delay2_off) ]) range_learn = np.amin([ len(events_learn_stim_on), len(events_learn_stim_off), len(events_learn_delay1_off), len(events_learn_delay2_off) ]) # Iterate the event list and add information into each epoch and trial table for i in range(range_learn): nwbfile.add_trial( start_time=(events_learn_stim_on.iloc[i][0]) / (TIME_SCALING), stop_time=(events_learn_delay2_off.iloc[i][0]) / (TIME_SCALING), stim_on_time=(events_learn_stim_on.iloc[i][0]) / (TIME_SCALING), stim_off_time=(events_learn_stim_off.iloc[i][0]) / (TIME_SCALING), delay1_time=(events_learn_delay1_off.iloc[i][0]) / (TIME_SCALING), delay2_time=(events_learn_delay2_off.iloc[i][0]) / (TIME_SCALING), stim_phase='learn', stimCategory=cat_id_learn[i], category_name=cat_name_learn[i], external_image_file=stimuli_learn_path[i], new_old_labels_recog='NA', response_value=events_learn_response[i], response_time=(events_learn_response_time[i]) / (TIME_SCALING)) for i in range(range_recog): nwbfile.add_trial( start_time=events_recog_stim_on.iloc[i][0] / (TIME_SCALING), stop_time=events_recog_delay2_off.iloc[i][0] / (TIME_SCALING), stim_on_time=events_recog_stim_on.iloc[i][0] / (TIME_SCALING), stim_off_time=events_recog_stim_off.iloc[i][0] / (TIME_SCALING), delay1_time=events_recog_delay1_off.iloc[i][0] / (TIME_SCALING), delay2_time=events_recog_delay2_off.iloc[i][0] / (TIME_SCALING), stim_phase='recog', stimCategory=cat_id_recog[i], category_name=cat_name_recog[i], external_image_file=stimuli_recog_path[i], new_old_labels_recog=new_old_recog[i], response_value=events_recog_response[i], response_time=events_recog_response_time[i] / (TIME_SCALING)) # Add the waveform clustering and the spike data. # Get the unique channel id that we will be iterate over channel_ids = np.unique([cell_id[0] for cell_id in cell_ids]) # unique unit id unit_id = 0 # Create unit columns nwbfile.add_unit_column('origClusterID', 'The original cluster id') nwbfile.add_unit_column('waveform_mean_encoding', 'The mean waveform for encoding phase.') nwbfile.add_unit_column('waveform_mean_recognition', 'The mean waveform for the recognition phase.') nwbfile.add_unit_column('IsolationDist', 'IsolDist') nwbfile.add_unit_column('SNR', 'SNR') nwbfile.add_unit_column('waveform_mean_sampling_rate', 'The Sampling Rate of Waveform') #Add Stimuli stimuli_presentation = [] # Add stimuli learn counter = 1 for path in stimuli_learn_path: if path == 'NA': continue folders = path.split('\\') path = os.path.join(path_to_data, 'Stimuli', folders[0], folders[1], folders[2]) img = cv2.imread(path) resized_image = cv2.resize(img, (300, 400)) stimuli_presentation.append(resized_image) # Add stimuli recog counter = 1 for path in stimuli_recog_path: folders = path.split('\\') path = os.path.join(path_to_data, 'Stimuli', folders[0], folders[1], folders[2]) img = cv2.imread(path) resized_image = cv2.resize(img, (300, 400)) stimuli_presentation.append(resized_image) name = 'stimuli_recog_' + str(counter) # Add stimuli to OpticalSeries stimulus_presentation_on_time = [] for n in range(0, len(events_learn_stim_on)): stimulus_presentation_on_time.append(events_learn_stim_on.iloc[n][0] / (TIME_SCALING)) for n in range(0, len(events_recog_stim_on)): stimulus_presentation_on_time.append(events_recog_stim_on.iloc[n][0] / (TIME_SCALING)) name = 'StimulusPresentation' stimulus = OpticalSeries(name=name, data=stimuli_presentation, timestamps=stimulus_presentation_on_time[:], orientation='lower left', format='raw', unit='meters', field_of_view=[.2, .3, .7], distance=0.7, dimension=[300, 400, 3]) nwbfile.add_stimulus(stimulus) # Get Unit data all_spike_cluster_ids = [] all_selected_time_stamps = [] all_IsolDist = [] all_SNR = [] all_selected_mean_waveform_learn = [] all_selected_mean_waveform_recog = [] all_mean_waveform = [] all_channel_id = [] all_oriClusterIDs = [] all_channel_numbers = [] all_brain_area = [] # Iterate the channel list # load brain area file brain_area_file_path = os.path.join(path_to_data, 'Data', 'events', session['session'], task_descr, 'brainArea.mat') try: brain_area_mat = loadmat(brain_area_file_path) except FileNotFoundError: print("brain_area_mat file not found") for channel_id in channel_ids: cell_name = 'A' + str(channel_id) + '_cells.mat' cell_file_path = os.path.join(path_to_data, 'Data', 'sorted', session['session'], task_descr, cell_name) try: cell_mat = loadmat(cell_file_path) except FileNotFoundError: print("cell mat file not found") continue spikes = cell_mat['spikes'] meanWaveform_recog = cell_mat['meanWaveform_recog'] meanWaveform_learn = cell_mat['meanWaveform_learn'] IsolDist_SNR = cell_mat['IsolDist_SNR'] spike_cluster_id = np.asarray([spike[1] for spike in spikes ]) # Each Cluster ID of the spike spike_timestamps = (np.asarray([spike[2] for spike in spikes])) / ( TIME_SCALING) # Timestamps of spikes for each ClusterID unique_cluster_ids = np.unique(spike_cluster_id) # If there are more than one cluster. for id in unique_cluster_ids: # Grab brain area brain_area = extra_brain_area(brain_area_mat, channel_id) selected_spike_timestamps = spike_timestamps[spike_cluster_id == id] IsolDist, SNR = extract_IsolDist_SNR_by_cluster_id( IsolDist_SNR, id) selected_mean_waveform_learn = extra_mean_waveform( meanWaveform_learn, id) selected_mean_waveform_recog = extra_mean_waveform( meanWaveform_recog, id) # If the mean waveform does not have 256 elements, we set the mean wave form to all 0 if len(selected_mean_waveform_learn) != 256: selected_mean_waveform_learn = np.zeros(256) if len(selected_mean_waveform_recog) != 256: selected_mean_waveform_recog = np.zeros(256) mean_waveform = np.hstack( [selected_mean_waveform_learn, selected_mean_waveform_recog]) # Append unit data all_spike_cluster_ids.append(id) all_selected_time_stamps.append(selected_spike_timestamps) all_IsolDist.append(IsolDist) all_SNR.append(SNR) all_selected_mean_waveform_learn.append( selected_mean_waveform_learn) all_selected_mean_waveform_recog.append( selected_mean_waveform_recog) all_mean_waveform.append(mean_waveform) all_channel_id.append(channel_id) all_oriClusterIDs.append(int(id)) all_channel_numbers.append(channel_id) all_brain_area.append(brain_area) unit_id += 1 nwbfile.add_electrode_column( name='origChannel', description='The original channel ID for the channel') #Add Device device = nwbfile.create_device(name=signalSystem) # Add Electrodes (brain Area Locations, MNI coordinates for microwires) length_all_spike_cluster_ids = len(all_spike_cluster_ids) for electrodeNumber in range(0, len(channel_ids)): brainArea_location = extra_brain_area(brain_area_mat, channel_ids[electrodeNumber]) if brainArea_location == 'RH': # Right Hippocampus full_brainArea_Location = 'Right Hippocampus' electrode_name = '{}-microwires-{}'.format( signalSystem, channel_ids[electrodeNumber]) description = "Behnke Fried/Micro Inner Wire Bundle (Behnke-Fried BF08R-SP05X-000 and WB09R-SP00X-0B6; Ad-Tech Medical)" location = full_brainArea_Location # Add electrode group electrode_group = nwbfile.create_electrode_group( electrode_name, description=description, location=location, device=device) #Add Electrode nwbfile.add_electrode([channel_ids[electrodeNumber]], x=RH_x, y=RH_y, z=RH_z, imp=np.nan, location=full_brainArea_Location, filtering='300-3000Hz', group=electrode_group, origChannel=channel_ids[electrodeNumber]) if brainArea_location == 'LH': full_brainArea_Location = 'Left Hippocampus' electrode_name = '{}-microwires-{}'.format( signalSystem, channel_ids[electrodeNumber]) description = "Behnke Fried/Micro Inner Wire Bundle (Behnke-Fried BF08R-SP05X-000 and WB09R-SP00X-0B6; Ad-Tech Medical)" location = full_brainArea_Location # Add electrode group electrode_group = nwbfile.create_electrode_group( electrode_name, description=description, location=location, device=device) nwbfile.add_electrode([all_channel_id[electrodeNumber]], x=LH_x, y=LH_y, z=LH_z, imp=np.nan, location=full_brainArea_Location, filtering='300-3000Hz', group=electrode_group, origChannel=channel_ids[electrodeNumber]) if brainArea_location == 'RA': full_brainArea_Location = 'Right Amygdala' electrode_name = '{}-microwires-{}'.format( signalSystem, channel_ids[electrodeNumber]) description = "Behnke Fried/Micro Inner Wire Bundle (Behnke-Fried BF08R-SP05X-000 and WB09R-SP00X-0B6; Ad-Tech Medical)" location = full_brainArea_Location # Add electrode group electrode_group = nwbfile.create_electrode_group( electrode_name, description=description, location=location, device=device) nwbfile.add_electrode([all_channel_id[electrodeNumber]], x=RA_x, y=RA_y, z=RA_z, imp=np.nan, location=full_brainArea_Location, filtering='300-3000Hz', group=electrode_group, origChannel=channel_ids[electrodeNumber]) if brainArea_location == 'LA': full_brainArea_Location = 'Left Amygdala' electrode_name = '{}-microwires-{}'.format( signalSystem, channel_ids[electrodeNumber]) description = "Behnke Fried/Micro Inner Wire Bundle (Behnke-Fried BF08R-SP05X-000 and WB09R-SP00X-0B6; Ad-Tech Medical)" location = full_brainArea_Location # Add electrode group electrode_group = nwbfile.create_electrode_group( electrode_name, description=description, location=location, device=device) nwbfile.add_electrode([all_channel_id[electrodeNumber]], x=LA_x, y=LA_y, z=LA_z, imp=np.nan, location=full_brainArea_Location, filtering='300-3000Hz', group=electrode_group, origChannel=channel_ids[electrodeNumber]) # Create Channel list index channel_list = list(range(0, length_all_spike_cluster_ids)) unique_channel_ids = np.unique(all_channel_id) length_ChannelIds = len(np.unique(all_channel_id)) for yy in range(0, length_ChannelIds): a = np.array(np.where(unique_channel_ids[yy] == all_channel_id)) b = a[0] c = b.tolist() for i in c: channel_list[i] = yy #Add WAVEFORM Sampling RATE waveform_mean_sampling_rate = [98.4 * 10**3] waveform_mean_sampling_rate_matrix = [waveform_mean_sampling_rate ] * (length_all_spike_cluster_ids) # Add Units to NWB file for index_id in range(0, length_all_spike_cluster_ids): nwbfile.add_unit( id=index_id, spike_times=all_selected_time_stamps[index_id], origClusterID=all_oriClusterIDs[index_id], IsolationDist=all_IsolDist[index_id], SNR=all_SNR[index_id], waveform_mean_encoding=all_selected_mean_waveform_learn[index_id], waveform_mean_recognition=all_selected_mean_waveform_recog[ index_id], electrodes=[channel_list[index_id]], waveform_mean_sampling_rate=waveform_mean_sampling_rate_matrix[ index_id]) return nwbfile
elec_inds = [] for i, (elec_id, elec_label) in tqdm(enumerate(elecs)): if elec_label[:4] == 'ainp': electrode_group = ainp_electrode_group else: electrode_group = elec_electrode_group elecs_data = nev_file.getdata([elec_id]) spikes = (np.array(elecs_data['spike_events']['TimeStamps'][0]) / 30000).tolist() elec_inds.append(i) ut.add_spike_times(elec_id, spikes) nwbfile.add_electrode( elec_id, np.nan, np.nan, np.nan, # position? imp=np.nan, location='unknown', filtering='unknown', description='description', group=electrode_group) all_table_region = nwbfile.create_electrode_table_region( elec_inds, 'all_electrodes') print('done.') # lfp print('reading LFPs...', end='', flush=True) print('done.') print('making ElectricalSeries objects for LFP...', end='', flush=True)
class ProcessingDataTestCase(unittest.TestCase): def setUp(self): self.nwbfile = NWBFile( 'my first synthetic recording', 'EXAMPLE_ID', datetime.now(tzlocal()), experimenter='Dr. Bilbo Baggins', lab='Bag End Laboratory', institution='University of Middle Earth at the Shire', experiment_description='I went on an adventure with thirteen dwarves to reclaim vast treasures.', session_id='LONELYMTN' ) device = self.nwbfile.create_device(name='trodes_rig123') electrode_name = 'tetrode1' description = "an example tetrode" location = "somewhere in the hippocampus" electrode_group = self.nwbfile.create_electrode_group( electrode_name, description=description, location=location, device=device ) for idx in [1, 2, 3, 4]: self.nwbfile.add_electrode( id=idx, x=1.0, y=2.0, z=3.0, imp=float(-idx), location='CA1', filtering='none', group=electrode_group ) electrode_table_region = self.nwbfile.create_electrode_table_region([0, 2], 'the first and third electrodes') rate = 5.0 np.random.seed(1234) data_len = 50 ephys_data = np.array([[0.76711663, 0.70811536], [0.79686718, 0.55776083], [0.96583653, 0.1471569], [0.029647, 0.59389349], [0.1140657, 0.95080985], [0.32570741, 0.19361869], [0.45781165, 0.92040257], [0.87906916, 0.25261576], [0.34800879, 0.18258873], [0.90179605, 0.70652816], [0.72665846, 0.90008784], [0.7791638, 0.59915478], [0.29112524, 0.15139526], [0.33517466, 0.65755178], [0.07334254, 0.0550064], [0.32319481, 0.5904818], [0.85389857, 0.28706243], [0.17306723, 0.13402121], [0.99465383, 0.17949787], [0.31754682, 0.5682914], [0.00934857, 0.90064862], [0.97724143, 0.55689468], [0.08477384, 0.33300247], [0.72842868, 0.14243537], [0.55246894, 0.27304326], [0.97449514, 0.66778691], [0.25565329, 0.10831149], [0.77618072, 0.78247799], [0.76160391, 0.91440311], [0.65862278, 0.56836758], [0.20175569, 0.69829638], [0.95219541, 0.88996329], [0.99356736, 0.81870351], [0.54512217, 0.45125405], [0.89055719, 0.97326479], [0.59341133, 0.3660745], [0.32309469, 0.87142326], [0.21563406, 0.73494519], [0.36561909, 0.8016026], [0.78273559, 0.70135538], [0.62277659, 0.49368265], [0.8405377, 0.71209699], [0.44390898, 0.03103486], [0.36323976, 0.73072179], [0.47556657, 0.34441697], [0.64088043, 0.12620532], [0.17146526, 0.73708649], [0.12702939, 0.36964987], [0.604334, 0.10310444], [0.80237418, 0.94555324]]) ephys_timestamps = np.arange(data_len) / rate ephys_ts = ElectricalSeries('preprocessed', ephys_data, electrode_table_region, starting_time=ephys_timestamps[0], rate=rate, resolution=0.001, comments="This data was randomly generated with numpy, using 1234 as the seed", description="Random numbers generated with numpy.random.rand") lfp = LFP(ephys_ts) self.nwbfile.create_processing_module( name='ecephys', description='preprocessed ecephys data' ) self.nwbfile.processing['ecephys'].add(lfp) self.nwbfile_new = NWBFile( 'my first synthetic recording', 'EXAMPLE_ID', datetime.now(tzlocal()), experimenter='Dr. Bilbo Baggins', lab='Bag End Laboratory', institution='University of Middle Earth at the Shire', experiment_description='I went on an adventure with thirteen dwarves to reclaim vast treasures.', session_id='LONELYMTN' ) def test_high_gamma_estimation(self): with NWBHDF5IO('ecephys_exmpl_gamma.nwb', 'w') as io: io.write(self.nwbfile) bands_vals = np.random.rand(2, 10) * 80 + 70 high_gamma_estimation('ecephys_exmpl_gamma.nwb', bands_vals) io = NWBHDF5IO('ecephys_exmpl_gamma.nwb', 'r') nwbfile_in = io.read() high_gamma_data = nwbfile_in.processing['ecephys'].data_interfaces['high_gamma'].data[:] high_gamma_data_expected = np.array([[114432.12734375, 106926.36953125], [104311.51640625, 81010.54921875], [158632.765625, 29015.66972656], [87235.18125, 109977.53828125], [40694.96054688, 143791.29375], [39189.63359375, 24476.98222656], [99898.77265625, 131793.8921875], [116746.00546875, 82916.5953125], [56977.66171875, 55775.99765625], [122025.39375, 100550.2734375], [110798.99609375, 128243.16484375], [110201.42265625, 118032.4765625], [73953.45234375, 22560.153125], [41865.0109375, 95126.09453125], [23743.01894531, 19107.33242187], [85232.5453125, 83586.396875], [127444.34921875, 60134.734375], [17301.87333984, 21913.7796875], [153644.3453125, 44228.69492188], [108004.7703125, 107790.89140625], [92584.2421875, 128566.275], [130929.23828125, 82646.0515625], [22233.11679688, 52573.65625], [106470.29765625, 17475.74941406], [89623.346875, 73826.7125], [129937.9359375, 93547.39375], [44125.3484375, 34720.43320313], [115818.246875, 149635.4359375], [114519.30625, 130255.1828125], [87249.54921875, 79923.99765625], [35482.24257812, 102406.0171875], [149241.865625, 126403.61484375], [155159.1921875, 123572.7953125], [68665.5015625, 63900.49492187], [133760.8578125, 139165.9765625], [97677.2953125, 51414.00859375], [64852.78320312, 129346.84296875], [24607.39375, 106858.39453125], [72500.85078125, 114212.22421875], [103932.5, 117112.81796875], [93862.08828125, 70807.0515625], [112166.11640625, 120027.41953125], [86554.1046875, 19128.88339844], [43686.26601562, 101883.1171875], [73509.96875, 82221.49609375], [85105.04296875, 32386.06582031], [52379.96210938, 107256.77421875], [49256.02304688, 69351.2296875], [106910.11328125, 53854.99570313], [108948.4109375, 138653.6015625]]) np.testing.assert_almost_equal(high_gamma_data, high_gamma_data_expected) # Remove test nwb files io.close() os.remove('ecephys_exmpl_gamma.nwb') def test_spectral_decomposition(self): with NWBHDF5IO('ecephys_exmpl_decomp.nwb', 'w') as io: io.write(self.nwbfile) bands_vals = np.random.rand(2, 10) * 80 + 70 spectral_decomposition('ecephys_exmpl_decomp.nwb', bands_vals) io = NWBHDF5IO('ecephys_exmpl_decomp.nwb', 'r') nwbfile_in = io.read() decomposition_data = nwbfile_in.processing['ecephys'].data_interfaces['DecompositionSeries'].data[:] decomposition_data_expected = np.array([[[114617.296875 , 114486.0078125 , 114848.0546875 , 114675.953125 , 114086.171875 , 114826.0546875 , 114754.0390625 , 112567.6015625 , 114651.6171875 , 114808.4765625 ], [107103.5859375 , 106978.0390625 , 107322.3828125 , 107158.4609375 , 106597.3828125 , 107301.71875 , 107233.3046875 , 105149.265625 , 107135.1796875 , 107284.375 ]], [[104542.0625 , 104378.6796875 , 104826.75 , 104613.4453125 , 103883.40625 , 104799.859375 , 104710.84375 , 101999.6953125 , 104583.140625 , 104777.28125 ], [ 81147.546875 , 81050.4140625 , 81318.34375 , 81190.9921875 , 80754.515625 , 81302.0625 , 81248.7578125 , 79630.8046875 , 81172.984375 , 81289.0703125 ]], [[158760.78125 , 158670.578125 , 158918.875 , 158800.859375 , 158395.78125 , 158903.84375 , 158854.5 , 157346.59375 , 158784.15625 , 158891.6875 ], [ 29102.65429688, 29037.88867188, 29218.96875 , 29132.79296875, 28841.1015625 , 29207.6640625 , 29171.3984375 , 28124.09765625, 29120.74609375, 29199.38476562]], [[ 87250.3984375 , 87238.7890625 , 87270.2734375 , 87255.125 , 87204.71875 , 87268.4453125 , 87262.1640625 , 87082.296875 , 87252.953125 , 87266.6484375 ], [110059.9453125 , 110001.0390625 , 110163.3046875 , 110086.0859375 , 109822.2578125 , 110153.4765625 , 110121.1796875 , 109147.4453125 , 110075.15625 , 110145.4921875 ]], [[ 40677.609375 , 40688.921875 , 40660.45703125, 40674.203125 , 40721.69921875, 40661.8203125 , 40667.31640625, 40857.2578125 , 40676.30078125, 40664.01953125], [143883.140625 , 143818.203125 , 143998.140625 , 143912.75 , 143619.421875 , 143987.09375 , 143951.265625 , 142863.53125 , 143900.71875 , 143978.671875 ]], [[ 39313.33984375, 39225.09765625, 39468.546875 , 39352.76171875, 38956.734375 , 39453.74609375, 39405.29296875, 37942.51171875, 39336.39453125, 39441.91015625], [ 24713.640625 , 24545.43945312, 25007.27539062, 24787.41992188, 24035.4765625 , 24979.49609375, 24887.69726562, 22100.8046875 , 24756.22070312, 24956.3515625 ]], [[100002.8828125 , 99928.78125 , 100133.0078125 , 100035.8671875 , 99703.484375 , 100120.6171875 , 100079.984375 , 98850.34375 , 100022.125 , 100110.6328125 ], [131870.265625 , 131816.25 , 131966.625 , 131895.34375 , 131650.25 , 131957.296875 , 131927.3125 , 131019.75 , 131885.34375 , 131950.484375 ]], [[116872.1015625 , 116782.671875 , 117029.625 , 116912.2734375 , 116510.015625 , 117014.5703125 , 116965.4296875 , 115474.9765625 , 116895.6953125 , 117002.6953125 ], [ 82944.453125 , 82923.578125 , 82981.71875 , 82954. , 82860.5 , 82978.125 , 82966.4765625 , 82631.6171875 , 82950.109375 , 82975.375 ]], [[ 57186.56640625, 57038.0390625 , 57446.73828125, 57252.28515625, 56586.92578125, 57422.03125 , 57340.75390625, 54876.6953125 , 57224.73828125, 57401.84375 ], [ 55797.07421875, 55780.6328125 , 55827.8203125 , 55805.421875 , 55730.19921875, 55824.71875 , 55815.1796875 , 55553.68359375, 55802.35546875, 55822.890625 ]], [[122179.578125 , 122070.3828125 , 122371.640625 , 122228.4609375 , 121737.5859375 , 122353.3125 , 122293.3828125 , 120472.625 , 122208.2265625 , 122338.7421875 ], [100709.890625 , 100597.0078125 , 100906.890625 , 100759.4375 , 100254.3125 , 100888.25 , 100826.6875 , 98948.984375 , 100738.515625 , 100872.7578125 ]], [[111004.203125 , 110858.9453125 , 111257.671875 , 111067.921875 , 110418.1171875 , 111233.6953125 , 111154.46875 , 108740.2109375 , 111040.9921875 , 111213.734375 ], [128413.328125 , 128293.0390625 , 128622.9921875 , 128465.96875 , 127928.0546875 , 128603.1796875 , 128537.640625 , 126537.171875 , 128443.6640625 , 128586.609375 ]], [[110364.5078125 , 110249.078125 , 110566.71875 , 110415.6640625 , 109898. , 110547.5078125 , 110484.359375 , 108562.234375 , 110394.2734375 , 110531.8828125 ], [118127.28125 , 118059.953125 , 118246.0234375 , 118157.609375 , 117854.6171875 , 118234.6640625 , 118197.625 , 117076.1171875 , 118145.125 , 118225.75 ]], [[ 74073.4375 , 73988.0078125 , 74223.2578125 , 74111.3359375 , 73728.4921875 , 74209.015625 , 74162.21875 , 72745.828125 , 74095.4921875 , 74197.4375 ], [ 22709.97460938, 22600.88867188, 22901.94335938, 22758.49414062, 22270.98046875, 22883.65429688, 22823.63867188, 21044.90234375, 22738.22460938, 22868.83007812]], [[ 41966.58984375, 41894.28125 , 42094.3046875 , 41999.265625 , 41673.734375 , 42082.0703125 , 42042.2421875 , 40839.22265625, 41985.859375 , 42072.5390625 ], [ 95182.1796875 , 95142.4609375 , 95253.84375 , 95201.140625 , 95019.671875 , 95246.8203125 , 95224.578125 , 94554.421875 , 95193.7890625 , 95242.0390625 ]], [[ 23771.328125 , 23749.13085938, 23813.07421875, 23782.74023438, 23680.88867188, 23808.84179688, 23795.90429688, 23443.24414062, 23778.60351562, 23806.43359375], [ 19185.515625 , 19125.25195312, 19292.16796875, 19212.27539062, 18945.38671875, 19281.98632812, 19248.54492188, 18307.54296875, 19201.01953125, 19273.6328125 ]], [[ 85284.265625 , 85247. , 85349.34375 , 85300.5625 , 85134.46875 , 85343.1953125 , 85322.828125 , 84712.125 , 85293.640625 , 85338.0234375 ], [ 83637.5546875 , 83601.1953125 , 83702.796875 , 83654.65625 , 83489.2578125 , 83696.4453125 , 83676.171875 , 83066.0234375 , 83647.921875 , 83691.9453125 ]], [[127513.3359375 , 127464.5703125 , 127600.4453125 , 127536.0546875 , 127314.578125 , 127591.9921875 , 127564.9140625 , 126744.6875 , 127527.03125 , 127585.8828125 ], [ 60189.546875 , 60150.15625 , 60258.734375 , 60207.04296875, 60030.73046875, 60252.1484375 , 60230.53125 , 59581.91796875, 60199.73046875, 60246.8046875 ]], [[ 17533.41601562, 17367.984375 , 17821.8203125 , 17605.61914062, 16867.51171875, 17794.5859375 , 17704.36328125, 14976.88574219, 17574.91601562, 17771.63085938], [ 21968.08984375, 21928.48046875, 22039.79296875, 21987.00195312, 21806.87304688, 22032.7578125 , 22010.47265625, 21356.734375 , 21979.65234375, 22027.94140625]], [[153698.0625 , 153660.21875 , 153766.09375 , 153715.984375 , 153543.28125 , 153759.453125 , 153738.328125 , 153098.21875 , 153708.984375 , 153754.828125 ], [ 44348.2734375 , 44263.34765625, 44496.57421875, 44385.5625 , 44005.76953125, 44482.5390625 , 44436.18359375, 43028.01171875, 44369.8125 , 44470.875 ]], [[107953.4140625 , 107989.0078125 , 107892.7265625 , 107938.625 , 108096.3984375 , 107898.328125 , 107917.359375 , 108513.078125 , 107945.21875 , 107903.546875 ], [107917.4453125 , 107827.84375 , 108073.8515625 , 107956.78125 , 107555.8828125 , 108059.0546875 , 108010.171875 , 106520.953125 , 107940.171875 , 108046.7578125 ]], [[ 92517.5078125 , 92563.8515625 , 92438.5234375 , 92498.2890625 , 92703.546875 , 92445.8125 , 92470.5859375 , 93244.8046875 , 92506.875 , 92452.625 ], [128713.953125 , 128609.6796875 , 128895.9609375 , 128759.765625 , 128292.9296875 , 128878.734375 , 128821.859375 , 127084.9765625 , 128740.4375 , 128864.453125 ]], [[130982.6796875 , 130944.7890625 , 131050.984375 , 131000.7265625 , 130827.75 , 131044.296875 , 131023.09375 , 130384.6328125 , 130993.7109375 , 131039.71875 ], [ 82797.28125 , 82690.0703125 , 82984.3359375 , 82844.2734375 , 82364.875 , 82966.6484375 , 82908.171875 , 81128.578125 , 82824.390625 , 82951.890625 ]], [[ 22414.328125 , 22282.98828125, 22645.05664062, 22472.5625 , 21885.6171875 , 22623.109375 , 22550.97460938, 20403.16015625, 22448.16601562, 22605.20507812], [ 52676.65234375, 52603.47265625, 52805.58984375, 52709.52734375, 52380.4453125 , 52793.26953125, 52753.04296875, 51535.05859375, 52695.9609375 , 52783.54296875]], [[106585.1015625 , 106503.6953125 , 106729.59375 , 106622.390625 , 106254.421875 , 106715.6796875 , 106670.6796875 , 105308.921875 , 106607.3125 , 106705.1796875 ], [ 17574.67382812, 17503.72851562, 17700.84960938, 17607.23046875, 17286.98242188, 17688.6796875 , 17649.3671875 , 16472.38476562, 17594.07421875, 17679.5234375 ]], [[ 89841.609375 , 89687. , 90110.859375 , 89909.0625 , 89218.390625 , 90085.453125 , 90001.2578125 , 87435.40625 , 89880.390625 , 90064.0390625 ], [ 73912.234375 , 73851.3359375 , 74018.96875 , 73939.203125 , 73666.40625 , 74008.828125 , 73975.484375 , 72966.203125 , 73927.90625 , 74000.5546875 ]], [[130067.0703125 , 129975.640625 , 130228.828125 , 130108.625 , 129696.0546875 , 130213.296875 , 130162.890625 , 128633.890625 , 130091.6875 , 130201.375 ], [ 93639.2421875 , 93574.015625 , 93754.9921875 , 93669.09375 , 93374.3984375 , 93743.8515625 , 93707.796875 , 92618.125 , 93657. , 93735.421875 ]], [[ 44317.23046875, 44179.5078125 , 44558.93359375, 44378.296875 , 43761.9453125 , 44535.953125 , 44460.421875 , 42191.2265625 , 44352.734375 , 44517.234375 ], [ 34893.8828125 , 34768.875 , 35112.75 , 34948.90234375, 34390.81640625, 35092. , 35023.546875 , 32973.06640625, 34925.6875 , 35074.8046875 ]], [[115943.078125 , 115854.3359375 , 116100.1015625 , 115983.3828125 , 115583.28125 , 116085.03125 , 116036.0859375 , 114556.8125 , 115966.9296875 , 116073.4296875 ], [149762.703125 , 149672.703125 , 149920.90625 , 149802.953125 , 149398.375 , 149905.828125 , 149856.453125 , 148354.34375 , 149786.28125 , 149893.8125 ]], [[114704.3125 , 114573.2890625 , 114933.1640625 , 114761.9296875 , 114175.5 , 114911.4921875 , 114839.9765625 , 112662.2109375 , 114737.6328125 , 114893.5546875 ], [130433.8984375 , 130307.078125 , 130655.90625 , 130489.953125 , 129921.8046875 , 130634.8359375 , 130565.484375 , 128458.859375 , 130466.4296875 , 130617.578125 ]], [[ 87400.578125 , 87293.3515625 , 87589.6875 , 87448.890625 , 86966.3125 , 87571.6015625 , 87512.6171875 , 85726.0234375 , 87429.015625 , 87557.4140625 ], [ 80134.59375 , 79984.9296875 , 80397.6875 , 80201.4296875 , 79529.4140625 , 80372.609375 , 80290.484375 , 77802.6015625 , 80173.6875 , 80352.5390625 ]], [[ 35690.89453125, 35542.4765625 , 35951.64453125, 35757.0625 , 35091.03125 , 35926.8046875 , 35845.39453125, 33380.73046875, 35729.5390625 , 35906.84765625], [102604.6484375 , 102463.7421875 , 102852.3125 , 102667.59375 , 102034.6796875 , 102828.7109375 , 102751.40625 , 100405.78125 , 102641.46875 , 102809.828125 ]], [[149377.171875 , 149281.203125 , 149545.625 , 149419.890625 , 148989.1875 , 149529.59375 , 149477. , 147880.203125 , 149402.109375 , 149516.671875 ], [126608.765625 , 126463.4140625 , 126863.078125 , 126672.953125 , 126021.7578125 , 126838.9609375 , 126759.5078125 , 124342.5390625 , 126646.0078125 , 126819.1640625 ]], [[155320.53125 , 155206.171875 , 155521.375 , 155371.515625 , 154858.015625 , 155502.25 , 155439.546875 , 153535.328125 , 155350.3125 , 155486.875 ], [123725.328125 , 123616.875 , 123916.859375 , 123774.3359375 , 123285.9921875 , 123898.515625 , 123838.78125 , 122032.8046875 , 123754.234375 , 123884.2265625 ]], [[ 68918.1328125 , 68738.6953125 , 69232.140625 , 68997.3515625 , 68193.828125 , 69202.359375 , 69104.25 , 66126.2890625 , 68964.0703125 , 69177.8984375 ], [ 64116.609375 , 63962.26171875, 64387.06640625, 64184.87109375, 63494.01953125, 64361.3828125 , 64276.8671875 , 61725.27734375, 64156.234375 , 64340.359375 ]], [[133915.78125 , 133806.109375 , 134108.9375 , 133965.0625 , 133471.5625 , 134090.484375 , 134030.234375 , 132199.734375 , 133944.734375 , 134075.9375 ], [139290.890625 , 139202.421875 , 139448.03125 , 139331.515625 , 138931.3125 , 139432.875 , 139383.953125 , 137902.109375 , 139315.125 , 139421.53125 ]], [[ 97851.0859375 , 97727.8515625 , 98066.171875 , 97905.1484375 , 97354.0078125 , 98045.828125 , 97978.59375 , 95933.09375 , 97882.2890625 , 98028.8828125 ], [ 51638.5703125 , 51478.11328125, 51919.62109375, 51709.453125 , 50991.50390625, 51892.9453125 , 51805.109375 , 49154.03515625, 51679.6796875 , 51871.0546875 ]], [[ 64976.17578125, 64888.53125 , 65130.69921875, 65015.62109375, 64621.30078125, 65115.921875 , 65067.71875 , 63608.1796875 , 64999.375 , 65104.30859375], [129480.15625 , 129385.4375 , 129648.0390625 , 129523.3671875 , 129095.8125 , 129631.8984375 , 129579.5859375 , 127998.71875 , 129505.8125 , 129619.6015625 ]], [[ 24721.80273438, 24639.79296875, 24867.24804688, 24759.17382812, 24389.60351562, 24853.25976562, 24807.91601562, 23448.61328125, 24743.96484375, 24842.5625 ], [107061.8515625 , 106917.234375 , 107315.234375 , 107125.8828125 , 106477.8984375 , 107291.171875 , 107212.0234375 , 104812.0546875 , 107099.0625 , 107271.53125 ]], [[ 72607.0625 , 72531.4296875 , 72740.0078125 , 72640.8125 , 72301.3828125 , 72727.3359375 , 72685.828125 , 71430.6796875 , 72626.7890625 , 72717.1796875 ], [114398.0078125 , 114266. , 114629.921875 , 114456.875 , 113864.3359375 , 114607.828125 , 114535.4296875 , 112341.3515625 , 114432.3984375 , 114590.09375 ]], [[104087.21875 , 103977.6953125 , 104279.203125 , 104135.8359375 , 103644.46875 , 104260.953125 , 104201.0078125 , 102376.9296875 , 104115.53125 , 104246.15625 ], [117260.9921875 , 117155.6328125 , 117446.8359375 , 117308.4453125 , 116834.40625 , 117429.0546875 , 117371.0859375 , 115617.7109375 , 117288.9140625 , 117415.1015625 ]], [[ 94057.4609375 , 93919.03125 , 94299.5625 , 94118.53125 , 93498.515625 , 94276.609375 , 94200.96875 , 91899.6015625 , 94092.8671875 , 94257.734375 ], [ 71002.0078125 , 70863.09375 , 71245.2421875 , 71063.375 , 70441.546875 , 71222.1640625 , 71146.15625 , 68846.09375 , 71037.609375 , 71203.2265625 ]], [[112330.8515625 , 112214.2421875 , 112535.1953125 , 112382.5703125 , 111859.5234375 , 112515.7734375 , 112451.96875 , 110510.0703125 , 112360.9609375 , 112500.0078125 ], [120118.9453125 , 120054.171875 , 120234.0859375 , 120148.75 , 119855.546875 , 120222.9765625 , 120187.1328125 , 119101.140625 , 120136.75 , 120214.6953125 ]], [[ 86687.7578125 , 86592.7578125 , 86854.5859375 , 86730.0703125 , 86303.8046875 , 86838.703125 , 86786.609375 , 85208.390625 , 86712.453125 , 86825.9140625 ], [ 19218.1953125 , 19147.984375 , 19342.8671875 , 19249.48046875, 18939.14648438, 19330.9375 , 19291.82226562, 18210.8515625 , 19236.34765625, 19321.20117188]], [[ 43832.3671875 , 43728.375 , 44015.71875 , 43879.14453125, 43411.4921875 , 43998.1875 , 43940.984375 , 42212.13671875, 43859.8671875 , 43984.38671875], [101950.578125 , 101902.671875 , 102035.890625 , 101972.703125 , 101755.78125 , 102027.6484375 , 102001.09375 , 101199.4296875 , 101963.828125 , 102021.546875 ]], [[ 73639.2578125 , 73547.5625 , 73800.359375 , 73680.1796875 , 73268.3984375 , 73785.0078125 , 73734.7265625 , 72208.3046875 , 73663.1796875 , 73772.7109375 ], [ 82278.609375 , 82237.65625 , 82350.9765625 , 82297.09375 , 82112.9921875 , 82344.0390625 , 82321.4609375 , 81644.0078125 , 82289.5 , 82338.625 ]], [[ 85226.90625 , 85140.6953125 , 85377.8125 , 85265.0390625 , 84878.5546875 , 85363.4921875 , 85316.359375 , 83880.734375 , 85249.0546875 , 85351.78125 ], [ 32416.81445312, 32392.0703125 , 32461.36914062, 32428.15625 , 32318.44140625, 32457.04882812, 32443.0859375 , 32066.41992188, 32423.52148438, 32453.73046875]], [[ 52421.3828125 , 52391.21484375, 52475.328125 , 52435.3515625 , 52299.20703125, 52470.1015625 , 52453.29296875, 51957.75 , 52429.75 , 52466.2421875 ], [107343.4375 , 107282.2890625 , 107450.890625 , 107370.78125 , 107095.8046875 , 107440.6484375 , 107407.1171875 , 106384.828125 , 107359.453125 , 107432.4921875 ]], [[ 49289.08984375, 49264.3203125 , 49332.95703125, 49300.1875 , 49189.8125 , 49328.7578125 , 49315.02734375, 48919.109375 , 49295.57421875, 49325.39453125], [ 69407.6171875 , 69366.828125 , 69479.984375 , 69426.171875 , 69242.7109375 , 69473.03125 , 69450.453125 , 68779.2265625 , 69418.59375 , 69467.6796875 ]], [[107046.53125 , 106950.0546875 , 107215.546875 , 107089.3046875 , 106656.546875 , 107199.484375 , 107146.7109375 , 105539.09375 , 107071.421875 , 107186.4375 ], [ 53900.2734375 , 53866.16796875, 53960.3125 , 53915.29296875, 53764.0859375 , 53954.60546875, 53935.78515625, 53394.6484375 , 53908.93359375, 53949.8515625 ]], [[109147.5546875 , 109006.59375 , 109393.609375 , 109209.453125 , 108578.7109375 , 109370.328125 , 109293.4296875 , 106950.125 , 109183.3125 , 109350.9921875 ], [138774.28125 , 138689.15625 , 138923.515625 , 138812.109375 , 138429.875 , 138909.3125 , 138862.734375 , 137440.828125 , 138796.34375 , 138897.859375 ]]]) np.testing.assert_almost_equal(decomposition_data, decomposition_data_expected) # Remove test nwb files io.close() os.remove('ecephys_exmpl_decomp.nwb') def test_preprocess_raw_data(self): with NWBHDF5IO('ecephys_exmpl_raw.nwb', 'w') as io: io.write(self.nwbfile) config = {'CAR': 16, 'Notch': 60, 'Downsample': 400} preprocess_raw_data('ecephys_exmpl_raw.nwb', config) io = NWBHDF5IO('ecephys_exmpl_raw.nwb', 'r') nwbfile_in = io.read() raw_data = nwbfile_in.processing['ecephys'].data_interfaces['LFP'].electrical_series['preprocessed'].data[:] raw_data_expected = np.array([[0.76711663, 0.70811536], [0.79686718, 0.55776083], [0.96583653, 0.1471569], [0.029647, 0.59389349], [0.1140657, 0.95080985], [0.32570741, 0.19361869], [0.45781165, 0.92040257], [0.87906916, 0.25261576], [0.34800879, 0.18258873], [0.90179605, 0.70652816], [0.72665846, 0.90008784], [0.7791638, 0.59915478], [0.29112524, 0.15139526], [0.33517466, 0.65755178], [0.07334254, 0.0550064], [0.32319481, 0.5904818], [0.85389857, 0.28706243], [0.17306723, 0.13402121], [0.99465383, 0.17949787], [0.31754682, 0.5682914], [0.00934857, 0.90064862], [0.97724143, 0.55689468], [0.08477384, 0.33300247], [0.72842868, 0.14243537], [0.55246894, 0.27304326], [0.97449514, 0.66778691], [0.25565329, 0.10831149], [0.77618072, 0.78247799], [0.76160391, 0.91440311], [0.65862278, 0.56836758], [0.20175569, 0.69829638], [0.95219541, 0.88996329], [0.99356736, 0.81870351], [0.54512217, 0.45125405], [0.89055719, 0.97326479], [0.59341133, 0.3660745], [0.32309469, 0.87142326], [0.21563406, 0.73494519], [0.36561909, 0.8016026], [0.78273559, 0.70135538], [0.62277659, 0.49368265], [0.8405377, 0.71209699], [0.44390898, 0.03103486], [0.36323976, 0.73072179], [0.47556657, 0.34441697], [0.64088043, 0.12620532], [0.17146526, 0.73708649], [0.12702939, 0.36964987], [0.604334, 0.10310444], [0.80237418, 0.94555324]]) np.testing.assert_almost_equal(raw_data, raw_data_expected) # Remove test nwb files io.close() os.remove('ecephys_exmpl_raw.nwb') def test_make_new_nwb(self): with NWBHDF5IO('ecephys_exmpl_make.nwb', 'w') as io: io.write(self.nwbfile) with NWBHDF5IO('new_ecephys_example.nwb', 'w') as io: io.write(self.nwbfile_new) cp_objs = { 'institution': True, 'lab': True, 'session': True, 'devices': True, 'electrode_groups': True, 'electrodes': True, 'intervals': True, 'stimulus': True, 'acquisition': 'default', 'ecephys': 'default' } make_new_nwb('ecephys_exmpl_make.nwb', 'new_ecephys_example.nwb', cp_objs=cp_objs) io1 = NWBHDF5IO('ecephys_exmpl_make.nwb', 'r') nwbfile_in = io1.read() io2 = NWBHDF5IO('new_ecephys_example.nwb', 'r') new_nwbfile_in = io2.read() assert (set(cp_objs.keys()) & set(new_nwbfile_in.fields.keys())).issubset(set(nwbfile_in.fields.keys())) # Remove test nwb files io1.close() io2.close() os.remove('ecephys_exmpl_make.nwb') os.remove('new_ecephys_example.nwb')
class Intan2NWB(NWBConverter): def __init__(self, nwbfile=None, metadata=None, source_paths=None): """ Reads data from Intantech .rhd files, using an adapted version of the rhd reader scripts: http://intantech.com/downloads.html?tabSelect=Software Parameters ---------- nwbfile: pynwb.NWBFile metadata: dict """ super().__init__(nwbfile=nwbfile, metadata=metadata, source_paths=source_paths) def create_nwbfile(self, metadata_nwbfile): """ Overriding method to get session_start_time form rhd files. """ nwbfile_args = dict(identifier=str(uuid.uuid4()), ) nwbfile_args.update(**metadata_nwbfile) session_start_time = self.get_session_start_time( self.source_paths['dir_ecephys_rhd']['path']) nwbfile_args.update(**session_start_time) self.nwbfile = NWBFile(**nwbfile_args) def get_session_start_time(self, dir_ecephys_rhd): """ Gets session_start_time from first rhd file in dir_ecephys_rhd. Parameters ---------- dir_ecephys_rhd: string or Path Returns ------- dict """ dir_ecephys_rhd = Path(dir_ecephys_rhd) all_files_rhd = list(dir_ecephys_rhd.glob('*.rhd')) all_files_rhd.sort() # Gets data/time info from first file name date_string = Path(all_files_rhd[0]).name.split('.')[0].split('_')[1] time_string = Path(all_files_rhd[0]).name.split('.')[0].split('_')[2] date_time_string = date_string + ' ' + time_string date_time_obj = datetime.strptime(date_time_string, '%y%m%d %H%M%S') return {'session_start_time': date_time_obj} def run_conversion(self): """ Reads extracellular electrophysiology data from .rhd files and adds data to nwbfile. """ dir_ecephys_rhd = Path(self.source_paths['dir_ecephys_rhd']['path']) if 'file_electrodes' in self.source_paths: electrodes_file = Path( self.source_paths['file_electrodes']['path']) else: electrodes_file = None def data_gen(source_dir): all_files_rhd = list(dir_ecephys_rhd.glob('*.rhd')) n_files = len(all_files_rhd) # Iterates over all files within the directory for ii, fname in enumerate(all_files_rhd): print("Converting ecephys rhd data: {}%".format(100 * ii / n_files)) file_data = load_intan.read_data(filename=fname) # Gets only valid timestamps valid_ts = file_data['board_dig_in_data'][0] analog_data = file_data['amplifier_data'][:, valid_ts] n_samples = analog_data.shape[1] for sample in range(n_samples): yield analog_data[:, sample] # Gets header data from first file all_files_rhd = list(dir_ecephys_rhd.glob('*.rhd')) all_files_rhd.sort() fid = open(all_files_rhd[0], 'rb') header = read_header.read_header(fid) sampling_rate = header['sample_rate'] self.create_electrodes_ecephys(all_files_rhd=all_files_rhd, electrodes_file=electrodes_file) # Gets electrodes info from first rhd file file_data = load_intan.read_data(filename=all_files_rhd[0]) electrodes_info = file_data['amplifier_channels'] n_electrodes = len(electrodes_info) electrode_table_region = self.nwbfile.create_electrode_table_region( region=list(np.arange(n_electrodes)), description='no description') # Create iterator data_iter = DataChunkIterator( data=data_gen(source_dir=dir_ecephys_rhd), iter_axis=0, buffer_size=10000, maxshape=(None, n_electrodes)) # Electrical Series metadata_ecephys = self.metadata['Ecephys'] # Gets electricalseries conversion factor es_conversion_factor = file_data['amplifier_data_conversion_factor'] ephys_ts = ElectricalSeries( name=metadata_ecephys['ElectricalSeries'][0]['name'], description=metadata_ecephys['ElectricalSeries'][0]['description'], data=data_iter, electrodes=electrode_table_region, rate=sampling_rate, starting_time=0.0, conversion=es_conversion_factor) self.nwbfile.add_acquisition(ephys_ts) def create_electrodes_ecephys(self, all_files_rhd, electrodes_file): """ Parameters ---------- all_files_rhd: list List of paths to rhd files electrodes_file : str Path to CSV file containing extra electrodes information """ # Gets electrodes info from first rhd file file_data = load_intan.read_data(filename=all_files_rhd[0]) electrodes_info = file_data['amplifier_channels'] n_electrodes = len(electrodes_info) # Electrodes if electrodes_file is not None: # if an electrodes info file was provided df_electrodes = pd.read_csv(electrodes_file, index_col='Channel Number') for idx, elec in enumerate(electrodes_info): elec_name = elec['native_channel_name'] elec_group = df_electrodes.loc[elec_name]['electrode_group'] elec_imp = df_electrodes.loc[elec_name][ 'Impedance Magnitude at 1000 Hz (ohms)'] self.nwbfile.add_electrode( id=idx, x=np.nan, y=np.nan, z=np.nan, imp=float(elec_imp), location='location', filtering='none', group=self.nwbfile.electrode_groups[elec_group]) else: # if no electrodes file info was provided first_el_grp = list(self.nwbfile.electrode_groups.keys())[0] electrode_group = self.nwbfile.electrode_groups[first_el_grp] for idx in range(n_electrodes): self.nwbfile.add_electrode(id=idx, x=np.nan, y=np.nan, z=np.nan, imp=np.nan, location='location', filtering='none', group=electrode_group)
device_name = 'LFP device' device = nwbfile.create_device(device_name, source=source) electrode_group = nwbfile.create_electrode_group(name=device_name + '_electrodes', source=lfp_xml_fpath, description=device_name, device=device, location='unknown') for channel in channel_groups[0]: nwbfile.add_electrode( channel, np.nan, np.nan, np.nan, # position? imp=np.nan, location='unknown', filtering='unknown', description='lfp electrode {}'.format(channel), group=electrode_group) lfp_table_region = nwbfile.create_electrode_table_region( list(range(4)), 'lfp electrodes') lfp_elec_series = ElectricalSeries('lfp', 'lfp', gzip(lfp_signal), lfp_table_region, conversion=np.nan, starting_time=0.0, rate=lfp_fs,
class NWBFileTest(TestCase): def setUp(self): self.start = datetime(2017, 5, 1, 12, 0, 0, tzinfo=tzlocal()) self.ref_time = datetime(1979, 1, 1, 0, tzinfo=tzutc()) self.create = [ datetime(2017, 5, 1, 12, tzinfo=tzlocal()), datetime(2017, 5, 2, 13, 0, 0, 1, tzinfo=tzutc()), datetime(2017, 5, 2, 14, tzinfo=tzutc()) ] self.path = 'nwbfile_test.h5' self.nwbfile = NWBFile( 'a test session description for a test NWBFile', 'FILE123', self.start, file_create_date=self.create, timestamps_reference_time=self.ref_time, experimenter='A test experimenter', lab='a test lab', institution='a test institution', experiment_description='a test experiment description', session_id='test1', notes='my notes', pharmacology='drugs', protocol='protocol', related_publications='my pubs', slices='my slices', surgery='surgery', virus='a virus', source_script='noscript', source_script_file_name='nofilename', stimulus_notes='test stimulus notes', data_collection='test data collection notes', keywords=('these', 'are', 'keywords')) def test_constructor(self): self.assertEqual(self.nwbfile.session_description, 'a test session description for a test NWBFile') self.assertEqual(self.nwbfile.identifier, 'FILE123') self.assertEqual(self.nwbfile.session_start_time, self.start) self.assertEqual(self.nwbfile.file_create_date, self.create) self.assertEqual(self.nwbfile.lab, 'a test lab') self.assertEqual(self.nwbfile.experimenter, ('A test experimenter', )) self.assertEqual(self.nwbfile.institution, 'a test institution') self.assertEqual(self.nwbfile.experiment_description, 'a test experiment description') self.assertEqual(self.nwbfile.session_id, 'test1') self.assertEqual(self.nwbfile.stimulus_notes, 'test stimulus notes') self.assertEqual(self.nwbfile.data_collection, 'test data collection notes') self.assertEqual(self.nwbfile.related_publications, ('my pubs', )) self.assertEqual(self.nwbfile.source_script, 'noscript') self.assertEqual(self.nwbfile.source_script_file_name, 'nofilename') self.assertEqual(self.nwbfile.keywords, ('these', 'are', 'keywords')) self.assertEqual(self.nwbfile.timestamps_reference_time, self.ref_time) def test_create_electrode_group(self): name = 'example_electrode_group' desc = 'An example electrode' loc = 'an example location' d = self.nwbfile.create_device('a fake device') elecgrp = self.nwbfile.create_electrode_group(name, desc, loc, d) self.assertEqual(elecgrp.description, desc) self.assertEqual(elecgrp.location, loc) self.assertIs(elecgrp.device, d) def test_create_custom_intervals(self): df_words = pd.DataFrame({ 'start_time': [.1, 2.], 'stop_time': [.8, 2.3], 'label': ['hello', 'there'] }) words = TimeIntervals.from_dataframe(df_words, name='words') self.nwbfile.add_time_intervals(words) self.assertEqual(self.nwbfile.intervals['words'], words) def test_create_electrode_group_invalid_index(self): """ Test the case where the user creates an electrode table region with indexes that are out of range of the amount of electrodes added. """ nwbfile = NWBFile('a', 'b', datetime.now(tzlocal())) device = nwbfile.create_device('a') elecgrp = nwbfile.create_electrode_group('a', 'b', device=device, location='a') for i in range(4): nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'a', 'a', elecgrp, id=i) with self.assertRaises(IndexError): nwbfile.create_electrode_table_region(list(range(6)), 'test') def test_access_group_after_io(self): """ Motivated by #739 """ nwbfile = NWBFile('a', 'b', datetime.now(tzlocal())) device = nwbfile.create_device('a') elecgrp = nwbfile.create_electrode_group('a', 'b', device=device, location='a') nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'a', 'a', elecgrp, id=0) with NWBHDF5IO('electrodes_mwe.nwb', 'w') as io: io.write(nwbfile) with NWBHDF5IO('electrodes_mwe.nwb', 'a') as io: nwbfile_i = io.read() for aa, bb in zip(nwbfile_i.electrodes['group'][:], nwbfile.electrodes['group'][:]): self.assertEqual(aa.name, bb.name) for i in range(4): nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'a', 'a', elecgrp, id=i + 1) with NWBHDF5IO('electrodes_mwe.nwb', 'w') as io: io.write(nwbfile) with NWBHDF5IO('electrodes_mwe.nwb', 'a') as io: nwbfile_i = io.read() for aa, bb in zip(nwbfile_i.electrodes['group'][:], nwbfile.electrodes['group'][:]): self.assertEqual(aa.name, bb.name) remove_test_file("electrodes_mwe.nwb") def test_access_processing(self): self.nwbfile.create_processing_module('test_mod', 'test_description') # test deprecate .modules with self.assertWarnsWith(DeprecationWarning, 'replaced by NWBFile.processing'): modules = self.nwbfile.modules['test_mod'] self.assertIs(self.nwbfile.processing['test_mod'], modules) def test_epoch_tags(self): tags1 = ['t1', 't2'] tags2 = ['t3', 't4'] tstamps = np.arange(1.0, 100.0, 0.1, dtype=np.float) ts = TimeSeries("test_ts", list(range(len(tstamps))), 'unit', timestamps=tstamps) expected_tags = tags1 + tags2 self.nwbfile.add_epoch(0.0, 1.0, tags1, ts) self.nwbfile.add_epoch(0.0, 1.0, tags2, ts) tags = self.nwbfile.epoch_tags self.assertEqual(set(expected_tags), set(tags)) def test_add_acquisition(self): self.nwbfile.add_acquisition( TimeSeries('test_ts', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) self.assertEqual(len(self.nwbfile.acquisition), 1) def test_add_stimulus(self): self.nwbfile.add_stimulus( TimeSeries('test_ts', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) self.assertEqual(len(self.nwbfile.stimulus), 1) def test_add_stimulus_template(self): self.nwbfile.add_stimulus_template( TimeSeries('test_ts', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) self.assertEqual(len(self.nwbfile.stimulus_template), 1) def test_add_analysis(self): self.nwbfile.add_analysis( TimeSeries('test_ts', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) self.assertEqual(len(self.nwbfile.analysis), 1) def test_add_acquisition_check_dups(self): self.nwbfile.add_acquisition( TimeSeries('test_ts', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) with self.assertRaises(ValueError): self.nwbfile.add_acquisition( TimeSeries('test_ts', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) def test_get_acquisition_empty(self): with self.assertRaisesWith(ValueError, "acquisition of NWBFile 'root' is empty"): self.nwbfile.get_acquisition() def test_get_acquisition_multiple_elements(self): self.nwbfile.add_acquisition( TimeSeries('test_ts1', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) self.nwbfile.add_acquisition( TimeSeries('test_ts2', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) msg = "more than one element in acquisition of NWBFile 'root' -- must specify a name" with self.assertRaisesWith(ValueError, msg): self.nwbfile.get_acquisition() def test_add_acquisition_invalid_name(self): self.nwbfile.add_acquisition( TimeSeries('test_ts', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5])) msg = "\"'TEST_TS' not found in acquisition of NWBFile 'root'\"" with self.assertRaisesWith(KeyError, msg): self.nwbfile.get_acquisition("TEST_TS") def test_set_electrode_table(self): table = ElectrodeTable() dev1 = self.nwbfile.create_device('dev1') group = self.nwbfile.create_electrode_group('tetrode1', 'tetrode description', 'tetrode location', dev1) table.add_row(x=1.0, y=2.0, z=3.0, imp=-1.0, location='CA1', filtering='none', group=group, group_name='tetrode1') table.add_row(x=1.0, y=2.0, z=3.0, imp=-2.0, location='CA1', filtering='none', group=group, group_name='tetrode1') table.add_row(x=1.0, y=2.0, z=3.0, imp=-3.0, location='CA1', filtering='none', group=group, group_name='tetrode1') table.add_row(x=1.0, y=2.0, z=3.0, imp=-4.0, location='CA1', filtering='none', group=group, group_name='tetrode1') self.nwbfile.set_electrode_table(table) self.assertIs(self.nwbfile.electrodes, table) self.assertIs(table.parent, self.nwbfile) def test_add_unit_column(self): self.nwbfile.add_unit_column('unit_type', 'the type of unit') self.assertEqual(self.nwbfile.units.colnames, ('unit_type', )) def test_add_unit(self): self.nwbfile.add_unit(id=1) self.assertEqual(len(self.nwbfile.units), 1) self.nwbfile.add_unit(id=2) self.nwbfile.add_unit(id=3) self.assertEqual(len(self.nwbfile.units), 3) def test_add_trial_column(self): self.nwbfile.add_trial_column('trial_type', 'the type of trial') self.assertEqual(self.nwbfile.trials.colnames, ('start_time', 'stop_time', 'trial_type')) def test_add_trial(self): self.nwbfile.add_trial(start_time=10.0, stop_time=20.0) self.assertEqual(len(self.nwbfile.trials), 1) self.nwbfile.add_trial(start_time=30.0, stop_time=40.0) self.nwbfile.add_trial(start_time=50.0, stop_time=70.0) self.assertEqual(len(self.nwbfile.trials), 3) def test_add_invalid_times_column(self): self.nwbfile.add_invalid_times_column( 'comments', 'description of reason for omitting time') self.assertEqual(self.nwbfile.invalid_times.colnames, ('start_time', 'stop_time', 'comments')) def test_add_invalid_time_interval(self): self.nwbfile.add_invalid_time_interval(start_time=0.0, stop_time=12.0) self.assertEqual(len(self.nwbfile.invalid_times), 1) self.nwbfile.add_invalid_time_interval(start_time=15.0, stop_time=16.0) self.nwbfile.add_invalid_time_interval(start_time=17.0, stop_time=20.5) self.assertEqual(len(self.nwbfile.invalid_times), 3) def test_add_invalid_time_w_ts(self): ts = TimeSeries(name='name', data=[1.2], rate=1.0, unit='na') self.nwbfile.add_invalid_time_interval(start_time=18.0, stop_time=20.6, timeseries=ts, tags=('hi', 'there')) def test_add_electrode(self): dev1 = self.nwbfile.create_device('dev1') group = self.nwbfile.create_electrode_group('tetrode1', 'tetrode description', 'tetrode location', dev1) self.nwbfile.add_electrode(1.0, 2.0, 3.0, -1.0, 'CA1', 'none', group=group, id=1) elec = self.nwbfile.electrodes[0] self.assertEqual(elec.index[0], 1) self.assertEqual(elec.iloc[0]['x'], 1.0) self.assertEqual(elec.iloc[0]['y'], 2.0) self.assertEqual(elec.iloc[0]['z'], 3.0) self.assertEqual(elec.iloc[0]['location'], 'CA1') self.assertEqual(elec.iloc[0]['filtering'], 'none') self.assertEqual(elec.iloc[0]['group'], group) def test_all_children(self): ts1 = TimeSeries('test_ts1', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]) ts2 = TimeSeries('test_ts2', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]) self.nwbfile.add_acquisition(ts1) self.nwbfile.add_acquisition(ts2) name = 'example_electrode_group' desc = 'An example electrode' loc = 'an example location' device = self.nwbfile.create_device('a fake device') elecgrp = self.nwbfile.create_electrode_group(name, desc, loc, device) children = self.nwbfile.all_children() self.assertIn(ts1, children) self.assertIn(ts2, children) self.assertIn(device, children) self.assertIn(elecgrp, children) def test_fail_if_source_script_file_name_without_source_script(self): with self.assertRaises(ValueError): # <-- source_script_file_name without source_script is not allowed NWBFile('a test session description for a test NWBFile', 'FILE123', self.start, source_script=None, source_script_file_name='nofilename') def test_get_neurodata_type(self): ts1 = TimeSeries('test_ts1', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]) ts2 = TimeSeries('test_ts2', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]) self.nwbfile.add_acquisition(ts1) self.nwbfile.add_acquisition(ts2) p1 = ts1.get_ancestor(neurodata_type='NWBFile') self.assertIs(p1, self.nwbfile) p2 = ts2.get_ancestor(neurodata_type='NWBFile') self.assertIs(p2, self.nwbfile) def test_print_units(self): self.nwbfile.add_unit(spike_times=[1., 2., 3.]) expected = """units pynwb.misc.Units at 0x%d Fields: colnames: ['spike_times'] columns: ( spike_times_index <class 'hdmf.common.table.VectorIndex'>, spike_times <class 'hdmf.common.table.VectorData'> ) description: Autogenerated by NWBFile id: id <class 'hdmf.common.table.ElementIdentifiers'> """ expected = expected % id(self.nwbfile.units) self.assertEqual(str(self.nwbfile.units), expected) def test_copy(self): self.nwbfile.add_unit(spike_times=[1., 2., 3.]) device = self.nwbfile.create_device('a') elecgrp = self.nwbfile.create_electrode_group('a', 'b', device=device, location='a') self.nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'a', 'a', elecgrp, id=0) self.nwbfile.add_electrode(np.nan, np.nan, np.nan, np.nan, 'b', 'b', elecgrp) elec_region = self.nwbfile.create_electrode_table_region([1], 'name') ts1 = TimeSeries('test_ts1', [0, 1, 2, 3, 4, 5], 'grams', timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]) ts2 = ElectricalSeries('test_ts2', [0, 1, 2, 3, 4, 5], electrodes=elec_region, timestamps=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5]) self.nwbfile.add_acquisition(ts1) self.nwbfile.add_acquisition(ts2) self.nwbfile.add_trial(start_time=50.0, stop_time=70.0) self.nwbfile.add_invalid_times_column( 'comments', 'description of reason for omitting time') self.nwbfile.create_processing_module('test_mod', 'test_description') self.nwbfile.create_time_intervals('custom_interval', 'a custom time interval') self.nwbfile.intervals['custom_interval'].add_interval(start_time=10., stop_time=20.) newfile = self.nwbfile.copy() # test dictionaries self.assertIs(self.nwbfile.devices['a'], newfile.devices['a']) self.assertIs(self.nwbfile.acquisition['test_ts1'], newfile.acquisition['test_ts1']) self.assertIs(self.nwbfile.acquisition['test_ts2'], newfile.acquisition['test_ts2']) self.assertIs(self.nwbfile.processing['test_mod'], newfile.processing['test_mod']) # test dynamic tables self.assertIsNot(self.nwbfile.electrodes, newfile.electrodes) self.assertIs(self.nwbfile.electrodes['x'], newfile.electrodes['x']) self.assertIsNot(self.nwbfile.units, newfile.units) self.assertIs(self.nwbfile.units['spike_times'], newfile.units['spike_times']) self.assertIsNot(self.nwbfile.trials, newfile.trials) self.assertIsNot(self.nwbfile.trials.parent, newfile.trials.parent) self.assertIs(self.nwbfile.trials.id, newfile.trials.id) self.assertIs(self.nwbfile.trials['start_time'], newfile.trials['start_time']) self.assertIs(self.nwbfile.trials['stop_time'], newfile.trials['stop_time']) self.assertIsNot(self.nwbfile.invalid_times, newfile.invalid_times) self.assertTupleEqual(self.nwbfile.invalid_times.colnames, newfile.invalid_times.colnames) self.assertIsNot(self.nwbfile.intervals['custom_interval'], newfile.intervals['custom_interval']) self.assertTupleEqual( self.nwbfile.intervals['custom_interval'].colnames, newfile.intervals['custom_interval'].colnames) self.assertIs(self.nwbfile.intervals['custom_interval']['start_time'], newfile.intervals['custom_interval']['start_time']) self.assertIs(self.nwbfile.intervals['custom_interval']['stop_time'], newfile.intervals['custom_interval']['stop_time']) def test_multi_experimenters(self): self.nwbfile = NWBFile('a test session description for a test NWBFile', 'FILE123', self.start, experimenter=('experimenter1', 'experimenter2')) self.assertTupleEqual(self.nwbfile.experimenter, ('experimenter1', 'experimenter2')) def test_multi_publications(self): self.nwbfile = NWBFile('a test session description for a test NWBFile', 'FILE123', self.start, related_publications=('pub1', 'pub2')) self.assertTupleEqual(self.nwbfile.related_publications, ('pub1', 'pub2'))
ns.write_electrode_table(nwbfile, fpath) # shank electrodes device = nwbfile.create_device('implant', fname + '.xml') electrode_counter = 0 for shankn, channels in enumerate(shank_channels): electrode_group = nwbfile.create_electrode_group( name='shank{}'.format(shankn), description=fname, device=device, location='unknown') for channel in channels: nwbfile.add_electrode( np.nan, np.nan, np.nan, # position? imp=np.nan, location='unknown', filtering='unknown', description='electrode {} of shank {}, channel {}'.format( electrode_counter, shankn, channel), group=electrode_group) if channel == lfp_channel: lfp_table_region = nwbfile.create_electrode_table_region( [electrode_counter], 'lfp electrode') electrode_counter += 1 all_table_region = nwbfile.create_electrode_table_region( list(range(electrode_counter)), 'all electrodes') print('done.')
def writeRecording(recording, save_path, acquisition_name): try: from pynwb import NWBHDF5IO from pynwb import NWBFile from pynwb.ecephys import ElectricalSeries except ModuleNotFoundError: raise ModuleNotFoundError( "To use the Nwb extractors, install pynwb: \n\n" "pip install pynwb\n\n") M = recording.getNumChannels() N = recording.getNumFrames() nwbfile = NWBFile(source='SpikeInterface::NwbRecordingExtractor', session_description='', identifier='', session_start_time=datetime.now(), experimenter='', lab='', institution='', experiment_description='', session_id='') device = nwbfile.create_device(name='device_name', source="device_source") eg_name = 'electrode_group_name' eg_source = "electrode_group_source" eg_description = "electrode_group_description" eg_location = "electrode_group_location" electrode_group = nwbfile.create_electrode_group( name=eg_name, source=eg_source, location=eg_location, device=device, description=eg_description) for m in range(M): id = m location = recording.getChannelProperty(m, 'location') impedence = -1.0 while len(location) < 3: location = np.append(location, [0]) nwbfile.add_electrode(id, x=float(location[0]), y=float(location[1]), z=float(location[2]), imp=impedence, location='electrode_location', filtering='none', group=electrode_group, description='electrode_description') electrode_table_region = nwbfile.create_electrode_table_region( list(range(M)), 'electrode_table_region') rate = recording.getSamplingFrequency() / 1000 ephys_data = recording.getTraces().T ephys_ts = ElectricalSeries( name=acquisition_name, source='acquisition_source', data=ephys_data, electrodes=electrode_table_region, starting_time=recording.frameToTime(0), rate=rate, resolution=1e-6, comments='Generated from SpikeInterface::NwbRecordingExtractor', description='acquisition_description') nwbfile.add_acquisition(ephys_ts) if os.path.exists(save_path): os.remove(save_path) with NWBHDF5IO(save_path, 'w') as io: io.write(nwbfile)