Braindecode 1.8.0.dev180516540__tar.gz → 1.8.0.dev180935432__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 (180) hide show
  1. {braindecode-1.8.0.dev180516540/braindecode.egg-info → braindecode-1.8.0.dev180935432}/PKG-INFO +2 -2
  2. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/base.py +0 -3
  3. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/functional/functions.py +3 -4
  4. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/base.py +3 -3
  5. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/luna.py +4 -29
  6. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/summary.csv +1 -1
  7. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/usleep.py +7 -3
  8. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/zuna.py +11 -25
  9. braindecode-1.8.0.dev180935432/braindecode/version.py +1 -0
  10. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432/braindecode.egg-info}/PKG-INFO +2 -2
  11. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode.egg-info/SOURCES.txt +0 -1
  12. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode.egg-info/requires.txt +1 -1
  13. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/whats_new.rst +1 -26
  14. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/pyproject.toml +1 -1
  15. braindecode-1.8.0.dev180516540/braindecode/datasets/_notebook_viewer.py +0 -255
  16. braindecode-1.8.0.dev180516540/braindecode/version.py +0 -1
  17. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/LICENSE.txt +0 -0
  18. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/MANIFEST.in +0 -0
  19. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/NOTICE.txt +0 -0
  20. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/README.rst +0 -0
  21. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/__init__.py +0 -0
  22. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/augmentation/__init__.py +0 -0
  23. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/augmentation/base.py +0 -0
  24. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/augmentation/functional.py +0 -0
  25. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/augmentation/transforms.py +0 -0
  26. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/classifier.py +0 -0
  27. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/__init__.py +0 -0
  28. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bbci.py +0 -0
  29. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bcicomp.py +0 -0
  30. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/__init__.py +0 -0
  31. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/datasets.py +0 -0
  32. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/format.py +0 -0
  33. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/hub.py +0 -0
  34. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/hub_format.py +0 -0
  35. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/hub_io.py +0 -0
  36. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/hub_validation.py +0 -0
  37. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/bids/iterable.py +0 -0
  38. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/chb_mit.py +0 -0
  39. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/collate.py +0 -0
  40. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/mne.py +0 -0
  41. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/moabb.py +0 -0
  42. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/nmt.py +0 -0
  43. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/registry.py +0 -0
  44. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/siena.py +0 -0
  45. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  46. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/sleep_physionet.py +0 -0
  47. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/tuh.py +0 -0
  48. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/utils.py +0 -0
  49. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datasets/xy.py +0 -0
  50. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datautil/__init__.py +0 -0
  51. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datautil/channel_utils.py +0 -0
  52. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datautil/hub_formats.py +0 -0
  53. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datautil/serialization.py +0 -0
  54. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/datautil/util.py +0 -0
  55. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/eegneuralnet.py +0 -0
  56. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/functional/__init__.py +0 -0
  57. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/functional/initialization.py +0 -0
  58. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/__init__.py +0 -0
  59. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/atcnet.py +0 -0
  60. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/attentionbasenet.py +0 -0
  61. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/attn_sleep.py +0 -0
  62. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/bendr.py +0 -0
  63. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/biot.py +0 -0
  64. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/brainmodule.py +0 -0
  65. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/cbramod.py +0 -0
  66. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/codebrain.py +0 -0
  67. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/config.py +0 -0
  68. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/contrawr.py +0 -0
  69. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/ctnet.py +0 -0
  70. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/dance.py +0 -0
  71. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/deep4.py +0 -0
  72. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/deepsleepnet.py +0 -0
  73. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/dgcnn.py +0 -0
  74. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegconformer.py +0 -0
  75. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegdino.py +0 -0
  76. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eeginception_erp.py +0 -0
  77. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eeginception_mi.py +0 -0
  78. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegitnet.py +0 -0
  79. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegminer.py +0 -0
  80. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegnet.py +0 -0
  81. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegnex.py +0 -0
  82. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegpt.py +0 -0
  83. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegsimpleconv.py +0 -0
  84. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegsym.py +0 -0
  85. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/eegtcnet.py +0 -0
  86. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/emg2qwerty.py +0 -0
  87. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/fbcnet.py +0 -0
  88. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/fblightconvnet.py +0 -0
  89. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/fbmsnet.py +0 -0
  90. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/hybrid.py +0 -0
  91. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/ifnet.py +0 -0
  92. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/interpolated.py +0 -0
  93. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/labram.py +0 -0
  94. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/medformer.py +0 -0
  95. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/meta_neuromotor.py +0 -0
  96. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/msvtnet.py +0 -0
  97. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/mvpformer.py +0 -0
  98. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/patchedtransformer.py +0 -0
  99. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/reve.py +0 -0
  100. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/sccnet.py +0 -0
  101. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/shallow_fbcsp.py +0 -0
  102. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/signal_jepa.py +0 -0
  103. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/sinc_shallow.py +0 -0
  104. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/sleep_stager_blanco_2020.py +0 -0
  105. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/sleep_stager_chambon_2018.py +0 -0
  106. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/sparcnet.py +0 -0
  107. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/sstdpn.py +0 -0
  108. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/steegformer.py +0 -0
  109. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/syncnet.py +0 -0
  110. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/tcformer.py +0 -0
  111. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/tcn.py +0 -0
  112. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/tidnet.py +0 -0
  113. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/tsinception.py +0 -0
  114. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/models/util.py +0 -0
  115. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/__init__.py +0 -0
  116. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/activation.py +0 -0
  117. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/attention.py +0 -0
  118. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/blocks.py +0 -0
  119. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/convolution.py +0 -0
  120. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/dance_modules.py +0 -0
  121. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/filter.py +0 -0
  122. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/interpolation.py +0 -0
  123. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/layers.py +0 -0
  124. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/linear.py +0 -0
  125. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/parametrization.py +0 -0
  126. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/stats.py +0 -0
  127. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/util.py +0 -0
  128. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/modules/wrapper.py +0 -0
  129. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/preprocessing/__init__.py +0 -0
  130. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  131. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/preprocessing/mne_preprocess.py +0 -0
  132. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/preprocessing/preprocess.py +0 -0
  133. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/preprocessing/util.py +0 -0
  134. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/preprocessing/windowers.py +0 -0
  135. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/regressor.py +0 -0
  136. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/samplers/__init__.py +0 -0
  137. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/samplers/base.py +0 -0
  138. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/samplers/ssl.py +0 -0
  139. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/training/__init__.py +0 -0
  140. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/training/callbacks.py +0 -0
  141. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/training/losses.py +0 -0
  142. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/training/scoring.py +0 -0
  143. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/util.py +0 -0
  144. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/visualization/__init__.py +0 -0
  145. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/visualization/attribution.py +0 -0
  146. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/visualization/confusion_matrices.py +0 -0
  147. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/visualization/frequency.py +0 -0
  148. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/visualization/metrics.py +0 -0
  149. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/visualization/sanity.py +0 -0
  150. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode/visualization/topology.py +0 -0
  151. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode.egg-info/dependency_links.txt +0 -0
  152. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/braindecode.egg-info/top_level.txt +0 -0
  153. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/Makefile +0 -0
  154. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/_templates/autosummary/class.rst +0 -0
  155. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/_templates/autosummary/class_in_subdir.rst +0 -0
  156. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/_templates/autosummary/function.rst +0 -0
  157. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/_templates/autosummary/function_in_subdir.rst +0 -0
  158. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/api.rst +0 -0
  159. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/cite.rst +0 -0
  160. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/conf.py +0 -0
  161. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/help.rst +0 -0
  162. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/index.rst +0 -0
  163. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/install/install.rst +0 -0
  164. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/install/install_pip.rst +0 -0
  165. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/install/install_source.rst +0 -0
  166. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/attention.rst +0 -0
  167. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/channel.rst +0 -0
  168. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/convolution.rst +0 -0
  169. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/filterbank.rst +0 -0
  170. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/gnn.rst +0 -0
  171. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/interpretable.rst +0 -0
  172. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/lbm.rst +0 -0
  173. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/recurrent.rst +0 -0
  174. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/categorization/spd.rst +0 -0
  175. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/models.rst +0 -0
  176. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/models_categorization.rst +0 -0
  177. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/models_table.rst +0 -0
  178. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/models/models_visualization.rst +0 -0
  179. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/docs/sg_execution_times.rst +0 -0
  180. {braindecode-1.8.0.dev180516540 → braindecode-1.8.0.dev180935432}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.0.dev180516540
3
+ Version: 1.8.0.dev180935432
4
4
  Summary: Deep learning software to decode EEG, ECG or MEG signals
5
5
  Author-email: Robin Tibor Schirrmeister <robintibor@gmail.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Alexandre Gramfort <agramfort@meta.com>
6
6
  Maintainer-email: Alexandre Gramfort <agramfort@meta.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Robin Tibor Schirrmeister <robintibor@gmail.com>
@@ -34,6 +34,7 @@ Requires-Dist: pandas
34
34
  Requires-Dist: wfdb>=4.3.1
35
35
  Requires-Dist: linear_attention_transformer
36
36
  Requires-Dist: docstring_inheritance
37
+ Requires-Dist: rotary_embedding_torch
37
38
  Requires-Dist: pydantic>=2.0
38
39
  Provides-Extra: moabb
39
40
  Requires-Dist: moabb>=1.4.3; extra == "moabb"
@@ -50,7 +51,6 @@ Requires-Dist: pytest-cov; extra == "tests"
50
51
  Requires-Dist: codecov; extra == "tests"
51
52
  Requires-Dist: pytest_cases; extra == "tests"
52
53
  Requires-Dist: mypy; extra == "tests"
53
- Requires-Dist: ipython; extra == "tests"
54
54
  Requires-Dist: transformers>=4.57.0; extra == "tests"
55
55
  Requires-Dist: bids_validator; extra == "tests"
56
56
  Provides-Extra: typing
@@ -32,7 +32,6 @@ from mne.utils.docs import deprecated
32
32
  from torch.utils.data import ConcatDataset, Dataset, IterableDataset
33
33
  from typing_extensions import TypeVar
34
34
 
35
- from ._notebook_viewer import plot as _viewer_plot
36
35
  from .bids.hub import HubDatasetMixin
37
36
  from .bids.hub_io import _restore_nan_from_json
38
37
  from .registry import register_dataset
@@ -1175,8 +1174,6 @@ class BaseConcatDataset(ConcatDataset, HubDatasetMixin, Generic[T]):
1175
1174
  If True, defer computing cumulative sizes until length or item access.
1176
1175
  """
1177
1176
 
1178
- plot = _viewer_plot # eegdash-viewer embed; a direct member so the API docs list it
1179
-
1180
1177
  datasets: list[T]
1181
1178
 
1182
1179
  def __init__(
@@ -40,7 +40,7 @@ def drop_path(
40
40
  x : torch.Tensor
41
41
  input tensor
42
42
  drop_prob : float, optional
43
- probability of dropping a path, by default 0.0
43
+ survival rate (i.e. probability of being kept), by default 0.0
44
44
  training : bool, optional
45
45
  whether the model is in training mode, by default False
46
46
  scale_by_keep : bool, optional
@@ -68,10 +68,9 @@ def drop_path(
68
68
  shape = (x.shape[0],) + (1,) * (
69
69
  x.ndim - 1
70
70
  ) # work with diff dim tensors, not just 2D ConvNets
71
- probabilities = torch.full(shape, keep_prob, dtype=torch.float32, device=x.device)
72
- random_tensor = torch.bernoulli(probabilities).to(dtype=x.dtype)
71
+ random_tensor = x.new_empty(shape).bernoulli_(keep_prob)
73
72
  if keep_prob > 0.0 and scale_by_keep:
74
- random_tensor = random_tensor / keep_prob
73
+ random_tensor.div_(keep_prob)
75
74
  return x * random_tensor
76
75
 
77
76
 
@@ -80,7 +80,7 @@ class _BraindecodeDocstringMeta(NumpyDocstringInheritanceInitMeta):
80
80
  unwrapped function and correctly inherits ``cls.__doc__``.
81
81
  """
82
82
 
83
- def __init__(cls, class_name, class_bases, class_dict, **kwargs):
83
+ def __init__(cls, class_name, class_bases, class_dict):
84
84
  super().__init__(class_name, class_bases, class_dict)
85
85
  # Only wrap subclass __init__s, not EEGModuleMixin itself.
86
86
  # Wrapping the mixin would cause super().__init__() calls to
@@ -214,8 +214,6 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
214
214
  __jit_unused_properties__ = ["chs_info"]
215
215
 
216
216
  def __init_subclass__(cls, **kwargs):
217
- license = kwargs.pop("license", "bsd-3-clause")
218
-
219
217
  # TorchScript only honours ``__jit_ignored_attributes__`` for
220
218
  # properties defined directly on the concrete class: it collects them
221
219
  # with ``vars(type(module))``, which skips inherited ones. Rebinding
@@ -255,6 +253,8 @@ class EEGModuleMixin(_BaseHubMixin, metaclass=_BraindecodeDocstringMeta):
255
253
  )
256
254
  repo_url = kwargs.pop("repo_url", "https://braindecode.org")
257
255
  library_name = kwargs.pop("library_name", "braindecode")
256
+ license = kwargs.pop("license", "bsd-3-clause")
257
+
258
258
  # Register a coder so that type[nn.Module] parameters
259
259
  # (e.g. activation=nn.ELU) are serialized as importable
260
260
  # strings in config.json and decoded back on load.
@@ -20,6 +20,7 @@ import torch.fft as fft
20
20
  import torch.nn as nn
21
21
  import torch.nn.functional as F
22
22
  from einops import rearrange
23
+ from rotary_embedding_torch import RotaryEmbedding
23
24
 
24
25
  from braindecode.models.base import EEGModuleMixin
25
26
  from braindecode.models.util import extract_channel_locations_from_chs_info
@@ -534,7 +535,7 @@ class _RotarySelfAttentionBlock(nn.Module):
534
535
  self.dim = dim
535
536
  self.num_heads = num_heads
536
537
  head_dim = dim // num_heads
537
- self.rotary_emb = _RotaryEmbedding(head_dim)
538
+ self.rotary_emb = RotaryEmbedding(dim=head_dim, learned_freq=False)
538
539
 
539
540
  self.scale = qk_scale or head_dim**-0.5
540
541
 
@@ -544,17 +545,6 @@ class _RotarySelfAttentionBlock(nn.Module):
544
545
  self.proj = nn.Linear(dim, dim)
545
546
  self.proj_drop = nn.Dropout(proj_drop)
546
547
 
547
- def _rotate_queries_or_keys(self, tensor: torch.Tensor) -> torch.Tensor:
548
- """Apply full-head RoPE without concatenating empty boundary views."""
549
- seq_len = tensor.shape[-2]
550
- positions = torch.arange(seq_len, device=tensor.device, dtype=tensor.dtype)
551
- freqs = self.rotary_emb(positions)
552
-
553
- pairs = tensor.reshape(*tensor.shape[:-1], -1, 2)
554
- rotated = torch.stack((-pairs[..., 1], pairs[..., 0]), dim=-1).flatten(-2)
555
- transformed = tensor * freqs.cos() + rotated * freqs.sin()
556
- return transformed.to(tensor.dtype)
557
-
558
548
  def forward(self, x: torch.Tensor) -> torch.Tensor:
559
549
  B, N, C = x.shape
560
550
  qkv = (
@@ -563,8 +553,8 @@ class _RotarySelfAttentionBlock(nn.Module):
563
553
  .permute(2, 0, 3, 1, 4)
564
554
  ) # (K, B, H, N, D)
565
555
  q, k, v = qkv[0], qkv[1], qkv[2]
566
- q = self._rotate_queries_or_keys(q)
567
- k = self._rotate_queries_or_keys(k)
556
+ q = self.rotary_emb.rotate_queries_or_keys(q)
557
+ k = self.rotary_emb.rotate_queries_or_keys(k)
568
558
  # Calculate attention scores
569
559
  attn_weights = (q @ k.transpose(-2, -1)) * self.scale # (B, H, N, N)
570
560
 
@@ -580,21 +570,6 @@ class _RotarySelfAttentionBlock(nn.Module):
580
570
  return self.proj_drop(self.proj(attn))
581
571
 
582
572
 
583
- class _RotaryEmbedding(nn.Module):
584
- """Minimal language RoPE frequency generator used by LUNA."""
585
-
586
- def __init__(self, dim: int, theta: float = 10000.0) -> None:
587
- super().__init__()
588
- frequencies = 1.0 / (
589
- theta ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim)
590
- )
591
- self.freqs = nn.Parameter(frequencies, requires_grad=False)
592
-
593
- def forward(self, positions: torch.Tensor) -> torch.Tensor:
594
- angles = positions.to(self.freqs.dtype).unsqueeze(-1) * self.freqs
595
- return angles.repeat_interleave(2, dim=-1)
596
-
597
-
598
573
  class _FeedForwardBlock(nn.Module):
599
574
  def __init__(self, dim: int, hidden_dim: int, dropout: float = 0.0) -> None:
600
575
  super().__init__()
@@ -31,7 +31,7 @@ SincShallowNet,Motor Imagery,Prediction,250,"n_chans, n_outputs, n_times, sfreq"
31
31
  ShallowFBCSPNet,General,Prediction,250,"n_chans, n_outputs, n_times",46084,"ShallowFBCSPNet(n_chans=22, n_outputs=4, n_times=1000, sfreq=250)","Convolution",EEG
32
32
  SleepStagerBlanco2020,Sleep Staging,Prediction,100,"n_chans, n_outputs, n_times",2845,"SleepStagerBlanco2020(n_chans=2, n_outputs=5, n_times=3000, sfreq=100)","Convolution",EEG
33
33
  SleepStagerChambon2018,Sleep Staging,Prediction,128,"n_chans, n_outputs, n_times, sfreq",5835,"SleepStagerChambon2018(n_chans=2, n_outputs=5, n_times=3840, sfreq=128)","Convolution",EEG
34
- AttnSleep,Sleep Staging,Prediction,100,"n_chans, n_outputs, n_times, sfreq",522805,"AttnSleep(n_chans=1, n_outputs=5, n_times=3000, sfreq=100)","Convolution, Attention/Transformer",EEG
34
+ AttnSleep,Sleep Staging,Prediction,100,"n_chans, n_outputs, n_times, sfreq",719925,"AttnSleep(n_chans=2, n_outputs=5, n_times=3000, sfreq=100)","Convolution, Attention/Transformer",EEG
35
35
  SPARCNet,Epilepsy,Prediction,200,"n_chans, n_outputs, n_times",1141921,"SPARCNet(n_chans=16, n_outputs=6, n_times=2000, sfreq=200)","Convolution",EEG
36
36
  SyncNet,"Emotion Recognition, Alcoholism",Prediction,256,"n_chans, n_outputs, n_times",554,"SyncNet(n_chans=62, n_outputs=3, n_times=5120, sfreq=256)","Interpretability",EEG
37
37
  TSception,Emotion Recognition,Prediction,256,"n_chans, n_outputs, n_times, sfreq",2187206,"TSception(n_chans=62, n_outputs=3, n_times=5120, sfreq=256)","Convolution",EEG
@@ -431,7 +431,11 @@ class _DecoderBlock(nn.Module):
431
431
  ) -> tuple[torch.Tensor, torch.Tensor]:
432
432
  """Crops two tensors to their lowest-common-dimension along an axis."""
433
433
  dim_cropped = min(x1.shape[axis], x2.shape[axis])
434
- return (
435
- x1.narrow(axis, 0, dim_cropped),
436
- x2.narrow(axis, 0, dim_cropped),
434
+
435
+ x1_cropped = torch.index_select(
436
+ x1, dim=axis, index=torch.arange(dim_cropped).to(device=x1.device)
437
+ )
438
+ x2_cropped = torch.index_select(
439
+ x2, dim=axis, index=torch.arange(dim_cropped).to(device=x1.device)
437
440
  )
441
+ return x1_cropped, x2_cropped
@@ -11,6 +11,7 @@ from typing import Optional
11
11
  import torch
12
12
  from einops import rearrange
13
13
  from einops.layers.torch import Rearrange
14
+ from rotary_embedding_torch import RotaryEmbedding
14
15
  from torch import nn
15
16
  from torch.nn import functional
16
17
 
@@ -274,11 +275,18 @@ class ZUNA(EEGModuleMixin, nn.Module):
274
275
  (channel_position_indices, coarse_time_indices.unsqueeze(1)), dim=1
275
276
  )
276
277
 
277
- rotary_frequency_table = _build_rotary_frequency_table(
278
- torch.arange(max_seqlen, dtype=torch.float32),
279
- axis_dim=rotary_axis_dim,
278
+ rotary_embedding = RotaryEmbedding(
279
+ # rotary_embedding_torch cannot construct dim=2 directly because
280
+ # of its theta-rescaling formula; dim=4 followed by slicing is
281
+ # equivalent for the single-frequency dim=2 case.
282
+ dim=max(rotary_axis_dim, 4),
280
283
  theta=rope_theta,
284
+ cache_if_possible=False,
281
285
  )
286
+ with torch.no_grad():
287
+ rotary_frequency_table = rotary_embedding(
288
+ torch.arange(max_seqlen, dtype=torch.float32)
289
+ )[:, :rotary_axis_dim]
282
290
  token_rotary_frequencies = rearrange(
283
291
  rotary_frequency_table[token_position_indices],
284
292
  "token coordinate rotary_frequency -> token (coordinate rotary_frequency)",
@@ -336,28 +344,6 @@ class ZUNA(EEGModuleMixin, nn.Module):
336
344
  )
337
345
 
338
346
 
339
- def _build_rotary_frequency_table(
340
- positions: torch.Tensor, *, axis_dim: int, theta: float
341
- ) -> torch.Tensor:
342
- """Build ZUNA's per-axis rotary frequencies with native PyTorch."""
343
- embedding_dim = max(axis_dim, 4)
344
- inverse_frequencies = 1.0 / (
345
- theta
346
- ** (
347
- torch.arange(
348
- 0,
349
- embedding_dim,
350
- 2,
351
- device=positions.device,
352
- dtype=torch.float32,
353
- )
354
- / embedding_dim
355
- )
356
- )
357
- angles = positions.to(torch.float32).unsqueeze(-1) * inverse_frequencies
358
- return angles.repeat_interleave(2, dim=-1)[:, :axis_dim]
359
-
360
-
361
347
  class _RotaryPositionEmbedding(nn.Module):
362
348
  def __init__(self):
363
349
  super().__init__()
@@ -0,0 +1 @@
1
+ __version__ = "1.8.0.dev180935432"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.8.0.dev180516540
3
+ Version: 1.8.0.dev180935432
4
4
  Summary: Deep learning software to decode EEG, ECG or MEG signals
5
5
  Author-email: Robin Tibor Schirrmeister <robintibor@gmail.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Alexandre Gramfort <agramfort@meta.com>
6
6
  Maintainer-email: Alexandre Gramfort <agramfort@meta.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Robin Tibor Schirrmeister <robintibor@gmail.com>
@@ -34,6 +34,7 @@ Requires-Dist: pandas
34
34
  Requires-Dist: wfdb>=4.3.1
35
35
  Requires-Dist: linear_attention_transformer
36
36
  Requires-Dist: docstring_inheritance
37
+ Requires-Dist: rotary_embedding_torch
37
38
  Requires-Dist: pydantic>=2.0
38
39
  Provides-Extra: moabb
39
40
  Requires-Dist: moabb>=1.4.3; extra == "moabb"
@@ -50,7 +51,6 @@ Requires-Dist: pytest-cov; extra == "tests"
50
51
  Requires-Dist: codecov; extra == "tests"
51
52
  Requires-Dist: pytest_cases; extra == "tests"
52
53
  Requires-Dist: mypy; extra == "tests"
53
- Requires-Dist: ipython; extra == "tests"
54
54
  Requires-Dist: transformers>=4.57.0; extra == "tests"
55
55
  Requires-Dist: bids_validator; extra == "tests"
56
56
  Provides-Extra: typing
@@ -20,7 +20,6 @@ braindecode/augmentation/base.py
20
20
  braindecode/augmentation/functional.py
21
21
  braindecode/augmentation/transforms.py
22
22
  braindecode/datasets/__init__.py
23
- braindecode/datasets/_notebook_viewer.py
24
23
  braindecode/datasets/base.py
25
24
  braindecode/datasets/bbci.py
26
25
  braindecode/datasets/bcicomp.py
@@ -10,6 +10,7 @@ pandas
10
10
  wfdb>=4.3.1
11
11
  linear_attention_transformer
12
12
  docstring_inheritance
13
+ rotary_embedding_torch
13
14
  pydantic>=2.0
14
15
 
15
16
  [all]
@@ -60,7 +61,6 @@ pytest-cov
60
61
  codecov
61
62
  pytest_cases
62
63
  mypy
63
- ipython
64
64
  transformers>=4.57.0
65
65
  bids_validator
66
66
 
@@ -28,12 +28,6 @@ Current 1.8.0 (GitHub)
28
28
  Enhancements
29
29
  ============
30
30
 
31
- - Add :meth:`braindecode.datasets.BaseConcatDataset.plot` (every dataset, ``BIDSDataset`` included): show a recording in the
32
- `eegdash-viewer <https://github.com/eegdash/eegdash-viewer>`_ inside a
33
- Jupyter cell — serverless (bytes inlined, viewer from CDN), with the
34
- synchronized hand-pose panel when a ``*_desc-pose.json`` sidecar is present
35
- (:gh:`1133` by `Bruno Aristimunha`_)
36
-
37
31
  - Preserve the recording-local row of each canonical MNE annotation as
38
32
  ``i_trial_in_dataset`` in event-window metadata, keeping it aligned with
39
33
  targets and annotation extras through event mapping, duration filtering,
@@ -73,30 +67,11 @@ API and behavior changes
73
67
  Requirements
74
68
  ============
75
69
 
76
- - Remove the ``rotary_embedding_torch`` dependency. The rotary frequency
77
- generation used by :class:`braindecode.models.LUNA` and
78
- :class:`braindecode.models.ZUNA` is now implemented directly with PyTorch.
79
- (:gh:`1136` by `Bruno Aristimunha`_)
70
+ - None yet
80
71
 
81
72
  Bug fixes
82
73
  ==========
83
74
 
84
- - Sample stochastic-depth masks with out-of-place
85
- :func:`torch.bernoulli` instead of in-place ``Tensor.bernoulli_``. This keeps
86
- the same per-sample Bernoulli mask and scaling while avoiding lazy
87
- recipe-cache offset failures on Gaudi accelerators. The
88
- :func:`braindecode.functional.drop_path` documentation now also correctly
89
- describes ``drop_prob`` as the probability of dropping a path. By `Bruno
90
- Aristimunha`_.
91
-
92
- - Make :class:`braindecode.models.LUNA` rotary attention portable to
93
- accelerators that reject concatenations containing empty tensor views, while
94
- preserving its pretrained-checkpoint parameter keys and numerical behavior.
95
- Also crop mismatched :class:`braindecode.models.USleep` decoder tensors with
96
- views instead of allocating index tensors, avoiding unsupported accelerator
97
- lowering without changing the selected samples. (:gh:`1136` by `Bruno
98
- Aristimunha`_)
99
-
100
75
  - Fix the docstrings of :class:`braindecode.models.ATCNet`,
101
76
  :class:`braindecode.models.AttnSleep`, :class:`braindecode.models.CTNet`,
102
77
  :class:`braindecode.models.EEGSimpleConv`, :class:`braindecode.models.IFNet`,
@@ -57,6 +57,7 @@ dependencies = [
57
57
  'wfdb>=4.3.1', # requests comes transitively via mne→pooch and wfdb
58
58
  'linear_attention_transformer',
59
59
  'docstring_inheritance', # we get einops from here
60
+ 'rotary_embedding_torch',
60
61
  'pydantic>=2.0',
61
62
  ]
62
63
 
@@ -84,7 +85,6 @@ tests = [
84
85
  'codecov',
85
86
  'pytest_cases',
86
87
  'mypy',
87
- 'ipython',
88
88
  "transformers>=4.57.0",
89
89
  "bids_validator",
90
90
  ]
@@ -1,255 +0,0 @@
1
- # Authors: Bruno Aristimunha <b.aristimunha@gmail.com>
2
- #
3
- # License: BSD (3-clause)
4
- """Serverless in-notebook viewer for file-backed recordings.
5
-
6
- The bytes on disk behind a dataset element are inlined in the cell output
7
- as base64 and handed to the deployed eegdash-viewer over its ``postMessage``
8
- bridge (``docs/embedding.md`` in https://github.com/eegdash/eegdash-viewer):
9
- no server, no CORS. The output is an iframe plus an inline script, so it
10
- renders when the cell ran in your session or the saved notebook is trusted
11
- (``jupyter trust``).
12
- """
13
-
14
- from __future__ import annotations
15
-
16
- import base64
17
- import json
18
- import os
19
- import uuid
20
- from pathlib import Path
21
- from urllib.parse import urlsplit
22
-
23
- import mne_bids
24
- from mne.utils import _soft_import
25
-
26
- CDN = "https://eegdash.github.io/eegdash-viewer"
27
- MAX_BYTES = 64 * 2**20 # base64 output per call; it is saved with the notebook
28
- EXTENSIONS = {
29
- ".set",
30
- ".edf",
31
- ".bdf",
32
- ".vhdr",
33
- ".fif",
34
- ".snirf",
35
- ".nwb",
36
- } # viewer readers
37
- _BIDS = {"eeg", "ieeg", "emg", "meg", "nirs"}
38
- _SIBLINGS = {".vhdr": (".eeg", ".vmrk"), ".set": (".fdt",)} # travel with the header
39
- _HEADER = {s: h for h, ss in _SIBLINGS.items() for s in ss} # data file -> header
40
-
41
- _SCRIPT = """<iframe id=%(id)s title="eegdash trace viewer" style="width:100%%;height:%(height)spx;
42
- border:1px solid var(--jp-border-color1,#d9dce1);border-radius:6px;background:transparent"></iframe>
43
- <script>
44
- (function () {
45
- var self = document.currentScript, id = %(id)s; // Lab re-runs scripts in place; VS Code/nbclassic elsewhere
46
- var frame = (self && self.previousElementSibling && self.previousElementSibling.tagName === "IFRAME")
47
- ? self.previousElementSibling : document.getElementById(id);
48
- if (!frame) { console.error("eegdash viewer: output iframe " + id + " not found"); return; }
49
- var payload = %(payload)s, origin = %(origin)s, files = null, pose = null;
50
- function decode(b64) {
51
- if (Uint8Array.fromBase64) return Uint8Array.fromBase64(b64);
52
- var bin = atob(b64), out = new Uint8Array(bin.length);
53
- for (var i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
54
- return out;
55
- }
56
- function send(target) {
57
- try {
58
- if (!files) {
59
- files = payload.files.map(function (f) { return new File([decode(f.b64)], f.name); });
60
- pose = payload.pose ? "data:application/json;base64," + payload.pose : null;
61
- payload = null;
62
- }
63
- frame.contentWindow.postMessage({ type: "eegdash-viewer:open", files: files, pose: pose }, target || origin);
64
- } catch (err) {
65
- frame.insertAdjacentHTML("afterend", '<div style="font:12px system-ui;color:#b3261e">eegdash viewer: '
66
- + String(err.message).replace(/</g, "&lt;") + "</div>");
67
- }
68
- }
69
- window.addEventListener("message", function onMessage(e) {
70
- if (e.source === frame.contentWindow && e.data && e.data.type === "eegdash-viewer:ready") send(e.origin);
71
- else if (!frame.isConnected) window.removeEventListener("message", onMessage);
72
- });
73
- frame.src = %(src)s; // after the listener, so "ready" can never precede it
74
- })();
75
- </script>"""
76
-
77
-
78
- def recording_files(recording: Path) -> tuple[list[Path], Path | None]:
79
- """``(files, pose)`` to inline for a recording: the header first, then the
80
- split-format siblings, the BIDS-inherited ``_channels.tsv``/``_events.tsv``
81
- (``mne_bids`` parses the name; plain names get none) and, separately, the
82
- ``<prefix>_desc-pose.json`` hand-pose sidecar next to it. Symlinks keep
83
- their name (git-annex/datalad)."""
84
- rec = Path(recording)
85
- if not rec.exists():
86
- raise ValueError(
87
- f"{rec.name}: file not found (a datalad symlink may need `datalad get`)"
88
- )
89
- if (
90
- rec.is_dir()
91
- or rec.suffix.lower() not in EXTENSIONS
92
- or rec.stem.endswith("_epo")
93
- ):
94
- raise ValueError(
95
- f"{rec.name}: the viewer opens raw recordings in {' '.join(sorted(EXTENSIONS))}"
96
- )
97
- sidecars: list[Path | None] = []
98
- try:
99
- bids = mne_bids.get_bids_path_from_fname(rec, check=False)
100
- if bids.subject is not None: # hyphen-free names parse, but are not BIDS
101
- sidecars = [
102
- bids.find_matching_sidecar(
103
- suffix=s, extension=".tsv", on_error="ignore"
104
- )
105
- for s in ("channels", "events")
106
- ]
107
- except (
108
- KeyError,
109
- ValueError,
110
- ): # not a BIDS name / unknown entity somewhere in the tree
111
- pass
112
- files = [rec]
113
- for p in [
114
- rec.with_suffix(e) for e in _SIBLINGS.get(rec.suffix.lower(), ())
115
- ] + sidecars:
116
- if p and p.is_file():
117
- if p not in files:
118
- files.append(p)
119
- elif p and p.is_symlink(): # dangling: git-annex/datalad content not fetched
120
- raise ValueError(f"{p.name}: dangling symlink (try `datalad get`)")
121
- stem, _, token = rec.stem.rpartition("_")
122
- pose = rec.with_name((stem if token in _BIDS else rec.stem) + "_desc-pose.json")
123
- return files, pose if pose.is_file() else None
124
-
125
-
126
- def build_viewer_html(
127
- recording: Path,
128
- *,
129
- height: int = 520,
130
- cdn_url: str = CDN,
131
- max_bytes: int = MAX_BYTES,
132
- ) -> str:
133
- """Viewer iframe + inlined bytes + bridge script for one recording."""
134
- url = urlsplit(cdn_url)
135
- if (
136
- url.scheme not in ("http", "https")
137
- or not url.netloc
138
- or url.username
139
- or url.query
140
- or url.fragment
141
- or url.path.endswith(("index.html", "index.htm"))
142
- ):
143
- raise ValueError(
144
- f"cdn_url must be the viewer's base http(s) URL, got {cdn_url!r}"
145
- )
146
- files, pose = recording_files(recording)
147
- encoded = sum(
148
- 4 * -(-p.stat().st_size // 3) for p in files + ([pose] if pose else [])
149
- )
150
- if encoded > max_bytes:
151
- raise ValueError(
152
- f"{files[0].name}: {encoded / 2**20:.1f} MiB of base64 would be inlined into the "
153
- f"notebook output (max_bytes={max_bytes / 2**20:.1f} MiB); crop/downsample or raise it"
154
- )
155
- rec = files[0]
156
- # The viewer picks the recording by its *_<datatype>.<ext> name: plain names
157
- # are posted as <stem>_eeg<ext>, an EEGLAB .fdt next to the posted .set name.
158
- head = (
159
- rec.name
160
- if rec.stem.rpartition("_")[2] in _BIDS
161
- else f"{rec.stem}_eeg{rec.suffix.lower()}"
162
- )
163
- names = [head] + [
164
- head.rsplit("_", 1)[0] + "_eeg.fdt" if p.suffix.lower() == ".fdt" else p.name
165
- for p in files[1:]
166
- ]
167
- b64 = [base64.b64encode(p.read_bytes()).decode() for p in files]
168
- literals = {
169
- "id": f"eegdash-viewer-{uuid.uuid4().hex[:8]}",
170
- "height": int(height),
171
- "payload": {
172
- "files": [{"name": n, "b64": b} for n, b in zip(names, b64)],
173
- "pose": base64.b64encode(pose.read_bytes()).decode() if pose else None,
174
- },
175
- "origin": f"{url.scheme}://{url.netloc}",
176
- "src": f"{url.geturl().rstrip('/')}/index.html?embed=1",
177
- }
178
- return _SCRIPT % {
179
- k: json.dumps(v).replace("<", "\\u003c") for k, v in literals.items()
180
- }
181
-
182
-
183
- def _recording(dataset, index: int) -> Path:
184
- """File behind ``dataset.datasets[index]``: the one its mne ``raw`` reads (a
185
- data file maps back to its header; lazily downloading datasets fetch it when
186
- ``raw`` is accessed) or the recorded ``description["path"]``."""
187
- ds = dataset.datasets[index]
188
- names = [
189
- Path(f)
190
- for f in getattr(getattr(ds, "raw", None), "filenames", None) or ()
191
- if isinstance(f, (str, os.PathLike))
192
- ]
193
- if len(names) > 1:
194
- raise ValueError(
195
- f"{type(dataset).__name__}[{index}]: split recordings are not supported"
196
- )
197
- desc = getattr(ds, "description", None) # dict or pandas Series
198
- recorded = desc.get("path") if desc is not None else None
199
- path = (
200
- names[0]
201
- if names
202
- else Path(recorded)
203
- if isinstance(recorded, (str, os.PathLike))
204
- else None
205
- )
206
- if path is None:
207
- raise ValueError(
208
- f"{type(dataset).__name__}[{index}] is not backed by a recording file"
209
- )
210
- header = path.with_suffix(_HEADER.get(path.suffix.lower(), path.suffix))
211
- return header if header.is_file() else path
212
-
213
-
214
- def plot(
215
- dataset,
216
- index: int = 0,
217
- *,
218
- height: int = 520,
219
- cdn_url: str = CDN,
220
- max_bytes: int = MAX_BYTES,
221
- ):
222
- """Show one recording in the eegdash-viewer inside a Jupyter cell.
223
-
224
- Serverless: the recording bytes (as on disk) are inlined in the output and
225
- pushed to the viewer at ``cdn_url`` over ``postMessage``; the output renders
226
- when the cell ran in your session or the notebook is trusted. A
227
- ``*_desc-pose.json`` sidecar next to the recording adds the synchronized
228
- hand-pose panel. Needs IPython (soft dependency).
229
-
230
- Parameters
231
- ----------
232
- index : int
233
- Recording to display.
234
- height : int
235
- Viewer height in pixels.
236
- cdn_url : str
237
- Base URL of a deployed eegdash-viewer.
238
- max_bytes : int
239
- Refuse to inline more than this much base64 (default 64 MiB); the
240
- payload is saved with the notebook and, like any cell output, stays
241
- referenced by IPython's ``Out`` history for the session.
242
-
243
- Returns
244
- -------
245
- IPython.display.HTML
246
- """
247
- ipython = _soft_import("IPython", purpose=f"{type(dataset).__name__}.plot()")
248
- return ipython.display.HTML(
249
- build_viewer_html(
250
- _recording(dataset, index),
251
- height=height,
252
- cdn_url=cdn_url,
253
- max_bytes=max_bytes,
254
- )
255
- )
@@ -1 +0,0 @@
1
- __version__ = "1.8.0.dev180516540"