Example #1
0
def load_acq(filename, chtrig=0):
    """
    Populate object phys_input from acq extension files.

    Parameters
    ----------
    filename : str
        path to the txt labchart file
    chtrig : int, optional
        index of trigger channel. Default is 0.

    Returns
    -------
    BlueprintInput

    Note
    ----
    chtrig is not a 0-based Python index - instead, it's human readable (i.e., 1-based).
    This is handy because, when initialising the class, a new channel corresponding
    to time is added at the beginning - that is already taken into account!

    See Also
    --------
    physio_obj.BlueprintInput
    """
    from bioread import read_file
    with warnings.catch_warnings():
        warnings.filterwarnings('ignore', category=DeprecationWarning)
        data = read_file(filename).channels

    freq = [
        data[0].samples_per_second,
    ]
    timeseries = [
        data[0].time_index,
    ]
    units = [
        's',
    ]
    names = [
        'time',
    ]

    for k, ch in enumerate(data):
        LGR.info(f'{k:02d}. {ch}')
        timeseries.append(ch.data)
        freq.append(ch.samples_per_second)
        units.append(ch.units)
        names.append(ch.name)

    return BlueprintInput(timeseries, freq, names, units, chtrig)
Example #2
0
def populate_phys_input(filename, chtrig):
    """
    Populate object phys_input from acq files.

    Parameters
    ----------
    filename: str
        path to the txt labchart file
    chtrig : int
        index of trigger channel

    Returns
    -------
    BlueprintInput

    See Also
    --------
    physio_obj.BlueprintInput
    """

    with warnings.catch_warnings():
        warnings.filterwarnings('ignore', category=DeprecationWarning)
        data = read_file(filename).channels

    freq = [
        data[chtrig].samples_per_second,
    ]
    timeseries = [
        data[chtrig].time_index,
    ]
    units = [
        's',
    ]
    names = [
        'time',
    ]

    for k, ch in enumerate(data):
        LGR.info(f'{k:02d}. {ch}')
        timeseries.append(ch.data)
        freq.append(ch.samples_per_second)
        units.append(ch.units)
        names.append(ch.name)

    return BlueprintInput(timeseries, freq, names, units)
Example #3
0
def populate_phys_input(filename, chtrig):
    """
    Populate object phys_input
    """

    data = read_file(filename).channels

    freq = [data[chtrig].samples_per_second] * 2
    timeseries = [data[chtrig].time_index, data[chtrig].data]
    units = ['s', data[chtrig].units]
    names = ['time', 'trigger']

    for k, ch in enumerate(data):
        if k != chtrig:
            print(f'{k:02d}. {ch}')
            timeseries.append(ch.data)
            freq.append(ch.samples_per_second)
            units.append(ch.units)
            names.append(ch.name)

    return BlueprintInput(timeseries, freq, names, units)
Example #4
0
def process_labchart(channel_list, chtrig, header=[]):
    """
    Process labchart header and channel_list and make a physio_obj.BlueprintInput.

    Parameters
    ----------
    channel_list: list
        list with channels only
    chtrig : int
        index of trigger channel, starting in 1 for human readability
    header: list
        list with that contains file header

    Returns
    -------
    BlueprintInput

    Raises
    ------
    ValueError
        If len(header) == 0 and therefore there is no header
        If sampling is not in ['hr', 'min', 's', 'ms', 'µs'] reference:
        https://www.adinstruments.com/support/knowledge-base/how-can-channel-titles-ranges-intervals-etc-text-file-be-imported-labchart

    See Also
    --------
    physio_obj.BlueprintInput
    """
    # get frequency
    # check header has some length
    if len(header) == 0:
        raise AttributeError('Files without header are not supported yet')
    interval = header[0][1].split(" ")
    # check the interval is in some of the correct labchart units
    if interval[-1] not in ['hr', 'min', 's', 'ms', 'µs']:
        raise AttributeError(
            f'Interval unit "{interval[-1]}" is not in a valid LabChart'
            'time unit, this probably means your file is not in Labchart format'
        )
    # check if interval is in seconds, if not change the units to seconds
    if interval[-1] != 's':
        LGR.warning('Interval is not in seconds. Converting its value.')
        if interval[-1] == 'hr':
            interval[0] = float(interval[0]) * 3600
            interval[-1] = 's'
        elif interval[-1] == 'min':
            interval[0] = float(interval[0]) * 60
            interval[-1] = 's'
        elif interval[-1] == 'ms':
            interval[0] = float(interval[0]) / 1000
            interval[-1] = 's'
        elif interval[-1] == 'µs':
            interval[0] = float(interval[0]) / 1000000
            interval[-1] = 's'
    else:
        interval[0] = float(interval[0])
    # get units
    range_list = header[5][1:]
    orig_units = []
    for item in range_list:
        orig_units.append(item.split(' ')[1])
    units = [
        's',
    ]
    # get names
    orig_names = header[4][1:]
    orig_names_len = len(orig_names)
    names = [
        'time',
    ]
    # get channels
    # this transposes the channel_list from a list of samples x channels to
    # a list of channels x samples
    timeseries = list(map(list, zip(*channel_list)))
    freq = [1 / interval[0]] * len(timeseries)
    timeseries = [np.array(darray) for darray in timeseries]
    # check the file has a time channel if not create it and add it
    # As the "time" doesn't have a column header, if the number of header names
    # is less than the number of timesieries, then "time" is column 0...
    # ...otherwise, create the time channel
    if not (orig_names_len < len(timeseries)):
        duration = (timeseries[0].shape[0] + 1) * interval[0]
        t_ch = np.ogrid[0:duration:interval[0]][:-1]  # create time channel
        timeseries = [
            t_ch,
        ] + timeseries
    names = names + orig_names
    units = units + orig_units
    freq = [1 / interval[0]] * len(timeseries)
    freq = check_multifreq(timeseries, freq)
    return BlueprintInput(timeseries, freq, names, units, chtrig)
Example #5
0
def process_acq(channel_list, chtrig, header=[]):
    """
    Process AcqKnowledge header and channel_list to make a physio_obj.BlueprintInput.

    Parameters
    ----------
    channel_list: list
        list with channels only
    chtrig : int
        index of trigger channel, starting in 1 for human readability
    header: list
        list with that contains file header

    Returns
    -------
    BlueprintInput

    Raises
    ------
    ValueError
        If len(header) == 0 and therefore there is no header
        If sampling is not in ['min', 'sec', 'µsec', 'msec','MHz', 'kHz', 'Hz'] reference:
        https://www.biopac.com/wp-content/uploads/acqknowledge_software_guide.pdf page 194

    See Also
    --------
    physio_obj.BlueprintInput
    """
    # check header is not empty
    if len(header) == 0:
        raise AttributeError('Files without header are not supported yet')
    header.append(channel_list[0])
    del channel_list[0]  # delete sample size from channel list
    # this transposes the channel_list from a list of samples x channels to
    # a list of channels x samples
    timeseries = list(map(list, zip(*channel_list)))

    interval = header[1][0].split()
    # check the interval is in some of the correct AcqKnowledge units
    if interval[-1].split('/')[0] not in [
            'min', 'sec', 'µsec', 'msec', 'MHz', 'kHz', 'Hz'
    ]:
        raise AttributeError(
            f'Interval unit "{interval[-1]}" is not in a '
            'valid AcqKnowledge format time unit, this probably'
            'means your file is not in min, sec, msec, µsec, Mhz, KHz or Hz')
    interval[-1] = interval[-1].split('/')[0]
    # Check if the header is in frequency or sampling interval
    if 'Hz' in interval[-1].split('/')[0]:
        print('frequency is given in the header, calculating sample Interval'
              ' and standarizing to Hz if needed')
        freq = float(interval[0])
        freq_unit = interval[-1]
        if freq_unit == 'MHz':
            freq = freq * (1000000)
        elif freq_unit == 'kHz':
            freq = freq * 1000
        interval[0] = 1 / freq
        freq = [freq] * (len(timeseries) + 1)
    else:
        # check if interval is in seconds, if not change the units to seconds and
        # calculate frequency
        if interval[-1].split('/')[0] != 'sec':
            LGR.warning('Interval is not in seconds. Converting its value.')
            if interval[-1].split('/')[0] == 'min':
                interval[0] = float(interval[0]) * 60
                interval[-1] = 's'
            elif interval[-1].split('/')[0] == 'msec':
                interval[0] = float(interval[0]) / 1000
                interval[-1] = 's'
            elif interval[-1].split('/')[0] == 'µsec':
                interval[0] = float(interval[0]) / 1000000
                interval[-1] = 's'
        else:
            interval[0] = float(interval[0])
            interval[-1] = 's'
        freq = [1 / interval[0]] * (len(timeseries) + 1)
    # get units and names
    orig_units = []
    orig_names = []
    # the for loop starts at index1 at 3 because that's the first line of the header
    # with channel name info and ends in 2 + twice the number of channels because
    # that should be the last channel name
    for index1 in range(3, 3 + len(header[-1]) * 2, 2):
        orig_names.append(header[index1][0])
        # since units are in the line imediately after we get the units at the same time
        orig_units.append(header[index1 + 1][0])
    # reorder channels names
    names = [
        'time',
    ]
    names = names + orig_names
    # reoder channels units
    units = [
        's',
    ]
    units = units + orig_units
    # get channels
    timeseries = [np.array(darray) for darray in timeseries]
    duration = (timeseries[0].shape[0] + 1) * interval[0]
    t_ch = np.ogrid[0:duration:interval[0]][:-1]  # create time channel
    timeseries = [
        t_ch,
    ] + timeseries
    freq = check_multifreq(timeseries, freq)
    return BlueprintInput(timeseries, freq, names, units, chtrig)
Example #6
0
def generate_blueprint(channel_list, chtrig, interval, orig_units, orig_names):
    """
    Standarize channel_list, chtrig interval orig_units and orig_names.

    Standarize channel_list, chtrig interval orig_units and orig_names in the correct units and
    format and generate a physio_obj.BlueprintInput object.

    Parameters
    ----------
    channel_list : list of strings
        list with channels only
    chtrig : int
        index of trigger channel, starting in 1 for human readability
    interval : list of strings
        maximum sampling frequency or interval value and unit for the recording.
        Example: ["400", "Hz"]
    orig_units : list of strings
        contains original channels units
    orig_names : list of strings
        contains original channels name

    Returns
    -------
    BlueprintInput

    Raises
    ------
    AttributeError
        If sampling is not in ['min', 'sec', 'µsec', 'msec', 'MHz', 'kHz', 'Hz', 'hr', 'min', 's',
        'ms', 'µs'] reference:
        https://www.adinstruments.com/support/knowledge-base/how-can-channel-titles-ranges-intervals-etc-text-file-be-imported-labchart
        https://www.biopac.com/wp-content/uploads/acqknowledge_software_guide.pdf page 194

    See Also
    --------
    physio_obj.BlueprintInput
    """
    # this transposes the channel_list from a list of samples x channels to
    # a list of channels x samples
    timeseries = list(map(list, zip(*channel_list)))
    if interval[-1] not in [
            'min', 'sec', 'µsec', 'msec', 'MHz', 'kHz', 'Hz', 'hr', 'min', 's',
            'ms', 'µs'
    ]:
        raise AttributeError(
            f'Interval unit "{interval[-1]}" is not in a '
            'valid frequency or time unit format, this probably '
            'means your file is not in min, sec, msec, µsec, hr, min, s, ms, µs, '
            'Mhz, KHz or Hz')
    # Check if the header is in frequency or sampling interval
    if 'Hz' in interval[-1]:
        LGR.info(
            'Retrieving frequency from file header, calculating sample interval, '
            'and standarizing to Hz if needed')
        freq = float(interval[0])
        freq_unit = interval[-1]
        if freq_unit == 'MHz':
            freq = freq * (1000000)
        elif freq_unit == 'kHz':
            freq = freq * 1000
        interval[0] = 1 / freq
        freq = [freq] * len(timeseries)
    else:
        # check if interval is in seconds, if not change the units to seconds and
        # calculate frequency
        if interval[-1] not in ('s', 'sec'):
            LGR.warning('Sampling interval not expressed in seconds. '
                        'Converting its value and unit.')
            if interval[-1] == 'min':
                interval[0] = float(interval[0]) * 60
            elif interval[-1] == 'msec':
                interval[0] = float(interval[0]) / 1000
            elif interval[-1] == 'µsec':
                interval[0] = float(interval[0]) / 1000000
            elif interval[-1] == 'hr':
                interval[0] = float(interval[0]) * 3600
            elif interval[-1] == 'ms':
                interval[0] = float(interval[0]) / 1000
            elif interval[-1] == 'µs':
                interval[0] = float(interval[0]) / 1000000
        else:
            interval[0] = float(interval[0])
        # get frequency
        freq = [1 / interval[0]] * len(timeseries)
    # reorder channels names
    names = [
        'time',
    ]
    names = names + orig_names
    # reoder channels units
    units = [
        's',
    ]
    units = units + orig_units
    timeseries = list(map(list, zip(*channel_list)))
    freq = [1 / interval[0]] * len(timeseries)
    timeseries = [np.array(darray) for darray in timeseries]
    # Check if the file has a time channel, otherwise create it.
    # As the "time" doesn't have a column header, if the number of header names
    # is less than the number of timeseries, then "time" is column 0...
    # ...otherwise, create the time channel
    if not (len(orig_names) < len(timeseries)):
        duration = (timeseries[0].shape[0] + 1) * interval[0]
        t_ch = np.ogrid[0:duration:interval[0]][:-1]  # create time channel
        timeseries = [
            t_ch,
        ] + timeseries
        freq = [max(freq)] + freq
    freq = check_multifreq(timeseries, freq)
    return BlueprintInput(timeseries, freq, names, units, chtrig)
Example #7
0
def load_mat(filename, chtrig=0):
    """
    Populate object phys_input from MATLAB files.

    Parameters
    ----------
    filename: str
        path to the txt labchart file
    chtrig : int
        index of trigger channel.
        !!! ATTENTION: IT'S MEANT TO REPRESENT AN INDEX STARTING FROM 1 !!!

    Returns
    -------
    BlueprintInput

    Note
    ----
    chtrig is not a 0-based Python index - instead, it's human readable (i.e., 1-based).
    This is handy because, when initialising the class, a new channel corresponding
    to time is added at the beginning - that is already taken into account!

    See Also
    --------
    physio_obj.BlueprintInput
    """
    # Load MATLAB file into dictionary.
    from pymatreader import read_mat
    mat_dict = read_mat(filename)
    if '__header__' in mat_dict:
        orig_names = list(mat_dict['labels'])
        orig_units = list(mat_dict['units'])
        interval = [mat_dict['isi'], mat_dict['isi_units']]
        channel_list = mat_dict['data']
        return generate_blueprint(channel_list, chtrig, interval, orig_units,
                                  orig_names)
    else:
        # Convert data into 1d numpy array for easier indexing.
        data = np.squeeze(np.asarray(mat_dict['data']))

        # Extract number of channels and tick rate.
        n_channels = len(mat_dict['titles'])
        t_freq = mat_dict['tickrate']

        # Stores MATLAB data into lists.
        timeseries = []
        freq = [
            t_freq,
        ]
        units = [
            's',
        ]
        names = [
            'time',
        ]

        for ch in range(n_channels):
            units.append(mat_dict['unittext'][int(mat_dict['unittextmap'][ch] -
                                                  1)].strip())
            names.append(mat_dict['titles'][ch].strip())
            freq.append(mat_dict['samplerate'][ch])
            idx_start = int(mat_dict['datastart'][ch])
            idx_end = int(mat_dict['dataend'][ch])
            timeseries.append(data[idx_start:idx_end])
        # Calculate duration based on frequency and create time channel.
        interval = 1 / t_freq
        duration = (timeseries[0].shape[0] + 1) * interval
        t_ch = np.ogrid[0:duration:interval][:-1]
        timeseries = [
            t_ch,
        ] + timeseries
        return BlueprintInput(timeseries, freq, names, units, chtrig)
Example #8
0
def populate_phys_input(filename, chtrig):
    """
    Populate object phys_input
    for now this works only with labchart files
        Input (Properties)
    ------------------
    filename: str 
        path to the txt labchart file
    chtrig : int
        index of trigger channel

    Output
    ------------------
    BlueprintInput object for more see BlueprintInput docs  
    """

    header = []
    channel_list = []
    with open(filename, 'r') as f:
        header_l = 0
        for line in f:
            line = line.rstrip('\n').split('\t')
            try:
                float(line[0])
            except ValueError:
                header.append(line)
                continue
            line = [float(i) for i in line]
            channel_list.append(line)
    # get frequency
    interval = header[0][1].split(" ")
    if interval[-1] not in ['hr', 'min', 's', 'ms', 'µs']:
        raise AttributeError(
            f'Interval unit "{interval[-1]}" is not in a valid LabChart time unit, '
            'this probably means your file is not in labchart format')

    if interval[-1] != 's':
        print('Interval is not in seconds. Converting its value.')
        if interval[-1] == 'hr':
            interval[0] = float(interval)[0] * 3600
            interval[-1] = 's'
        elif interval[-1] == 'min':
            interval[0] = float(interval[0]) * 60
            interval[-1] = 's'
        elif interval[-1] == 'ms':
            interval[0] = float(interval[0]) / 1000
            interval[-1] = 's'
        elif interval[-1] == 'µs':
            interval[0] = float(interval[0]) / 1000000
            interval[-1] = 's'
    else:
        interval[0] = float(interval[0])
    # get units
    range_list = header[5][1:]
    units = []
    for item in range_list:
        units.append(item.split(' ')[1])
    # get names
    orig_names = header[4][1:]
    names = ['time', 'trigger']
    orig_names.pop(chtrig)
    names = names + orig_names
    # get channels
    timeseries = np.matrix(channel_list).T.tolist()
    freq = [1 / interval[0]] * len(timeseries)
    timeseries = [np.array(darray) for darray in timeseries]
    ordered_timeseries = [timeseries[0], timeseries[chtrig]]
    timeseries.pop(chtrig)
    timeseries.pop(0)
    ordered_timeseries = ordered_timeseries + timeseries
    return BlueprintInput(ordered_timeseries, freq, names, units)