diff --git a/Bonsai.ML.sln b/Bonsai.ML.sln index aaa9ad7f..c5a91b13 100644 --- a/Bonsai.ML.sln +++ b/Bonsai.ML.sln @@ -1,4 +1,4 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 @@ -9,7 +9,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bonsai.ML", "src\Bonsai.ML\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bonsai.ML.LinearDynamicalSystems", "src\Bonsai.ML.LinearDynamicalSystems\Bonsai.ML.LinearDynamicalSystems.csproj", "{17AABD18-E275-4409-9E33-3D755B809FF6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bonsai.ML.Visualizers", "src\Bonsai.ML.Visualizers\Bonsai.ML.Visualizers.csproj", "{196AA5C7-AE8A-477B-B01A-B94676EC60EE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bonsai.ML.Design", "src\Bonsai.ML.Design\Bonsai.ML.Design.csproj", "{196AA5C7-AE8A-477B-B01A-B94676EC60EE}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{461FE3E2-21C4-47F9-8405-DF72326AAB2B}" EndProject @@ -26,6 +26,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bonsai.ML.Python", "src\Bon EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bonsai.ML.Data", "src\Bonsai.ML.Data\Bonsai.ML.Data.csproj", "{A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bonsai.ML.LinearDynamicalSystems.Design", "src\Bonsai.ML.LinearDynamicalSystems.Design\Bonsai.ML.LinearDynamicalSystems.Design.csproj", "{17DF50BE-F481-4904-A4C8-5DF9725B2CA1}" +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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,22 +60,32 @@ 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 + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {FC395DDC-62A4-4E14-A198-272AB05B33C7} = {12312384-8828-4786-AE19-EFCEDF968290} {AA6BE73F-1E15-49A5-AC3C-CD069035C940} = {12312384-8828-4786-AE19-EFCEDF968290} {17AABD18-E275-4409-9E33-3D755B809FF6} = {12312384-8828-4786-AE19-EFCEDF968290} {196AA5C7-AE8A-477B-B01A-B94676EC60EE} = {12312384-8828-4786-AE19-EFCEDF968290} {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} + {A135C7DB-EA50-4FC6-A6CB-6A5A5CC5FA13} = {12312384-8828-4786-AE19-EFCEDF968290} + {17DF50BE-F481-4904-A4C8-5DF9725B2CA1} = {12312384-8828-4786-AE19-EFCEDF968290} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B6468F13-97CD-45E0-9E1E-C122D7F1E09F} diff --git a/README.md b/README.md index e40ffcf9..cd875504 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ The **Bonsai.ML** project is a collection of packages designed to integrate mach - **Bonsai.ML** Provides common tools and functionality. +- **Bonsai.ML.Design** + Provides common tools and functionality for visualizers and editor features. + - **Bonsai.ML.Data** Provides common tools and functionality for working with data. @@ -24,6 +27,9 @@ Facilitates inference using linear dynamical systems (LDS). It interfaces with t - **Bonsai.ML.LinearDynamicalSystems.LinearRegression** Utilizes the Kalman Filter to perform online Bayesian linear regression. +### Bonsai.ML.LinearDynamicalSystems.Design +Visualizers and editor features for the LinearDynamicalSystems package. + ### Bonsai.ML.HiddenMarkovModels Facilitates inference using Hidden Markov Models (HMMs). It interfaces with the [ssm](https://github.com/lindermanlab/ssm) package using the [Bonsai - Python Scripting](https://github.com/bonsai-rx/python-scripting) library. @@ -32,9 +38,9 @@ Facilitates inference using Hidden Markov Models (HMMs). It interfaces with the - **Bonsai.ML.HiddenMarkovModels.Transitions** Provides functionality for specifying different types of transition models. - -### Bonsai.ML.Visualizers -Graphing and plotting library for visualizing data. + +### Bonsai.ML.HiddenMarkovModels.Design +Visualizers and editor features for the HiddenMarkovModels 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. diff --git a/src/Bonsai.ML.Visualizers/BarSeriesOxyPlotBase.cs b/src/Bonsai.ML.Design/BarSeriesOxyPlotBase.cs similarity index 94% rename from src/Bonsai.ML.Visualizers/BarSeriesOxyPlotBase.cs rename to src/Bonsai.ML.Design/BarSeriesOxyPlotBase.cs index 55188fea..528dece4 100644 --- a/src/Bonsai.ML.Visualizers/BarSeriesOxyPlotBase.cs +++ b/src/Bonsai.ML.Design/BarSeriesOxyPlotBase.cs @@ -3,19 +3,20 @@ using OxyPlot.Series; using OxyPlot.WindowsForms; using System.Drawing; -using System; using OxyPlot.Axes; -using System.Collections; -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.Design { - internal class BarSeriesOxyPlotBase : UserControl + /// + /// Provides a user control to display data as a bar plot using OxyPlot. + /// + public class BarSeriesOxyPlotBase : UserControl { private PlotView view; private PlotModel model; private OxyColor defaultBarSeriesColor = OxyColors.Automatic; - internal Axis xAxis; + private Axis xAxis; private Axis yAxis; private StatusStrip statusStrip; @@ -30,6 +31,16 @@ internal class BarSeriesOxyPlotBase : UserControl /// public StatusStrip StatusStrip => statusStrip; + /// + /// Gets the X Axis. + /// + public Axis XAxis => xAxis; + + /// + /// Gets the Y Axis. + /// + public Axis YAxis => yAxis; + /// /// Initializes a new instance of the class /// diff --git a/src/Bonsai.ML.Visualizers/Bonsai.ML.Visualizers.csproj b/src/Bonsai.ML.Design/Bonsai.ML.Design.csproj similarity index 53% rename from src/Bonsai.ML.Visualizers/Bonsai.ML.Visualizers.csproj rename to src/Bonsai.ML.Design/Bonsai.ML.Design.csproj index 89a48533..c559ab84 100644 --- a/src/Bonsai.ML.Visualizers/Bonsai.ML.Visualizers.csproj +++ b/src/Bonsai.ML.Design/Bonsai.ML.Design.csproj @@ -1,21 +1,15 @@ - Bonsai.ML.Visualizers + Bonsai.ML.Design A package for the Bonsai visual programming language. - Bonsai Rx ML Machine Learning Visualizers + Bonsai Rx ML Machine Learning Design net472 true - - - - - - \ No newline at end of file diff --git a/src/Bonsai.ML.Visualizers/ColorPalette.cs b/src/Bonsai.ML.Design/ColorPalette.cs similarity index 89% rename from src/Bonsai.ML.Visualizers/ColorPalette.cs rename to src/Bonsai.ML.Design/ColorPalette.cs index 5f887fe7..57dc2e28 100644 --- a/src/Bonsai.ML.Visualizers/ColorPalette.cs +++ b/src/Bonsai.ML.Design/ColorPalette.cs @@ -1,4 +1,4 @@ -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.Design { internal enum ColorPalette { diff --git a/src/Bonsai.ML.Design/EllipseHelper.cs b/src/Bonsai.ML.Design/EllipseHelper.cs new file mode 100644 index 00000000..42ee598c --- /dev/null +++ b/src/Bonsai.ML.Design/EllipseHelper.cs @@ -0,0 +1,66 @@ +using MathNet.Numerics.LinearAlgebra; +using System; + +namespace Bonsai.ML.Design +{ + /// + /// Provides helper methods to compute ellipse parameters from a covariance matrix. + /// + public static class EllipseHelper + { + /// + /// Computes the ellipse parameters from the specified covariance matrix. + /// + /// The variance of the x axis. + /// The variance of the y axis. + /// The covariance between the x and y axes. + public static EllipseParameters GetEllipseParameters(double xVar, double yVar, double xyCov) + { + var covariance = Matrix.Build.DenseOfArray(new double[,] { + { + xVar, + xyCov + }, + { + xyCov, + yVar + }, + }); + + var evd = covariance.Evd(); + var evals = evd.EigenValues.Real(); + evals = evals.PointwiseAbsoluteMaximum(0); + var evecs = evd.EigenVectors; + + double angle = Math.Atan2(evecs[1, 0], evecs[0, 0]); + + return new EllipseParameters + { + Angle = angle, + MajorAxis = Math.Sqrt(evals[0]), + MinorAxis = Math.Sqrt(evals[1]), + }; + } + } + + /// + /// Represents the parameters of an ellipse. + /// + public class EllipseParameters + { + /// + /// Gets or sets the angle of the ellipse. + /// + public double Angle { get; set; } + + /// + /// Gets or sets the major axis of the ellipse. + /// + public double MajorAxis { get; set; } + + /// + /// Gets or sets the minor axis of the ellipse. + /// + public double MinorAxis { get; set; } + } +} diff --git a/src/Bonsai.ML.Visualizers/HeatMapSeriesOxyPlotBase.cs b/src/Bonsai.ML.Design/HeatMapSeriesOxyPlotBase.cs similarity index 59% rename from src/Bonsai.ML.Visualizers/HeatMapSeriesOxyPlotBase.cs rename to src/Bonsai.ML.Design/HeatMapSeriesOxyPlotBase.cs index ee80be9b..e9ddf640 100644 --- a/src/Bonsai.ML.Visualizers/HeatMapSeriesOxyPlotBase.cs +++ b/src/Bonsai.ML.Design/HeatMapSeriesOxyPlotBase.cs @@ -7,9 +7,12 @@ using OxyPlot.Axes; using System.Collections.Generic; -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.Design { - internal class HeatMapSeriesOxyPlotBase : UserControl + /// + /// Provides a user control to display 2D data as a heatmap using OxyPlot. + /// + public class HeatMapSeriesOxyPlotBase : UserControl { private PlotView view; private PlotModel model; @@ -25,9 +28,14 @@ internal class HeatMapSeriesOxyPlotBase : UserControl private ToolStripLabel renderMethodLabel; private int _renderMethodSelectedIndex; private HeatMapRenderMethod renderMethod = HeatMapRenderMethod.Bitmap; - private StatusStrip statusStrip; + private ToolStripTextBox maxValueTextBox; + private ToolStripLabel maxValueLabel; + + private ToolStripTextBox minValueTextBox; + private ToolStripLabel minValueLabel; + private int _numColors = 100; /// @@ -35,12 +43,24 @@ internal class HeatMapSeriesOxyPlotBase : UserControl /// public event EventHandler PaletteComboBoxValueChanged; + /// + /// Gets the palette combobox. + /// public ToolStripComboBox PaletteComboBox => paletteComboBox; + /// + /// Event handler which can be used to hook into events generated when the render method combobox values have changed. + /// public event EventHandler RenderMethodComboBoxValueChanged; + /// + /// Gets the render method combobox. + /// public ToolStripComboBox RenderMethodComboBox => renderMethodComboBox; + /// + /// Gets the status strip control. + /// public StatusStrip StatusStrip => statusStrip; /// @@ -88,24 +108,93 @@ private void Initialize() InitializeColorPalette(); InitializeRenderMethod(); + InitializeColorAxisValues(); statusStrip = new StatusStrip { - Visible = false + Visible = false, }; - statusStrip.Items.AddRange(new ToolStripItem[] { + var toolStripItems = new ToolStripItem[] { paletteLabel, paletteComboBox, renderMethodLabel, - renderMethodComboBox - }); + renderMethodComboBox, + maxValueLabel, + maxValueTextBox, + minValueLabel, + minValueTextBox + }; + + ToolStripDropDownButton visualizerPropertiesButton = new ToolStripDropDownButton("Visualizer Properties"); + + foreach (var item in toolStripItems) + { + visualizerPropertiesButton.DropDownItems.Add(item); + } + + statusStrip.Items.Add(visualizerPropertiesButton); Controls.Add(statusStrip); view.MouseClick += new MouseEventHandler(onMouseClick); AutoScaleDimensions = new SizeF(6F, 13F); } + private void InitializeColorAxisValues() + { + maxValueLabel = new ToolStripLabel + { + Text = "Maximum Value:", + AutoSize = true + }; + + maxValueTextBox = new ToolStripTextBox() + { + Name = "maxValue", + AutoSize = true, + Text = "auto", + }; + + maxValueTextBox.TextChanged += (sender, e) => + { + if (double.TryParse(maxValueTextBox.Text, out double maxValue)) + { + colorAxis.Maximum = maxValue; + } + else + { + colorAxis.Maximum = heatMapSeries.MaxValue; + } + UpdatePlot(); + }; + + minValueLabel = new ToolStripLabel + { + Text = "Minimum Value:", + AutoSize = true + }; + + minValueTextBox = new ToolStripTextBox() + { + Name = "minValue", + AutoSize = true, + Text = "auto", + }; + + minValueTextBox.TextChanged += (sender, e) => + { + if (double.TryParse(minValueTextBox.Text, out double minValue)) + { + colorAxis.Minimum = minValue; + } + else + { + colorAxis.Minimum = heatMapSeries.MinValue; + } + UpdatePlot(); + }; + } + private void InitializeColorPalette() { paletteLabel = new ToolStripLabel @@ -116,8 +205,7 @@ private void InitializeColorPalette() paletteComboBox = new ToolStripComboBox() { - Name = "palette", - AutoSize = true, + Name = "palette" }; foreach (var value in Enum.GetValues(typeof(ColorPalette))) @@ -159,8 +247,7 @@ private void InitializeRenderMethod() renderMethodComboBox = new ToolStripComboBox() { - Name = "renderMethod", - AutoSize = true, + Name = "renderMethod" }; foreach (var value in Enum.GetValues(typeof(HeatMapRenderMethod))) @@ -198,6 +285,23 @@ private void onMouseClick(object sender, MouseEventArgs e) } } + /// + /// Method to update the heatmap series with new data. + /// + /// The data to be displayed. + public void UpdateHeatMapSeries(double[,] data) + { + heatMapSeries.Data = data; + } + + /// + /// Method to update the heatmap series with new data. + /// + /// The minimum x value. + /// The maximum x value. + /// The minimum y value. + /// The maximum y value. + /// The data to be displayed. public void UpdateHeatMapSeries(double x0, double x1, double y0, double y1, double[,] data) { heatMapSeries.X0 = x0; @@ -207,6 +311,9 @@ public void UpdateHeatMapSeries(double x0, double x1, double y0, double y1, doub heatMapSeries.Data = data; } + /// + /// Method to update the plot. + /// public void UpdatePlot() { model.InvalidatePlot(true); @@ -214,20 +321,20 @@ public void UpdatePlot() private static readonly Dictionary> paletteLookup = new Dictionary> { - { ColorPalette.Cividis, (numColors) => OxyPalettes.Cividis(numColors) }, - { ColorPalette.Inferno, (numColors) => OxyPalettes.Inferno(numColors) }, - { ColorPalette.Viridis, (numColors) => OxyPalettes.Viridis(numColors) }, - { ColorPalette.Magma, (numColors) => OxyPalettes.Magma(numColors) }, - { ColorPalette.Plasma, (numColors) => OxyPalettes.Plasma(numColors) }, - { ColorPalette.BlackWhiteRed, (numColors) => OxyPalettes.BlackWhiteRed(numColors) }, - { ColorPalette.BlueWhiteRed, (numColors) => OxyPalettes.BlueWhiteRed(numColors) }, - { ColorPalette.Cool, (numColors) => OxyPalettes.Cool(numColors) }, - { ColorPalette.Gray, (numColors) => OxyPalettes.Gray(numColors) }, - { ColorPalette.Hot, (numColors) => OxyPalettes.Hot(numColors) }, - { ColorPalette.Hue, (numColors) => OxyPalettes.Hue(numColors) }, - { ColorPalette.HueDistinct, (numColors) => OxyPalettes.HueDistinct(numColors) }, - { ColorPalette.Jet, (numColors) => OxyPalettes.Jet(numColors) }, - { ColorPalette.Rainbow, (numColors) => OxyPalettes.Rainbow(numColors) }, + { ColorPalette.Cividis, OxyPalettes.Cividis }, + { ColorPalette.Inferno, OxyPalettes.Inferno }, + { ColorPalette.Viridis, OxyPalettes.Viridis }, + { ColorPalette.Magma, OxyPalettes.Magma }, + { ColorPalette.Plasma, OxyPalettes.Plasma }, + { ColorPalette.BlackWhiteRed, OxyPalettes.BlackWhiteRed }, + { ColorPalette.BlueWhiteRed, OxyPalettes.BlueWhiteRed }, + { ColorPalette.Cool, OxyPalettes.Cool }, + { ColorPalette.Gray, OxyPalettes.Gray }, + { ColorPalette.Hot, OxyPalettes.Hot }, + { ColorPalette.Hue, OxyPalettes.Hue }, + { ColorPalette.HueDistinct, OxyPalettes.HueDistinct }, + { ColorPalette.Jet, OxyPalettes.Jet }, + { ColorPalette.Rainbow, OxyPalettes.Rainbow }, }; } } diff --git a/src/Bonsai.ML.Visualizers/MultidimensionalArrayVisualizer.cs b/src/Bonsai.ML.Design/MultidimensionalArrayVisualizer.cs similarity index 80% rename from src/Bonsai.ML.Visualizers/MultidimensionalArrayVisualizer.cs rename to src/Bonsai.ML.Design/MultidimensionalArrayVisualizer.cs index 6977f8bd..397d947e 100644 --- a/src/Bonsai.ML.Visualizers/MultidimensionalArrayVisualizer.cs +++ b/src/Bonsai.ML.Design/MultidimensionalArrayVisualizer.cs @@ -1,26 +1,13 @@ using System; using System.Windows.Forms; -using System.Collections.Generic; -using System.Reflection; -using Bonsai; using Bonsai.Design; -using Bonsai.ML.Visualizers; -using Bonsai.ML.LinearDynamicalSystems; -using Bonsai.ML.LinearDynamicalSystems.LinearRegression; -using System.Drawing; -using System.Reactive; -using Bonsai.Reactive; -using Bonsai.Expressions; -using OxyPlot; -[assembly: TypeVisualizer(typeof(MultidimensionalArrayVisualizer), Target = typeof(double[,]))] - -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.Design { - /// - /// Provides a type visualizer to display the state components of a Kalman Filter kinematics model. + /// Provides a type visualizer to display multi dimensional array data as a heatmap. /// + [TypeVisualizer(typeof(MultidimensionalArrayVisualizer), Target = typeof(double[,]))] public class MultidimensionalArrayVisualizer : DialogTypeVisualizer { /// diff --git a/src/Bonsai.ML.Visualizers/Properties/launchSettings.json b/src/Bonsai.ML.Design/Properties/launchSettings.json similarity index 100% rename from src/Bonsai.ML.Visualizers/Properties/launchSettings.json rename to src/Bonsai.ML.Design/Properties/launchSettings.json diff --git a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs b/src/Bonsai.ML.Design/TimeSeriesOxyPlotBase.cs similarity index 97% rename from src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs rename to src/Bonsai.ML.Design/TimeSeriesOxyPlotBase.cs index 7a252623..1d234eb3 100644 --- a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs +++ b/src/Bonsai.ML.Design/TimeSeriesOxyPlotBase.cs @@ -7,9 +7,12 @@ using OxyPlot.Axes; using System.Collections; -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.Design { - internal class TimeSeriesOxyPlotBase : UserControl + /// + /// Provides a user control to display time series data using OxyPlot. + /// + public class TimeSeriesOxyPlotBase : UserControl { private readonly PlotView view; private readonly PlotModel model; diff --git a/src/Bonsai.ML.HiddenMarkovModels.Design/Bonsai.ML.HiddenMarkovModels.Design.csproj b/src/Bonsai.ML.HiddenMarkovModels.Design/Bonsai.ML.HiddenMarkovModels.Design.csproj new file mode 100644 index 00000000..ae086476 --- /dev/null +++ b/src/Bonsai.ML.HiddenMarkovModels.Design/Bonsai.ML.HiddenMarkovModels.Design.csproj @@ -0,0 +1,16 @@ + + + Bonsai.ML.HiddenMarkovModels.Design + A package for visualizing data from the Bonsai.ML.HiddenMarkovModels package. + Bonsai Rx ML Machine Learning Hidden Markov Models Design + net472 + true + + + + + + + + + \ No newline at end of file diff --git a/src/Bonsai.ML.Visualizers/GaussianObservationsStatisticsClustersVisualizer.cs b/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsClustersVisualizer.cs similarity index 87% rename from src/Bonsai.ML.Visualizers/GaussianObservationsStatisticsClustersVisualizer.cs rename to src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsClustersVisualizer.cs index 0393b837..d5400317 100644 --- a/src/Bonsai.ML.Visualizers/GaussianObservationsStatisticsClustersVisualizer.cs +++ b/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsClustersVisualizer.cs @@ -3,20 +3,19 @@ using System.Collections.Generic; using Bonsai; using Bonsai.Design; -using Bonsai.ML.Visualizers; -using Bonsai.ML.HiddenMarkovModels.Observations; +using Bonsai.ML.Design; using OxyPlot; using OxyPlot.Series; using OxyPlot.Axes; using OxyPlot.WindowsForms; -using MathNet.Numerics.LinearAlgebra; -[assembly: TypeVisualizer(typeof(GaussianObservationsStatisticsClustersVisualizer), Target = typeof(GaussianObservationsStatistics))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.HiddenMarkovModels.Design.GaussianObservationsStatisticsClustersVisualizer), + Target = typeof(Bonsai.ML.HiddenMarkovModels.Observations.GaussianObservationsStatistics))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.HiddenMarkovModels.Design { /// - /// Provides a type visualizer of to display how the observations + /// Provides a type visualizer of to display how the observations /// cluster with respect to the mean and covariance of each state of an HMM with gaussian observations model. /// public class GaussianObservationsStatisticsClustersVisualizer : DialogTypeVisualizer @@ -148,7 +147,7 @@ public override void Load(IServiceProvider provider) /// public override void Show(object value) { - if (value is GaussianObservationsStatistics gaussianObservationsStatistics) + if (value is Observations.GaussianObservationsStatistics gaussianObservationsStatistics) { var statesCount = gaussianObservationsStatistics.Means.GetLength(0); @@ -245,40 +244,20 @@ public override void Show(object value) var yVar = gaussianObservationsStatistics.CovarianceMatrices[i, dimension2SelectedIndex, dimension2SelectedIndex]; var xyCov = gaussianObservationsStatistics.CovarianceMatrices[i, dimension2SelectedIndex, dimension1SelectedIndex]; - var covariance = Matrix.Build.DenseOfArray(new double[,] { - { - xVar, - xyCov - }, - { - xyCov, - yVar - }, - }); - - var evd = covariance.Evd(); - var evals = evd.EigenValues.Real(); - evals = evals.PointwiseAbsoluteMaximum(0); - var evecs = evd.EigenVectors; - - double angle = Math.Atan2(evecs[1, 0], evecs[0, 0]); + var ellipseParameters = EllipseHelper.GetEllipseParameters(xVar, yVar, xyCov); for (int j = 1; j < 4; j++) { - - var majorAxis = j * Math.Sqrt(evals[0]); - var minorAxis = j * Math.Sqrt(evals[1]); - var points = new List(); int numPoints = 100; for (int k = 0; k < numPoints + 1; k++) { double theta = 2 * Math.PI * k / numPoints; - double x = majorAxis * Math.Cos(theta); - double y = minorAxis * Math.Sin(theta); + double x = j * ellipseParameters.MajorAxis * Math.Cos(theta); + double y = j * ellipseParameters.MinorAxis * Math.Sin(theta); - double xRot = x * Math.Cos(angle) - y * Math.Sin(angle); - double yRot = x * Math.Sin(angle) + y * Math.Cos(angle); + double xRot = x * Math.Cos(ellipseParameters.Angle) - y * Math.Sin(ellipseParameters.Angle); + double yRot = x * Math.Sin(ellipseParameters.Angle) + y * Math.Cos(ellipseParameters.Angle); points.Add(new DataPoint(xMean + xRot, yMean + yRot)); } diff --git a/src/Bonsai.ML.Visualizers/GaussianObservationsStatisticsVisualizer.cs b/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsVisualizer.cs similarity index 84% rename from src/Bonsai.ML.Visualizers/GaussianObservationsStatisticsVisualizer.cs rename to src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsVisualizer.cs index 64a5884a..775ff3ec 100644 --- a/src/Bonsai.ML.Visualizers/GaussianObservationsStatisticsVisualizer.cs +++ b/src/Bonsai.ML.HiddenMarkovModels.Design/GaussianObservationsStatisticsVisualizer.cs @@ -3,17 +3,17 @@ using System.Collections.Generic; using Bonsai; using Bonsai.Design; -using Bonsai.ML.Visualizers; -using Bonsai.ML.HiddenMarkovModels.Observations; +using Bonsai.ML.Design; using OxyPlot; using OxyPlot.Series; -[assembly: TypeVisualizer(typeof(GaussianObservationStatisticsVisualizer), Target = typeof(GaussianObservationsStatistics))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.HiddenMarkovModels.Design.GaussianObservationStatisticsVisualizer), + Target = typeof(Bonsai.ML.HiddenMarkovModels.Observations.GaussianObservationsStatistics))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.HiddenMarkovModels.Design { /// - /// Provides a type visualizer of to display the means and standard + /// Provides a type visualizer of to display the means and standard /// deviations of each state of an HMM with gaussian observations model. /// public class GaussianObservationStatisticsVisualizer : DialogTypeVisualizer @@ -21,7 +21,7 @@ public class GaussianObservationStatisticsVisualizer : DialogTypeVisualizer private BarSeriesOxyPlotBase Plot; private List allBarSeries = null; - private GaussianObservationsStatistics shown = null; + private Observations.GaussianObservationsStatistics shown = null; /// public override void Load(IServiceProvider provider) @@ -49,7 +49,7 @@ public override void Load(IServiceProvider provider) /// public override void Show(object value) { - if (value is GaussianObservationsStatistics statistics && statistics != shown) + if (value is Observations.GaussianObservationsStatistics statistics && statistics != shown) { if (statistics.Means == null || statistics.StdDevs == null) { diff --git a/src/Bonsai.ML.HiddenMarkovModels.Design/Properties/launchSettings.json b/src/Bonsai.ML.HiddenMarkovModels.Design/Properties/launchSettings.json new file mode 100644 index 00000000..b48bcfa9 --- /dev/null +++ b/src/Bonsai.ML.HiddenMarkovModels.Design/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "Bonsai": { + "commandName": "Executable", + "executablePath": "$(registry:HKEY_CURRENT_USER\\Software\\Bonsai Foundation\\Bonsai@InstallDir)Bonsai.exe", + "commandLineArgs": "--lib:\"$(TargetDir).\"", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/src/Bonsai.ML.Visualizers/StateProbabilityVisualizer.cs b/src/Bonsai.ML.HiddenMarkovModels.Design/StateProbabilityVisualizer.cs similarity index 90% rename from src/Bonsai.ML.Visualizers/StateProbabilityVisualizer.cs rename to src/Bonsai.ML.HiddenMarkovModels.Design/StateProbabilityVisualizer.cs index 13ddf4fd..20301512 100644 --- a/src/Bonsai.ML.Visualizers/StateProbabilityVisualizer.cs +++ b/src/Bonsai.ML.HiddenMarkovModels.Design/StateProbabilityVisualizer.cs @@ -4,15 +4,15 @@ using System.Linq; using Bonsai; using Bonsai.Design; -using Bonsai.ML.Visualizers; -using Bonsai.ML.HiddenMarkovModels; +using Bonsai.ML.Design; using OxyPlot; using OxyPlot.Series; using OxyPlot.Axes; -[assembly: TypeVisualizer(typeof(StateProbabilityVisualizer), Target = typeof(StateProbability))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.HiddenMarkovModels.Design.StateProbabilityVisualizer), + Target = typeof(Bonsai.ML.HiddenMarkovModels.StateProbability))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.HiddenMarkovModels.Design { /// /// Provides a type visualizer of to display the probabilities @@ -67,7 +67,7 @@ public override void Show(object value) var paddingPercentage = 0.05; var nStates = stateProbability.Probabilities.Length; - CategoryAxis categoryAxis = (CategoryAxis)Plot.xAxis; + CategoryAxis categoryAxis = (CategoryAxis)Plot.XAxis; categoryAxis.ItemsSource = Enumerable.Range(0, nStates); for (int i = 0; i < nStates; i++) diff --git a/src/Bonsai.ML.LinearDynamicalSystems.Design/Bonsai.ML.LinearDynamicalSystems.Design.csproj b/src/Bonsai.ML.LinearDynamicalSystems.Design/Bonsai.ML.LinearDynamicalSystems.Design.csproj new file mode 100644 index 00000000..e2adc8f5 --- /dev/null +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/Bonsai.ML.LinearDynamicalSystems.Design.csproj @@ -0,0 +1,20 @@ + + + + Bonsai.ML.LinearDynamicalSystems.Design + A package for visualizing data from the Bonsai.ML.LinearDynamicalSystems package. + Bonsai Rx ML Machine Learning LinearDynamicalSystems LDS Design + net472 + true + + + + + + + + + + + + diff --git a/src/Bonsai.ML.Visualizers/ForecastImageOverlay.cs b/src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastImageOverlay.cs similarity index 66% rename from src/Bonsai.ML.Visualizers/ForecastImageOverlay.cs rename to src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastImageOverlay.cs index c5a87954..f9593fbc 100644 --- a/src/Bonsai.ML.Visualizers/ForecastImageOverlay.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastImageOverlay.cs @@ -1,17 +1,16 @@ +using Bonsai; using Bonsai.Design; using Bonsai.Vision.Design; -using Bonsai; -using Bonsai.ML.Visualizers; -using Bonsai.ML.LinearDynamicalSystems.Kinematics; +using Bonsai.ML.Design; using System; using System.Collections.Generic; using OpenCV.Net; -using MathNet.Numerics.LinearAlgebra; using OxyPlot; -[assembly: TypeVisualizer(typeof(ForecastImageOverlay), Target = typeof(MashupSource))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.LinearDynamicalSystems.Design.ForecastImageOverlay), + Target = typeof(Bonsai.ML.LinearDynamicalSystems.Kinematics.Forecast))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.LinearDynamicalSystems.Design { /// /// Provides a mashup visualizer to display the forecast of a Kalman Filter kinematics model overtime of an ImageMashupVisualizer. @@ -33,8 +32,8 @@ public override void Show(object value) overlay = new IplImage(size, depth, channels); var alpha = 0.1; - Forecast forecast = (Forecast)value; - List forecastResults = forecast.ForecastResults; + Kinematics.Forecast forecast = (Kinematics.Forecast)value; + List forecastResults = forecast.ForecastResults; for (int i = 0; i < forecastResults.Count; i++) { @@ -50,26 +49,17 @@ public override void Show(object value) double yVar = kinematicState.Position.Y.Variance; double xyCov = kinematicState.Position.Covariance; - var covariance = Matrix.Build.DenseOfArray(new double[,] { - { xVar, xyCov }, - { xyCov, yVar } - }); - - var evd = covariance.Evd(); - var evals = evd.EigenValues.Real(); - var evecs = evd.EigenVectors; - - double angle = Math.Atan2(evecs[1, 0], evecs[0, 0]) * 180 / Math.PI; + EllipseParameters ellipseParameters = EllipseHelper.GetEllipseParameters(xVar, yVar, xyCov); Size axes = new Size { - Width = (int)(2 * Math.Sqrt(evals[0])), - Height = (int)(2 * Math.Sqrt(evals[1])) + Width = (int)(2 * ellipseParameters.MajorAxis), + Height = (int)(2 * ellipseParameters.MinorAxis) }; OxyColor color = OxyColors.Yellow; - CV.Ellipse(overlay, center, axes, angle, 0, 360, new Scalar(color.B, color.G, color.R, color.A), -1); + CV.Ellipse(overlay, center, axes, ellipseParameters.Angle, 0, 360, new Scalar(color.B, color.G, color.R, color.A), -1); } CV.AddWeighted(image, 1 - alpha, overlay, alpha, 1, image); diff --git a/src/Bonsai.ML.Visualizers/ForecastPlotOverlay.cs b/src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastPlotOverlay.cs similarity index 90% rename from src/Bonsai.ML.Visualizers/ForecastPlotOverlay.cs rename to src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastPlotOverlay.cs index 26a48a65..b586476a 100644 --- a/src/Bonsai.ML.Visualizers/ForecastPlotOverlay.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastPlotOverlay.cs @@ -1,19 +1,19 @@ -using Bonsai.Design; using Bonsai; -using Bonsai.ML.Visualizers; -using Bonsai.ML.LinearDynamicalSystems; +using Bonsai.Design; using Bonsai.ML.LinearDynamicalSystems.Kinematics; +using Bonsai.ML.Design; using System; using System.Collections.Generic; using OxyPlot.Series; using OxyPlot; -[assembly: TypeVisualizer(typeof(ForecastPlotOverlay), Target = typeof(MashupSource))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.LinearDynamicalSystems.Design.ForecastImageOverlay), + Target = typeof(MashupSource))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.LinearDynamicalSystems.Design { /// - /// Provides a mashup visualizer to display the forecast of a Kalman Filter kinematics model overtime of a KinematicStateVisualizer. + /// Provides a mashup visualizer to display the forecast of a Kalman Filter kinematics model alongside the kinematic state. /// public class ForecastPlotOverlay : DialogTypeVisualizer { diff --git a/src/Bonsai.ML.Visualizers/ForecastVisualizer.cs b/src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastVisualizer.cs similarity index 93% rename from src/Bonsai.ML.Visualizers/ForecastVisualizer.cs rename to src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastVisualizer.cs index 856f412b..645786b0 100644 --- a/src/Bonsai.ML.Visualizers/ForecastVisualizer.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/ForecastVisualizer.cs @@ -3,16 +3,15 @@ using System.Collections.Generic; using Bonsai; using Bonsai.Design; -using Bonsai.ML.Visualizers; -using Bonsai.ML.LinearDynamicalSystems.Kinematics; using OxyPlot; using System.Reactive; using System.Linq; using System.Reactive.Linq; -[assembly: TypeVisualizer(typeof(ForecastVisualizer), Target = typeof(Forecast))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.LinearDynamicalSystems.Design.ForecastVisualizer), + Target = typeof(Bonsai.ML.LinearDynamicalSystems.Kinematics.Forecast))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.LinearDynamicalSystems.Design { /// /// Provides a type visualizer to display the forecast of a Kalman Filter kinematics model. @@ -22,14 +21,14 @@ public class ForecastVisualizer : BufferedVisualizer private int rowCount = 3; private int columnCount = 2; - private string[] labels = new string[] { + private string[] labels = [ "Forecast Position X", "Forecast Position Y", "Forecast Velocity X", "Forecast Velocity Y", "Forecast Acceleration X", "Forecast Acceleration Y" - }; + ]; private List componentVisualizers = new(); private TableLayoutPanel container; @@ -88,7 +87,7 @@ protected override void ShowBuffer(IList> values) if (values.Count == 0) return; var latestForecast = values.Last(); var timestamp = latestForecast.Timestamp; - var forecast = (Forecast)latestForecast.Value; + var forecast = (Kinematics.Forecast)latestForecast.Value; var futureTime = timestamp; List> positionX = new(); diff --git a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs b/src/Bonsai.ML.LinearDynamicalSystems.Design/KinematicStateVisualizer.cs similarity index 89% rename from src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs rename to src/Bonsai.ML.LinearDynamicalSystems.Design/KinematicStateVisualizer.cs index 8409eab1..ed07270d 100644 --- a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/KinematicStateVisualizer.cs @@ -1,7 +1,5 @@ -using Bonsai.Design; using Bonsai; -using Bonsai.ML.LinearDynamicalSystems.Kinematics; -using Bonsai.ML.Visualizers; +using Bonsai.Design; using System.Collections.Generic; using System; using System.Windows.Forms; @@ -9,32 +7,32 @@ using System.Linq; using System.Reactive; -[assembly: TypeVisualizer(typeof(KinematicStateVisualizer), Target = typeof(KinematicState))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.LinearDynamicalSystems.Design.KinematicStateVisualizer), + Target = typeof(Bonsai.ML.LinearDynamicalSystems.Kinematics.KinematicState))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.LinearDynamicalSystems.Design { - /// /// Provides a type visualizer to display the state components of a Kalman Filter Kinematics model. /// public class KinematicStateVisualizer : MashupVisualizer { private TableLayoutPanel container; - private int updateFrequency = 1000 / 50; + private int updateFrequency = 20; private bool resetAxes = true; private int rowCount = 3; private int columnCount = 2; internal List ComponentVisualizers { get; private set; } = new(); - internal string[] Labels = new string[] { + internal string[] Labels = [ "Position X", "Position Y", "Velocity X", "Velocity Y", "Acceleration X", "Acceleration Y" - }; + ]; /// public override void Load(IServiceProvider provider) @@ -97,12 +95,12 @@ public void ShowBuffer(IList> values) foreach (var value in values) { - positionX.Add(new Timestamped(((KinematicState)value.Value).Position.X, value.Timestamp)); - positionY.Add(new Timestamped(((KinematicState)value.Value).Position.Y, value.Timestamp)); - velocityX.Add(new Timestamped(((KinematicState)value.Value).Velocity.X, value.Timestamp)); - velocityY.Add(new Timestamped(((KinematicState)value.Value).Velocity.Y, value.Timestamp)); - accelerationX.Add(new Timestamped(((KinematicState)value.Value).Acceleration.X, value.Timestamp)); - accelerationY.Add(new Timestamped(((KinematicState)value.Value).Acceleration.Y, value.Timestamp)); + positionX.Add(new Timestamped(((Kinematics.KinematicState)value.Value).Position.X, value.Timestamp)); + positionY.Add(new Timestamped(((Kinematics.KinematicState)value.Value).Position.Y, value.Timestamp)); + velocityX.Add(new Timestamped(((Kinematics.KinematicState)value.Value).Velocity.X, value.Timestamp)); + velocityY.Add(new Timestamped(((Kinematics.KinematicState)value.Value).Velocity.Y, value.Timestamp)); + accelerationX.Add(new Timestamped(((Kinematics.KinematicState)value.Value).Acceleration.X, value.Timestamp)); + accelerationY.Add(new Timestamped(((Kinematics.KinematicState)value.Value).Acceleration.Y, value.Timestamp)); } ComponentVisualizers[0].ShowDataBuffer(positionX, resetAxes); diff --git a/src/Bonsai.ML.Visualizers/MultivariatePDFVisualizer.cs b/src/Bonsai.ML.LinearDynamicalSystems.Design/MultivariatePDFVisualizer.cs similarity index 81% rename from src/Bonsai.ML.Visualizers/MultivariatePDFVisualizer.cs rename to src/Bonsai.ML.LinearDynamicalSystems.Design/MultivariatePDFVisualizer.cs index 4b9012c1..a43befe3 100644 --- a/src/Bonsai.ML.Visualizers/MultivariatePDFVisualizer.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/MultivariatePDFVisualizer.cs @@ -1,23 +1,16 @@ using System; using System.Windows.Forms; -using System.Collections.Generic; -using System.Reflection; using Bonsai; using Bonsai.Design; -using Bonsai.ML.Visualizers; -using Bonsai.ML.LinearDynamicalSystems; -using Bonsai.ML.LinearDynamicalSystems.LinearRegression; -using System.Drawing; -using System.Reactive; -using Bonsai.Reactive; +using Bonsai.ML.Design; -[assembly: TypeVisualizer(typeof(MultivariatePDFVisualizer), Target = typeof(MultivariatePDF))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.LinearDynamicalSystems.Design.MultivariatePDFVisualizer), + Target = typeof(Bonsai.ML.LinearDynamicalSystems.LinearRegression.MultivariatePDF))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.LinearDynamicalSystems.Design { - /// - /// Provides a type visualizer to display the state components of a Kalman Filter kinematics model. + /// Provides a type visualizer to display a multivariate probability distribution as a heatmap. /// public class MultivariatePDFVisualizer : DialogTypeVisualizer { @@ -54,7 +47,7 @@ public override void Load(IServiceProvider provider) /// public override void Show(object value) { - var pdf = (MultivariatePDF)value; + var pdf = (LinearRegression.MultivariatePDF)value; Plot.UpdateHeatMapSeries( pdf.GridParameters.X0 - (1 / 2 * pdf.GridParameters.XSteps), pdf.GridParameters.X1 - (1 / 2 * pdf.GridParameters.XSteps), diff --git a/src/Bonsai.ML.LinearDynamicalSystems.Design/Properties/launchSettings.json b/src/Bonsai.ML.LinearDynamicalSystems.Design/Properties/launchSettings.json new file mode 100644 index 00000000..b48bcfa9 --- /dev/null +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "profiles": { + "Bonsai": { + "commandName": "Executable", + "executablePath": "$(registry:HKEY_CURRENT_USER\\Software\\Bonsai Foundation\\Bonsai@InstallDir)Bonsai.exe", + "commandLineArgs": "--lib:\"$(TargetDir).\"", + "nativeDebugging": true + } + } +} \ No newline at end of file diff --git a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs b/src/Bonsai.ML.LinearDynamicalSystems.Design/StateComponentVisualizer.cs similarity index 94% rename from src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs rename to src/Bonsai.ML.LinearDynamicalSystems.Design/StateComponentVisualizer.cs index 8d83fcd9..ca292d97 100644 --- a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs +++ b/src/Bonsai.ML.LinearDynamicalSystems.Design/StateComponentVisualizer.cs @@ -3,16 +3,16 @@ using System.Collections.Generic; using Bonsai; using Bonsai.Design; -using Bonsai.ML.Visualizers; -using Bonsai.ML.LinearDynamicalSystems; +using Bonsai.ML.Design; using OxyPlot; using System.Reactive; using OxyPlot.Series; using System.Linq; -[assembly: TypeVisualizer(typeof(StateComponentVisualizer), Target = typeof(StateComponent))] +[assembly: TypeVisualizer(typeof(Bonsai.ML.LinearDynamicalSystems.Design.StateComponentVisualizer), + Target = typeof(Bonsai.ML.LinearDynamicalSystems.StateComponent))] -namespace Bonsai.ML.Visualizers +namespace Bonsai.ML.LinearDynamicalSystems.Design { /// /// Provides a type visualizer to display the state components of a Kalman Filter kinematics model.