Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
22e347a
MAINT: add the CITATION.cff for Zenodo
ctrltz Mar 17, 2025
e7efc3e
Merge branch 'master' into ctrltz/how-to-cite
ctrltz Mar 29, 2025
e0557a0
DOC: how to cite page & badge in the README
ctrltz Mar 29, 2025
8a686cf
DOC: bibtex & citations for method papers
ctrltz Mar 29, 2025
84e3010
Update the main tutorial
ctrltz Apr 6, 2025
38a63f9
DOC: restructure the examples
ctrltz Apr 6, 2025
8088f6c
DOC: citations for SNR approaches
ctrltz Apr 6, 2025
7d7375c
DOC: example on plotting the configuration
ctrltz Apr 6, 2025
87229bf
MAINT: install required packages for plotting in docs
ctrltz Apr 6, 2025
363cc9f
MAINT: try mocking PyQt
ctrltz Apr 6, 2025
520452b
DOC: comment out the brain plot due to problems with Qt
ctrltz Apr 6, 2025
8d341bd
MAINT: another try with ReadTheDocs and xvfb
ctrltz Apr 6, 2025
b480635
MAINT: add plotting deps to the GitHub Action for docs
ctrltz May 31, 2025
7784323
MAINT: try headless display action
ctrltz May 31, 2025
58ce043
MAINT: try disabling brain plots on CIs
ctrltz May 31, 2025
d8bad2f
MAINT: plot dependency is still required
ctrltz May 31, 2025
886ac0e
New attempt
ctrltz May 31, 2025
2f2b798
DOC: try to hack the brain plot in
ctrltz May 31, 2025
b86f519
DOC: another run through getting started, finished next steps
ctrltz Jun 3, 2025
47338f6
DOC: customization with third-party packages
ctrltz Jun 3, 2025
3ec7d0e
DOC: backreferences to examples in the API reference
ctrltz Jun 7, 2025
c9e47ef
DOC: configure the order of examples
ctrltz Jun 7, 2025
f03a978
DOC: example on customization
ctrltz Jun 8, 2025
b36830f
Merge branch 'master' into ctrltz/how-to-cite
ctrltz Jun 8, 2025
d9d2e9b
DOC: NeuroDSP to intersphinx, use sc[name]
ctrltz Jun 8, 2025
b31d4a3
DOC: move "What's new?"
ctrltz Jun 9, 2025
ef2fa0b
DOC: updated all examples, von Mises and local SNR do not work
ctrltz Jun 9, 2025
708032b
DOC: WIP example for std control
ctrltz Jun 10, 2025
8a88beb
DOC: fix filename_pattern for CI build env
ctrltz Jun 10, 2025
2ba9d6e
DOC: temporarily disable the std example
ctrltz Jun 10, 2025
741d7dc
Merge branch 'master' into ctrltz/how-to-cite
ctrltz Jul 22, 2025
8e885a9
Add missing docstring
ctrltz Jul 22, 2025
6f959da
DOC: fix the local SNR example
ctrltz Jul 22, 2025
21a849b
Add warnings on misuse of SNR mode
ctrltz Jul 22, 2025
6ff6b20
Updates after review, one more run through everything
ctrltz Aug 16, 2025
f291739
Fix band_limited
ctrltz Aug 16, 2025
01dffc7
DOC: fix and rework the SD example
ctrltz Aug 17, 2025
3ee6965
Fix warnings, clean autodoc with make
ctrltz Aug 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ on:
pull_request:
branches: [ "master" ]

env:
BUILD_ENV: ci

permissions:
contents: read

Expand All @@ -25,7 +28,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e .[docs]
pip install -e .[docs,plot]

- name: Sphinx build
run: |
Expand Down
1 change: 1 addition & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ python:
path: .
extra_requirements:
- docs
- plot
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ noise ([#58](https://github.com/ctrltz/meegsim/pull/58))
- Allow specifying standard deviation via a SourceEstimate object ([#67](https://github.com/ctrltz/meegsim/pull/67))
- A method for setting phase-phase coupling by adding noise to the shifted copy of input waveform ([#71](https://github.com/ctrltz/meegsim/pull/71))
- Function to convert the sources to mne.Label ([#73](https://github.com/ctrltz/meegsim/pull/73))
- Quick list-like access to the simulated sources ([#82](https://github.com/ctrltz/meegsim/pull/82))
- Control over the amplitude envelope of the coupled waveform ([#87](https://github.com/ctrltz/meegsim/pull/87))
- Quick dict-like access to the simulated sources ([#82](https://github.com/ctrltz/meegsim/pull/82))
- Partial control over the amplitude envelope of the coupled waveform: same as input or randomly generated ([#87](https://github.com/ctrltz/meegsim/pull/87))

### Changed

Expand Down
37 changes: 37 additions & 0 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# This CITATION.cff file was generated with cffinit.
# Visit https://bit.ly/cffinit to generate yours today!

cff-version: 1.2.0
title: MEEGsim
message: >-
If you use this software, please cite it using the
metadata from this file.
type: software
authors:
- given-names: Nikolai
family-names: Kapralov
email: kapralov@cbs.mpg.de
affiliation: >-
Max Planck Institute for Human Cognitive and Brain
Sciences, Leipzig, Germany
orcid: 'https://orcid.org/0000-0002-5659-7307'
- given-names: Alina
family-names: Studenova
email: studenova@cbs.mpg.de
affiliation: >-
Max Planck Institute for Human Cognitive and Brain
Sciences, Leipzig, Germany
orcid: 'https://orcid.org/0000-0003-0821-9966'
- given-names: Mina
family-names: Jamshidi Idaji
orcid: 'https://orcid.org/0000-0003-1593-3201'
repository-code: 'https://github.com/ctrltz/meegsim'
url: 'https://meegsim.readthedocs.io/en/stable/'
keywords:
- simulation
- MEG
- EEG
- connectivity
license: BSD-3-Clause
version: 0.0.1
date-released: '2024-10-31'
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,21 @@ SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = docs
BUILDDIR = _build
EXAMPLESDIR = docs/auto_examples
AUTODOCDIR = docs/generated

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

clean:
rm -rf $(BUILDDIR)/*
rm -rf $(EXAMPLESDIR)/*
rm -rf $(AUTODOCDIR)/*

collect: html
./collect_example_stubs.sh

show:
python -m webbrowser -t "$(BUILDDIR)/html/index.html"

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# MEEGsim

[![DOI](https://zenodo.org/badge/832185753.svg)](https://doi.org/10.5281/zenodo.15106042)

## Overview

**MEEGsim** is a Python package that provides template waveforms for simulating M/EEG data with known ground truth source activity. In addition, it simplifies the manipulation of relevant simulation parameters (e.g., signal-to-noise ratio and source connectivity). As a result, the users can focus on _what_ to simulate, not on _how_ to implement the simulation. The package is compatible with MNE-Python and re-uses the forward and inverse modeling functionality provided by MNE.
Expand Down
15 changes: 15 additions & 0 deletions collect_example_stubs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# NOTE: brain plots cannot be rendered with ReadTheDocs, therefore
# we build the docs locally and add generated brain images in correct places
# to show in the online version

STATIC_THUMB=docs/_static/example_stubs/thumb
STATIC_IMAGES=docs/_static/example_stubs/images

# examples/basics/02_plot_brain_configuration.py
cp docs/auto_examples/basics/images/thumb/sphx_glr_02_plot_brain_configuration_thumb.png $STATIC_THUMB
cp docs/auto_examples/basics/images/sphx_glr_02_plot_brain_configuration_001.png $STATIC_IMAGES

# examples/building_blocks/04_plot_std.py
cp docs/auto_examples/building_blocks/images/thumb/sphx_glr_04_plot_brain_std_thumb.png $STATIC_THUMB
cp docs/auto_examples/building_blocks/images/sphx_glr_04_plot_brain_std_001.png $STATIC_IMAGES
cp docs/auto_examples/building_blocks/images/sphx_glr_04_plot_brain_std_002.png $STATIC_IMAGES
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions docs/_templates/autosummary/class.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@
:special-members: __contains__,__getitem__,__iter__,__len__,__add__,__sub__,__mul__,__div__,__neg__
:members:
:inherited-members:

.. _sphx_glr_backreferences_{{ fullname }}:

.. minigallery:: {{ fullname }}
:add-heading:
10 changes: 10 additions & 0 deletions docs/_templates/autosummary/function.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{{ fullname | escape | underline }}

.. currentmodule:: {{ module }}

.. autofunction:: {{ objname }}

.. _sphx_glr_backref_{{ fullname }}:

.. minigallery:: {{ fullname }}
:add-heading:
22 changes: 22 additions & 0 deletions docs/changelog/devel.md
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
# [Unreleased]

## Added

- A desired level of white noise can be added in sensor space to model measurement
noise ([#58](https://github.com/ctrltz/meegsim/pull/58))
- A possibility to plot the source configuration ([#59](https://github.com/ctrltz/meegsim/pull/59))
- Adjustment of global (all signal vs. all noise sources) SNR ([#64](https://github.com/ctrltz/meegsim/pull/64))
- Adjustment of the standard deviation of source activity ([#66](https://github.com/ctrltz/meegsim/pull/66))
- Allow specifying standard deviation via a SourceEstimate object ([#67](https://github.com/ctrltz/meegsim/pull/67))
- A method for setting phase-phase coupling by adding noise to the shifted copy of input waveform ([#71](https://github.com/ctrltz/meegsim/pull/71))
- Function to convert the sources to mne.Label ([#73](https://github.com/ctrltz/meegsim/pull/73))
- Quick dict-like access to the simulated sources ([#82](https://github.com/ctrltz/meegsim/pull/82))
- Partial control over the amplitude envelope of the coupled waveform: same as input or randomly generated ([#87](https://github.com/ctrltz/meegsim/pull/87))

## Changed

- Reworked normalization of source activity: by default, all source time courses are scaled to make their standard deviation equal to 1 nAm ([#66](https://github.com/ctrltz/meegsim/pull/66))
- Improved performance when adjusting the SNR for a large number of sources ([#68](https://github.com/ctrltz/meegsim/pull/68))

## Fixed

- Fixed a bug that caused different sources to have the same location and/or waveform when random state was explicitly provided ([#76](https://github.com/ctrltz/meegsim/pull/76))
28 changes: 26 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information


import pyvista
import os
import sys

Expand Down Expand Up @@ -128,8 +129,9 @@ def linkcode_resolve(domain, info):


# Intersphinx
intersphinx_mapping = get_intersphinx_mapping(
packages={"matplotlib", "mne", "numpy", "python"}
intersphinx_mapping = {"neurodsp": ("https://neurodsp-tools.github.io/neurodsp/", None)}
intersphinx_mapping.update(
get_intersphinx_mapping(packages={"matplotlib", "mne", "numpy", "python"})
)


Expand All @@ -138,8 +140,30 @@ def linkcode_resolve(domain, info):
bibtex_default_style = "unsrt"


# Enabling PyVista scraper
pyvista.BUILDING_GALLERY = True
pyvista.OFF_SCREEN = False


# Sphinx Gallery
sphinx_gallery_conf = {
"backreferences_dir": "generated",
"doc_module": ("meegsim",),
"examples_dirs": "../examples",
"filename_pattern": "/\\d{2}_plot_",
"gallery_dirs": "auto_examples",
"image_scrapers": ("matplotlib", "pyvista"),
"subsection_order": [
"../examples/basics",
"../examples/building_blocks",
"../examples/advanced",
],
"within_subsection_order": "FileNameSortKey",
}

# Disable brain plots for CIs
if os.environ.get("BUILD_ENV", "local") == "ci":
sphinx_gallery_conf["filename_pattern"] = "/\\d{2}_plot_(?!brain)"

print(os.environ.get("BUILD_ENV", "local"))
print(sphinx_gallery_conf)
1 change: 0 additions & 1 deletion docs/development/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ Development
:maxdepth: 2

setup
whats_new
internals/index
11 changes: 11 additions & 0 deletions docs/references.bib
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
@article{HaufeEwald2019,
title = {{A} {S}imulation {F}ramework for {B}enchmarking {EEG}-{B}ased {B}rain {C}onnectivity {E}stimation {M}ethodologies},
author = {Haufe, Stefan and Ewald, Arne},
journal = {{B}rain {T}opography},
journal-short={{B}rain {T}opogr},
volume = {32},
pages = {625-642},
year = 2019,
doi = "10.1007/s10548-016-0498-y"
}

@article{Nikulin2011,
title = "A novel method for reliable and fast extraction of neuronal
{EEG/MEG} oscillations on the basis of spatio-spectral
Expand Down
73 changes: 68 additions & 5 deletions docs/user_guide/advanced/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ Customization
=============

If the built-in functions for location, waveform or coupling do not satisfy the
needs of your project, you are always welcome use a custom function instead.
In this section, we provide a short description of requirements for such functions:
needs of your project, you are always welcome use a custom function instead (either
created by you or re-used from another toolbox). In this section, we provide a short
description of requirements for such functions:

* which arguments should be accepted (but not necessarily used)

Expand All @@ -13,8 +14,8 @@ In this section, we provide a short description of requirements for such functio
In addition, we provide minimal examples of custom functions for each case.

.. note::
When adding sources, we always try to execute the provided functions with 0
as ``random_state`` to making the debugging a bit easier.
When adding sources, we always call the provided functions with 0
as ``random_state`` to making the debugging a bit easier in case errors occur.

Location
========
Expand Down Expand Up @@ -59,7 +60,12 @@ The waveform function should accept:

* keyword argument ``random_state``

The result is expected to be an array with shape ``(n_series, n_times)``.
The result is expected to be an array with shape ``(n_series, n_times)``. Below,
we show two examples: the first relies on an own custom function, the second shows
how to adapt the function from another toolbox to be used with MEEGsim.

Own custom function
-------------------

The function below returns white noise, and it produces different results every
time unless ``random_state`` is fixed:
Expand All @@ -83,6 +89,63 @@ are not required in this case):
waveform=my_white_noise
)

Function from another package
-----------------------------

For this example, we use a
`function <https://neurodsp-tools.github.io/neurodsp/generated/neurodsp.sim.sim_bursty_oscillation.html>`_
from the NeuroDSP package that allows simulating bursty oscillations (currently not possible with our toolbox).
First, we need to create a wrapper function to adapt the input and output formats to match
the built-in functions of MEEGsim:

.. code-block:: python

from neurodsp.sim import sim_bursty_oscillation
from neurodsp.sim.multi import sim_multiple
from meegsim.utils import normalize_variance

def bursty_osc(n_series, times, **kwargs):
# Convert MEEGsim input to NeuroDSP input
tstep = (times[1] - times[0])
n_seconds = times.max() + tstep
fs = 1.0 / tstep

params = dict(n_seconds=n_seconds, fs=fs)
params.update(kwargs)
params.pop("random_state") # is not accepted by NeuroDSP function

sims = sim_multiple(sim_bursty_oscillation, params, n_sims=n_series)

return normalize_variance(sims.signals)

.. note::
We use ``**kwargs`` in the example above to forward all additional arguments to the
simulation function from the NeuroDSP package. This way, the names and meaning of
each argument remains the same.

Once adapted, the function can be used similar to other built-in functions when
adding sources:

.. code-block:: python

# src should be loaded before
sim = SourceSimulator(src)

sim.add_point_sources(
location=[(0, 123), (1, 456)],
waveform=bursty_osc,
waveform_params=dict( # NeuroDSP parameters
freq=20,
burst_def='durations',
burst_params={'n_cycles_burst' : 3, 'n_cycles_off' : 3}
),
... # snr / std / names
)

However, it is important to keep in mind that coupling methods might also need to be
adapted in order to preserve any special features of the simulated time series (e.g.,
presence of bursts).

Coupling
========

Expand Down
2 changes: 2 additions & 0 deletions docs/user_guide/advanced/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ for the toolbox.
:maxdepth: 2

patches
standard_deviation
local_snr
customization
Loading