Skip to content

Commit 4df9772

Browse files
committed
adding new examples
1 parent a53a7f2 commit 4df9772

File tree

7 files changed

+310
-7
lines changed

7 files changed

+310
-7
lines changed

docs/source/conf.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,10 +140,13 @@
140140
'backreferences_dir': 'generated',
141141
'filename_pattern': '/plot_|sim_',
142142
'default_thumb_file': 'source/_static/frites.png',
143-
'subsection_order': ExplicitOrder(['../../examples/mi',
144-
'../../examples/it',
145-
'../../examples/statistics',
146-
'../../examples/simulations']),
143+
'subsection_order': ExplicitOrder([
144+
'../../examples/dataset',
145+
'../../examples/mi',
146+
'../../examples/it',
147+
'../../examples/statistics',
148+
'../../examples/simulations',
149+
]),
147150
# 'thumbnail_size': (100, 100),
148151
}
149152

docs/source/whatsnew.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,19 @@ What's new
1010
v0.3.2
1111
------
1212

13+
Breaking changes
14+
++++++++++++++++
15+
* Avoid duplicates dataset construction when using MNE / xarray (:commit:`fef9`, :commit:`9dde`)
16+
* :py:class:`frites.dataset.DatasetEphy` supports None for the y input (:commit:`a53a`)
17+
1318
Internal Changes
1419
++++++++++++++++
1520
* Dtypes of `y` and `z` inputs are systematically check in :py:class:`frites.dataset.DatasetEphy` in order to define which MI can then be computed (:commit:`7cc1`)
1621

22+
New Features
23+
++++++++++++
24+
* :py:class:`frites.dataset.DatasetEphy` supports Xarray inputs + selection though coordinates (:commit:`7418`)
25+
1726

1827
.. raw:: html
1928

examples/dataset/README.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Build an electrophysiological dataset
2+
-------------------------------------
3+
4+
Build an electrophysiological dataset, with different input types and apply some basing operations to it?
5+
6+
.. contents:: Contents
7+
:local:
8+
:depth: 2

examples/dataset/plot_dataset_ephy.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"""
2+
Build an electrophysiological dataset
3+
=====================================
4+
5+
In Frites, a dataset is a structure for grouping the electrophysiological data
6+
(e.g MEG / EEG / Intracranial) coming from multiple subjects. In addition,
7+
some basic operations can also be performed (like slicing, smoothing etc.). In
8+
this example we illutrate how to define a dataset using NumPy arrays.
9+
"""
10+
import numpy as np
11+
12+
from frites.dataset import DatasetEphy
13+
14+
import matplotlib.pyplot as plt
15+
16+
###############################################################################
17+
# Create artificial data
18+
# ----------------------
19+
#
20+
# We start by creating some random data for several subjects. To do that, each
21+
# subject is going have a 3 dimensional array of shape
22+
# (n_epochs, n_channels, n_times). Then, all of the arrays are grouped together
23+
# in a list of length (n_subjects,)
24+
25+
n_subjects = 5
26+
n_epochs = 10
27+
n_channels = 5
28+
n_times = 1000
29+
sf = 512
30+
31+
x, ch = [], []
32+
for k in range(n_subjects):
33+
# generate single subject data
34+
x_suj = np.random.rand(n_epochs, n_channels, n_times)
35+
# generate some random channel names
36+
ch_suj = np.array([f"ch_{r}" for r in range(n_channels)])
37+
# concatenate in a list
38+
x.append(x_suj)
39+
ch.append(ch_suj)
40+
# finally lets create a time vector
41+
times = np.arange(n_times) / sf
42+
43+
###############################################################################
44+
# Create the dataset
45+
# ------------------
46+
#
47+
# The creation of the dataset is performed using the class
48+
# :class:`frites.dataset.DatasetEphy`
49+
50+
dt = DatasetEphy(x.copy(), roi=ch, times=times)
51+
print(dt)
52+
53+
plt.plot(dt.times, dt.x[0][:, 0, :].T)
54+
plt.xlabel('Times')
55+
plt.title('Electrophysiological data of the first subject, for the first '
56+
'channel')
57+
plt.show()
58+
59+
###############################################################################
60+
# Data smoothing
61+
# --------------
62+
#
63+
# If you have MNE-Python installed, you can also smooth the data using
64+
# :class:`frites.dataset.DatasetEphy.savgol_filter`. One important thing is
65+
# that operations are performed inplace, which means that once launched, the
66+
# data are modified inside the dataset without copy
67+
68+
# high cut-off frequency at 4Hz
69+
dt.savgol_filter(4)
70+
71+
plt.plot(dt.times, dt.x[0][:, 0, :].T)
72+
plt.xlabel('Times')
73+
plt.title('Smoothed dataset')
74+
plt.show()
75+
76+
###############################################################################
77+
# Data resampling
78+
#
79+
# Still using MNE-Python, you can also resample the dataset using
80+
# :class:`frites.dataset.DatasetEphy.resample`
81+
82+
# resample the dataset using a new sampling rate of 256Hz
83+
dt.resample(256)
84+
85+
plt.plot(dt.times, dt.x[0][:, 0, :].T)
86+
plt.xlabel('Times')
87+
plt.title('Resampled dataset')
88+
plt.show()
89+
90+
###############################################################################
91+
# Spatio-temporal slicing
92+
# -----------------------
93+
#
94+
# The dataset also supports some basic slicing operations through time and
95+
# space. Slicing is still performed inplace
96+
97+
# temporal selection between [0.25, 1.75]
98+
dt[0.25:1.75, :] # the ':' symbol means that we are selecting every channel
99+
100+
plt.plot(dt.times, dt.x[0][:, 0, :].T)
101+
plt.xlabel('Times')
102+
plt.title('Temporal slicing')
103+
plt.show()
104+
105+
# spatial selection of channels ch_0 and ch_1
106+
dt[:, ['ch_0', 'ch_1']]
107+
print(dt.roi)

examples/dataset/plot_dataset_mne.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""
2+
Define an electrophysiological dataset using MNE-Python structures
3+
==================================================================
4+
5+
This example illustrates how to define a dataset using MNE-Python Epochs.
6+
"""
7+
import numpy as np
8+
9+
from mne import EpochsArray, create_info
10+
from frites.dataset import DatasetEphy
11+
12+
import matplotlib.pyplot as plt
13+
14+
###############################################################################
15+
# Create artificial data
16+
# ----------------------
17+
#
18+
# We start by creating some random data for several subjects. To do that, each
19+
# subject is going have a 3 dimensional array of shape
20+
# (n_epochs, n_channels, n_times). Then, all of the arrays are grouped together
21+
# in a list of length (n_subjects,)
22+
23+
n_subjects = 5
24+
n_epochs = 10
25+
n_channels = 5
26+
n_times = 100
27+
sf = 512
28+
29+
x, ch = [], []
30+
for k in range(n_subjects):
31+
# generate single subject data
32+
x_suj = np.random.rand(n_epochs, n_channels, n_times)
33+
# generate some random channel names
34+
ch_suj = np.array([f"ch_{r}" for r in range(n_channels)])
35+
# concatenate in a list
36+
x.append(x_suj)
37+
ch.append(ch_suj)
38+
# finally lets create a time vector
39+
times = np.arange(n_times) / sf
40+
41+
###############################################################################
42+
# MNE conversion to Epoch
43+
# -----------------------
44+
#
45+
# Here, we convert our illustrative data into EpochsArray. With real data, you
46+
# are probbaly going to have mne.Epochs objects which also going to work just
47+
# the same
48+
49+
x_mne = []
50+
for k in range(n_subjects):
51+
# create some informations
52+
info = create_info(ch[k].tolist(), sf)
53+
# create the Epoch of this subject
54+
epoch = EpochsArray(x[k], info, tmin=times[0], verbose=False)
55+
# finally, replace it in the original list
56+
x_mne.append(epoch)
57+
print(x_mne[0])
58+
59+
###############################################################################
60+
# Build the dataset
61+
# -----------------
62+
#
63+
# Finally, we pass the data to the :class:`frites.dataset.DatasetEphy` class
64+
# in order to create the dataset
65+
66+
dt = DatasetEphy(x_mne)
67+
print(dt)
68+
69+
print('Time vector : ', dt.times)
70+
print('ROI (first subject) : ', dt.roi[0])
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
"""
2+
Define an electrophysiological dataset using Xarray
3+
===================================================
4+
5+
This example illustrates how to define a dataset using Xarray. If you don't
6+
know this library, we can simplify by saying that it provides containers that
7+
accept arrays but you can also labelize your dimensions. Another way of seeing
8+
it, pandas is mostly made for tables (i.e 2D arrays) while Xarray provide
9+
almost the same functionalities but for multi-dimensional arrays.
10+
11+
"""
12+
import numpy as np
13+
import pandas as pd
14+
15+
from xarray import DataArray
16+
from frites.dataset import DatasetEphy
17+
18+
import matplotlib.pyplot as plt
19+
20+
###############################################################################
21+
# Create artificial data
22+
# ----------------------
23+
#
24+
# We start by creating some random data for several subjects. To do that, each
25+
# subject is going have a 3 dimensional array of shape
26+
# (n_epochs, n_channels, n_times). Then, all of the arrays are grouped together
27+
# in a list of length (n_subjects,)
28+
29+
n_subjects = 5
30+
n_epochs = 10
31+
n_channels = 5
32+
n_times = 100
33+
sf = 512
34+
35+
x, ch = [], []
36+
for k in range(n_subjects):
37+
# generate single subject data
38+
x_suj = np.random.rand(n_epochs, n_channels, n_times)
39+
# generate some random channel names
40+
ch_suj = np.array([f"ch_{r}" for r in range(n_channels)])
41+
# concatenate in a list
42+
x.append(x_suj)
43+
ch.append(ch_suj)
44+
# finally lets create a time vector
45+
times = np.arange(n_times) / sf
46+
epochs = np.arange(n_epochs)
47+
48+
###############################################################################
49+
# Xarray conversion to DataArray
50+
# ------------------------------
51+
#
52+
# Here, we convert the NumPy arrays to xarray.DataArray
53+
54+
x_xr = []
55+
for k in range(n_subjects):
56+
# DataArray conversion
57+
arr_xr = DataArray(x[k], dims=('epochs', 'channels', 'times'),
58+
coords=(epochs, ch[k], times))
59+
# finally, replace it in the original list
60+
x_xr.append(arr_xr)
61+
print(x_xr[0])
62+
63+
###############################################################################
64+
# Build the dataset
65+
# -----------------
66+
#
67+
# Finally, we pass the data to the :class:`frites.dataset.DatasetEphy` class
68+
# in order to create the dataset
69+
70+
# here, we specify to the DatasetEphy class that the roi dimension is actually
71+
# called 'channels' in the DataArray and the times dimension is called 'times'
72+
dt = DatasetEphy(x_xr, roi='channels', times='times')
73+
print(dt)
74+
75+
print('Time vector : ', dt.times)
76+
print('ROI (first subject) : ', dt.roi[0])
77+
78+
###############################################################################
79+
# MultiIndex support
80+
# ------------------
81+
#
82+
# DataArray also supports multi-indexing of a single dimension.
83+
84+
# create a continuous regressor (prediction error, delta P etc.)
85+
dp = np.random.uniform(-1, 1, (n_epochs,))
86+
# create a discret variable (e.g experimental conditions)
87+
cond = np.array([0] * 5 + [1] * 5)
88+
89+
# now, create a multi-index using pandas
90+
midx = pd.MultiIndex.from_arrays((dp, cond), names=('dp', 'blocks'))
91+
92+
# convert again the original arrays but this time, the epoch dimension is going
93+
# to be a multi-index
94+
x_xr = []
95+
for k in range(n_subjects):
96+
# DataArray conversion
97+
arr_xr = DataArray(x[k], dims=('epochs', 'channels', 'times'),
98+
coords=(midx, ch[k], times))
99+
# finally, replace it in the original list
100+
x_xr.append(arr_xr)
101+
print(x_xr[0])
102+
103+
# finally, when you create your dataset you can also specify the y and z inputs
104+
# by providing their names in the DataArray
105+
dt = DatasetEphy(x_xr, roi='channels', times='times', y='dp', z='blocks')
106+
print(dt)

frites/dataset/ds_ephy.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ def __init__(self, x, y=None, roi=None, z=None, times=None,
6868
# ---------------------------------------------------------------------
6969
# conversion of the electrophysiocal data
7070
# ---------------------------------------------------------------------
71+
x, y, z, roi, times = ds_ephy_io(x, roi=roi, y=y, z=z, times=times,
72+
verbose=verbose)
7173
if y is None:
7274
logger.debug("Fill the y input because otherwise everything fails")
7375
y = [np.zeros((x[k].shape[0])) for k in range(len(x))]
74-
x, y, z, roi, times = ds_ephy_io(x, roi=roi, y=y, z=z, times=times,
75-
verbose=verbose)
7676

7777
# ---------------------------------------------------------------------
7878
# check the types of y (and z)
@@ -482,7 +482,7 @@ def resample(self, sfreq, npad='auto', window='boxcar', n_jobs=1,
482482
window=window, n_jobs=n_jobs, pad=pad)
483483
self.sfreq = float(sfreq)
484484

485-
self.times = (np.arange(self._x[0].shape[1], dtype=np.float) /
485+
self.times = (np.arange(self._x[0].shape[-1], dtype=np.float) /
486486
sfreq + self.times[0])
487487
self.n_times = len(self.times)
488488

0 commit comments

Comments
 (0)