seapipe 0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. seapipe-0.1/LICENSE +21 -0
  2. seapipe-0.1/PKG-INFO +61 -0
  3. seapipe-0.1/README.md +10 -0
  4. seapipe-0.1/pyproject.toml +47 -0
  5. seapipe-0.1/seapipe/__init__.py +14 -0
  6. seapipe-0.1/seapipe/cfc/__init__.py +10 -0
  7. seapipe-0.1/seapipe/cfc/cfc_func.py +221 -0
  8. seapipe-0.1/seapipe/cfc/erpac.py +823 -0
  9. seapipe-0.1/seapipe/cfc/event_cfc.py +314 -0
  10. seapipe-0.1/seapipe/cfc/mean_amps.py +1232 -0
  11. seapipe-0.1/seapipe/cfc/plots.py +598 -0
  12. seapipe-0.1/seapipe/cfc/synchrony.py +295 -0
  13. seapipe-0.1/seapipe/dataset.py +569 -0
  14. seapipe-0.1/seapipe/events/__init__.py +7 -0
  15. seapipe-0.1/seapipe/events/eel.py +20 -0
  16. seapipe-0.1/seapipe/events/fish.py +886 -0
  17. seapipe-0.1/seapipe/events/seasnakes.py +336 -0
  18. seapipe-0.1/seapipe/events/surf.py +449 -0
  19. seapipe-0.1/seapipe/events/whales.py +365 -0
  20. seapipe-0.1/seapipe/spectrum/__init__.py +8 -0
  21. seapipe-0.1/seapipe/spectrum/psa.py +1052 -0
  22. seapipe-0.1/seapipe/spectrum/spectrogram.py +476 -0
  23. seapipe-0.1/seapipe/stats/__init__.py +6 -0
  24. seapipe-0.1/seapipe/stats/peth.py +143 -0
  25. seapipe-0.1/seapipe/stats/sleepstats.py +269 -0
  26. seapipe-0.1/seapipe/utils/__init__.py +19 -0
  27. seapipe-0.1/seapipe/utils/audit.py +577 -0
  28. seapipe-0.1/seapipe/utils/load.py +421 -0
  29. seapipe-0.1/seapipe/utils/logs.py +126 -0
  30. seapipe-0.1/seapipe/utils/misc.py +571 -0
  31. seapipe-0.1/seapipe/utils/process.py +17 -0
  32. seapipe-0.1/seapipe/utils/splitter.py +113 -0
  33. seapipe-0.1/seapipe/version.py +1 -0
  34. seapipe-0.1/seapipe.egg-info/PKG-INFO +61 -0
  35. seapipe-0.1/seapipe.egg-info/SOURCES.txt +40 -0
  36. seapipe-0.1/seapipe.egg-info/dependency_links.txt +1 -0
  37. seapipe-0.1/seapipe.egg-info/entry_points.txt +2 -0
  38. seapipe-0.1/seapipe.egg-info/requires.txt +10 -0
  39. seapipe-0.1/seapipe.egg-info/top_level.txt +1 -0
  40. seapipe-0.1/setup.cfg +10 -0
  41. seapipe-0.1/setup.py +56 -0
seapipe-0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 nathanecross
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
seapipe-0.1/PKG-INFO ADDED
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.1
2
+ Name: seapipe
3
+ Version: 0.1
4
+ Summary: A package pipeline for Sleep Events Analysis of EEG data.
5
+ Home-page: https://github.com/nathanecross/seapipe
6
+ Author: Nathan E. Cross
7
+ Author-email: Nathan Cross <nathan.cross@sydney.edu.au>
8
+ Maintainer-email: Nathan Cross <nathan.cross@sydney.edu.au>
9
+ License: MIT License
10
+
11
+ Copyright (c) 2023 nathanecross
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+
31
+ Project-URL: Homepage, https://seapipe.readthedocs.io/
32
+ Project-URL: Documentation, https://seapipe.readthedocs.io/
33
+ Project-URL: Repository, https://github.com/nathanecross/seapipe
34
+ Project-URL: Bug Tracker, https://github.com/nathanecross/seapipe/issues
35
+ Project-URL: Changelog, https://github.com/nathanecross/seapipe/blob/master/CHANGELOG.md
36
+ Keywords: sleep,eeg,detection,signal processing,neuroscience,analysis
37
+ Classifier: Development Status :: 4 - Beta
38
+ Classifier: Programming Language :: Python
39
+ Requires-Python: >=3.7
40
+ Description-Content-Type: text/markdown
41
+ License-File: LICENSE
42
+ Requires-Dist: pandas
43
+ Requires-Dist: wonambi>7.0
44
+ Requires-Dist: fooof
45
+ Requires-Dist: scipy>=0.19
46
+ Requires-Dist: mne>1.6.0
47
+ Requires-Dist: tensorpac>0.5.6
48
+ Provides-Extra: plot
49
+ Requires-Dist: PyQt5; extra == "plot"
50
+ Requires-Dist: matplotlib; extra == "plot"
51
+
52
+ # seapipe
53
+ A package pipeline for Sleep Events Analysis of EEG data.
54
+
55
+ seapipe is a Python pipeline for **S**leep **E**vents **A**nalysis. The package reads EEG recordings with the purpose of detecting and analysing sleep neurophysiology, such as sleep architecture statistics, sleep spindles, slow oscillations, phase amplitude coupling, and power spectral analyses.
56
+
57
+ It pulls functions from a range of other open source packages, including: Wonambi, the MNE and Tensorpac
58
+
59
+ It offers a simple and intuitive, yet fully customisable API. The major advantage of seapipe is that it can be deployed on full, diverse datasets that might require flexibility in certain parameters (e.g. electrode names, polarity of recordings, individualised frequency bands etc). The only requirement is that the data should be structured in BIDS.
60
+
61
+
seapipe-0.1/README.md ADDED
@@ -0,0 +1,10 @@
1
+ # seapipe
2
+ A package pipeline for Sleep Events Analysis of EEG data.
3
+
4
+ seapipe is a Python pipeline for **S**leep **E**vents **A**nalysis. The package reads EEG recordings with the purpose of detecting and analysing sleep neurophysiology, such as sleep architecture statistics, sleep spindles, slow oscillations, phase amplitude coupling, and power spectral analyses.
5
+
6
+ It pulls functions from a range of other open source packages, including: Wonambi, the MNE and Tensorpac
7
+
8
+ It offers a simple and intuitive, yet fully customisable API. The major advantage of seapipe is that it can be deployed on full, diverse datasets that might require flexibility in certain parameters (e.g. electrode names, polarity of recordings, individualised frequency bands etc). The only requirement is that the data should be structured in BIDS.
9
+
10
+
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "seapipe"
7
+ dynamic = ["version"]
8
+
9
+ dependencies = [
10
+ "pandas",
11
+ "wonambi>7.0",
12
+ "fooof",
13
+ "scipy>=0.19",
14
+ "mne>1.6.0",
15
+ "tensorpac>0.5.6",
16
+ ]
17
+ requires-python = ">=3.8"
18
+ authors = [
19
+ {name = "Nathan Cross", email = "nathan.cross@sydney.edu.au"},
20
+ ]
21
+ maintainers = [
22
+ {name = "Nathan Cross", email = "nathan.cross@sydney.edu.au"}
23
+ ]
24
+ description = "A package pipeline for Sleep Events Analysis of EEG data."
25
+ readme = "README.md"
26
+ license = {file = "LICENSE"}
27
+ keywords = ["sleep", "eeg", "detection", "signal processing", "neuroscience", "analysis"]
28
+ classifiers = [
29
+ "Development Status :: 4 - Beta",
30
+ "Programming Language :: Python"
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ plot = ["PyQt5",
35
+ "matplotlib"]
36
+
37
+
38
+ [project.urls]
39
+ Homepage = "https://seapipe.readthedocs.io/"
40
+ Documentation = "https://seapipe.readthedocs.io/"
41
+ Repository = "https://github.com/nathanecross/seapipe"
42
+ "Bug Tracker" = "https://github.com/nathanecross/seapipe/issues"
43
+ Changelog = "https://github.com/nathanecross/seapipe/blob/master/CHANGELOG.md"
44
+
45
+ [project.scripts]
46
+ seapipe = "dataset:pipeline"
47
+
@@ -0,0 +1,14 @@
1
+ """
2
+ SEA main module
3
+ """
4
+
5
+ __author__ = 'Nathan Cross'
6
+ __credits__ = 'Concordia University (Canada), University of Sydney (Australia)'
7
+
8
+ from .version import __version__
9
+
10
+ from .dataset import pipeline
11
+
12
+
13
+
14
+
@@ -0,0 +1,10 @@
1
+
2
+ from .cfc_func import circ_wwtest, circ_kappa, mean_amp, klentropy, cohend
3
+ from .erpac import pac_it, cfc_grouplevel, generate_adap_bands, watson_williams
4
+ from .event_cfc import pac_it_joint
5
+ from .mean_amps import pac_it, pac_it_2, cfc_grouplevel, generate_adap_bands, watson_williams
6
+ from .plots import plot_mean_amps, plot_prefphase, plot_prefphase_group, plot_meanamps_group
7
+ from .synchrony import event_sync, event_sync_dataset
8
+
9
+ __all__ = ['circ_wwtest', 'circ_kappa', 'mean_amp', 'klentropy', 'cohend', 'pac_it', 'cfc_grouplevel', 'generate_adap_bands', 'watson_williams', 'pac_it_joint', 'pac_it', 'pac_it_2', 'cfc_grouplevel', 'generate_adap_bands', 'watson_williams', 'plot_mean_amps', 'plot_prefphase', 'plot_prefphase_group', 'plot_meanamps_group', 'event_sync', 'event_sync_dataset']
10
+
@@ -0,0 +1,221 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Mon May 13 13:10:09 2019
4
+
5
+ CFC Functions
6
+
7
+ @author: jordan
8
+ """
9
+
10
+ from numpy import (any, arange, arctan2, argmin, around, array, asarray,
11
+ atleast_2d, ceil, concatenate, cumsum, dot, empty, exp, floor, genfromtxt,
12
+ hstack, hypot, identity, linalg, linspace, log, logical_and,
13
+ max, mean, minimum, multiply, nan, nanmean, nanstd, ones,
14
+ pi, power, prod, reshape, roll, sin, sqrt, squeeze, std, sum,
15
+ transpose, vstack, where, zeros)
16
+ from os import listdir, mkdir, path
17
+ from scipy.stats import f as fdist
18
+ from scipy.special import lpn
19
+ import matplotlib.pyplot as plt
20
+ from pingouin import circ_r
21
+ from safepickle import load
22
+ import warnings
23
+
24
+
25
+ def circ_wwtest(alpha1, alpha2, w1, w2, warnings=True):
26
+ """Parametric Watson-Williams multi-sample test for equal means. Can be
27
+ used as a one-way ANOVA test for cicular data. Adapted for binned data."""
28
+ n1 = sum(w1)
29
+ n2 = sum(w2)
30
+ N = n1 + n2
31
+
32
+ r1 = circ_r(alpha1, w1)
33
+ r2 = circ_r(alpha2, w2)
34
+
35
+ r = circ_r(concatenate((alpha1, alpha2)), concatenate((w1, w2)))
36
+ rw = sum((n1 * r1, n2 * r2)) / N
37
+
38
+ if warnings:
39
+ # check assumptions
40
+ if N >= 11 and rw < .45:
41
+ print('Warning: Test not applicable.'
42
+ 'Average resultant vector length < 0.45.')
43
+ elif N < 11 and N >= 7 and rw < .5:
44
+ print('Test not applicable. Average number of samples per population '
45
+ '6 < x < 11 and average resultant vector length < 0.5.')
46
+ elif N >= 5 and N < 7 and rw < .55:
47
+ print('Test not applicable. Average number of samples per population '
48
+ '4 < x < 7 and average resultant vector length < 0.55.')
49
+ elif N < 5:
50
+ print('Test not applicable. '
51
+ 'Average number of samples per population < 5.')
52
+
53
+ # test statistic
54
+ kk = circ_kappa(rw)
55
+ beta = 1 + 3 / (8 * kk) # correction factor
56
+ A = sum((n1 * r1, n2 * r2)) - r * N
57
+ B = N - sum((n1 * r1, n2 * r2))
58
+
59
+ F = beta * (N - 2) * A / B
60
+ pval = 1 - fdist.cdf(F, 1, N - 2)
61
+
62
+ return F, pval
63
+
64
+ def circ_kappa(alpha, w=None):
65
+ """ Computes an approximation to the ML estimate of the concentration
66
+ parameter kappa of the von Mises distribution."""
67
+ if isinstance(alpha, float):
68
+ r = alpha
69
+ N = 1
70
+ else:
71
+ r = circ_r(alpha, w)
72
+ N = len(alpha)
73
+
74
+ if r < .53:
75
+ kappa = (2 * r) + (r ** 3) + (5 * r ** (5/6))
76
+ elif r >= .53 and r < .85:
77
+ kappa = -.4 + 1.39 * r + .43 / (1 - r)
78
+ else:
79
+ kappa = 1 / (r ** 3 - 4 * r ** 2 + 3 * r)
80
+
81
+ if N < 15 and N > 1:
82
+ if kappa < 2:
83
+ kappa = max(kappa - 2 / (N * kappa), 0)
84
+ else:
85
+ kappa = (N - 1) ** 3 * kappa / (N ** 3 + N)
86
+
87
+ return kappa
88
+
89
+ def polar_plot(w, bin_edges):
90
+ nbins = len(bin_edges) - 1
91
+ width = 2 * pi / nbins
92
+ f, ax = plt.subplots(1, 1, subplot_kw=dict(projection='polar'))
93
+ ax.bar(bin_edges[:nbins], w, width=width, bottom=0.0)
94
+ xL = ['0', '', '', '', r'+/- $\pi$', '', '', '']
95
+ ax.set_xticklabels(xL)
96
+ ax.set_yticks([])
97
+ f.show()
98
+
99
+ def mean_amp(phase, amp, nbins=18):
100
+ # Meanamp taking Hilbert transformed phase and amplitude signals (for comodulogram)
101
+ # phase is the phase time series, type = array
102
+ # amp is the amplitude time series, type = array
103
+ # position is the array of phase bin left boundaries, type = array
104
+ # First, we break 2pi into phase bins
105
+ # 0 degrees corresponds to the negative trough of the Phase freq
106
+ # 180 degrees corresponds to the positive peak of the Phase freq
107
+ position = zeros(nbins)
108
+ winsize = 2 * pi / nbins
109
+ for i in range(nbins):
110
+ position[i] = -pi + i * winsize
111
+ position = roll(position, int(floor(nbins/4)-1), axis=-1)
112
+ # Then, we compute mean amplitude in each phase bin:
113
+ ma = zeros(nbins)
114
+ with warnings.catch_warnings():
115
+ warnings.simplefilter("ignore", category=RuntimeWarning)
116
+ for i, j in enumerate(position):
117
+ ma[i] = nanmean(amp[where(
118
+ logical_and(phase < (j + winsize), phase >= j)
119
+ )])
120
+ return ma
121
+
122
+ def klentropy(MeanAmp, axis=-1):
123
+ # Quantify the amount of amp modulation by means of a normalized
124
+ # Kullback-Leibler entropy index
125
+ nbin = MeanAmp.shape[-1]
126
+ MI = (log(nbin) - (-sum((MeanAmp / sum(MeanAmp, axis=axis, keepdims=True)) * \
127
+ log((MeanAmp / sum(MeanAmp, axis=axis, keepdims=True))), axis=axis,
128
+ keepdims=True))) / log(nbin)
129
+ return MI.squeeze()
130
+
131
+ # =============================================================================
132
+ # ALL NIGHT AMPBIN WITH STD DEV
133
+ # def _allnight_ampbin(a, nodat, nbins, norm=True, sd=False):
134
+ # out = zeros((*a.shape[:-2], nbins))
135
+ # out_sd = zeros((*a.shape[:-2], nbins))
136
+ # for i in range(a.shape[0]): # part
137
+ # for j in range(a.shape[1]): # night
138
+ # allcyc = [x for x in a[i, j, 0, :] if x is not nodat]
139
+ # allcyc = concatenate(allcyc)
140
+ # if norm:
141
+ # allcyc /= allcyc.sum(axis=1, keepdims=True)
142
+ # out[i, j, :] = nanmean(allcyc, axis=0)
143
+ # if std:
144
+ # out_sd[i, j, :] = nanstd(allcyc, axis=0)
145
+ # out = (out, out_sd)
146
+ # return out
147
+ #
148
+ # OLD _allnight_ampbin
149
+ # def _allnight_ampbin(a, nodat, nbins, norm=True):
150
+ # out = zeros((*a.shape[:-2], nbins))
151
+ # for i in range(a.shape[0]): # part
152
+ # for j in range(a.shape[1]): # night
153
+ # allcyc = [x for x in a[i, j, 0, :] if x is not nodat]
154
+ # allcyc = concatenate(allcyc)
155
+ # if norm:
156
+ # allcyc /= allcyc.sum(axis=1, keepdims=True)
157
+ # out[i, j, :] = nanmean(allcyc, axis=0)
158
+ # return out
159
+ # =============================================================================
160
+
161
+ def _allnight_ampbin(a, nodat, nbins, norm=True):
162
+ out = zeros((*a.shape[:-2], nbins))
163
+ for i in range(a.shape[0]): # part
164
+ allcyc = [x for x in a[i] if x is not nodat]
165
+ allcyc = concatenate(allcyc)
166
+ if norm:
167
+ allcyc /= allcyc.sum(axis=1, keepdims=True)
168
+ out[i, :] = nanmean(allcyc, axis=0)
169
+ return out
170
+
171
+ def ab_loader(ab_file, nbins, shift, norm=True):
172
+ with open(ab_file, 'rb') as f:
173
+ ab = load(f)
174
+ try:
175
+ ab = _allnight_ampbin(ab, 0, nbins, norm=norm)
176
+ except(ValueError):
177
+ ab = ab / ab.sum(-1, keepdims=True)
178
+ ab = ab.squeeze()
179
+ ab = roll(ab, shift, axis=-1)
180
+
181
+ return ab
182
+
183
+ def _idx_to_phase(idx, vecbin):
184
+ phase = zeros(idx.shape, dtype='O')
185
+ for i in range(idx.shape[0]):
186
+ for j in range(idx.shape[1]):
187
+ one_idx = asarray(idx[i][j], dtype='int')
188
+ phase[i][j] = vecbin[one_idx]
189
+
190
+ return phase
191
+
192
+ def logsd(m, sd):
193
+ print('M: ' + str(around(exp(m), 3)))
194
+ print('SD: ' + str(around(sqrt((exp(sd ** 2) - 1) * exp(2 * m + sd ** 2)), 3)))
195
+
196
+ def logse(m, sd, N=15):
197
+ print('M: ' + str(around(exp(m), 3)))
198
+ print('SE: ' + str(around(
199
+ sqrt((exp(sd ** 2) - 1) * exp(2 * m + sd ** 2)) / sqrt(N), 3)))
200
+
201
+ def cohend(x, y):
202
+ mean_diff = x.mean() - y.mean()
203
+ pooled_sd = sqrt((x.std() ** 2 + y.std() ** 2) / 2)
204
+ return mean_diff / pooled_sd
205
+
206
+
207
+ def paplot(ma):
208
+ f, axarr = plt.subplots(nrows=2, sharex=True)
209
+ width = 2 * pi / len(ma)
210
+ pos = arange(0, 4 * pi, width)
211
+ x = linspace(0, 4 * pi, 1000)
212
+ pa = axarr[0]
213
+ pa.bar(pos, hstack((ma, ma)), width=width, color='k', edgecolor='w')
214
+ pa.set_xticks([0, pi/2, pi, 3 * pi / 2, 2 * pi, 5 * pi / 2, 3 * pi, 7 * pi / 2, 4 * pi])
215
+ pa.set_xticklabels(['0'] + [r'$\pi$/2', r'$\pi$', r'3$\pi$/2', r'2$\pi$'] * 2)
216
+ sine = axarr[1]
217
+ sine.plot(sin(x))
218
+ sine.set_xticks([])
219
+ sine.set_yticks([])
220
+ plt.show()
221
+