OSCR

Optimal Transport Theory to Extract Spiking Motifs

Code ↔ Paper

The paper beside its authors' code: matches between them have not been computed for this paper yet.

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Jupyter notebook · 154 lines · 7.8 KB · no license

  1. # %%
  2. %load_ext autoreload
  3. %autoreload 2
  4. # %%
  5. import torch
  6. import matplotlib.pyplot as plt
  7. import numpy as np
  8. from dataset_generation import generate_dataset, sm_generative_model
  9. from wassa_plots import plot_SM, plot_colored_raster
  10. # %% [markdown]
  11. # # Generative model for raster plots and spiking motifs
  12. # %% [markdown]
  13. # List of parameters for this generative model
  14. # %%
  15. dataset_parameters = {
  16. 'seed' : 81,
  17. 'N_pre' : 100, # number of neurons
  18. 'N_timesteps' : 1000, # number of timesteps for the raster plot (in ms)
  19. 'N_samples' : 60, # total number of samples in the dataset
  20. 'N_delays' : 51, # number of timesteps in spiking motifs, must be a odd number for convolutions
  21. 'N_SMs' : 3, # number of structured spiking motifs
  22. 'avg_fr' : 20, # average firing rate of the neurons (in Hz)
  23. 'std_fr' : .1, # standard deviation for the firing rates of the different neurons
  24. 'overlapping_sms' : True, # possibility to have overlapping sequences
  25. 'temporal_jitter' : .1, # temporal jitter for the spike generation in motifs
  26. 'dropout_proba' : 0, # probabilistic participations of the different neurons to the spiking motif
  27. 'additive_noise' : .1, # percentage of background noise/spontaneous activity
  28. 'warping_coef' : 1, # coefficient for time warping
  29. }
  30. dataset_parameters.update({'N_involved':dataset_parameters['N_pre']*torch.ones(dataset_parameters['N_SMs'])}) # number of neurons involved in the spiking motif
  31. dataset_parameters.update({'frs' : torch.normal(dataset_parameters['avg_fr'], dataset_parameters['std_fr'], size=(dataset_parameters['N_pre'],)).abs()})
  32. dataset_parameters.update({'freq_sms' : 4*torch.ones(dataset_parameters['N_SMs'])}) # frequency of apparition of the different spiking motifs (in Hz)
  33. dataset_parameters.update({'coefficient_variation' : 1*torch.ones(dataset_parameters['N_pre'])}) # coefficient of variation of the FRs of each neuron (within VS. without a motif)
  34. # %%
  35. sm = sm_generative_model(dataset_parameters)
  36. # %% [markdown]
  37. # The generative model will draw raster plots generated from both a spontaneous (random) activity and from spiking motifs. There are *parameters.N_SM* spiking motifs represented in the next plot. There are given as a spiking probability for each presynatpic neuron and each timestep (or delay).
  38. # %%
  39. plot_SM(sm.SMs);
  40. # %% [markdown]
  41. # The raster plot is produced with a sequence of apparition of the different motifs and random activity when no motif occurs.
  42. # %%
  43. number_of_trials = 100
  44. input_rp, output_rp = sm.draw_input(nb_trials=number_of_trials)
  45. # %%
  46. random_ind = torch.randint(dataset_parameters['N_samples'],[1])
  47. plot_colored_raster(input_rp[random_ind].squeeze(0), output_rp[random_ind].squeeze(0), dataset_parameters['N_delays'], dataset_parameters['warping_coef']);
  48. # %% [markdown]
  49. # The not structured spiking activity of the different neurons is given by their FRs (*parameters.frs*). Then, it is given by the occurence of a motif (colored parts of the raster plot) and the structure of the motif. The occurence of a motif is given by a random trial defining its timing and its type (or color).
  50. #
  51. # The raster plot is obtained with a Bernoulli trial on the probability distribution representing the non structured (flat distribution) or the structured (probability distributions of the different motifs). When motifs overlap the formula used to merge the motifs and obtain the expected raster plot is the following:
  52. # $$Bernoulli(p) + Bernoulli(q) = Bernoulli(p+q-p*q)$$
  53. #
  54. # It leads to Poisson distribution with an expected number of spike during the trial and their relative temporal dependencies that can vary with the number of motifs, their frequency of apparition (*parameters.freq_sm*) or the number of neurons involved in the motif (*parameters.N_involved*)
  55. # %%
  56. def moving_average(x, w):
  57. return np.convolve(x, np.ones(w), 'valid') / w
  58. fig, ax = plt.subplots(figsize = (12, 1.61803))
  59. ax.plot(moving_average(input_rp[0].sum(axis=(0)),1))
  60. ax.set_xlim(0, dataset_parameters['N_timesteps'])
  61. ax.set_xlabel('Time (a. u.)')
  62. ax.set_ylabel('Spike number')
  63. ax.set_title('Moving average of the number of spike per timebin');
  64. # %% [markdown]
  65. # The instantaneous firing rate sumed over the different trials shows that the distribution is Poisson. And we can check the effective number of spikes per neuron compared to the expected firing rate. Firing rate of the different neurons can be easily changed, default is chosen by following a normal distribution around an average firing rate.
  66. # %%
  67. fig, ax = plt.subplots()
  68. ax.bar(np.arange(dataset_parameters['N_pre']),1e3*input_rp.mean(axis=(0,2)))
  69. ax.plot(dataset_parameters['frs'], 'ro', label='expected firing rate')
  70. ax.set_xlabel('@ Neuron')
  71. ax.set_ylabel('Firing rate (in Hz)')
  72. ax.legend();
  73. ax.set_title('Average number of spikes per neuron');
  74. # %% [markdown]
  75. # We can also check the number of occurence of the motifs and compare it to the expected number of occurence.
  76. # %%
  77. fig, ax = plt.subplots()
  78. ax.bar(np.arange(dataset_parameters['N_SMs']),output_rp.sum(axis=(0,2)))
  79. ax.plot(dataset_parameters['freq_sms']*number_of_trials*dataset_parameters['N_timesteps']*1e-3, 'ro', label='expected number')
  80. ax.set_xlabel('Spiking motif #')
  81. ax.set_ylabel('Number of occurence')
  82. ax.set_title('Occurence of the different motifs');
  83. ax.legend();
  84. # %% [markdown]
  85. # ## No overlap of the motifs
  86. #
  87. # If you set the following parameter to False, then the overlap of the motifs is prevented.
  88. # %%
  89. sm.opt['overlapping_sms'] = False
  90. input_rp, output_rp = sm.draw_input(nb_trials=100)
  91. # %%
  92. random_ind = torch.randint(dataset_parameters['N_samples'],[1])
  93. plot_colored_raster(input_rp[random_ind].squeeze(0), output_rp[random_ind].squeeze(0), dataset_parameters['N_delays'], dataset_parameters['warping_coef']);
  94. # %%
  95. fig, ax = plt.subplots()
  96. ax.bar(np.arange(dataset_parameters['N_SMs']),output_rp.sum(axis=(0,2)))
  97. ax.plot(dataset_parameters['freq_sms']*dataset_parameters['N_timesteps']*number_of_trials*1e-3, 'ro', label='expected number')
  98. ax.set_xlabel('Spiking motif #')
  99. ax.set_ylabel('Number of occurence')
  100. ax.set_title('Occurence of the different motifs');
  101. ax.legend();
  102. # %% [markdown]
  103. # ## Save a dataset
  104. #
  105. # You can also easily save a dataset with a defined number of trials (*total_number_of_trials*). It will split the dataset into a training (80% of the trials) and a testing (20% of the trials) of the trials sets.
  106. # %%
  107. total_number_of_trials = 1000
  108. sm, dataset_input, dataset_output = generate_dataset(dataset_parameters, record_path = './synthetic_data/')
  109. # %%
  110. random_ind = torch.randint(dataset_parameters['N_samples'],[1])
  111. plot_colored_raster(input_rp[random_ind].squeeze(0), output_rp[random_ind].squeeze(0), dataset_parameters['N_delays'], dataset_parameters['warping_coef']);
  112. # %% [markdown]
  113. # ## Alteration of the motifs
  114. #
  115. # There are different types of noise that can be added to the motifs:
  116. # - temporal jitter: the timing of a spiking can be shifted in time. It is modeled by convolving the precise spiking motifs with a gaussian kernel (its standard deviation (*parameters.temporal_jitter*) gives the amount of jitter).
  117. # - stochatistic activation of the neurons: neurons can also not participate in the generation of a spike at a specific spatio temporal location. This participation is obtained with a random trial on which neurons will be activated with a probability of activation for each neuron (*parameters.dropout_proba*)
  118. # - additive noise: percentage of background activity given by (*parameters.additive_noise*).
  119. # - time warping: the kernel is streched in time with a specific coefficient (parameters.warping_coef)
  120. # %% [markdown]
  121. # Because we maintain a constant firing rates for the different trials and the way the generative model is defined, these types of alteration will occur only at the motif level and then, a background activity of 100% leads to the same type of unstructured activity as a dropout probability of 1 for each of the neurons or an infinite temporal jitter.
  122. # %%

TUTO_generation_synthetic_datasets.ipynb at commit bb3d841, no license · at the source

Overview

Authors: Antoine Grimaldi1, Boris Sotomayor-Gómez2,3,4, Mathieu Gilson5, Laurent U Perrinet5, Andrea Alamia1, Martin Vinck2,6
  1. Centre de Recherche Cerveau et Cognition (CerCo), UMR 5549, CNRS, Université Toulouse III – Paul Sabatier, Toulouse, France
  2. Ernst Strüngmann Institute for Neuroscience, Ernst Strüngmann Institute, Frankfurt am Main, Germany
  3. Center for Neurology, Department of Parkinson, Sleep and Movement Disorders (DZNE), Bonn, Germany
  4. Institute of Informatics, Austral University of Chile, Valdivia, Chile
  5. Institut de Neurosciences de la Timone (INT), UMR 7289, CNRS, Aix-Marseille Université, Marseille, France
  6. Donders Centre for Neuroscience, Radboud University Nijmegen, Nijmegen, Netherlands
Dates: published online 30 April 2026
Type: Preprint
License: CC BY
Identifiers: DOI 10.21203/rs.3.rs-9518938/v1 · OpenAlex W7160085958
Open access: green, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: computational (subfield)
Methods: Machine learning, Single-unit activity, calcium imaging, Smoothing, state filtering, decompositions
Keywords: Optimal Transport Theory, Temporal Codes, Spiking Motifs, Neural Decoding
Topic: Neural dynamics and brain function (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: European Research Council (850861)
Citations: not cited yet (Europe PMC); 21 references in the paper

Abstract

Spatiotemporal spike motifs, i.e. repeating temporal sequences, of neural activity are thought to carry information beyond average firing rates, yet extracting such motifs from noisy spike trains remains challenging. In particular, most approaches rely on bin-by-bin comparisons that are sensitive to bin size and temporal jitter. Here, we investigate the use of the Earth Mover’s Distance (EMD), a metric from optimal transport theory, as a reconstruction loss for learning spiking motifs. We compare EMD to the conventional mean squared error (MSE) by training single-layer autoencoders with tied positive weights to reconstruct neural raster plots. Using synthetic spike trains with known ground-truth motifs, we systematically evaluate how each loss recovers spatiotemporal structure under varying numbers of training samples and different noise regimes, including temporal jitter, sequence warping, neuron dropout, and additive Poisson noise. We show that EMD-based training is more robust to temporal jitter and sequence warping, and more reliably estimates aligned spike timings when the number of training samples is limited. In contrast, MSE better captures the full spike distribution, i.e. the relative timing of the spikes as well as their temporal precision, when large datasets are available and is more resilient to additive noise. Applying the same framework to Neuropixels recordings from the Allen Institute visual coding dataset reveals that motifs learned with EMD are more discriminative of visual stimuli than those learned with MSE. Together, these results highlight the advantages of optimal transport–based losses for learning spatiotemporal motifs in neural population activity.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above.

antoinegrimaldi/wassa

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Commit: bb3d84170378752c63ec54cde202c8143b612ee0, 8 July 2026
Languages: Jupyter (21), Python (18)
Size: 43 files, 39 scripts
Software Heritage: not archived
Found in: “Code Availability”
Holds: README, 21 notebooks
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: PyTorch (39 files), Matplotlib (24 files), NumPy (24 files), SciPy (8 files), pandas (3 files), seaborn (3 files)
Availability: 1 check, the latest on 30 September 2026: the link answers
  • 30 September 2026: the link answers
40 files

Code Availability

This work is made reproducible. The code reproducing the manuscript and all figures is available on https://github.com/AntoineGrimaldi/wassa/tree/main/results_paper. It also contains supplementary figures and results.

Reproduced under the paper's license (CC BY), from the paper cited above.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 39 scripts, each with its path and the digest of its content;
  • no match between paragraphs and code yet;
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data and Materials Availability

Not applicable.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 30 September 2026: the first record

Recorded: type, journal, dates, 6 authors, 4 keywords, 1 funder, 18 references.

Cite

This paper

Grimaldi, A., Sotomayor-Gómez, B., Gilson, M., Perrinet, L. U., Alamia, A., & Vinck, M. (2026). Optimal Transport Theory to Extract Spiking Motifs. Research Square (preprint). https://doi.org/10.21203/rs.3.rs-9518938/v1

BibTeX

@article{grimaldi2026optimal,
author = {Grimaldi, Antoine and Sotomayor-Gómez, Boris and Gilson, Mathieu and Perrinet, Laurent U and Alamia, Andrea and Vinck, Martin},
title = {{Optimal Transport Theory to Extract Spiking Motifs}},
journal = {Research Square (preprint)},
year = {2026},
month = apr,
publisher = {Research Square},
issn = {2693-5015},
doi = {10.21203/rs.3.rs-9518938/v1},
url = {https://doi.org/10.21203/rs.3.rs-9518938/v1}
}

RIS

TY - JOUR
AU - Grimaldi, Antoine
AU - Sotomayor-Gómez, Boris
AU - Gilson, Mathieu
AU - Perrinet, Laurent U
AU - Alamia, Andrea
AU - Vinck, Martin
TI - Optimal Transport Theory to Extract Spiking Motifs
T2 - Research Square (preprint)
J2 - Res Sq
PY - 2026
DA - 2026/04/30
SN - 2693-5015
PB - Research Square
DO - 10.21203/rs.3.rs-9518938/v1
UR - https://doi.org/10.21203/rs.3.rs-9518938/v1
ER -

CSL-JSON

{
"id": "10.21203/rs.3.rs-9518938/v1",
"type": "article",
"title": "Optimal Transport Theory to Extract Spiking Motifs",
"container-title": "Research Square (preprint)",
"author": [
{
"family": "Grimaldi",
"given": "Antoine"
},
{
"family": "Sotomayor-Gómez",
"given": "Boris"
},
{
"family": "Gilson",
"given": "Mathieu"
},
{
"family": "Perrinet",
"given": "Laurent U"
},
{
"family": "Alamia",
"given": "Andrea"
},
{
"family": "Vinck",
"given": "Martin"
}
],
"container-title-short": "Res Sq",
"DOI": "10.21203/rs.3.rs-9518938/v1",
"ISSN": "2693-5015",
"publisher": "Research Square",
"URL": "https://doi.org/10.21203/rs.3.rs-9518938/v1",
"issued": {
"date-parts": [
[
2026,
4,
30
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.3390/brainsci13010068 [code]
Precise Spiking Motifs in Neurobiological and Neuromorphic Data.
Journal: Brain sciences
In common: PyTorch, seaborn, pandas, 3 other tools, computational, 1 reference
[2] doi:10.1371/journal.pcbi.1010764 [code]
Improved visualization of high-dimensional data using the distance-of-distance transformation.
Journal: PLoS computational biology
In common: PyTorch, pandas, SciPy, 2 other tools, 2 references
[3] doi:10.1016/j.celrep.2026.117159 [code]
Cellular and subcellular specialization enables biology-constrained deep learning.
Journal: Cell reports
In common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
[4] doi:10.1038/s41467-026-76939-w [code]
HIPPIE: a generative model for electrophysiological analysis across species, technologies, and modalities.
Journal: Nature communications
In common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
[5] doi:10.1038/s41467-025-64259-4 [code]
Data-driven fine-grained region discovery in the mouse brain with transformers.
Journal: Nature communications
In common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
[6] doi:10.1038/s41562-025-02252-z [code]
In silico discovery of representational relationships across visual cortex.
Journal: Nature human behaviour
In common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
[7] doi:10.1371/journal.pcbi.1010233 [code]
Sequence learning, prediction, and replay in networks of spiking neurons.
Journal: PLoS computational biology
In common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
[8] doi:10.1038/s41593-024-01626-2 [code]
Dimensionality reduction beyond neural subspaces with slice tensor component analysis.
Journal: Nature neuroscience
In common: PyTorch, seaborn, pandas, 3 other tools, 1 reference
[9] doi:10.1371/journal.pcbi.1011335 [code]
SpikeShip: A method for fast, unsupervised discovery of high-dimensional neural spiking patterns.
Journal: PLoS computational biology
In common: Matplotlib, NumPy, 3 references
[10] doi:10.1007/s00422-026-01048-2 [code]
A quality measure for repeating multiple-unit spike patterns.
Journal: Biological cybernetics
In common: Matplotlib, NumPy, computational, 2 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1.svg)](https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1.svg
   :target: https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1"><img src="https://openscicode.org/badge/doi/10.21203/rs.3.rs-9518938/v1.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.