mffpy is a lean reader for EGI's MFF file format. These files are directories containing several files of mostly xml files, but also binary files.
The main entry point into the library is class Reader that accesses a selection of functions in the .mff directory to return signal data and its meta information.
$ conda create -n mffpy python=3.6 pip $ conda activate mffpy $ pip install -r requirements-dev.txt $ pip install . $ # and to run the test $ make testDefinitely run:
$ pre-commit install============================= test session starts ============================== platform linux -- Python 3.6.7, pytest-7.0.1, pluggy-1.0.0 rootdir: /home/runner/work/mffpy/mffpy plugins: cov-4.0.0 collected 124 items mffpy/tests/test_cached_property.py .. [ 1%] mffpy/tests/test_devices.py .............. [ 12%] mffpy/tests/test_dict2xml.py . [ 13%] mffpy/tests/test_header_block.py .. [ 15%] mffpy/tests/test_mffdir.py .... [ 18%] mffpy/tests/test_raw_bin_files.py .................. [ 33%] mffpy/tests/test_reader.py ...................... [ 50%] mffpy/tests/test_writer.py ........... [ 59%] mffpy/tests/test_xml_files.py .......................................... [ 93%] ... [ 95%] mffpy/tests/test_zipfile.py ..... [100%] ----------- coverage: platform linux, python 3.6.7-final-0 ----------- Name Stmts Miss Cover ----------------------------------------------------------------- mffpy/__init__.py 4 0 100% mffpy/bin_files.py 40 2 95% mffpy/bin_writer.py 71 0 100% mffpy/cached_property.py 25 1 96% mffpy/devices.py 10 0 100% mffpy/dict2xml.py 31 3 90% mffpy/epoch.py 24 3 88% mffpy/header_block/__init__.py 1 0 100% mffpy/header_block/header_block.py 48 2 96% mffpy/header_block/helpers.py 15 0 100% mffpy/header_block/optional_header_block.py 32 1 97% mffpy/mffdir.py 92 7 92% mffpy/raw_bin_files.py 113 0 100% mffpy/reader.py 110 2 98% mffpy/tests/__init__.py 0 0 100% mffpy/tests/conftest.py 15 0 100% mffpy/tests/test_cached_property.py 33 0 100% mffpy/tests/test_devices.py 12 0 100% mffpy/tests/test_dict2xml.py 16 0 100% mffpy/tests/test_header_block.py 33 0 100% mffpy/tests/test_mffdir.py 30 0 100% mffpy/tests/test_raw_bin_files.py 63 0 100% mffpy/tests/test_reader.py 96 0 100% mffpy/tests/test_writer.py 212 0 100% mffpy/tests/test_xml_files.py 214 1 99% mffpy/tests/test_zipfile.py 34 0 100% mffpy/version.py 1 0 100% mffpy/writer.py 71 0 100% mffpy/xml_files.py 607 22 96% mffpy/zipfile.py 47 0 100% ----------------------------------------------------------------- TOTAL 2100 44 98% ============================= 122 passed in 7.19s ============================== All documentation and API guidance are generated from the python doc-strings and this README file using pydoc-markdown. To view the docs:
- install pydoc-markdown:
pip install pydoc-markdown - build and run:
pydocmd build; pydocmd serve - Navigate to the docs
importmffpyfo=mffpy.Reader("./examples/example_1.mff") print("time and date of the start of recording:", fo.startdatetime) print("number of channels:", fo.num_channels) print("sampling rates:", fo.sampling_rates, "(in Hz)") print("durations:", fo.durations, "(in sec.)") print("Here's the epoch information") fori, einenumerate(fo.epochs): print("Epoch number", i) print(e)frommffpyimportReaderfo=Reader("./examples/example_1.mff") fo.set_unit('EEG', 'uV') eeg_in_mV, t0_EEG=fo.get_physical_samples_from_epoch(fo.epochs[0], dt=0.1)['EEG'] fo.set_unit('EEG', 'V') eeg_in_V, t0_EEG=fo.get_physical_samples_from_epoch(fo.epochs[0], dt=0.1)['EEG'] print('data in mV:', eeg_in_mV[0]) print('data in V :', eeg_in_V[0])frommffpyimportXMLcategories=XML.from_file("./examples/example_1.mff/categories.xml") print(categories['ULRN'])fromos.pathimportjoinfromdatetimeimportdatetimeimportnumpyasnpfrommffpy.writerimport*# write 256 channels of 10 data points at a sampling rate of 128 HzB=BinWriter(sampling_rate=128) B.add_block(np.random.randn(256, 10).astype(np.float32)) W=Writer(join('.cache', 'example_4_output.mff')) startdatetime=datetime.strptime('1984-02-18T14:00:10.000000+0100', "%Y-%m-%dT%H:%M:%S.%f%z") W.addxml('fileInfo', recordTime=startdatetime) W.add_coordinates_and_sensor_layout(device='HydroCel GSN 256 1.0') W.addbin(B) W.write()frommffpyimportReader, Writer# Read data from an MFF filereader=Reader("./examples/example_2.mff") data=reader.get_mff_content() # Write data to a JSON filewriter=Writer(".cache/example_5_output.json") writer.export_to_json(data)Note: for now, the JSON exporting feature only works for segmented mffs files.
Xml-type files are specified in "/schemata/" using XML Schema Definition. Any .xml file can be checked for compliance with the command-line tool xmllint. One can validate your xml files by: xmllint --schema schemata/categories.xsd /path/to/my/file.xml --noout. We are using the following version of xmllint:
$ xmllint --version xmllint: using libxml version 20909 compiled with: Threads Tree Output Push Reader Patterns Writer SAXv1 FTP HTTP DTDValid HTML Legacy C14N Catalog XPath XPointer XInclude Iconv ISO8859X Unicode Regexps Automata Expr Schemas Schematron Modules Debug Zlib LzmaCurrently we describe the following .xml file types:
Copyright 2019 Brain Electrophysiology Laboratory Company LLC
Licensed under the ApacheLicense, Version 2.0(the "License"); you may not use this module except in compliance with the License. You may obtain a copy of the License at:
http: // www.apache.org / licenses / LICENSE - 2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.