How it works

The sample mkh5 file is for a single subject in an auditory oddball paradigm with some epochs tables previously marked.

Converting mkh5 HDF5 to MNE RawMkh5 does several things:

  • concatenates the separate mkh5 datablock EEG and event data channels into one long mne.Raw strip chart

  • populates the mne.Info structure with header info including electrode names and locations

  • extracts all the mkpy epochs tables from the HDF5 and packs them into the mne.Info

  • for each epoch table, a new “stim” event code channel is created in the mne.Raw with the name of the epochs table and all and only the events from that table.

FYI … environment and versions.

import os
import mne
import mkpy
from mkpy.io import mkh5mne

mne.viz.set_browser_backend("matplotlib")  # for docs generation

print("conda env", os.environ["CONDA_DEFAULT_ENV"])
for pkg in [mkpy, mne]:
    print(pkg.__name__, pkg.__version__)

Out:

conda env env_3.8
mkpy 0.2.7
mne 1.0.3

Convert the EEG and event-tagged epochs. Electrode locations are required, they can be included in the YAML .yhdr when the mkh5 file is created or added during conversion as shown.

p3_h5_f = "../mkh5_data/sub000p3.h5"
mne_raw = mkh5mne.from_mkh5(p3_h5_f, apparatus_yaml="mne_32chan_xyz_spherical.yml")

Out:

../mkh5_data/sub000p3.h5
looking up data block paths, larger files take longer ...
ok
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_0 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
checking info, montage sub000/dblock_1
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_1 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
checking info, montage sub000/dblock_2
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_2 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
checking info, montage sub000/dblock_3
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_3 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
checking info, montage sub000/dblock_4
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_4 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_0 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
Creating RawArray with float64 data, n_channels=39, n_times=31232
    Range : 0 ... 31231 =      0.000 ...   124.924 secs
Ready.
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1478: RuntimeWarning: Not setting position of 1 eog channel found in montage:
['HEOG']
Consider setting the channel types to be of EEG/sEEG/ECoG/DBS/fNIRS using inst.set_channel_types before calling inst.set_montage, or omit these channels when creating your montage.
  raw_dblock.set_montage(montage)
sub000/dblock_0 setting mkh5 epochs table ms100 events and metadata
sub000/dblock_0 setting mkh5 epochs table ms10000 events and metadata
sub000/dblock_0 setting mkh5 epochs table ms1500 events and metadata
sub000/dblock_0 setting mkh5 epochs table ms3000 events and metadata
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_1 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
Creating RawArray with float64 data, n_channels=39, n_times=32768
    Range : 0 ... 32767 =      0.000 ...   131.068 secs
Ready.
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1478: RuntimeWarning: Not setting position of 1 eog channel found in montage:
['HEOG']
Consider setting the channel types to be of EEG/sEEG/ECoG/DBS/fNIRS using inst.set_channel_types before calling inst.set_montage, or omit these channels when creating your montage.
  raw_dblock.set_montage(montage)
sub000/dblock_1 setting mkh5 epochs table ms100 events and metadata
sub000/dblock_1 setting mkh5 epochs table ms10000 events and metadata
sub000/dblock_1 setting mkh5 epochs table ms1500 events and metadata
sub000/dblock_1 setting mkh5 epochs table ms3000 events and metadata
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_2 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
Creating RawArray with float64 data, n_channels=39, n_times=31744
    Range : 0 ... 31743 =      0.000 ...   126.972 secs
Ready.
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1478: RuntimeWarning: Not setting position of 1 eog channel found in montage:
['HEOG']
Consider setting the channel types to be of EEG/sEEG/ECoG/DBS/fNIRS using inst.set_channel_types before calling inst.set_montage, or omit these channels when creating your montage.
  raw_dblock.set_montage(montage)
sub000/dblock_2 setting mkh5 epochs table ms100 events and metadata
sub000/dblock_2 setting mkh5 epochs table ms10000 events and metadata
sub000/dblock_2 setting mkh5 epochs table ms1500 events and metadata
sub000/dblock_2 setting mkh5 epochs table ms3000 events and metadata
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_3 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
Creating RawArray with float64 data, n_channels=39, n_times=32512
    Range : 0 ... 32511 =      0.000 ...   130.044 secs
Ready.
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1478: RuntimeWarning: Not setting position of 1 eog channel found in montage:
['HEOG']
Consider setting the channel types to be of EEG/sEEG/ECoG/DBS/fNIRS using inst.set_channel_types before calling inst.set_montage, or omit these channels when creating your montage.
  raw_dblock.set_montage(montage)
sub000/dblock_3 setting mkh5 epochs table ms100 events and metadata
sub000/dblock_3 setting mkh5 epochs table ms10000 events and metadata
sub000/dblock_3 setting mkh5 epochs table ms1500 events and metadata
sub000/dblock_3 setting mkh5 epochs table ms3000 events and metadata
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1190: UserWarning: Overriding /sub000/dblock_4 with sensor locations from mne_32chan_xyz_spherical.yml
  warnings.warn(msg)
Creating RawArray with float64 data, n_channels=39, n_times=28416
    Range : 0 ... 28415 =      0.000 ...   113.660 secs
Ready.
/usr/share/miniconda/envs/env_3.8/lib/python3.8/site-packages/mkpy/io/mkh5mne.py:1478: RuntimeWarning: Not setting position of 1 eog channel found in montage:
['HEOG']
Consider setting the channel types to be of EEG/sEEG/ECoG/DBS/fNIRS using inst.set_channel_types before calling inst.set_montage, or omit these channels when creating your montage.
  raw_dblock.set_montage(montage)
sub000/dblock_4 setting mkh5 epochs table ms100 events and metadata
sub000/dblock_4 setting mkh5 epochs table ms10000 events and metadata
sub000/dblock_4 setting mkh5 epochs table ms1500 events and metadata
sub000/dblock_4 setting mkh5 epochs table ms3000 events and metadata
EEG data marked as already having the desired reference.

When the mkh5 datablocks are knit together for MNE, the discontinuities at edges are tracked automatically as mne.Annotations

mne_raw.annotations.description

Out:

array(['sub000/dblock_0', 'sub000/dblock_1', 'BAD boundary',
       'EDGE boundary', 'sub000/dblock_2', 'BAD boundary',
       'EDGE boundary', 'sub000/dblock_3', 'BAD boundary',
       'EDGE boundary', 'sub000/dblock_4', 'BAD boundary',
       'EDGE boundary'], dtype='<U15')

The mne_raw object has the mne.Info attached. You can see the mkh5 epoch_table info peeking out of the mne.Info[“description”] field.

mne_raw.info
Measurement date July 25, 2020 14:23:44 GMT
Experimenter Unknown
Participant 33f90cab-395e-4871-8641-3be5c9e9d579
Digitized points 0 points
Good channels 2 misc, 9 Stimulus, 31 EEG, 1 EOG
Bad channels None
EOG channels HEOG
ECG channels Not available
Sampling frequency 250.00 Hz
Highpass 0.00 Hz
Lowpass 125.00 Hz


This RawMkh5 object can do all the usual mne.Raw tricks like plotting and writing itself to an MNE raw .fif file. %%

p3_events = mkh5mne.find_mkh5_events(mne_raw, "ms1500")
_ = mne_raw.plot(
    p3_events,
    start=53.0,
    duration=3.0,
)
_ = mne.viz.plot_sensors(mne_raw.info)
  • how it works
  • how it works

Out:

Opening raw-browser...

Annotate garv artifacts (optional)

The mkh5 log_flags that indicate garv artifact events after avg -x can be converted to BAD_garv mne.Annotations for events on any of the event channels.

# Select the event channel to annotate ("log_evcodes" for all), then
# then add the annotations to the mne.Raw
garv_bads = mkh5mne.get_garv_bads(
    mne_raw, event_channel="ms1500", tmin=-750, tmax=750, units="ms"
)
mne_raw.set_annotations(mne_raw.annotations + garv_bads)
mne_raw.annotations

Out:

<Annotations | 71 segments: BAD boundary (4), BAD_garv_32 (33), ...>

mne.Epochs codemap metadata

Use :py:meth:.`get_epochs_metadata` to extract mne.Epochs with the codemap metatdata as MNE format metata when constructing mne.Epochs.

mne_epochs = mkh5mne.get_epochs(
    mne_raw,
    "ms1500",
    preload=True,  # populate the Epochs with data and apply projections
    reject_by_annotation=True,  # drop the BAD_* annotations or set False to keep them
    baseline=(-0.2, 0.0),  # center on this interval
)
mne_epochs

Out:

Adding metadata with 40 columns
600 matching events found
Applying baseline correction (mode: mean)
0 projection items activated
Using data from preloaded Raw for 600 events and 376 original time points ...
131 bad epochs dropped
Number of events 469
Events 1: 49
10: 100
11: 22
2: 47
20: 116
21: 23
3: 56
4: 56
Time range -0.748 – 0.752 sec
Baseline -0.200 – 0.000 sec


The mkh5 codemap tags are attached as native mne.Epochs.metadata

mne_epochs.metadata
epoch_id data_group dblock_path dblock_tick_idx dblock_ticks crw_ticks raw_evcodes log_evcodes log_ccodes log_flags epoch_match_tick_delta epoch_ticks dblock_srate match_group idx dlim anchor_str match_str anchor_code match_code anchor_tick match_tick anchor_tick_delta is_anchor regexp ccode instrument bin tone stim accuracy acc_type match_time anchor_time anchor_time_delta diti_t_0 diti_hop diti_len mne_dblock_path_idx mne_raw_tick
0 27 sub000 sub000/dblock_0 0 943 943 10 10 1 0 -187 375 250.0 1 0 1 10 10 10 10 943 943 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 943 -187 375 0 943
1 28 sub000 sub000/dblock_0 1 1212 1212 10 10 1 0 -187 375 250.0 1 1 4 10 10 10 10 1212 1212 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 1212 -187 375 0 1212
2 0 sub000 sub000/dblock_0 2 1468 1468 11 11 1 0 -187 375 250.0 1 2 7 11 11 11 11 1468 1468 0 True (#11) 1040 1 eeg 3 hi target correct hit 0 0 0 1468 -187 375 0 1468
3 29 sub000 sub000/dblock_0 4 1814 1814 10 10 1 0 -187 375 250.0 1 4 15 10 10 10 10 1814 1814 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 1814 -187 375 0 1814
4 30 sub000 sub000/dblock_0 5 2066 2066 10 10 1 0 -187 375 250.0 1 5 18 10 10 10 10 2066 2066 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 2066 -187 375 0 2066
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
595 596 sub000 sub000/dblock_4 204 27315 27315 4 4 0 0 -187 375 250.0 1 204 409 4 4 4 4 27315 27315 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27315 -187 375 4 155571
596 597 sub000 sub000/dblock_4 205 27444 27444 2 2 0 0 -187 375 250.0 1 205 411 2 2 2 2 27444 27444 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27444 -187 375 4 155700
597 598 sub000 sub000/dblock_4 206 27573 27573 3 3 0 0 -187 375 250.0 1 206 413 3 3 3 3 27573 27573 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27573 -187 375 4 155829
598 599 sub000 sub000/dblock_4 207 27703 27703 4 4 0 0 -187 375 250.0 1 207 415 4 4 4 4 27703 27703 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27703 -187 375 4 155959
599 600 sub000 sub000/dblock_4 208 27832 27832 2 2 0 0 -187 375 250.0 1 208 417 2 2 2 2 27832 27832 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27832 -187 375 4 156088

469 rows × 40 columns



mkh5mne raw data utilities

These utility functions access mkh5 information embedded in the RawMkH5 object.

find_mkh5_events()

This is a replacement for mne.find_events() that creates the 3 column array of [sample, 0, event] used for native mne.Raw epoching and plotting without doing wrong things like converting negative event codes to positive.

print(garv_bads, garv_bads.description)
p3_events = mkh5mne.find_mkh5_events(mne_raw, "ms1500")
p3_events

# :py:meth:`.get_find_mkh5_events`
# ----------------------------
#
# This extracts the embedded epochs table from the RawMkh5.
metadata = mkh5mne.get_epochs_metadata(mne_raw, "ms1500")
metadata

Out:

<Annotations | 58 segments: BAD_garv_32 (33), BAD_garv_48 (25)> ['BAD_garv_48' 'BAD_garv_48' 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_48'
 'BAD_garv_48' 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_48' 'BAD_garv_32'
 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_48' 'BAD_garv_32'
 'BAD_garv_48' 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32'
 'BAD_garv_48' 'BAD_garv_48' 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_48'
 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32'
 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32'
 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32'
 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_48'
 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_32' 'BAD_garv_48'
 'BAD_garv_32' 'BAD_garv_48' 'BAD_garv_32' 'BAD_garv_48' 'BAD_garv_48'
 'BAD_garv_32' 'BAD_garv_48' 'BAD_garv_48']
epoch_id data_group dblock_path dblock_tick_idx dblock_ticks crw_ticks raw_evcodes log_evcodes log_ccodes log_flags epoch_match_tick_delta epoch_ticks dblock_srate match_group idx dlim anchor_str match_str anchor_code match_code anchor_tick match_tick anchor_tick_delta is_anchor regexp ccode instrument bin tone stim accuracy acc_type match_time anchor_time anchor_time_delta diti_t_0 diti_hop diti_len mne_dblock_path_idx mne_raw_tick
27 27 sub000 sub000/dblock_0 0 943 943 10 10 1 0 -187 375 250.0 1 0 1 10 10 10 10 943 943 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 943 -187 375 0 943
28 28 sub000 sub000/dblock_0 1 1212 1212 10 10 1 0 -187 375 250.0 1 1 4 10 10 10 10 1212 1212 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 1212 -187 375 0 1212
0 0 sub000 sub000/dblock_0 2 1468 1468 11 11 1 0 -187 375 250.0 1 2 7 11 11 11 11 1468 1468 0 True (#11) 1040 1 eeg 3 hi target correct hit 0 0 0 1468 -187 375 0 1468
29 29 sub000 sub000/dblock_0 4 1814 1814 10 10 1 0 -187 375 250.0 1 4 15 10 10 10 10 1814 1814 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 1814 -187 375 0 1814
30 30 sub000 sub000/dblock_0 5 2066 2066 10 10 1 0 -187 375 250.0 1 5 18 10 10 10 10 2066 2066 0 True (#10) (?!1040) 1 eeg 4 lo standard correct cr 0 0 0 2066 -187 375 0 2066
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
595 596 sub000 sub000/dblock_4 204 27315 27315 4 4 0 0 -187 375 250.0 1 204 409 4 4 4 4 27315 27315 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27315 -187 375 4 155571
596 597 sub000 sub000/dblock_4 205 27444 27444 2 2 0 0 -187 375 250.0 1 205 411 2 2 2 2 27444 27444 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27444 -187 375 4 155700
597 598 sub000 sub000/dblock_4 206 27573 27573 3 3 0 0 -187 375 250.0 1 206 413 3 3 3 3 27573 27573 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27573 -187 375 4 155829
598 599 sub000 sub000/dblock_4 207 27703 27703 4 4 0 0 -187 375 250.0 1 207 415 4 4 4 4 27703 27703 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27703 -187 375 4 155959
599 600 sub000 sub000/dblock_4 208 27832 27832 2 2 0 0 -187 375 250.0 1 208 417 2 2 2 2 27832 27832 0 True (#\d+) 0 cal 0 cal cal cal cal 0 0 0 27832 -187 375 4 156088

600 rows × 40 columns



Total running time of the script: ( 0 minutes 20.620 seconds)

Gallery generated by Sphinx-Gallery