def make(self, nwb_content: NWBFile):
        position = Position(name='position')
        cameras_ids = get_cameras_ids(self.dataset_names, self.metadata)
        meters_per_pixels = get_meters_per_pixels(cameras_ids, self.metadata)
        pos_online_paths = []
        for dataset in self.datasets:
            for pos_file in dataset.get_all_data_from_dataset('pos'):
                if pos_file.endswith('.pos_online.dat'):
                    pos_online_paths.append(
                        os.path.join(dataset.get_data_path_from_dataset('pos'),
                                     pos_file))
        first_timestamps = []
        for series_id, (conversion, pos_online_path) in enumerate(
                zip(meters_per_pixels, pos_online_paths)):
            position_df = self.get_position_with_corrected_timestamps(
                pos_online_path)
            position.create_spatial_series(
                name=f'series_{series_id}',
                description=', '.join(position_df.columns.tolist()),
                data=np.asarray(position_df),
                conversion=conversion,
                reference_frame='Upper left corner of video frame',
                timestamps=np.asarray(position_df.index),
            )
            first_timestamps.append(position_df.index[0])

        # check if timestamps are in order
        first_timestamps = np.asarray(first_timestamps)
        assert np.all(first_timestamps[:-1] < first_timestamps[1:])

        logger.info('Position: Injecting into Processing Module')
        nwb_content.processing['behavior'].add(position)
Example #2
0
def add_behavior(nwbfile, expt):

    bd = expt.behaviorData(imageSync=True)

    fs = 1 / expt.frame_period()

    behavior_module = nwbfile.create_processing_module(
        name='Behavior', description='Data relevant to behavior')

    # Add Normalized Position

    pos = Position(name='Normalized Position')
    pos.create_spatial_series(name='Normalized Position',
                              rate=fs,
                              data=bd['treadmillPosition'][:, np.newaxis],
                              reference_frame='0 is belt start',
                              conversion=0.001 * bd['trackLength'])

    behavior_module.add_container(pos)

    # Add Licking

    licking = BehavioralTimeSeries(name='Licking')
    licking.create_timeseries(
        name='Licking',
        data=bd['licking'],
        rate=fs,
        unit='na',
        description='1 if mouse licked during this imaging frame')

    behavior_module.add_container(licking)

    # Add Water Reward Delivery

    water = BehavioralTimeSeries(name='Water')
    water.create_timeseries(
        name='Water',
        data=bd['water'],
        rate=fs,
        unit='na',
        description='1 if water was delivered during this imaging frame')

    behavior_module.add_container(water)

    # Add Lap Times
    laps = BehavioralEvents(name='Lap Starts')
    # TODO probably not best to have laps as data and timestamps here
    laps.create_timeseries(name='Lap Starts',
                           data=bd['lap'],
                           timestamps=bd['lap'],
                           description='Frames at which laps began',
                           unit='na')

    behavior_module.add_container(laps)
Example #3
0
 def create(position: Position, series_id: int, fl_position: FlPosition):
     validate_parameters_not_none(__name__, fl_position.column_labels, fl_position.position_data,
                                  fl_position.conversion)
     position.create_spatial_series(
         name='series_' + str(series_id),
         description=fl_position.column_labels,
         data=fl_position.position_data,
         conversion=fl_position.conversion,
         reference_frame='Upper left corner of video frame',
         timestamps=fl_position.timestamps,
     )
Example #4
0
# :py:class:`~pynwb.behavior.SpatialSeries` objects. :py:class:`~pynwb.behavior.SpatialSeries` is a subtype of
# :py:class:`~pynwb.base.TimeSeries` that represents the spatial position of an animal over time. By putting
# your position data into a :py:class:`~pynwb.behavior.Position` container, downstream users and
# tools know where to look to retrieve position data. For a comprehensive list of available data interfaces, see the
# :ref:`overview page <modules_overview>`. Here is how to create a :py:class:`~pynwb.behavior.Position` object
# named '`Position'` [#]_.

from pynwb.behavior import Position

position = Position()

####################
# You can add objects to a data interface as a method of the data interface:

position.create_spatial_series(name='position1',
                               data=np.linspace(0, 1, 20),
                               rate=50.,
                               reference_frame='starting gate')

####################
# or you can add pre-existing objects:

from pynwb.behavior import SpatialSeries

spatial_series = SpatialSeries(name='position2',
                               data=np.linspace(0, 1, 20),
                               rate=50.,
                               reference_frame='starting gate')

position.add_spatial_series(spatial_series)

####################
Example #5
0
def conversion_function(source_paths,
                        f_nwb,
                        metadata,
                        add_raw=False,
                        add_processed=True,
                        add_behavior=True,
                        plot_rois=False):
    """
    Copy data stored in a set of .npz files to a single NWB file.

    Parameters
    ----------
    source_paths : dict
        Dictionary with paths to source files/directories. e.g.:
        {'raw_data': {'type': 'file', 'path': ''},
         'raw_info': {'type': 'file', 'path': ''}
         'processed_data': {'type': 'file', 'path': ''},
         'sparse_matrix': {'type': 'file', 'path': ''},
         'ref_image',: {'type': 'file', 'path': ''}}
    f_nwb : str
        Path to output NWB file, e.g. 'my_file.nwb'.
    metadata : dict
        Metadata dictionary
    add_raw : bool
        Whether to convert raw data or not.
    add_processed : bool
        Whether to convert processed data or not.
    add_behavior : bool
        Whether to convert behavior data or not.
    plot_rois : bool
        Plot ROIs
    """

    # Source files
    file_raw = None
    file_info = None
    file_processed = None
    file_sparse_matrix = None
    file_reference_image = None
    for k, v in source_paths.items():
        if source_paths[k]['path'] != '':
            fname = source_paths[k]['path']
            if k == 'raw_data':
                file_raw = h5py.File(fname, 'r')
            if k == 'raw_info':
                file_info = scipy.io.loadmat(fname,
                                             struct_as_record=False,
                                             squeeze_me=True)
            if k == 'processed_data':
                file_processed = np.load(fname)
            if k == 'sparse_matrix':
                file_sparse_matrix = np.load(fname)
            if k == 'ref_image':
                file_reference_image = np.load(fname)

    # Initialize a NWB object
    nwb = NWBFile(**metadata['NWBFile'])

    # Create and add device
    device = Device(name=metadata['Ophys']['Device'][0]['name'])
    nwb.add_device(device)

    # Creates one Imaging Plane for each channel
    fs = 1. / (file_processed['time'][0][1] - file_processed['time'][0][0])
    for meta_ip in metadata['Ophys']['ImagingPlane']:
        # Optical channel
        opt_ch = OpticalChannel(
            name=meta_ip['optical_channel'][0]['name'],
            description=meta_ip['optical_channel'][0]['description'],
            emission_lambda=meta_ip['optical_channel'][0]['emission_lambda'])
        nwb.create_imaging_plane(
            name=meta_ip['name'],
            optical_channel=opt_ch,
            description=meta_ip['description'],
            device=device,
            excitation_lambda=meta_ip['excitation_lambda'],
            imaging_rate=fs,
            indicator=meta_ip['indicator'],
            location=meta_ip['location'],
        )

    # Raw optical data
    if add_raw:
        print('Adding raw data...')
        for meta_tps in metadata['Ophys']['TwoPhotonSeries']:
            if meta_tps['name'][-1] == 'R':
                raw_data = file_raw['R']
            else:
                raw_data = file_raw['Y']

            def data_gen(data):
                xl, yl, zl, tl = data.shape
                chunk = 0
                while chunk < tl:
                    val = data[:, :, :, chunk]
                    chunk += 1
                    print('adding data chunk: ', chunk)
                    yield val

            xl, yl, zl, tl = raw_data.shape
            tps_data = DataChunkIterator(data=data_gen(data=raw_data),
                                         iter_axis=0,
                                         maxshape=(tl, xl, yl, zl))

            # Change dimensions from (X,Y,Z,T) in mat file to (T,X,Y,Z) nwb standard
            #raw_data = np.moveaxis(raw_data, -1, 0)

            tps = TwoPhotonSeries(
                name=meta_tps['name'],
                imaging_plane=nwb.imaging_planes[meta_tps['imaging_plane']],
                data=tps_data,
                rate=file_info['info'].daq.scanRate)
            nwb.add_acquisition(tps)

    # Processed data
    if add_processed:
        print('Adding processed data...')
        ophys_module = ProcessingModule(
            name='Ophys',
            description='contains optical physiology processed data.',
        )
        nwb.add_processing_module(ophys_module)

        # Create Image Segmentation compartment
        img_seg = ImageSegmentation(
            name=metadata['Ophys']['ImageSegmentation']['name'])
        ophys_module.add(img_seg)

        # Create plane segmentation and add ROIs
        meta_ps = metadata['Ophys']['ImageSegmentation'][
            'plane_segmentations'][0]
        ps = img_seg.create_plane_segmentation(
            name=meta_ps['name'],
            description=meta_ps['description'],
            imaging_plane=nwb.imaging_planes[meta_ps['imaging_plane']],
        )

        # Add ROIs
        indices = file_sparse_matrix['indices']
        indptr = file_sparse_matrix['indptr']
        dims = np.squeeze(file_processed['dims'])
        for start, stop in zip(indptr, indptr[1:]):
            voxel_mask = make_voxel_mask(indices[start:stop], dims)
            ps.add_roi(voxel_mask=voxel_mask)

        # Visualize 3D voxel masks
        if plot_rois:
            plot_rois_function(plane_segmentation=ps, indptr=indptr)

        # DFF measures
        dff = DfOverF(name=metadata['Ophys']['DfOverF']['name'])
        ophys_module.add(dff)

        # create ROI regions
        n_cells = file_processed['dFF'].shape[0]
        roi_region = ps.create_roi_table_region(description='RoiTableRegion',
                                                region=list(range(n_cells)))

        # create ROI response series
        dff_data = file_processed['dFF']
        tt = file_processed['time'].ravel()
        meta_rrs = metadata['Ophys']['DfOverF']['roi_response_series'][0]
        meta_rrs['data'] = dff_data.T
        meta_rrs['rois'] = roi_region
        meta_rrs['timestamps'] = tt
        dff.create_roi_response_series(**meta_rrs)

        # Creates GrayscaleVolume containers and add a reference image
        grayscale_volume = GrayscaleVolume(
            name=metadata['Ophys']['GrayscaleVolume']['name'],
            data=file_reference_image['im'])
        ophys_module.add(grayscale_volume)

    # Behavior data
    if add_behavior:
        print('Adding behavior data...')
        # Ball motion
        behavior_mod = nwb.create_processing_module(
            name='Behavior',
            description='holds processed behavior data',
        )
        meta_ts = metadata['Behavior']['TimeSeries'][0]
        meta_ts['data'] = file_processed['ball'].ravel()
        tt = file_processed['time'].ravel()
        meta_ts['timestamps'] = tt
        behavior_ts = TimeSeries(**meta_ts)
        behavior_mod.add(behavior_ts)

        # Re-arranges spatial data of body-points positions tracking
        pos = file_processed['dlc']
        n_points = 8
        pos_reshaped = pos.reshape(
            (-1, n_points, 3))  # dims=(nSamples,n_points,3)

        # Creates a Position object and add one SpatialSeries for each body-point position
        position = Position()
        for i in range(n_points):
            position.create_spatial_series(
                name='SpatialSeries_' + str(i),
                data=pos_reshaped[:, i, :],
                timestamps=tt,
                reference_frame=
                'Description defining what the zero-position is.',
                conversion=np.nan)
        behavior_mod.add(position)

    # Trial times
    trialFlag = file_processed['trialFlag'].ravel()
    trial_inds = np.hstack(
        (0, np.where(np.diff(trialFlag))[0], trialFlag.shape[0] - 1))
    trial_times = tt[trial_inds]

    for start, stop in zip(trial_times, trial_times[1:]):
        nwb.add_trial(start_time=start, stop_time=stop)

    # Saves to NWB file
    with NWBHDF5IO(f_nwb, mode='w') as io:
        io.write(nwb)
    print('NWB file saved with size: ', os.stat(f_nwb).st_size / 1e6, ' mb')
Example #6
0
def convert(
        input_file,
        session_start_time,
        subject_date_of_birth,
        subject_id='I5',
        subject_description='naive',
        subject_genotype='wild-type',
        subject_sex='M',
        subject_weight='11.6g',
        subject_species='Mus musculus',
        subject_brain_region='Medial Entorhinal Cortex',
        surgery='Probe: +/-3.3mm ML, 0.2mm A of sinus, then as deep as possible',
        session_id='npI5_0417_baseline_1',
        experimenter='Kei Masuda',
        experiment_description='Virtual Hallway Task',
        institution='Stanford University School of Medicine',
        lab_name='Giocomo Lab'):
    """
    Read in the .mat file specified by input_file and convert to .nwb format.

    Parameters
    ----------
    input_file : np.ndarray (..., n_channels, n_time)
        the .mat file to be converted
    subject_id : string
        the unique subject ID number for the subject of the experiment
    subject_date_of_birth : datetime ISO 8601
        the date and time the subject was born
    subject_description : string
        important information specific to this subject that differentiates it from other members of it's species
    subject_genotype : string
        the genetic strain of this species.
    subject_sex : string
        Male or Female
    subject_weight :
        the weight of the subject around the time of the experiment
    subject_species : string
        the name of the species of the subject
    subject_brain_region : basestring
        the name of the brain region where the electrode probe is recording from
    surgery : str
        information about the subject's surgery to implant electrodes
    session_id: string
        human-readable ID# for the experiment session that has a one-to-one relationship with a recording session
    session_start_time : datetime
        date and time that the experiment started
    experimenter : string
        who ran the experiment, first and last name
    experiment_description : string
        what task was being run during the session
    institution : string
        what institution was the experiment performed in
    lab_name : string
        the lab where the experiment was performed

    Returns
    -------
    nwbfile : NWBFile
        The contents of the .mat file converted into the NWB format.  The nwbfile is saved to disk using NDWHDF5
    """

    # input matlab data
    matfile = hdf5storage.loadmat(input_file)

    # output path for nwb data
    def replace_last(source_string, replace_what, replace_with):
        head, _sep, tail = source_string.rpartition(replace_what)
        return head + replace_with + tail

    outpath = replace_last(input_file, '.mat', '.nwb')

    create_date = datetime.today()
    timezone_cali = pytz.timezone('US/Pacific')
    create_date_tz = timezone_cali.localize(create_date)

    # if loading data from config.yaml, convert string dates into datetime
    if isinstance(session_start_time, str):
        session_start_time = datetime.strptime(session_start_time,
                                               '%B %d, %Y %I:%M%p')
        session_start_time = timezone_cali.localize(session_start_time)

    if isinstance(subject_date_of_birth, str):
        subject_date_of_birth = datetime.strptime(subject_date_of_birth,
                                                  '%B %d, %Y %I:%M%p')
        subject_date_of_birth = timezone_cali.localize(subject_date_of_birth)

    # create unique identifier for this experimental session
    uuid_identifier = uuid.uuid1()

    # Create NWB file
    nwbfile = NWBFile(
        session_description=experiment_description,  # required
        identifier=uuid_identifier.hex,  # required
        session_id=session_id,
        experiment_description=experiment_description,
        experimenter=experimenter,
        surgery=surgery,
        institution=institution,
        lab=lab_name,
        session_start_time=session_start_time,  # required
        file_create_date=create_date_tz)  # optional

    # add information about the subject of the experiment
    experiment_subject = Subject(subject_id=subject_id,
                                 species=subject_species,
                                 description=subject_description,
                                 genotype=subject_genotype,
                                 date_of_birth=subject_date_of_birth,
                                 weight=subject_weight,
                                 sex=subject_sex)
    nwbfile.subject = experiment_subject

    # adding constants via LabMetaData container
    # constants
    sample_rate = float(matfile['sp'][0]['sample_rate'][0][0][0])
    n_channels_dat = int(matfile['sp'][0]['n_channels_dat'][0][0][0])
    dat_path = matfile['sp'][0]['dat_path'][0][0][0]
    offset = int(matfile['sp'][0]['offset'][0][0][0])
    data_dtype = matfile['sp'][0]['dtype'][0][0][0]
    hp_filtered = bool(matfile['sp'][0]['hp_filtered'][0][0][0])
    vr_session_offset = matfile['sp'][0]['vr_session_offset'][0][0][0]
    # container
    lab_metadata = LabMetaData_ext(name='LabMetaData',
                                   acquisition_sampling_rate=sample_rate,
                                   number_of_electrodes=n_channels_dat,
                                   file_path=dat_path,
                                   bytes_to_skip=offset,
                                   raw_data_dtype=data_dtype,
                                   high_pass_filtered=hp_filtered,
                                   movie_start_time=vr_session_offset)
    nwbfile.add_lab_meta_data(lab_metadata)

    # Adding trial information
    nwbfile.add_trial_column(
        'trial_contrast',
        'visual contrast of the maze through which the mouse is running')
    trial = np.ravel(matfile['trial'])
    trial_nums = np.unique(trial)
    position_time = np.ravel(matfile['post'])
    # matlab trial numbers start at 1. To correctly index trial_contract vector,
    # subtracting 1 from 'num' so index starts at 0
    for num in trial_nums:
        trial_times = position_time[trial == num]
        nwbfile.add_trial(start_time=trial_times[0],
                          stop_time=trial_times[-1],
                          trial_contrast=matfile['trial_contrast'][num - 1][0])

    # Add mouse position inside:
    position = Position()
    position_virtual = np.ravel(matfile['posx'])
    # position inside the virtual environment
    sampling_rate = 1 / (position_time[1] - position_time[0])
    position.create_spatial_series(
        name='Position',
        data=position_virtual,
        starting_time=position_time[0],
        rate=sampling_rate,
        reference_frame='The start of the trial, which begins at the start '
        'of the virtual hallway.',
        conversion=0.01,
        description='Subject position in the virtual hallway.',
        comments='The values should be >0 and <400cm. Values greater than '
        '400cm mean that the mouse briefly exited the maze.',
    )

    # physical position on the mouse wheel
    physical_posx = position_virtual
    trial_gain = np.ravel(matfile['trial_gain'])
    for num in trial_nums:
        physical_posx[trial ==
                      num] = physical_posx[trial == num] / trial_gain[num - 1]

    position.create_spatial_series(
        name='PhysicalPosition',
        data=physical_posx,
        starting_time=position_time[0],
        rate=sampling_rate,
        reference_frame='Location on wheel re-referenced to zero '
        'at the start of each trial.',
        conversion=0.01,
        description='Physical location on the wheel measured '
        'since the beginning of the trial.',
        comments='Physical location found by dividing the '
        'virtual position by the "trial_gain"')
    nwbfile.add_acquisition(position)

    # Add timing of lick events, as well as mouse's virtual position during lick event
    lick_events = BehavioralEvents()
    lick_events.create_timeseries(
        'LickEvents',
        data=np.ravel(matfile['lickx']),
        timestamps=np.ravel(matfile['lickt']),
        unit='centimeter',
        description='Subject position in virtual hallway during the lick.')
    nwbfile.add_acquisition(lick_events)

    # Add information on the visual stimulus that was shown to the subject
    # Assumed rate=60 [Hz]. Update if necessary
    # Update external_file to link to Unity environment file
    visualization = ImageSeries(
        name='ImageSeries',
        unit='seconds',
        format='external',
        external_file=list(['https://unity.com/VR-and-AR-corner']),
        starting_time=vr_session_offset,
        starting_frame=[[0]],
        rate=float(60),
        description='virtual Unity environment that the mouse navigates through'
    )
    nwbfile.add_stimulus(visualization)

    # Add the recording device, a neuropixel probe
    recording_device = nwbfile.create_device(name='neuropixel_probes')
    electrode_group_description = 'single neuropixels probe http://www.open-ephys.org/neuropixelscorded'
    electrode_group_name = 'probe1'

    electrode_group = nwbfile.create_electrode_group(
        electrode_group_name,
        description=electrode_group_description,
        location=subject_brain_region,
        device=recording_device)

    # Add information about each electrode
    xcoords = np.ravel(matfile['sp'][0]['xcoords'][0])
    ycoords = np.ravel(matfile['sp'][0]['ycoords'][0])
    data_filtered_flag = matfile['sp'][0]['hp_filtered'][0][0]
    if data_filtered_flag:
        filter_desc = 'The raw voltage signals from the electrodes were high-pass filtered'
    else:
        filter_desc = 'The raw voltage signals from the electrodes were not high-pass filtered'

    num_recording_electrodes = xcoords.shape[0]
    recording_electrodes = range(0, num_recording_electrodes)

    # create electrode columns for the x,y location on the neuropixel  probe
    # the standard x,y,z locations are reserved for Allen Brain Atlas location
    nwbfile.add_electrode_column('rel_x', 'electrode x-location on the probe')
    nwbfile.add_electrode_column('rel_y', 'electrode y-location on the probe')

    for idx in recording_electrodes:
        nwbfile.add_electrode(id=idx,
                              x=np.nan,
                              y=np.nan,
                              z=np.nan,
                              rel_x=float(xcoords[idx]),
                              rel_y=float(ycoords[idx]),
                              imp=np.nan,
                              location='medial entorhinal cortex',
                              filtering=filter_desc,
                              group=electrode_group)

    # Add information about each unit, termed 'cluster' in giocomo data
    # create new columns in unit table
    nwbfile.add_unit_column(
        'quality',
        'labels given to clusters during manual sorting in phy (1=MUA, '
        '2=Good, 3=Unsorted)')

    # cluster information
    cluster_ids = matfile['sp'][0]['cids'][0][0]
    cluster_quality = matfile['sp'][0]['cgs'][0][0]
    # spikes in time
    spike_times = np.ravel(matfile['sp'][0]['st'][0])  # the time of each spike
    spike_cluster = np.ravel(
        matfile['sp'][0]['clu'][0])  # the cluster_id that spiked at that time

    for i, cluster_id in enumerate(cluster_ids):
        unit_spike_times = spike_times[spike_cluster == cluster_id]
        waveforms = matfile['sp'][0]['temps'][0][cluster_id]
        nwbfile.add_unit(id=int(cluster_id),
                         spike_times=unit_spike_times,
                         quality=cluster_quality[i],
                         waveform_mean=waveforms,
                         electrode_group=electrode_group)

    # Trying to add another Units table to hold the results of the automatic spike sorting
    # create TemplateUnits units table
    template_units = Units(
        name='TemplateUnits',
        description='units assigned during automatic spike sorting')
    template_units.add_column(
        'tempScalingAmps',
        'scaling amplitude applied to the template when extracting spike',
        index=True)

    # information on extracted spike templates
    spike_templates = np.ravel(matfile['sp'][0]['spikeTemplates'][0])
    spike_template_ids = np.unique(spike_templates)
    # template scaling amplitudes
    temp_scaling_amps = np.ravel(matfile['sp'][0]['tempScalingAmps'][0])

    for i, spike_template_id in enumerate(spike_template_ids):
        template_spike_times = spike_times[spike_templates ==
                                           spike_template_id]
        temp_scaling_amps_per_template = temp_scaling_amps[spike_templates ==
                                                           spike_template_id]
        template_units.add_unit(id=int(spike_template_id),
                                spike_times=template_spike_times,
                                electrode_group=electrode_group,
                                tempScalingAmps=temp_scaling_amps_per_template)

    # create ecephys processing module
    spike_template_module = nwbfile.create_processing_module(
        name='ecephys',
        description='units assigned during automatic spike sorting')

    # add template_units table to processing module
    spike_template_module.add(template_units)

    print(nwbfile)
    print('converted to NWB:N')
    print('saving ...')

    with NWBHDF5IO(outpath, 'w') as io:
        io.write(nwbfile)
        print('saved', outpath)
Example #7
0
def add_behavior(nwbfile, behavior_file, metadata_behavior, t0):
    # The timestamps for behavior data, coming from .mat files, are in milliseconds
    # and should be transformed to seconds with / 1000

    print("adding behavior...")
    # process raw behavior
    behavior_data = loadmat(behavior_file)
    behavior_module = nwbfile.create_processing_module(
        name='behavior', description='preprocessed behavioral data')
    # Player Position
    meta_pos = metadata_behavior['Position']
    pos = Position(name=meta_pos['name'])
    all_pos = np.atleast_1d([[], [], []]).T
    all_tme = []
    for iepoch in range(len(behavior_data["behavior"])):
        if 'posdat' in behavior_data['behavior'][iepoch]:
            epoch_data = behavior_data["behavior"][iepoch]
            all_pos = np.r_[all_pos, epoch_data['posdat']]
            all_tme = np.r_[all_tme, epoch_data['tme']]

    # Metadata for SpatialSeries stored in Position
    pos.create_spatial_series(
        name=meta_pos['spatial_series'][0]['name'],
        data=all_pos,
        reference_frame=meta_pos['spatial_series'][0]['reference_frame'],
        timestamps=all_tme / 1000. - t0,
        conversion=np.nan)
    behavior_module.add(pos)

    # nlx eye movements
    nlxeye = EyeTracking(name='EyeTracking')
    # metadata for SpatialSeries stored in EyeTracking
    meta_et = metadata_behavior['EyeTracking']
    tt = np.array(behavior_data["nlxtme"]) / 1000. - t0
    nlxeye.create_spatial_series(
        name=meta_et['spatial_series'][0]['name'],
        data=np.array(behavior_data["nlxeye"]).T,
        reference_frame=meta_et['spatial_series'][0]['reference_frame'],
        rate=len(tt) / (tt[-1] - tt[0]),
        starting_time=tt[0],
        #timestamps=np.array(behavior_data["nlxtme"]) / 1000. - t0,
        conversion=np.nan)
    behavior_module.add(nlxeye)

    # trial columns
    nwbfile.add_trial_column(
        name='environment',
        description='trial environment (calibration if calibration trial)')
    # nwbfile.add_trial_column(name='trial_vars', description='trial variables - different between calibration and task')

    # event key dictionary
    event_dict = {
        "new_trial": 1000,
        "right_trial": 1001,
        "left_trial": 1002,
        "reward_on": 1,
        "reward_off": 0,
        "end_trial": 100,
        "end_presentation": 101,
        "successful_trial": 200
    }

    # process behavior here
    for iepoch in range(len(behavior_data["behavior"])):
        epoch_data = behavior_data["behavior"][iepoch]
        if iepoch < 2:
            process_behavior_calibration(nwbfile, iepoch + 1, epoch_data, t0)
        else:
            banana_flag = 1
            process_behavior(nwbfile, iepoch + 1, epoch_data, banana_flag,
                             event_dict, t0)
def conversion_function(source_paths,
                        f_nwb,
                        metadata,
                        add_spikeglx=False,
                        add_processed=False):
    """
    Copy data stored in a set of .npz files to a single NWB file.

    Parameters
    ----------
    source_paths : dict
        Dictionary with paths to source files/directories. e.g.:
        {'spikeglx data': {'type': 'file', 'path': ''}
         'processed data': {'type': 'file', 'path': ''}}
    f_nwb : str
        Path to output NWB file, e.g. 'my_file.nwb'.
    metadata : dict
        Dictionary containing metadata
    add_spikeglx: bool
    add_processed: bool
    """

    # Source files
    npx_file_path = None
    mat_file_path = None
    for k, v in source_paths.items():
        if source_paths[k]['path'] != '':
            if k == 'spikeglx data':
                npx_file_path = source_paths[k]['path']
            if k == 'processed data':
                mat_file_path = source_paths[k]['path']

    # Remove lab_meta_data from metadata, it will be added later
    metadata0 = copy.deepcopy(metadata)
    metadata0['NWBFile'].pop('lab_meta_data', None)

    # Create nwb
    nwbfile = pynwb.NWBFile(**metadata0['NWBFile'])

    # If adding processed data
    if add_processed:
        # Source matlab data
        matfile = hdf5storage.loadmat(mat_file_path)

        # Adding trial information
        nwbfile.add_trial_column(
            name='trial_contrast',
            description=
            'visual contrast of the maze through which the mouse is running')
        trial = np.ravel(matfile['trial'])
        trial_nums = np.unique(trial)
        position_time = np.ravel(matfile['post'])
        # matlab trial numbers start at 1. To correctly index trial_contract vector,
        # subtracting 1 from 'num' so index starts at 0
        for num in trial_nums:
            trial_times = position_time[trial == num]
            nwbfile.add_trial(start_time=trial_times[0],
                              stop_time=trial_times[-1],
                              trial_contrast=matfile['trial_contrast'][num -
                                                                       1][0])

        # create behavior processing module
        behavior = nwbfile.create_processing_module(
            name='behavior', description='behavior processing module')

        # Add mouse position
        position = Position(name=metadata['Behavior']['Position']['name'])
        meta_pos_names = [
            sps['name']
            for sps in metadata['Behavior']['Position']['spatial_series']
        ]

        # Position inside the virtual environment
        pos_vir_meta_ind = meta_pos_names.index('VirtualPosition')
        meta_vir = metadata['Behavior']['Position']['spatial_series'][
            pos_vir_meta_ind]
        position_virtual = np.ravel(matfile['posx'])
        sampling_rate = 1 / (position_time[1] - position_time[0])
        position.create_spatial_series(
            name=meta_vir['name'],
            data=position_virtual,
            starting_time=position_time[0],
            rate=sampling_rate,
            reference_frame=meta_vir['reference_frame'],
            conversion=meta_vir['conversion'],
            description=meta_vir['description'],
            comments=meta_vir['comments'])

        # Physical position on the mouse wheel
        pos_phys_meta_ind = meta_pos_names.index('PhysicalPosition')
        meta_phys = metadata['Behavior']['Position']['spatial_series'][
            pos_phys_meta_ind]
        physical_posx = position_virtual
        trial_gain = np.ravel(matfile['trial_gain'])
        for num in trial_nums:
            physical_posx[trial == num] = physical_posx[
                trial == num] / trial_gain[num - 1]
        position.create_spatial_series(
            name=meta_phys['name'],
            data=physical_posx,
            starting_time=position_time[0],
            rate=sampling_rate,
            reference_frame=meta_phys['reference_frame'],
            conversion=meta_phys['conversion'],
            description=meta_phys['description'],
            comments=meta_phys['comments'])

        behavior.add(position)

        # Add timing of lick events, as well as mouse's virtual position during lick event
        lick_events = BehavioralEvents(
            name=metadata['Behavior']['BehavioralEvents']['name'])
        meta_ts = metadata['Behavior']['BehavioralEvents']['time_series']
        meta_ts['data'] = np.ravel(matfile['lickx'])
        meta_ts['timestamps'] = np.ravel(matfile['lickt'])
        lick_events.create_timeseries(**meta_ts)

        behavior.add(lick_events)

        # Add the recording device, a neuropixel probe
        recording_device = nwbfile.create_device(
            name=metadata['Ecephys']['Device'][0]['name'])

        # Add ElectrodeGroup
        electrode_group = nwbfile.create_electrode_group(
            name=metadata['Ecephys']['ElectrodeGroup'][0]['name'],
            description=metadata['Ecephys']['ElectrodeGroup'][0]
            ['description'],
            location=metadata['Ecephys']['ElectrodeGroup'][0]['location'],
            device=recording_device)

        # Add information about each electrode
        xcoords = np.ravel(matfile['sp'][0]['xcoords'][0])
        ycoords = np.ravel(matfile['sp'][0]['ycoords'][0])
        data_filtered_flag = matfile['sp'][0]['hp_filtered'][0][0]
        if metadata['NWBFile']['lab_meta_data']['high_pass_filtered']:
            filter_desc = 'The raw voltage signals from the electrodes were high-pass filtered'
        else:
            filter_desc = 'The raw voltage signals from the electrodes were not high-pass filtered'
        num_recording_electrodes = xcoords.shape[0]
        recording_electrodes = range(0, num_recording_electrodes)

        # create electrode columns for the x,y location on the neuropixel  probe
        # the standard x,y,z locations are reserved for Allen Brain Atlas location
        nwbfile.add_electrode_column('relativex',
                                     'electrode x-location on the probe')
        nwbfile.add_electrode_column('relativey',
                                     'electrode y-location on the probe')
        for idx in recording_electrodes:
            nwbfile.add_electrode(id=idx,
                                  x=np.nan,
                                  y=np.nan,
                                  z=np.nan,
                                  relativex=float(xcoords[idx]),
                                  relativey=float(ycoords[idx]),
                                  imp=np.nan,
                                  location='medial entorhinal cortex',
                                  filtering=filter_desc,
                                  group=electrode_group)

        # Add information about each unit, termed 'cluster' in giocomo data
        # create new columns in unit table
        nwbfile.add_unit_column(
            name='quality',
            description='labels given to clusters during manual sorting in phy '
            '(1=MUA, 2=Good, 3=Unsorted)')

        # cluster information
        cluster_ids = matfile['sp'][0]['cids'][0][0]
        cluster_quality = matfile['sp'][0]['cgs'][0][0]
        # spikes in time
        spike_times = np.ravel(
            matfile['sp'][0]['st'][0])  # the time of each spike
        spike_cluster = np.ravel(
            matfile['sp'][0]['clu']
            [0])  # the cluster_id that spiked at that time
        for i, cluster_id in enumerate(cluster_ids):
            unit_spike_times = spike_times[spike_cluster == cluster_id]
            waveforms = matfile['sp'][0]['temps'][0][cluster_id]
            nwbfile.add_unit(id=int(cluster_id),
                             spike_times=unit_spike_times,
                             quality=cluster_quality[i],
                             waveform_mean=waveforms,
                             electrode_group=electrode_group)

        # Trying to add another Units table to hold the results of the automatic spike sorting
        # create TemplateUnits units table
        template_units = Units(
            name='TemplateUnits',
            description='units assigned during automatic spike sorting')
        template_units.add_column(
            name='tempScalingAmps',
            description=
            'scaling amplitude applied to the template when extracting spike',
            index=True)
        # information on extracted spike templates
        spike_templates = np.ravel(matfile['sp'][0]['spikeTemplates'][0])
        spike_template_ids = np.unique(spike_templates)
        # template scaling amplitudes
        temp_scaling_amps = np.ravel(matfile['sp'][0]['tempScalingAmps'][0])
        for i, spike_template_id in enumerate(spike_template_ids):
            template_spike_times = spike_times[spike_templates ==
                                               spike_template_id]
            temp_scaling_amps_per_template = temp_scaling_amps[
                spike_templates == spike_template_id]
            template_units.add_unit(
                id=int(spike_template_id),
                spike_times=template_spike_times,
                electrode_group=electrode_group,
                tempScalingAmps=temp_scaling_amps_per_template)

        # create ecephys processing module
        spike_template_module = nwbfile.create_processing_module(
            name='ecephys',
            description='units assigned during automatic spike sorting')
        # add template_units table to processing module
        spike_template_module.add(template_units)

    # Add other fields
    # Add lab_meta_data
    if 'lab_meta_data' in metadata['NWBFile']:
        lab_metadata = LabMetaData_ext(
            name=metadata['NWBFile']['lab_meta_data']['name'],
            acquisition_sampling_rate=metadata['NWBFile']['lab_meta_data']
            ['acquisition_sampling_rate'],
            number_of_electrodes=metadata['NWBFile']['lab_meta_data']
            ['number_of_electrodes'],
            file_path=metadata['NWBFile']['lab_meta_data']['file_path'],
            bytes_to_skip=metadata['NWBFile']['lab_meta_data']
            ['bytes_to_skip'],
            raw_data_dtype=metadata['NWBFile']['lab_meta_data']
            ['raw_data_dtype'],
            high_pass_filtered=metadata['NWBFile']['lab_meta_data']
            ['high_pass_filtered'],
            movie_start_time=metadata['NWBFile']['lab_meta_data']
            ['movie_start_time'],
            subject_brain_region=metadata['NWBFile']['lab_meta_data']
            ['subject_brain_region'])
        nwbfile.add_lab_meta_data(lab_metadata)

    # add information about the subject of the experiment
    if 'Subject' in metadata:
        experiment_subject = Subject(
            subject_id=metadata['Subject']['subject_id'],
            species=metadata['Subject']['species'],
            description=metadata['Subject']['description'],
            genotype=metadata['Subject']['genotype'],
            date_of_birth=metadata['Subject']['date_of_birth'],
            weight=metadata['Subject']['weight'],
            sex=metadata['Subject']['sex'])
        nwbfile.subject = experiment_subject

    # If adding SpikeGLX data
    if add_spikeglx:
        # Create extractor for SpikeGLX data
        extractor = Spikeglx2NWB(nwbfile=nwbfile,
                                 metadata=metadata0,
                                 npx_file=npx_file_path)
        # Add acquisition data
        extractor.add_acquisition(es_name='ElectricalSeries',
                                  metadata=metadata['Ecephys'])
        # Run spike sorting method
        #extractor.run_spike_sorting()
        # Save content to NWB file
        extractor.save(to_path=f_nwb)
    else:
        # Write to nwb file
        with pynwb.NWBHDF5IO(f_nwb, 'w') as io:
            io.write(nwbfile)
            print(nwbfile)

    # Check file was saved and inform on screen
    print('File saved at:')
    print(f_nwb)
    print('Size: ', os.stat(f_nwb).st_size / 1e6, ' mb')
Example #9
0
                    description=
                    'which side of the assay the mouse chose (correct or incorrect)'
                )

                for trial in range(0, len(concentration_level)):
                    nwbfile.add_trial(start_time=trial_start[trial],
                                      stop_time=trial_end[trial],
                                      level=concentration_level[trial],
                                      side=stimulus_side[trial],
                                      chosen=chosen_side[trial])

            if frame_data_exists == True:
                tracking = Position(
                )  #create a position container for tracking data
                tracking.create_spatial_series(name='nose x-position',
                                               data=nose_x,
                                               timestamps=frame_msec,
                                               reference_frame='session start')
                tracking.create_spatial_series(name='nose y-position',
                                               data=nose_y,
                                               timestamps=frame_msec,
                                               reference_frame='session start')
                tracking.create_spatial_series(name='head x-position',
                                               data=head_x,
                                               timestamps=frame_msec,
                                               reference_frame='session start')
                tracking.create_spatial_series(name='head y-position',
                                               data=head_y,
                                               timestamps=frame_msec,
                                               reference_frame='session start')
                tracking.create_spatial_series(name='body x-position',
                                               data=body_x,