"""Package to import and export common formats.
"""
from datetime import datetime, timedelta
from json import dump, load
from pathlib import Path
from numpy import c_, empty, float64, NaN, memmap
[docs]class Wonambi:
"""Class to read the data in Wonambi format, which is fast to write and read
Parameters
----------
filename : path to file
the name of the filename with extension .won
"""
def __init__(self, filename):
self.filename = filename
[docs] def return_hdr(self):
"""Return the header for further use.
Returns
-------
subj_id : str
subject identification code
start_time : datetime
start time of the dataset
s_freq : float
sampling frequency
chan_name : list of str
list of all the channels
n_samples : int
number of samples in the dataset
orig : dict
the json file
"""
with open(self.filename, 'r') as f:
orig = load(f)
start_time = datetime.strptime(orig['start_time'],
'%Y-%m-%d %H:%M:%S.%f')
self.memshape = (len(orig['chan_name']),
orig['n_samples'])
self.dtype = orig.get('dtype', 'float64')
return (orig['subj_id'], start_time, orig['s_freq'], orig['chan_name'],
orig['n_samples'], orig)
[docs] def return_dat(self, chan, begsam, endsam):
"""Return the data as 2D numpy.ndarray.
Parameters
----------
chan : int or list
index (indices) of the channels to read
begsam : int
index of the first sample
endsam : int
index of the last sample
Returns
-------
numpy.ndarray
A 2d matrix, with dimension chan X samples. To save memory, the
data are memory-mapped, and you cannot change the values on disk.
Raises
------
FileNotFoundError
if .dat file is not in the same directory, with the same name.
Notes
-----
When asking for an interval outside the data boundaries, it returns NaN
for those values. It then converts the memmap to a normal numpy array,
I think, and so it reads the data into memory. However, I'm not 100%
sure that this is what happens.
"""
memmap_file = Path(self.filename).with_suffix('.dat')
if not memmap_file.exists():
raise FileNotFoundError('Could not find ' + str(memmap_file))
data = memmap(str(memmap_file), self.dtype, mode='c',
shape=self.memshape, order='F')
n_smp = self.memshape[1]
dat = data[chan, max((begsam, 0)):min((endsam, n_smp))].astype(float64)
if begsam < 0:
pad = empty((dat.shape[0], 0 - begsam))
pad.fill(NaN)
dat = c_[pad, dat]
if endsam >= n_smp:
pad = empty((dat.shape[0], endsam - n_smp))
pad.fill(NaN)
dat = c_[dat, pad]
return dat
[docs] def return_markers(self):
"""This format doesn't have markers.
Returns
-------
empty list
Raises
------
FileNotFoundError
when it cannot read the events for some reason (don't use other
exceptions).
"""
return []
[docs]def write_wonambi(data, filename, subj_id='', dtype='float64'):
"""Write file in simple Wonambi format.
Parameters
----------
data : instance of ChanTime
data with only one trial
filename : path to file
file to export to (the extensions .won and .dat will be added)
subj_id : str
subject id
dtype : str
numpy dtype in which you want to save the data
Notes
-----
Wonambi format creates two files, one .won with the dataset info as json
file and one .dat with the memmap recordings.
It will happily overwrite any existing file with the same name.
Memory-mapped matrices are column-major, Fortran-style, to be compatible
with Matlab.
"""
filename = Path(filename)
json_file = filename.with_suffix('.won')
memmap_file = filename.with_suffix('.dat')
start_time = data.start_time + timedelta(seconds=data.axis['time'][0][0])
start_time_str = start_time.strftime('%Y-%m-%d %H:%M:%S.%f')
dataset = {'subj_id': subj_id,
'start_time': start_time_str,
's_freq': data.s_freq,
'chan_name': list(data.axis['chan'][0]),
'n_samples': int(data.number_of('time')[0]),
'dtype': dtype,
}
with json_file.open('w') as f:
dump(dataset, f, sort_keys=True, indent=4)
memshape = (len(dataset['chan_name']),
dataset['n_samples'])
mem = memmap(str(memmap_file), dtype, mode='w+', shape=memshape, order='F')
mem[:, :] = data.data[0]
mem.flush() # not sure if necessary