Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New package for decoding neural activity #37

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1b881ac
Updated package version to preview
ncguilbeault Nov 14, 2024
a1673e0
Added visualizer for unidimensional array heatmap time series data
ncguilbeault Nov 14, 2024
5182773
Added new neural decoding package
ncguilbeault Nov 14, 2024
d81967c
Make plot model public
ncguilbeault Nov 14, 2024
60a7d27
Make plot public
ncguilbeault Nov 14, 2024
5af6713
Added classes for getting posterior and position range
ncguilbeault Nov 14, 2024
dfea5b8
Added posterior time series heatmap visualizer
ncguilbeault Nov 14, 2024
80e6984
Remove position range in favor of a single class
ncguilbeault Nov 15, 2024
5424fdb
Rename posterior time series heatmap to posterior visualizer
ncguilbeault Nov 15, 2024
2298bbd
Added mashup visualizer
ncguilbeault Nov 15, 2024
2ff62fb
Exposed methods to specifically update axes
ncguilbeault Nov 15, 2024
792c71e
Added get properties to relay current count and length of data array
ncguilbeault Nov 15, 2024
2c217d2
Change position range to value range
ncguilbeault Nov 15, 2024
c353efe
Added default value range mapping
ncguilbeault Nov 15, 2024
c0b8aa5
Changed to true position overlay
ncguilbeault Nov 15, 2024
a0825a3
Updated visualize method to correctly merge source and mashup streams
ncguilbeault Nov 15, 2024
5009c50
Call base unload method
ncguilbeault Nov 15, 2024
df9db80
Added null checks when showing data
ncguilbeault Nov 15, 2024
1bd13c6
Fixed missing XML comment
ncguilbeault Nov 15, 2024
7580f4b
Added public getting to retrieve current count information
ncguilbeault Nov 15, 2024
1c8d49d
Initialize heatmap plot with specific properties
ncguilbeault Nov 15, 2024
9e37e23
Update heatmap to display data correctly in show method
ncguilbeault Nov 15, 2024
83e7649
Updated visualize function to make the correct call to the observable…
ncguilbeault Nov 15, 2024
0ce5f22
Correctly adding values to the series
ncguilbeault Nov 15, 2024
a1e00a3
Updated name to true position overlay
ncguilbeault Nov 15, 2024
8212d27
Added method to update y axis title on load
ncguilbeault Nov 15, 2024
269a8b5
Added method to update y axis title
ncguilbeault Nov 15, 2024
a2729f3
Changed name to decoder
ncguilbeault Nov 19, 2024
1a820c3
Added include workflows
ncguilbeault Nov 19, 2024
f9a9883
Removed preview from package version
ncguilbeault Nov 19, 2024
5b53766
Updated README
ncguilbeault Nov 19, 2024
7d3d9bf
Added getting started guide for neural decoder package
ncguilbeault Nov 19, 2024
1d07ed1
Add documentation to include workflows
ncguilbeault Nov 20, 2024
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
44 changes: 29 additions & 15 deletions Bonsai.ML.sln
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
Expand Down Expand Up @@ -30,6 +30,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bonsai.ML.LinearDynamicalSy
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bonsai.ML.HiddenMarkovModels.Design", "src\Bonsai.ML.HiddenMarkovModels.Design\Bonsai.ML.HiddenMarkovModels.Design.csproj", "{FC395DDC-62A4-4E14-A198-272AB05B33C7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bonsai.ML.NeuralDecoder", "src\Bonsai.ML.NeuralDecoder\Bonsai.ML.NeuralDecoder.csproj", "{CE083548-26CB-4CF6-AE51-D7E32AE7377A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bonsai.ML.NeuralDecoder.Design", "src\Bonsai.ML.NeuralDecoder.Design\Bonsai.ML.NeuralDecoder.Design.csproj", "{D2CECE2F-CE7C-41BC-9888-EA53493D64D6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -60,18 +64,26 @@ Global
{39A4414F-52B1-42D7-82FA-E65DAD885264}.Debug|Any CPU.Build.0 = Debug|Any CPU
{39A4414F-52B1-42D7-82FA-E65DAD885264}.Release|Any CPU.ActiveCfg = Release|Any CPU
{39A4414F-52B1-42D7-82FA-E65DAD885264}.Release|Any CPU.Build.0 = Release|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Release|Any CPU.Build.0 = Release|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Release|Any CPU.Build.0 = Release|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Release|Any CPU.Build.0 = Release|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}.Release|Any CPU.Build.0 = Release|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}.Release|Any CPU.Build.0 = Release|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC395DDC-62A4-4E14-A198-272AB05B33C7}.Release|Any CPU.Build.0 = Release|Any CPU
{CE083548-26CB-4CF6-AE51-D7E32AE7377A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CE083548-26CB-4CF6-AE51-D7E32AE7377A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE083548-26CB-4CF6-AE51-D7E32AE7377A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE083548-26CB-4CF6-AE51-D7E32AE7377A}.Release|Any CPU.Build.0 = Release|Any CPU
{D2CECE2F-CE7C-41BC-9888-EA53493D64D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D2CECE2F-CE7C-41BC-9888-EA53493D64D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2CECE2F-CE7C-41BC-9888-EA53493D64D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2CECE2F-CE7C-41BC-9888-EA53493D64D6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -84,8 +96,10 @@ Global
{81DB65B3-EA65-4947-8CF1-0E777324C082} = {461FE3E2-21C4-47F9-8405-DF72326AAB2B}
{BAD0A733-8EFB-4EAF-9648-9851656AF7FF} = {12312384-8828-4786-AE19-EFCEDF968290}
{39A4414F-52B1-42D7-82FA-E65DAD885264} = {12312384-8828-4786-AE19-EFCEDF968290}
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13} = {12312384-8828-4786-AE19-EFCEDF968290}
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1} = {12312384-8828-4786-AE19-EFCEDF968290}
{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13} = {12312384-8828-4786-AE19-EFCEDF968290}
{17DF50BE-F481-4904-A4C8-5DF9725B2CA1} = {12312384-8828-4786-AE19-EFCEDF968290}
{CE083548-26CB-4CF6-AE51-D7E32AE7377A} = {12312384-8828-4786-AE19-EFCEDF968290}
{D2CECE2F-CE7C-41BC-9888-EA53493D64D6} = {12312384-8828-4786-AE19-EFCEDF968290}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B6468F13-97CD-45E0-9E1E-C122D7F1E09F}
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageIcon>icon.png</PackageIcon>
<IncludeSymbols>true</IncludeSymbols>
<RepositoryType>git</RepositoryType>
<VersionPrefix>0.3.1</VersionPrefix>
<VersionPrefix>0.4.0</VersionPrefix>
<VersionSuffix></VersionSuffix>
<LangVersion>12.0</LangVersion>
</PropertyGroup>
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ Facilitates inference using Hidden Markov Models (HMMs). It interfaces with the
### Bonsai.ML.HiddenMarkovModels.Design
Visualizers and editor features for the HiddenMarkovModels package.

### Bonsai.ML.NeuralDecoder
Enables online neural decoding of spike sorted or clusterless neural activity. It interfaces with the [bayesian-neural-decoder](https://github.com/ncguilbeault/bayesian-neural-decoder) package using the [Bonsai - Python Scripting](https://github.com/bonsai-rx/python-scripting) library. The neural decoder consists of a bayesian state-space point process model to decode sorted spikes or clusterless neural activity. The technical details describing the models implementation are described in: Denovellis, E.L., Gillespie, A.K., Coulter, M.E., et al. Hippocampal replay of experience at real-world speeds. eLife 10, e64505 (2021). https://doi.org/10.7554/eLife.64505.

### Bonsai.ML.NeuralDecoder.Design
Visualizers for the Neural Decoder package.

> [!NOTE]
> Bonsai.ML packages can be installed through Bonsai's integrated package manager and are generally ready for immediate use. However, some packages may require additional installation steps. Refer to the specific package section for detailed installation guides and documentation.

Expand Down
26 changes: 26 additions & 0 deletions docs/articles/NeuralDecoder/nd-getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Getting Started

To get started using the Bonsai.ML.NeuralDecoder package, please read below or get started on the demo in the [Neural Decoding example guide](~/examples/README.md).

## Algorithm

The neural decoder consists of a bayesian state space point process model. With this model, latent variables such as an animals position can be decoded from neural activity. To read more about the theory behind the model and how the algorithm works, we refer the reader to: Denovellis, E.L., Gillespie, A.K., Coulter, M.E., et al. Hippocampal replay of experience at real-world speeds. eLife 10, e64505 (2021). https://doi.org/10.7554/eLife.64505.

## Installation

### Python

To install the python package needed to use the package, run the following:

```
cd \path\to\examples\NeuralDecoding\PositionDecodingFromHippocampus
python -m venv .venv
.\.venv\Scripts\activate
pip install git+https://github.com/ncguilbeault/bayesian-neural-decoder.git
```

You can test whether the installation was successful by launching python and running

```python
import bayesian_neural_decoder
```
5 changes: 4 additions & 1 deletion docs/articles/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
- name: Overview
href: HiddenMarkovModels/hmm-overview.md
- name: Getting Started
href: HiddenMarkovModels/hmm-getting-started.md
href: HiddenMarkovModels/hmm-getting-started.md
- name: NeuralDecoder
- name: Getting Started
href: NeuralDecoder/nd-getting-started.md
47 changes: 42 additions & 5 deletions src/Bonsai.ML.Design/HeatMapSeriesOxyPlotBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ public class HeatMapSeriesOxyPlotBase : UserControl
/// </summary>
public StatusStrip StatusStrip => statusStrip;

/// <summary>
/// Gets the plot model.
/// </summary>
public PlotModel Model => model;

/// <summary>
/// Constructor of the TimeSeriesOxyPlotBase class.
/// Requires a line series name and an area series name.
Expand Down Expand Up @@ -295,7 +300,42 @@ public void UpdateHeatMapSeries(double[,] data)
}

/// <summary>
/// Method to update the heatmap series with new data.
/// Method to update the heatmap x axis.
/// </summary>
/// <param name="x0"></param>
/// <param name="x1"></param>
public void UpdateHeatMapXAxis(double x0, double x1)
{
heatMapSeries.X0 = x0;
heatMapSeries.X1 = x1;
}

/// <summary>
/// Method to update the heatmap y axis.
/// </summary>
/// <param name="y0"></param>
/// <param name="y1"></param>
public void UpdateHeatMapYAxis(double y0, double y1)
{
heatMapSeries.Y0 = y0;
heatMapSeries.Y1 = y1;
}

/// <summary>
/// Method to update the heatmap axes.
/// </summary>
/// <param name="x0"></param>
/// <param name="x1"></param>
/// <param name="y0"></param>
/// <param name="y1"></param>
public void UpdateHeatMapAxes(double x0, double x1, double y0, double y1)
{
UpdateHeatMapXAxis(x0, x1);
UpdateHeatMapYAxis(y0, y1);
}

/// <summary>
/// Method to update the heatmap series data and axes.
/// </summary>
/// <param name="x0">The minimum x value.</param>
/// <param name="x1">The maximum x value.</param>
Expand All @@ -304,10 +344,7 @@ public void UpdateHeatMapSeries(double[,] data)
/// <param name="data">The data to be displayed.</param>
public void UpdateHeatMapSeries(double x0, double x1, double y0, double y1, double[,] data)
{
heatMapSeries.X0 = x0;
heatMapSeries.X1 = x1;
heatMapSeries.Y0 = y0;
heatMapSeries.Y1 = y1;
UpdateHeatMapAxes(x0, x1, y0, y1);
heatMapSeries.Data = data;
}

Expand Down
152 changes: 152 additions & 0 deletions src/Bonsai.ML.Design/UnidimensionalArrayTimeSeriesVisualizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Bonsai;
using Bonsai.Design;

[assembly: TypeVisualizer(typeof(Bonsai.ML.Design.UnidimensionalArrayTimeSeriesVisualizer),
Target = typeof(double[]))]

namespace Bonsai.ML.Design
{
/// <summary>
/// Provides a type visualizer to display unidimensional array data as a heatmap time series.
/// </summary>
public class UnidimensionalArrayTimeSeriesVisualizer : DialogTypeVisualizer
{
/// <summary>
/// Gets or sets the selected index of the color palette to use.
/// </summary>
public int PaletteSelectedIndex { get; set; }

/// <summary>
/// Gets or sets the selected index of the render method to use.
/// </summary>
public int RenderMethodSelectedIndex { get; set; }

private HeatMapSeriesOxyPlotBase plot;

/// <summary>
/// Gets the plot control.
/// </summary>
public HeatMapSeriesOxyPlotBase Plot => plot;

/// <summary>
/// Gets or sets the current count of data points.
/// </summary>
public int CurrentCount { get; set; }

/// <summary>
/// Gets or sets the current length of the data array.
/// </summary>
public int CurrentArrayLength { get; set; }

private int _capacity = 100;

/// <summary>
/// Gets or sets the integer value that determines how many data points should be shown along the x axis.
/// </summary>
public int Capacity
{
get => _capacity;
set
{
_capacity = value;
}
}

private List<double[]> dataList = new();

/// <inheritdoc/>
public override void Load(IServiceProvider provider)
{
plot = new HeatMapSeriesOxyPlotBase(PaletteSelectedIndex, RenderMethodSelectedIndex)
{
Dock = DockStyle.Fill,
};

plot.PaletteComboBoxValueChanged += PaletteIndexChanged;
plot.RenderMethodComboBoxValueChanged += RenderMethodIndexChanged;

var capacityLabel = new ToolStripLabel
{
Text = "Capacity:",
AutoSize = true
};
var capacityValue = new ToolStripLabel
{
Text = Capacity.ToString(),
AutoSize = true
};

plot.StatusStrip.Items.AddRange([
capacityLabel,
capacityValue
]);

var visualizerService = (IDialogTypeVisualizerService)provider.GetService(typeof(IDialogTypeVisualizerService));
if (visualizerService != null)
{
visualizerService.AddControl(plot);
}
}

/// <inheritdoc/>
public override void Show(object value)
{
var array = (double[])value;

if (dataList.Count < Capacity)
{
dataList.Add(array);
CurrentCount = dataList.Count;
}
else
{
while (dataList.Count >= Capacity)
{
dataList.RemoveAt(0);
}
dataList.Add(array);
}

if (array.Length != CurrentArrayLength)
{
CurrentArrayLength = array.Length;
plot.UpdateHeatMapYAxis(-0.5, CurrentArrayLength - 0.5);
}

var mdarray = new double[CurrentCount, CurrentArrayLength];
for (int i = 0; i < CurrentCount; i++)
{
for (int j = 0; j < CurrentArrayLength; j++)
{
mdarray[i, j] = dataList[i][j];
}
}

plot.UpdateHeatMapSeries(mdarray);
plot.UpdateHeatMapXAxis(-0.5, CurrentCount - 0.5);
plot.UpdatePlot();
}

/// <inheritdoc/>
public override void Unload()
{
if (!plot.IsDisposed)
{
plot.Dispose();
}
}

private void PaletteIndexChanged(object sender, EventArgs e)
{
PaletteSelectedIndex = plot.PaletteComboBox.SelectedIndex;
}

private void RenderMethodIndexChanged(object sender, EventArgs e)
{
RenderMethodSelectedIndex = plot.RenderMethodComboBox.SelectedIndex;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Title>Bonsai.ML.NeuralDecoder.Design</Title>
<Description>A Bonsai package for visualizing decoded neural activity.</Description>
<PackageTags>Bonsai Rx ML Neural Decoder Design</PackageTags>
<TargetFrameworks>net472</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Bonsai.Core" Version="2.8.5" />
<PackageReference Include="Bonsai.Design.Visualizers" Version="2.8.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Bonsai.ML\Bonsai.ML.csproj" />
<ProjectReference Include="..\Bonsai.ML.Design\Bonsai.ML.Design.csproj" />
<ProjectReference Include="..\Bonsai.ML.NeuralDecoder\Bonsai.ML.NeuralDecoder.csproj" />
</ItemGroup>
</Project>
Loading