Ejemplo n.º 1
0
def run():
    """Run the cp command."""
    from mne.commands.utils import get_optparser

    accepted_formats_msg = ('Accepted formats are BrainVision (.vhdr), '
                            'EEGLAB (.set), CTF (.ds).')

    parser = get_optparser(__file__,
                           usage="usage: %prog -i INPUT -o OUTPUT",
                           prog_prefix='mne_bids',
                           version=mne_bids.__version__)

    parser.add_option(
        '-i',
        '--input',
        dest='input',
        help=('Path to the input file. {}'.format(accepted_formats_msg)),
        metavar='INPUT')

    parser.add_option('-o',
                      '--output',
                      dest='output',
                      help=('Path to the output file. MUST be same format '
                            'as input file.'),
                      metavar='OUTPUT')

    parser.add_option('-v',
                      '--verbose',
                      dest="verbose",
                      help='Set logging level to verbose',
                      action="store_true")

    opt, args = parser.parse_args()
    opt_dict = vars(opt)

    # Check the usage and raise error if invalid
    if len(args) > 0:
        parser.print_help()
        parser.error('Do not specify arguments without flags. Found: "{}".\n'
                     'Did you forget to provide -i and -o?'.format(args))

    if not opt_dict.get('input') or not opt_dict.get('output'):
        parser.print_help()
        parser.error('Incorrect number of arguments. Supply one input and one '
                     'output file. You supplied: "{}"'.format(opt))

    # Attempt to do the copying. Errors will be raised by the copyfile
    # functions if there are issues with the file formats
    if opt.input.endswith('.vhdr'):
        copyfile_brainvision(opt.input, opt.output, opt.verbose)
    elif opt.input.endswith('.set'):
        copyfile_eeglab(opt.input, opt.output)
    elif opt.input.endswith('.ds'):
        copyfile_ctf(opt.input, opt.output)
    else:
        parser.error('{} You supplied: "{}"'.format(accepted_formats_msg, opt))
Ejemplo n.º 2
0
def test_copyfile_brainvision():
    """Test the copying of BrainVision vhdr, vmrk and eeg files."""
    bids_root = _TempDir()
    data_path = op.join(base_path, 'brainvision', 'tests', 'data')
    raw_fname = op.join(data_path, 'test.vhdr')
    new_name = op.join(bids_root, 'tested_conversion.vhdr')

    # IO error testing
    with pytest.raises(ValueError, match='Need to move data with same'):
        copyfile_brainvision(raw_fname, new_name + '.eeg')

    # Try to copy the file
    copyfile_brainvision(raw_fname, new_name, verbose=True)

    # Have all been copied?
    head, tail = op.split(new_name)
    assert op.exists(op.join(head, 'tested_conversion.vhdr'))
    assert op.exists(op.join(head, 'tested_conversion.vmrk'))
    assert op.exists(op.join(head, 'tested_conversion.eeg'))

    # Try to read with MNE - if this works, the links are correct
    raw = mne.io.read_raw_brainvision(new_name)
    assert raw.filenames[0] == (op.join(head, 'tested_conversion.eeg'))

    # Test with anonymization
    raw = mne.io.read_raw_brainvision(raw_fname)
    prev_date = raw.info['meas_date']
    anonymize = {'daysback': 32459}
    copyfile_brainvision(raw_fname, new_name, anonymize, verbose=True)
    raw = mne.io.read_raw_brainvision(new_name)
    new_date = raw.info['meas_date']
    assert new_date == (prev_date - datetime.timedelta(days=32459))
Ejemplo n.º 3
0
def test_copyfile_brainvision():
    """Test the copying of BrainVision vhdr, vmrk and eeg files."""
    output_path = _TempDir()
    data_path = op.join(base_path, 'brainvision', 'tests', 'data')
    raw_fname = op.join(data_path, 'test.vhdr')
    new_name = op.join(output_path, 'tested_conversion.vhdr')

    # IO error testing
    with pytest.raises(ValueError, match='Need to move data with same'):
        copyfile_brainvision(raw_fname, new_name + '.eeg')

    # Try to copy the file
    copyfile_brainvision(raw_fname, new_name, verbose=True)

    # Have all been copied?
    head, tail = op.split(new_name)
    assert op.exists(op.join(head, 'tested_conversion.vhdr'))
    assert op.exists(op.join(head, 'tested_conversion.vmrk'))
    assert op.exists(op.join(head, 'tested_conversion.eeg'))

    # Try to read with MNE - if this works, the links are correct
    raw = mne.io.read_raw_brainvision(new_name)
    assert raw.filenames[0] == (op.join(head, 'tested_conversion.eeg'))
###############################################################################
# Step 2: Rename the recording
# ----------------------------------
# Above, at the top of the example, we imported ``copyfile_brainvision`` from
# the MNE-BIDS ``utils.py`` module. This function takes two arguments as
# input: First, the path to the existing .vhdr file. And second, the path to
# the future .vhdr file.
#
# ``copyfile_brainvision`` will then create three new files (.vhdr, .vmrk, and
# .eeg) with the new names as provided with the second argument.
#
# Here, we rename test.vhdr to test_renamed.vhdr:
vhdr_file = os.path.join(examples_dir, 'test.vhdr')
vhdr_file_renamed = os.path.join(examples_dir, 'test_renamed.vhdr')
copyfile_brainvision(vhdr_file, vhdr_file_renamed)

###############################################################################
# Step 3: Assert that the renamed data can be read by a software
# --------------------------------------------------------------
# Finally, let's use MNE-Python to read in both, the original BrainVision data
# as well as the renamed data. They should be the same.
raw = read_raw_brainvision(vhdr_file)
raw_renamed = read_raw_brainvision(vhdr_file_renamed)

assert_array_equal(raw.get_data(), raw_renamed.get_data())

###############################################################################
# Further information
# -------------------
# There are alternative options to rename your BrainVision files. You could
Ejemplo n.º 5
0
# First, the path to the existing ``.vhdr`` file. And second, the path to
# the future ``.vhdr`` file.
#
# With the optional ``verbose`` parameter you can furthermore determine how
# much information you want to get during the procedure.
#
# :func:`mne_bids.copyfiles.copyfile_brainvision` will then create three new
# files (``.vhdr``, ``.vmrk``, and ``.eeg``) with the new names as provided
# with the second argument.
#
# Here, we rename a test file name:

# Rename the file
vhdr_file = op.join(examples_dir, 'Analyzer_nV_Export.vhdr')
vhdr_file_renamed = op.join(examples_dir, 'test_renamed.vhdr')
copyfile_brainvision(vhdr_file, vhdr_file_renamed, verbose=True)

# Check that MNE-Python can read in both, the original as well as the renamed
# data (two files: their contents are the same apart from the name)
raw = mne.io.read_raw_brainvision(vhdr_file)
raw_renamed = mne.io.read_raw_brainvision(vhdr_file_renamed)

###############################################################################
# Further information
# -------------------
#
# For converting data files, or writing new data to the BrainVision format, you
# can use the `pybv`_ Python package.
#
# There is node JS tool to check the integrity of your BrainVision files.
# For that, see the `BrainVision Validator <bv-validator_>`_
Ejemplo n.º 6
0
def write_raw_bids(raw, bids_basename, output_path, events_data=None,
                   event_id=None, overwrite=False, verbose=True):
    """Walk over a folder of files and create BIDS compatible folder.

    .. warning:: The original files are simply copied over if the original
                 file format is BIDS-supported for that modality. Otherwise,
                 this function will convert to a BIDS-supported file format
                 while warning the user. For EEG and iEEG data, conversion will
                 be to BrainVision format, for MEG conversion will be to FIF.

    Parameters
    ----------
    raw : instance of mne.io.Raw
        The raw data. It must be an instance of mne.Raw. The data should not be
        loaded on disk, i.e., raw.preload must be False.
    bids_basename : str
        The base filename of the BIDS compatible files. Typically, this can be
        generated using make_bids_basename.
        Example: `sub-01_ses-01_task-testing_acq-01_run-01`.
        This will write the following files in the correct subfolder of the
        output_path::

            sub-01_ses-01_task-testing_acq-01_run-01_meg.fif
            sub-01_ses-01_task-testing_acq-01_run-01_meg.json
            sub-01_ses-01_task-testing_acq-01_run-01_channels.tsv
            sub-01_ses-01_task-testing_acq-01_run-01_coordsystem.json

        and the following one if events_data is not None::

            sub-01_ses-01_task-testing_acq-01_run-01_events.tsv

        and add a line to the following files::

            participants.tsv
            scans.tsv

        Note that the modality 'meg' is automatically inferred from the raw
        object and extension '.fif' is copied from raw.filenames.
    output_path : str
        The path of the root of the BIDS compatible folder. The session and
        subject specific folders will be populated automatically by parsing
        bids_basename.
    events_data : str | array | None
        The events file. If a string, a path to the events file. If an array,
        the MNE events array (shape n_events, 3). If None, events will be
        inferred from the stim channel using `mne.find_events`.
    event_id : dict | None
        The event id dict used to create a 'trial_type' column in events.tsv
    overwrite : bool
        Whether to overwrite existing files or data in files.
        Defaults to False.
        If overwrite is True, any existing files with the same BIDS parameters
        will be overwritten with the exception of the `participants.tsv` and
        `scans.tsv` files. For these files, parts of pre-existing data that
        match the current data will be replaced.
        If overwrite is False, no existing data will be overwritten or
        replaced.
    verbose : bool
        If verbose is True, this will print a snippet of the sidecar files. If
        False, no content will be printed.

    Returns
    -------
    output_path : str
        The path of the root of the BIDS compatible folder.

    Notes
    -----
    For the participants.tsv file, the raw.info['subjects_info'] should be
    updated and raw.info['meas_date'] should not be None to compute the age
    of the participant correctly.

    """
    if not check_version('mne', '0.17'):
        raise ValueError('Your version of MNE is too old. '
                         'Please update to 0.17 or newer.')

    if not isinstance(raw, BaseRaw):
        raise ValueError('raw_file must be an instance of BaseRaw, '
                         'got %s' % type(raw))

    if not hasattr(raw, 'filenames') or raw.filenames[0] is None:
        raise ValueError('raw.filenames is missing. Please set raw.filenames'
                         'as a list with the full path of original raw file.')

    if raw.preload is not False:
        raise ValueError('The data should not be preloaded.')

    raw = raw.copy()

    raw_fname = raw.filenames[0]
    if '.ds' in op.dirname(raw.filenames[0]):
        raw_fname = op.dirname(raw.filenames[0])
    # point to file containing header info for multifile systems
    raw_fname = raw_fname.replace('.eeg', '.vhdr')
    raw_fname = raw_fname.replace('.fdt', '.set')
    _, ext = _parse_ext(raw_fname, verbose=verbose)

    raw_orig = reader[ext](**raw._init_kwargs)
    assert_array_equal(raw.times, raw_orig.times,
                       "raw.times should not have changed since reading"
                       " in from the file. It may have been cropped.")

    params = _parse_bids_filename(bids_basename, verbose)
    subject_id, session_id = params['sub'], params['ses']
    acquisition, task, run = params['acq'], params['task'], params['run']
    kind = _handle_kind(raw)

    bids_fname = bids_basename + '_%s%s' % (kind, ext)

    # check whether the info provided indicates that the data is emptyroom
    # data
    emptyroom = False
    if subject_id == 'emptyroom' and task == 'noise':
        emptyroom = True
        # check the session date provided is consistent with the value in raw
        meas_date = raw.info.get('meas_date', None)
        if meas_date is not None:
            er_date = datetime.fromtimestamp(
                raw.info['meas_date'][0]).strftime('%Y%m%d')
            if er_date != session_id:
                raise ValueError("Date provided for session doesn't match "
                                 "session date.")

    data_path = make_bids_folders(subject=subject_id, session=session_id,
                                  kind=kind, output_path=output_path,
                                  overwrite=False, verbose=verbose)
    if session_id is None:
        ses_path = os.sep.join(data_path.split(os.sep)[:-1])
    else:
        ses_path = make_bids_folders(subject=subject_id, session=session_id,
                                     output_path=output_path, make_dir=False,
                                     overwrite=False, verbose=verbose)

    # create filenames
    scans_fname = make_bids_basename(
        subject=subject_id, session=session_id, suffix='scans.tsv',
        prefix=ses_path)
    participants_tsv_fname = make_bids_basename(prefix=output_path,
                                                suffix='participants.tsv')
    participants_json_fname = make_bids_basename(prefix=output_path,
                                                 suffix='participants.json')
    coordsystem_fname = make_bids_basename(
        subject=subject_id, session=session_id, acquisition=acquisition,
        suffix='coordsystem.json', prefix=data_path)
    sidecar_fname = make_bids_basename(
        subject=subject_id, session=session_id, task=task, run=run,
        acquisition=acquisition, suffix='%s.json' % kind, prefix=data_path)
    events_fname = make_bids_basename(
        subject=subject_id, session=session_id, task=task,
        acquisition=acquisition, run=run, suffix='events.tsv',
        prefix=data_path)
    channels_fname = make_bids_basename(
        subject=subject_id, session=session_id, task=task, run=run,
        acquisition=acquisition, suffix='channels.tsv', prefix=data_path)
    if ext not in ['.fif', '.ds', '.vhdr', '.edf', '.bdf', '.set', '.con',
                   '.sqd']:
        bids_raw_folder = bids_fname.split('.')[0]
        bids_fname = op.join(bids_raw_folder, bids_fname)

    # Read in Raw object and extract metadata from Raw object if needed
    orient = ORIENTATION.get(ext, 'n/a')
    unit = UNITS.get(ext, 'n/a')
    manufacturer = MANUFACTURERS.get(ext, 'n/a')

    # save all meta data
    _participants_tsv(raw, subject_id, participants_tsv_fname, overwrite,
                      verbose)
    _participants_json(participants_json_fname, True, verbose)
    _scans_tsv(raw, op.join(kind, bids_fname), scans_fname, overwrite, verbose)

    # TODO: Implement coordystem.json and electrodes.tsv for EEG and  iEEG
    if kind == 'meg' and not emptyroom:
        _coordsystem_json(raw, unit, orient, manufacturer, coordsystem_fname,
                          overwrite, verbose)

    events, event_id = _read_events(events_data, event_id, raw, ext)
    if events is not None and len(events) > 0 and not emptyroom:
        _events_tsv(events, raw, events_fname, event_id, overwrite, verbose)

    make_dataset_description(output_path, name=" ", verbose=verbose)
    _sidecar_json(raw, task, manufacturer, sidecar_fname, kind, overwrite,
                  verbose)
    _channels_tsv(raw, channels_fname, overwrite, verbose)

    # set the raw file name to now be the absolute path to ensure the files
    # are placed in the right location
    bids_fname = op.join(data_path, bids_fname)
    if os.path.exists(bids_fname) and not overwrite:
        raise FileExistsError('"%s" already exists. Please set '  # noqa: F821
                              'overwrite to True.' % bids_fname)
    _mkdir_p(os.path.dirname(bids_fname))

    if verbose:
        print('Copying data files to %s' % op.splitext(bids_fname)[0])

    convert = ext not in ALLOWED_EXTENSIONS[kind]
    # Copy the imaging data files
    if convert:
        if kind == 'meg':
            raise ValueError('Got file extension %s for MEG data, ' +
                             'expected one of %s' % ALLOWED_EXTENSIONS['meg'])
        if verbose:
            warn('Converting data files to BrainVision format')
        if not check_version('pybv', '0.2'):
            raise ImportError('pybv >=0.2.0 is required for converting ' +
                              '%s files to Brainvision format' % ext)
        from pybv import write_brainvision
        events, event_id = events_from_annotations(raw)
        write_brainvision(raw.get_data(), raw.info['sfreq'],
                          raw.ch_names,
                          op.splitext(op.basename(bids_fname))[0],
                          op.dirname(bids_fname), events[:, [0, 2]],
                          resolution=1e-6)
    elif ext == '.fif':
        n_rawfiles = len(raw.filenames)
        if n_rawfiles > 1:
            split_naming = 'bids'
            raw.save(bids_fname, split_naming=split_naming, overwrite=True)
        else:
            # This ensures that single FIF files do not have the part param
            raw.save(bids_fname, split_naming='neuromag', overwrite=True)

    # CTF data is saved and renamed in a directory
    elif ext == '.ds':
        copyfile_ctf(raw_fname, bids_fname)
    # BrainVision is multifile, copy over all of them and fix pointers
    elif ext == '.vhdr':
        copyfile_brainvision(raw_fname, bids_fname)
    # EEGLAB .set might be accompanied by a .fdt - find out and copy it too
    elif ext == '.set':
        copyfile_eeglab(raw_fname, bids_fname)
    elif ext == '.pdf':
        copyfile_bti(raw_orig, op.join(data_path, bids_raw_folder))
    else:
        sh.copyfile(raw_fname, bids_fname)
    # KIT data requires the marker file to be copied over too
    if 'mrk' in raw._init_kwargs:
        hpi = raw._init_kwargs['mrk']
        acq_map = dict()
        if isinstance(hpi, list):
            if _get_mrk_meas_date(hpi[0]) > _get_mrk_meas_date(hpi[1]):
                raise ValueError('Markers provided in incorrect order.')
            _, marker_ext = _parse_ext(hpi[0])
            acq_map = dict(zip(['pre', 'post'], hpi))
        else:
            _, marker_ext = _parse_ext(hpi)
            acq_map[None] = hpi
        for key, value in acq_map.items():
            marker_fname = make_bids_basename(
                subject=subject_id, session=session_id, task=task, run=run,
                acquisition=key, suffix='markers%s' % marker_ext,
                prefix=data_path)
            sh.copyfile(value, marker_fname)

    return output_path
            # we define filenames that we will use
            ori_sess_name = sess.replace('.eeg', '')  # original name
            sess_name = sess.replace('.eeg', '').replace(" ", "_")
            data_orig = os.path.join(data_path, ori_sess_name)
            fname_in = os.path.join(data_orig, ori_sess_name + '.vhdr')

            bids_path = BIDSPath(
                subject=str(subj).zfill(2),
                session=str(session).zfill(2),  #sess_name, 
                task=task,
                root=bids_root)

            # rename brainvision file
            vhdr_ori = fname_in
            vhdr_new = os.path.join(data_orig, bids_path.basename + '.vhdr')
            copyfile_brainvision(vhdr_ori, vhdr_new, verbose=True)

            # add annotations to raw object
            raw = mne.io.read_raw_brainvision(vhdr_new, preload=False)

            #------------------------------

            # read data and add useful metadata

            # WARNING: these did not save as it does not correspond to field in the FIF standard - this information is still available in the fruition_blink spreadsheet

            raw.info['line_freq'] = int(df_spreadsheet['Electric Hz'][
                df_spreadsheet['Raw Filename'] ==
                sess].unique()[0])  # specify power line as requiered by BIDS
            raw.info['recording_place'] = df_spreadsheet['Setting'][
                df_spreadsheet['Raw Filename'] == sess].unique()[