py-neuromodulation 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.whl
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.
- docs/build/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +68 -0
- docs/build/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +233 -0
- docs/build/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +219 -0
- docs/build/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +97 -0
- docs/build/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +64 -0
- docs/build/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +192 -0
- docs/build/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +210 -0
- docs/build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +68 -0
- docs/build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +239 -0
- docs/build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +219 -0
- docs/build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +97 -0
- docs/build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +64 -0
- docs/build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +192 -0
- docs/build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +210 -0
- docs/source/_build/html/_downloads/09df217f95985497f45d69e2d4bdc5b1/plot_2_example_add_feature.py +76 -0
- docs/source/_build/html/_downloads/0d0d0a76e8f648d5d3cbc47da6351932/plot_real_time_demo.py +97 -0
- docs/source/_build/html/_downloads/3b4900a2b2818ff30362215b76f7d5eb/plot_1_example_BIDS.py +240 -0
- docs/source/_build/html/_downloads/5d73cadc59a8805c47e3b84063afc157/plot_example_BIDS.py +233 -0
- docs/source/_build/html/_downloads/7660317fa5a6bfbd12fcca9961457fc4/plot_example_rmap_computing.py +63 -0
- docs/source/_build/html/_downloads/7e92dd2e6cc86b239d14cafad972ae4f/plot_3_example_sharpwave_analysis.py +219 -0
- docs/source/_build/html/_downloads/839e5b319379f7fd9e867deb00fd797f/plot_example_gridPointProjection.py +210 -0
- docs/source/_build/html/_downloads/ae8be19afe5e559f011fc9b138968ba0/plot_first_demo.py +192 -0
- docs/source/_build/html/_downloads/b8b06cacc17969d3725a0b6f1d7741c5/plot_example_sharpwave_analysis.py +219 -0
- docs/source/_build/html/_downloads/c2db0bf2b334d541b00662b991682256/plot_6_real_time_demo.py +121 -0
- docs/source/_build/html/_downloads/c31a86c0b68cb4167d968091ace8080d/plot_example_add_feature.py +68 -0
- docs/source/_build/html/_downloads/ce3914826f782cbd1ea8fd024eaf0ac3/plot_5_example_rmap_computing.py +64 -0
- docs/source/_build/html/_downloads/da36848a41e6a3235d91fb7cfb6d59b4/plot_0_first_demo.py +189 -0
- docs/source/_build/html/_downloads/eaa4305c75b19a1e2eea941f742a6331/plot_4_example_gridPointProjection.py +210 -0
- docs/source/auto_examples/plot_0_first_demo.py +189 -0
- docs/source/auto_examples/plot_1_example_BIDS.py +240 -0
- docs/source/auto_examples/plot_2_example_add_feature.py +76 -0
- docs/source/auto_examples/plot_3_example_sharpwave_analysis.py +219 -0
- docs/source/auto_examples/plot_4_example_gridPointProjection.py +210 -0
- docs/source/auto_examples/plot_5_example_rmap_computing.py +64 -0
- docs/source/auto_examples/plot_6_real_time_demo.py +121 -0
- docs/source/conf.py +105 -0
- examples/plot_0_first_demo.py +189 -0
- examples/plot_1_example_BIDS.py +240 -0
- examples/plot_2_example_add_feature.py +76 -0
- examples/plot_3_example_sharpwave_analysis.py +219 -0
- examples/plot_4_example_gridPointProjection.py +210 -0
- examples/plot_5_example_rmap_computing.py +64 -0
- examples/plot_6_real_time_demo.py +121 -0
- packages/realtime_decoding/build/lib/realtime_decoding/__init__.py +4 -0
- packages/realtime_decoding/build/lib/realtime_decoding/decoder.py +104 -0
- packages/realtime_decoding/build/lib/realtime_decoding/features.py +163 -0
- packages/realtime_decoding/build/lib/realtime_decoding/helpers.py +15 -0
- packages/realtime_decoding/build/lib/realtime_decoding/run_decoding.py +345 -0
- packages/realtime_decoding/build/lib/realtime_decoding/trainer.py +54 -0
- packages/tmsi/build/lib/TMSiFileFormats/__init__.py +37 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/__init__.py +36 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/lsl_stream_writer.py +200 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_file_writer.py +496 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/poly5_to_edf_converter.py +236 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_formats/xdf_file_writer.py +977 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/__init__.py +35 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/edf_reader.py +116 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/poly5reader.py +294 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_readers/xdf_reader.py +229 -0
- packages/tmsi/build/lib/TMSiFileFormats/file_writer.py +102 -0
- packages/tmsi/build/lib/TMSiPlotters/__init__.py +2 -0
- packages/tmsi/build/lib/TMSiPlotters/gui/__init__.py +39 -0
- packages/tmsi/build/lib/TMSiPlotters/gui/_plotter_gui.py +234 -0
- packages/tmsi/build/lib/TMSiPlotters/gui/plotting_gui.py +440 -0
- packages/tmsi/build/lib/TMSiPlotters/plotters/__init__.py +44 -0
- packages/tmsi/build/lib/TMSiPlotters/plotters/hd_emg_plotter.py +446 -0
- packages/tmsi/build/lib/TMSiPlotters/plotters/impedance_plotter.py +589 -0
- packages/tmsi/build/lib/TMSiPlotters/plotters/signal_plotter.py +1326 -0
- packages/tmsi/build/lib/TMSiSDK/__init__.py +54 -0
- packages/tmsi/build/lib/TMSiSDK/device.py +588 -0
- packages/tmsi/build/lib/TMSiSDK/devices/__init__.py +34 -0
- packages/tmsi/build/lib/TMSiSDK/devices/saga/TMSi_Device_API.py +1764 -0
- packages/tmsi/build/lib/TMSiSDK/devices/saga/__init__.py +34 -0
- packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_device.py +1366 -0
- packages/tmsi/build/lib/TMSiSDK/devices/saga/saga_types.py +520 -0
- packages/tmsi/build/lib/TMSiSDK/devices/saga/xml_saga_config.py +165 -0
- packages/tmsi/build/lib/TMSiSDK/error.py +95 -0
- packages/tmsi/build/lib/TMSiSDK/sample_data.py +63 -0
- packages/tmsi/build/lib/TMSiSDK/sample_data_server.py +99 -0
- packages/tmsi/build/lib/TMSiSDK/settings.py +45 -0
- packages/tmsi/build/lib/TMSiSDK/tmsi_device.py +111 -0
- packages/tmsi/build/lib/__init__.py +4 -0
- packages/tmsi/build/lib/apex_sdk/__init__.py +34 -0
- packages/tmsi/build/lib/apex_sdk/device/__init__.py +41 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API.py +1009 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_enums.py +239 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_API_structures.py +668 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_device.py +1611 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_dongle.py +38 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_event_reader.py +57 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_channel.py +44 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_config.py +150 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_const.py +36 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_impedance_channel.py +48 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/apex_info.py +108 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/apex_structures/dongle_info.py +39 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/download_measurement.py +77 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/eeg_measurement.py +150 -0
- packages/tmsi/build/lib/apex_sdk/device/devices/apex/measurements/impedance_measurement.py +129 -0
- packages/tmsi/build/lib/apex_sdk/device/threads/conversion_thread.py +59 -0
- packages/tmsi/build/lib/apex_sdk/device/threads/sampling_thread.py +57 -0
- packages/tmsi/build/lib/apex_sdk/device/tmsi_channel.py +83 -0
- packages/tmsi/build/lib/apex_sdk/device/tmsi_device.py +201 -0
- packages/tmsi/build/lib/apex_sdk/device/tmsi_device_enums.py +103 -0
- packages/tmsi/build/lib/apex_sdk/device/tmsi_dongle.py +43 -0
- packages/tmsi/build/lib/apex_sdk/device/tmsi_event_reader.py +50 -0
- packages/tmsi/build/lib/apex_sdk/device/tmsi_measurement.py +118 -0
- packages/tmsi/build/lib/apex_sdk/sample_data_server/__init__.py +33 -0
- packages/tmsi/build/lib/apex_sdk/sample_data_server/event_data.py +44 -0
- packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data.py +50 -0
- packages/tmsi/build/lib/apex_sdk/sample_data_server/sample_data_server.py +136 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_errors/error.py +126 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_sdk.py +113 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/apex/apex_structure_generator.py +134 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/decorators.py +60 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/logger_filter.py +42 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/singleton.py +42 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/support_functions.py +72 -0
- packages/tmsi/build/lib/apex_sdk/tmsi_utilities/tmsi_logger.py +98 -0
- py_neuromodulation/{helper.py → _write_example_dataset_helper.py} +1 -1
- py_neuromodulation/nm_EpochStream.py +2 -3
- py_neuromodulation/nm_IO.py +43 -70
- py_neuromodulation/nm_RMAP.py +308 -11
- py_neuromodulation/nm_analysis.py +1 -1
- py_neuromodulation/nm_artifacts.py +25 -0
- py_neuromodulation/nm_bispectra.py +168 -0
- py_neuromodulation/nm_bursts.py +43 -31
- py_neuromodulation/nm_coherence.py +2 -1
- py_neuromodulation/nm_define_nmchannels.py +1 -1
- py_neuromodulation/nm_features.py +6 -1
- py_neuromodulation/nm_filter.py +63 -32
- py_neuromodulation/nm_filter_preprocessing.py +91 -0
- py_neuromodulation/nm_fooof.py +47 -29
- py_neuromodulation/nm_generator.py +10 -10
- py_neuromodulation/nm_mne_connectivity.py +1 -1
- py_neuromodulation/nm_normalization.py +50 -74
- py_neuromodulation/nm_oscillatory.py +151 -31
- py_neuromodulation/nm_plots.py +13 -10
- py_neuromodulation/nm_rereference.py +10 -8
- py_neuromodulation/nm_run_analysis.py +28 -13
- py_neuromodulation/nm_sharpwaves.py +103 -136
- py_neuromodulation/nm_stats.py +44 -30
- py_neuromodulation/nm_stream_abc.py +18 -10
- py_neuromodulation/nm_stream_offline.py +185 -43
- py_neuromodulation/utils/_logging.py +24 -0
- {py_neuromodulation-0.0.1.dist-info → py_neuromodulation-0.0.3.dist-info}/METADATA +182 -131
- py_neuromodulation-0.0.3.dist-info/RECORD +188 -0
- {py_neuromodulation-0.0.1.dist-info → py_neuromodulation-0.0.3.dist-info}/WHEEL +2 -1
- py_neuromodulation-0.0.3.dist-info/top_level.txt +5 -0
- tests/__init__.py +0 -0
- tests/conftest.py +117 -0
- tests/test_all_examples.py +10 -0
- tests/test_all_features.py +63 -0
- tests/test_bispectra.py +70 -0
- tests/test_bursts.py +105 -0
- tests/test_feature_sampling_rates.py +143 -0
- tests/test_fooof.py +16 -0
- tests/test_initalization_offline_stream.py +41 -0
- tests/test_multiprocessing.py +58 -0
- tests/test_nan_values.py +29 -0
- tests/test_nm_filter.py +95 -0
- tests/test_nm_resample.py +63 -0
- tests/test_normalization_settings.py +146 -0
- tests/test_notch_filter.py +31 -0
- tests/test_osc_features.py +424 -0
- tests/test_preprocessing_filter.py +151 -0
- tests/test_rereference.py +171 -0
- tests/test_sampling.py +57 -0
- tests/test_settings_change_after_init.py +76 -0
- tests/test_sharpwave.py +165 -0
- tests/test_target_channel_add.py +100 -0
- tests/test_timing.py +80 -0
- py_neuromodulation/data/README +0 -6
- py_neuromodulation/data/dataset_description.json +0 -8
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/MOV_aligned_features_ch_ECOG_RIGHT_0_all.png +0 -0
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/all_feature_plt.pdf +0 -0
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_FEATURES.csv +0 -182
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_LM_ML_RES.p +0 -0
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_SETTINGS.json +0 -273
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_SIDECAR.json +0 -6
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_decoding_performance.png +0 -0
- py_neuromodulation/data/derivatives/sub-testsub_ses-EphysMedOff_task-gripforce_run-0/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_nm_channels.csv +0 -11
- py_neuromodulation/data/participants.json +0 -32
- py_neuromodulation/data/participants.tsv +0 -2
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_coordsystem.json +0 -5
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_space-mni_electrodes.tsv +0 -11
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_channels.tsv +0 -11
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.eeg +0 -0
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.json +0 -18
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vhdr +0 -35
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/ieeg/sub-testsub_ses-EphysMedOff_task-gripforce_run-0_ieeg.vmrk +0 -13
- py_neuromodulation/data/sub-testsub/ses-EphysMedOff/sub-testsub_ses-EphysMedOff_scans.tsv +0 -2
- py_neuromodulation/grid_cortex.tsv +0 -40
- py_neuromodulation/grid_subcortex.tsv +0 -1429
- py_neuromodulation/nm_settings.json +0 -261
- py_neuromodulation/plots/STN_surf.mat +0 -0
- py_neuromodulation/plots/Vertices.mat +0 -0
- py_neuromodulation/plots/faces.mat +0 -0
- py_neuromodulation/plots/grid.mat +0 -0
- py_neuromodulation/py_neuromodulation.egg-info/PKG-INFO +0 -104
- py_neuromodulation/py_neuromodulation.egg-info/dependency_links.txt +0 -1
- py_neuromodulation/py_neuromodulation.egg-info/requires.txt +0 -26
- py_neuromodulation/py_neuromodulation.egg-info/top_level.txt +0 -1
- py_neuromodulation-0.0.1.dist-info/RECORD +0 -72
- /py_neuromodulation/{py_neuromodulation.egg-info/SOURCES.txt → utils/__init__.py} +0 -0
- {py_neuromodulation-0.0.1.dist-info → py_neuromodulation-0.0.3.dist-info}/LICENSE +0 -0
py_neuromodulation/nm_stats.py
CHANGED
|
@@ -2,6 +2,7 @@ import random
|
|
|
2
2
|
import copy
|
|
3
3
|
|
|
4
4
|
import matplotlib.pyplot as plt
|
|
5
|
+
|
|
5
6
|
# from numba import njit
|
|
6
7
|
import numpy as np
|
|
7
8
|
import pandas as pd
|
|
@@ -33,7 +34,7 @@ def fitlm_kfold(x, y, kfold_splits=5):
|
|
|
33
34
|
scores.append(score)
|
|
34
35
|
coeffs = np.vstack((coeffs, model.coef_))
|
|
35
36
|
coeffs = list(np.delete(coeffs, 0))
|
|
36
|
-
return scores, coeffs, model, [
|
|
37
|
+
return scores, coeffs, model, ["scores", "coeffs", "model"]
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
def zscore(data):
|
|
@@ -76,14 +77,14 @@ def permutationTestSpearmansRho(x, y, plot_distr=True, x_unit=None, p=5000):
|
|
|
76
77
|
|
|
77
78
|
# calculate p value
|
|
78
79
|
if gT < 0:
|
|
79
|
-
p_val = len(np.where(pD <= gT)[0])/p
|
|
80
|
+
p_val = len(np.where(pD <= gT)[0]) / p
|
|
80
81
|
else:
|
|
81
|
-
p_val = len(np.where(pD >= gT)[0])/p
|
|
82
|
+
p_val = len(np.where(pD >= gT)[0]) / p
|
|
82
83
|
|
|
83
84
|
if plot_distr is True:
|
|
84
85
|
plt.hist(pD, bins=30, label="permutation results")
|
|
85
86
|
plt.axvline(gT, color="orange", label="ground truth")
|
|
86
|
-
plt.title("ground truth " + x_unit + "="+str(gT) + " p=" + str(p_val))
|
|
87
|
+
plt.title("ground truth " + x_unit + "=" + str(gT) + " p=" + str(p_val))
|
|
87
88
|
plt.xlabel(x_unit)
|
|
88
89
|
plt.legend()
|
|
89
90
|
plt.show()
|
|
@@ -120,19 +121,23 @@ def permutationTest(x, y, plot_distr=True, x_unit=None, p=5000):
|
|
|
120
121
|
random.shuffle(pS)
|
|
121
122
|
# Compute permuted absolute difference of your two sampled
|
|
122
123
|
# distributions and store it in pD:
|
|
123
|
-
pD.append(
|
|
124
|
-
|
|
124
|
+
pD.append(
|
|
125
|
+
np.abs(
|
|
126
|
+
np.average(pS[0 : int(len(pS) / 2)])
|
|
127
|
+
- np.average(pS[int(len(pS) / 2) :])
|
|
128
|
+
)
|
|
129
|
+
)
|
|
125
130
|
|
|
126
131
|
# Calculate p-value
|
|
127
132
|
if gT < 0:
|
|
128
|
-
p_val = len(np.where(pD <= gT)[0])/p
|
|
133
|
+
p_val = len(np.where(pD <= gT)[0]) / p
|
|
129
134
|
else:
|
|
130
|
-
p_val = len(np.where(pD >= gT)[0])/p
|
|
135
|
+
p_val = len(np.where(pD >= gT)[0]) / p
|
|
131
136
|
|
|
132
137
|
if plot_distr is True:
|
|
133
138
|
plt.hist(pD, bins=30, label="permutation results")
|
|
134
139
|
plt.axvline(gT, color="orange", label="ground truth")
|
|
135
|
-
plt.title("ground truth "+x_unit+"="+str(gT)+" p="+str(p_val))
|
|
140
|
+
plt.title("ground truth " + x_unit + "=" + str(gT) + " p=" + str(p_val))
|
|
136
141
|
plt.xlabel(x_unit)
|
|
137
142
|
plt.legend()
|
|
138
143
|
plt.show()
|
|
@@ -165,17 +170,20 @@ def permutationTest_relative(x, y, plot_distr=True, x_unit=None, p=5000):
|
|
|
165
170
|
l_.append((x[i], y[i]))
|
|
166
171
|
else:
|
|
167
172
|
l_.append((y[i], x[i]))
|
|
168
|
-
pD.append(
|
|
169
|
-
np.
|
|
173
|
+
pD.append(
|
|
174
|
+
np.abs(
|
|
175
|
+
np.average(np.array(l_)[:, 0]) - np.average(np.array(l_)[:, 1])
|
|
176
|
+
)
|
|
177
|
+
)
|
|
170
178
|
if gT < 0:
|
|
171
|
-
p_val = len(np.where(pD <= gT)[0])/p
|
|
179
|
+
p_val = len(np.where(pD <= gT)[0]) / p
|
|
172
180
|
else:
|
|
173
|
-
p_val = len(np.where(pD >= gT)[0])/p
|
|
181
|
+
p_val = len(np.where(pD >= gT)[0]) / p
|
|
174
182
|
|
|
175
183
|
if plot_distr is True:
|
|
176
184
|
plt.hist(pD, bins=30, label="permutation results")
|
|
177
185
|
plt.axvline(gT, color="orange", label="ground truth")
|
|
178
|
-
plt.title("ground truth "+x_unit+"="+str(gT)+" p="+str(p_val))
|
|
186
|
+
plt.title("ground truth " + x_unit + "=" + str(gT) + " p=" + str(p_val))
|
|
179
187
|
plt.xlabel(x_unit)
|
|
180
188
|
plt.legend()
|
|
181
189
|
plt.show()
|
|
@@ -211,13 +219,13 @@ def permutation_numba_onesample(x, y, n_perm, two_tailed=True):
|
|
|
211
219
|
"""
|
|
212
220
|
if two_tailed is True:
|
|
213
221
|
zeroed = x - y
|
|
214
|
-
print(zeroed)
|
|
215
222
|
z = np.abs(np.mean(zeroed))
|
|
216
223
|
p = np.empty(n_perm)
|
|
217
224
|
# Run the simulation n_perm times
|
|
218
225
|
for i in np.arange(n_perm):
|
|
219
226
|
sign = np.random.choice(
|
|
220
|
-
a=np.array([-1
|
|
227
|
+
a=np.array([-1.0, 1.0]), size=len(x), replace=True
|
|
228
|
+
)
|
|
221
229
|
p[i] = np.abs(np.mean(zeroed * sign))
|
|
222
230
|
else:
|
|
223
231
|
zeroed = x - y
|
|
@@ -226,7 +234,8 @@ def permutation_numba_onesample(x, y, n_perm, two_tailed=True):
|
|
|
226
234
|
# Run the simulation n_perm times
|
|
227
235
|
for i in np.arange(n_perm):
|
|
228
236
|
sign = np.random.choice(
|
|
229
|
-
a=np.array([-1
|
|
237
|
+
a=np.array([-1.0, 1.0]), size=len(x), replace=True
|
|
238
|
+
)
|
|
230
239
|
p[i] = np.mean(zeroed * sign)
|
|
231
240
|
# Return p-value
|
|
232
241
|
return z, (np.sum(p >= z)) / n_perm
|
|
@@ -311,7 +320,8 @@ def cluster_wise_p_val_correction(p_arr, p_sig=0.05, num_permutations=10000):
|
|
|
311
320
|
# first cluster is assigned to be 1 from measure.label
|
|
312
321
|
index_cluster[cluster_i] = np.where(labels == cluster_i + 1)[0]
|
|
313
322
|
p_cluster_sum[cluster_i] = np.sum(
|
|
314
|
-
np.array(1 - p_arr)[index_cluster[cluster_i]]
|
|
323
|
+
np.array(1 - p_arr)[index_cluster[cluster_i]]
|
|
324
|
+
)
|
|
315
325
|
# p_min corresponds to the most unlikely cluster
|
|
316
326
|
p_min = np.max(p_cluster_sum)
|
|
317
327
|
|
|
@@ -320,11 +330,13 @@ def cluster_wise_p_val_correction(p_arr, p_sig=0.05, num_permutations=10000):
|
|
|
320
330
|
# loop through random permutation cycles
|
|
321
331
|
r_per_arr = np.zeros(num_permutations)
|
|
322
332
|
for r in range(num_permutations):
|
|
323
|
-
r_per = np.random.randint(
|
|
324
|
-
|
|
333
|
+
r_per = np.random.randint(
|
|
334
|
+
low=0, high=p_arr.shape[0], size=p_arr.shape[0]
|
|
335
|
+
)
|
|
325
336
|
|
|
326
|
-
labels, num_clusters = measure.label(
|
|
327
|
-
|
|
337
|
+
labels, num_clusters = measure.label(
|
|
338
|
+
p_arr[r_per] <= p_sig, return_num=True
|
|
339
|
+
)
|
|
328
340
|
|
|
329
341
|
index_cluster = {}
|
|
330
342
|
if num_clusters == 0:
|
|
@@ -332,11 +344,12 @@ def cluster_wise_p_val_correction(p_arr, p_sig=0.05, num_permutations=10000):
|
|
|
332
344
|
else:
|
|
333
345
|
p_cluster_sum = np.zeros(num_clusters)
|
|
334
346
|
for cluster_i in np.arange(num_clusters):
|
|
335
|
-
index_cluster[cluster_i] = np.where(
|
|
336
|
-
|
|
337
|
-
|
|
347
|
+
index_cluster[cluster_i] = np.where(labels == cluster_i + 1)[
|
|
348
|
+
0
|
|
349
|
+
] # first cluster is assigned to be 1 from measure.label
|
|
338
350
|
p_cluster_sum[cluster_i] = np.sum(
|
|
339
|
-
np.array(1 - p_arr[r_per])[index_cluster[cluster_i]]
|
|
351
|
+
np.array(1 - p_arr[r_per])[index_cluster[cluster_i]]
|
|
352
|
+
)
|
|
340
353
|
# corresponds to the most unlikely cluster
|
|
341
354
|
r_per_arr[r] = np.max(p_cluster_sum)
|
|
342
355
|
|
|
@@ -432,7 +445,8 @@ def cluster_wise_p_val_correction_numba(p_arr, p_sig, n_perm):
|
|
|
432
445
|
r_per_arr = np.zeros(n_perm_)
|
|
433
446
|
for r in range(n_perm_):
|
|
434
447
|
r_per = np.random.randint(
|
|
435
|
-
low=0, high=p_arr_.shape[0], size=p_arr_.shape[0]
|
|
448
|
+
low=0, high=p_arr_.shape[0], size=p_arr_.shape[0]
|
|
449
|
+
)
|
|
436
450
|
labels_, n_clusters = cluster(p_arr_[r_per] <= p_sig_)
|
|
437
451
|
|
|
438
452
|
cluster_ind = {}
|
|
@@ -441,10 +455,10 @@ def cluster_wise_p_val_correction_numba(p_arr, p_sig, n_perm):
|
|
|
441
455
|
else:
|
|
442
456
|
p_sum = np.zeros(n_clusters)
|
|
443
457
|
for ind in range(n_clusters):
|
|
444
|
-
cluster_ind[ind] =
|
|
445
|
-
np.where(labels_ == ind + 1)[0]
|
|
458
|
+
cluster_ind[ind] = np.where(labels_ == ind + 1)[0]
|
|
446
459
|
p_sum[ind] = np.sum(
|
|
447
|
-
np.asarray(1 - p_arr_[r_per])[cluster_ind[ind]]
|
|
460
|
+
np.asarray(1 - p_arr_[r_per])[cluster_ind[ind]]
|
|
461
|
+
)
|
|
448
462
|
r_per_arr[r] = np.max(p_sum)
|
|
449
463
|
return r_per_arr
|
|
450
464
|
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
"""Module that contains PNStream ABC."""
|
|
2
|
+
|
|
2
3
|
from abc import ABC, abstractmethod
|
|
3
4
|
import os
|
|
4
5
|
import pathlib
|
|
5
6
|
import _pickle as cPickle
|
|
6
7
|
|
|
8
|
+
from .utils import _logging # logger initialization
|
|
9
|
+
|
|
10
|
+
# Logger use in different modules: logger = logging.getLogger("PynmLogger")
|
|
11
|
+
|
|
12
|
+
|
|
7
13
|
import pandas as pd
|
|
8
14
|
from sklearn import base
|
|
9
15
|
|
|
@@ -12,7 +18,7 @@ from py_neuromodulation import (
|
|
|
12
18
|
nm_IO,
|
|
13
19
|
nm_plots,
|
|
14
20
|
nm_run_analysis,
|
|
15
|
-
nm_settings
|
|
21
|
+
nm_settings,
|
|
16
22
|
)
|
|
17
23
|
|
|
18
24
|
_PathLike = str | os.PathLike
|
|
@@ -72,7 +78,9 @@ class PNStream(ABC):
|
|
|
72
78
|
self.settings = self._load_settings(settings)
|
|
73
79
|
|
|
74
80
|
if sampling_rate_features_hz is not None:
|
|
75
|
-
self.settings["sampling_rate_features_hz"] =
|
|
81
|
+
self.settings["sampling_rate_features_hz"] = (
|
|
82
|
+
sampling_rate_features_hz
|
|
83
|
+
)
|
|
76
84
|
|
|
77
85
|
self.nm_channels = self._load_nm_channels(nm_channels)
|
|
78
86
|
if path_grids is None:
|
|
@@ -138,10 +146,12 @@ class PNStream(ABC):
|
|
|
138
146
|
nm_channels: pd.DataFrame | _PathLike,
|
|
139
147
|
) -> pd.DataFrame:
|
|
140
148
|
if not isinstance(nm_channels, pd.DataFrame):
|
|
141
|
-
nm_channels =
|
|
142
|
-
|
|
143
|
-
if nm_channels.query("used == 1 and target == 0").shape[0]
|
|
144
|
-
raise ValueError(
|
|
149
|
+
nm_channels = nm_IO.load_nm_channels(nm_channels)
|
|
150
|
+
|
|
151
|
+
if nm_channels.query("used == 1 and target == 0").shape[0] == 0:
|
|
152
|
+
raise ValueError(
|
|
153
|
+
"No channels selected for analysis that have column 'used' = 1 and 'target' = 0. Please check your nm_channels"
|
|
154
|
+
)
|
|
145
155
|
|
|
146
156
|
return nm_channels
|
|
147
157
|
|
|
@@ -149,7 +159,7 @@ class PNStream(ABC):
|
|
|
149
159
|
def _load_settings(settings: dict | _PathLike | None) -> dict:
|
|
150
160
|
if isinstance(settings, dict):
|
|
151
161
|
return settings
|
|
152
|
-
if settings is None:
|
|
162
|
+
if settings is None:
|
|
153
163
|
return nm_settings.get_default_settings()
|
|
154
164
|
return nm_IO.read_settings(str(settings))
|
|
155
165
|
|
|
@@ -196,9 +206,7 @@ class PNStream(ABC):
|
|
|
196
206
|
) -> None:
|
|
197
207
|
self.run_analysis.save_nm_channels(out_path_root, folder_name)
|
|
198
208
|
|
|
199
|
-
def save_settings(
|
|
200
|
-
self, out_path_root: _PathLike, folder_name: str
|
|
201
|
-
) -> None:
|
|
209
|
+
def save_settings(self, out_path_root: _PathLike, folder_name: str) -> None:
|
|
202
210
|
self.run_analysis.save_settings(out_path_root, folder_name)
|
|
203
211
|
|
|
204
212
|
def save_sidecar(self, out_path_root: _PathLike, folder_name: str) -> None:
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
"""Module for offline data streams."""
|
|
2
|
-
import math
|
|
3
|
-
import os
|
|
4
2
|
|
|
3
|
+
import os
|
|
4
|
+
from joblib import Parallel, delayed
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pandas as pd
|
|
7
|
+
from itertools import count
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger("PynmLogger")
|
|
11
|
+
|
|
12
|
+
import mne
|
|
7
13
|
|
|
8
|
-
from py_neuromodulation import
|
|
14
|
+
from py_neuromodulation import (
|
|
15
|
+
nm_generator,
|
|
16
|
+
nm_IO,
|
|
17
|
+
nm_stream_abc,
|
|
18
|
+
nm_define_nmchannels,
|
|
19
|
+
)
|
|
9
20
|
|
|
10
21
|
_PathLike = str | os.PathLike
|
|
11
22
|
|
|
12
23
|
|
|
13
24
|
class _OfflineStream(nm_stream_abc.PNStream):
|
|
14
|
-
"""Offline stream base class.
|
|
25
|
+
"""Offline stream base class.
|
|
15
26
|
This class can be inhereted for different types of offline streams, e.g. epoch-based or continuous.
|
|
16
27
|
|
|
17
28
|
Parameters
|
|
@@ -19,19 +30,38 @@ class _OfflineStream(nm_stream_abc.PNStream):
|
|
|
19
30
|
nm_stream_abc : nm_stream_abc.PNStream
|
|
20
31
|
"""
|
|
21
32
|
|
|
22
|
-
def
|
|
23
|
-
self,
|
|
24
|
-
) -> pd.
|
|
25
|
-
"""Add
|
|
33
|
+
def _add_target(
|
|
34
|
+
self, feature_series: pd.Series, data: np.ndarray
|
|
35
|
+
) -> pd.Series:
|
|
36
|
+
"""Add target channels to feature series.
|
|
37
|
+
|
|
38
|
+
Parameters
|
|
39
|
+
----------
|
|
40
|
+
feature_series : pd.Series
|
|
41
|
+
data : np.ndarray
|
|
42
|
+
Raw data with shape (n_channels, n_samples). Channels not for feature computation are also included
|
|
43
|
+
|
|
44
|
+
Returns
|
|
45
|
+
-------
|
|
46
|
+
pd.Series
|
|
47
|
+
feature series with target channels added
|
|
48
|
+
"""
|
|
49
|
+
|
|
26
50
|
if self.nm_channels["target"].sum() > 0:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
if not self.target_idx_initialized:
|
|
52
|
+
self.target_indexes = self.nm_channels[
|
|
53
|
+
self.nm_channels["target"] == 1
|
|
54
|
+
].index
|
|
55
|
+
self.target_names = self.nm_channels.loc[
|
|
56
|
+
self.target_indexes, "name"
|
|
57
|
+
].to_list()
|
|
58
|
+
self.target_idx_initialized = True
|
|
59
|
+
|
|
60
|
+
for target_idx, target_name in zip(
|
|
61
|
+
self.target_indexes, self.target_names
|
|
62
|
+
):
|
|
63
|
+
feature_series[target_name] = data[target_idx, -1]
|
|
64
|
+
return feature_series
|
|
35
65
|
|
|
36
66
|
def _add_timestamp(
|
|
37
67
|
self, feature_series: pd.Series, cnt_samples: int
|
|
@@ -41,11 +71,10 @@ class _OfflineStream(nm_stream_abc.PNStream):
|
|
|
41
71
|
Due to normalization run_analysis needs to keep track of the counted
|
|
42
72
|
samples. These are accessed here for time conversion.
|
|
43
73
|
"""
|
|
44
|
-
timestamp = cnt_samples * 1000 / self.sfreq
|
|
45
74
|
feature_series["time"] = cnt_samples * 1000 / self.sfreq
|
|
46
75
|
|
|
47
76
|
if self.verbose:
|
|
48
|
-
|
|
77
|
+
logging.info(
|
|
49
78
|
str(np.round(feature_series["time"] / 1000, 2))
|
|
50
79
|
+ " seconds of data processed"
|
|
51
80
|
)
|
|
@@ -76,45 +105,149 @@ class _OfflineStream(nm_stream_abc.PNStream):
|
|
|
76
105
|
)
|
|
77
106
|
return data.to_numpy()
|
|
78
107
|
|
|
108
|
+
def _check_settings_for_parallel(self):
|
|
109
|
+
"""Check specified settings and raise error if parallel processing is not possible.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ValueError: depending on the settings, parallel processing is not possible
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
if "raw_normalization" in self.settings["preprocessing"]:
|
|
116
|
+
raise ValueError(
|
|
117
|
+
"Parallel processing is not possible with raw_normalization normalization."
|
|
118
|
+
)
|
|
119
|
+
if self.settings["postprocessing"]["feature_normalization"] is True:
|
|
120
|
+
raise ValueError(
|
|
121
|
+
"Parallel processing is not possible with feature normalization."
|
|
122
|
+
)
|
|
123
|
+
if self.settings["features"]["bursts"] is True:
|
|
124
|
+
raise ValueError(
|
|
125
|
+
"Parallel processing is not possible with burst estimation."
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def _process_batch(self, data_batch, cnt_samples):
|
|
129
|
+
feature_series = self.run_analysis.process(
|
|
130
|
+
data_batch.astype(np.float64)
|
|
131
|
+
)
|
|
132
|
+
feature_series = self._add_timestamp(feature_series, cnt_samples)
|
|
133
|
+
feature_series = self._add_target(
|
|
134
|
+
feature_series=feature_series, data=data_batch
|
|
135
|
+
)
|
|
136
|
+
return feature_series
|
|
137
|
+
|
|
79
138
|
def _run_offline(
|
|
80
139
|
self,
|
|
81
140
|
data: np.ndarray,
|
|
82
141
|
out_path_root: _PathLike | None = None,
|
|
83
142
|
folder_name: str = "sub",
|
|
143
|
+
parallel: bool = False,
|
|
144
|
+
n_jobs: int = -2,
|
|
84
145
|
) -> pd.DataFrame:
|
|
85
146
|
generator = nm_generator.raw_data_generator(
|
|
86
147
|
data=data,
|
|
87
148
|
settings=self.settings,
|
|
88
|
-
sfreq=
|
|
149
|
+
sfreq=self.sfreq,
|
|
89
150
|
)
|
|
90
|
-
features = []
|
|
91
|
-
sample_add = int(self.sfreq / self.run_analysis.sfreq_features)
|
|
92
151
|
|
|
93
|
-
|
|
94
|
-
offset_start = np.ceil(offset_time / 1000 * self.sfreq).astype(int)
|
|
152
|
+
sample_add = self.sfreq / self.run_analysis.sfreq_features
|
|
95
153
|
|
|
96
|
-
|
|
154
|
+
offset_time = self.settings["segment_length_features_ms"]
|
|
155
|
+
# offset_start = np.ceil(offset_time / 1000 * self.sfreq).astype(int)
|
|
156
|
+
offset_start = offset_time / 1000 * self.sfreq
|
|
157
|
+
|
|
158
|
+
if parallel:
|
|
159
|
+
l_features = Parallel(n_jobs=n_jobs, verbose=10)(
|
|
160
|
+
delayed(self._process_batch)(data_batch, cnt_samples)
|
|
161
|
+
for data_batch, cnt_samples in zip(
|
|
162
|
+
generator, count(offset_start, sample_add)
|
|
163
|
+
)
|
|
164
|
+
)
|
|
97
165
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
166
|
+
else:
|
|
167
|
+
l_features = []
|
|
168
|
+
cnt_samples = offset_start
|
|
169
|
+
while True:
|
|
170
|
+
data_batch = next(generator, None)
|
|
171
|
+
if data_batch is None:
|
|
172
|
+
break
|
|
173
|
+
feature_series = self.run_analysis.process(
|
|
174
|
+
data_batch.astype(np.float64)
|
|
175
|
+
)
|
|
176
|
+
feature_series = self._add_timestamp(
|
|
177
|
+
feature_series, cnt_samples
|
|
178
|
+
)
|
|
105
179
|
|
|
106
|
-
|
|
107
|
-
|
|
180
|
+
feature_series = self._add_target(
|
|
181
|
+
feature_series=feature_series, data=data_batch
|
|
182
|
+
)
|
|
108
183
|
|
|
109
|
-
|
|
184
|
+
l_features.append(feature_series)
|
|
110
185
|
|
|
111
|
-
|
|
112
|
-
feature_df =
|
|
186
|
+
cnt_samples += sample_add
|
|
187
|
+
feature_df = pd.DataFrame(l_features)
|
|
113
188
|
|
|
114
189
|
self.save_after_stream(out_path_root, folder_name, feature_df)
|
|
115
190
|
|
|
116
191
|
return feature_df
|
|
117
192
|
|
|
193
|
+
def plot_raw_signal(
|
|
194
|
+
self,
|
|
195
|
+
sfreq: float = None,
|
|
196
|
+
data: np.array = None,
|
|
197
|
+
lowpass: float = None,
|
|
198
|
+
highpass: float = None,
|
|
199
|
+
picks: list = None,
|
|
200
|
+
plot_time: bool = True,
|
|
201
|
+
plot_psd: bool = False,
|
|
202
|
+
) -> None:
|
|
203
|
+
"""Use MNE-RawArray Plot to investigate PSD or raw_signal plot.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
sfreq : float
|
|
208
|
+
sampling frequency [Hz]
|
|
209
|
+
data : np.array, optional
|
|
210
|
+
data (n_channels, n_times), by default None
|
|
211
|
+
plot_time : bool, optional
|
|
212
|
+
mne.io.RawArray.plot(), by default True
|
|
213
|
+
plot_psd : bool, optional
|
|
214
|
+
mne.io.RawArray.plot(), by default True
|
|
215
|
+
|
|
216
|
+
Raises
|
|
217
|
+
------
|
|
218
|
+
ValueError
|
|
219
|
+
raise Exception when no data is passed
|
|
220
|
+
"""
|
|
221
|
+
if self.data is None and data is None:
|
|
222
|
+
raise ValueError("No data passed to plot_raw_signal function.")
|
|
223
|
+
|
|
224
|
+
if data is None and self.data is not None:
|
|
225
|
+
data = self.data
|
|
226
|
+
|
|
227
|
+
if sfreq is None:
|
|
228
|
+
sfreq = self.sfreq
|
|
229
|
+
|
|
230
|
+
if self.nm_channels is not None:
|
|
231
|
+
ch_names = self.nm_channels["name"].to_list()
|
|
232
|
+
ch_types = self.nm_channels["type"].to_list()
|
|
233
|
+
else:
|
|
234
|
+
ch_names = [f"ch_{i}" for i in range(data.shape[0])]
|
|
235
|
+
ch_types = ["ecog" for i in range(data.shape[0])]
|
|
236
|
+
|
|
237
|
+
# create mne.RawArray
|
|
238
|
+
info = mne.create_info(
|
|
239
|
+
ch_names=ch_names, sfreq=sfreq, ch_types=ch_types
|
|
240
|
+
)
|
|
241
|
+
raw = mne.io.RawArray(data, info)
|
|
242
|
+
|
|
243
|
+
if picks is not None:
|
|
244
|
+
raw = raw.pick(picks)
|
|
245
|
+
self.raw = raw
|
|
246
|
+
if plot_time:
|
|
247
|
+
raw.plot(highpass=highpass, lowpass=lowpass)
|
|
248
|
+
if plot_psd:
|
|
249
|
+
raw.compute_psd().plot()
|
|
250
|
+
|
|
118
251
|
|
|
119
252
|
class Stream(_OfflineStream):
|
|
120
253
|
def __init__(
|
|
@@ -128,7 +261,7 @@ class Stream(_OfflineStream):
|
|
|
128
261
|
path_grids: _PathLike | None = None,
|
|
129
262
|
coord_names: list | None = None,
|
|
130
263
|
coord_list: list | None = None,
|
|
131
|
-
verbose: bool = True,
|
|
264
|
+
verbose: bool = True,
|
|
132
265
|
) -> None:
|
|
133
266
|
"""Stream initialization
|
|
134
267
|
|
|
@@ -153,11 +286,13 @@ class Stream(_OfflineStream):
|
|
|
153
286
|
coord_list : list | None, optional
|
|
154
287
|
coordinates in the form [[coord_1_x, coord_1_y, coord_1_z], [coord_2_x, coord_2_y, coord_2_z],], by default None
|
|
155
288
|
verbose : bool, optional
|
|
156
|
-
|
|
289
|
+
log stream computation time information, by default True
|
|
157
290
|
"""
|
|
158
291
|
|
|
159
292
|
if nm_channels is None and data is not None:
|
|
160
|
-
nm_channels = nm_define_nmchannels.get_default_channels_from_data(
|
|
293
|
+
nm_channels = nm_define_nmchannels.get_default_channels_from_data(
|
|
294
|
+
data
|
|
295
|
+
)
|
|
161
296
|
|
|
162
297
|
if nm_channels is None and data is None:
|
|
163
298
|
raise ValueError(
|
|
@@ -178,11 +313,15 @@ class Stream(_OfflineStream):
|
|
|
178
313
|
|
|
179
314
|
self.data = data
|
|
180
315
|
|
|
316
|
+
self.target_idx_initialized = False
|
|
317
|
+
|
|
181
318
|
def run(
|
|
182
319
|
self,
|
|
183
320
|
data: np.ndarray | pd.DataFrame = None,
|
|
184
321
|
out_path_root: _PathLike | None = None,
|
|
185
322
|
folder_name: str = "sub",
|
|
323
|
+
parallel: bool = False,
|
|
324
|
+
n_jobs: int = -2,
|
|
186
325
|
) -> pd.DataFrame:
|
|
187
326
|
"""Call run function for offline stream.
|
|
188
327
|
|
|
@@ -209,8 +348,11 @@ class Stream(_OfflineStream):
|
|
|
209
348
|
elif self.data is not None:
|
|
210
349
|
data = self._handle_data(self.data)
|
|
211
350
|
elif self.data is None and data is None:
|
|
212
|
-
raise ValueError(
|
|
213
|
-
|
|
214
|
-
|
|
351
|
+
raise ValueError("No data passed to run function.")
|
|
352
|
+
|
|
353
|
+
if parallel is True:
|
|
354
|
+
self._check_settings_for_parallel()
|
|
215
355
|
|
|
216
|
-
return self._run_offline(
|
|
356
|
+
return self._run_offline(
|
|
357
|
+
data, out_path_root, folder_name, parallel=parallel, n_jobs=n_jobs
|
|
358
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
# include the filename in the log output
|
|
4
|
+
# Configure the logger
|
|
5
|
+
logger = logging.getLogger("PynmLogger")
|
|
6
|
+
logger.setLevel(logging.INFO)
|
|
7
|
+
|
|
8
|
+
# Create a file handler and set its level to DEBUG
|
|
9
|
+
file_handler = logging.FileHandler("logfile_pynm.log")
|
|
10
|
+
file_handler.setLevel(logging.INFO)
|
|
11
|
+
|
|
12
|
+
# console_handler = logging.StreamHandler()
|
|
13
|
+
# console_handler.setLevel(logging.DEBUG)
|
|
14
|
+
|
|
15
|
+
# Create a formatter and add it to the handler
|
|
16
|
+
formatter = logging.Formatter(
|
|
17
|
+
"%(asctime)s:%(levelname)s:%(name)s:%(filename)s:%(message)s"
|
|
18
|
+
)
|
|
19
|
+
file_handler.setFormatter(formatter)
|
|
20
|
+
# console_handler.setFormatter(formatter)
|
|
21
|
+
|
|
22
|
+
# Add the file handler to the logger
|
|
23
|
+
logger.addHandler(file_handler)
|
|
24
|
+
# logger.addHandler(console_handler)
|