From 496b9774ac6234da98a728a0bc3e1baebcfffc3b Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 10 May 2024 16:33:45 +0100 Subject: [PATCH 01/14] Update timeseries oxyplot base for improved usability across classes --- .../TimeSeriesOxyPlotBase.cs | 191 +++++++++++------- 1 file changed, 116 insertions(+), 75 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs b/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs index 2f28fd17..0b494c8e 100644 --- a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs +++ b/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs @@ -13,26 +13,14 @@ internal class TimeSeriesOxyPlotBase : UserControl { private PlotView view; private PlotModel model; - private ToolStripComboBox comboBox; - private ToolStripLabel label; + private OxyColor defaultLineSeriesColor = OxyColors.Blue; + private OxyColor defaultAreaSeriesColor = OxyColors.LightBlue; - private string _lineSeriesName; - private string _areaSeriesName; - private int _selectedIndex; - private IEnumerable _dataSource; - - private LineSeries lineSeries; - private AreaSeries areaSeries; private Axis xAxis; private Axis yAxis; private StatusStrip statusStrip; - /// - /// Event handler which can be used to hook into events generated when the combobox values have changed. - /// - public event EventHandler ComboBoxValueChanged; - /// /// DateTime value that determines the starting time of the data values. /// @@ -47,18 +35,16 @@ internal class TimeSeriesOxyPlotBase : UserControl public StatusStrip StatusStrip => statusStrip; + /// + /// Buffer the data beyond the capacity. + /// + public bool BufferData { get; set; } + /// /// Constructor of the TimeSeriesOxyPlotBase class. - /// Requires a line series name and an area series name. - /// Data source is optional, since pasing it to the constructor will populate the combobox and leave it empty otherwise. - /// The selected index is only needed when the data source is provided. /// - public TimeSeriesOxyPlotBase(string lineSeriesName, string areaSeriesName, IEnumerable dataSource = null, int selectedIndex = 0) + public TimeSeriesOxyPlotBase() { - _lineSeriesName = lineSeriesName; - _areaSeriesName = areaSeriesName; - _dataSource = dataSource; - _selectedIndex = selectedIndex; Initialize(); } @@ -72,17 +58,6 @@ private void Initialize() model = new PlotModel(); - lineSeries = new LineSeries { - Title = _lineSeriesName, - Color = OxyColors.Blue - }; - - areaSeries = new AreaSeries { - Title = _areaSeriesName, - Color = OxyColors.LightBlue, - Fill = OxyColor.FromArgb(100, 173, 216, 230) - }; - xAxis = new DateTimeAxis { Position = AxisPosition.Bottom, Title = "Time", @@ -102,9 +77,6 @@ private void Initialize() model.Axes.Add(xAxis); model.Axes.Add(yAxis); - model.Series.Add(lineSeries); - model.Series.Add(areaSeries); - view.Model = model; Controls.Add(view); @@ -113,17 +85,8 @@ private void Initialize() Visible = false }; - if (_dataSource != null) - { - InitializeComboBox(_dataSource); - - statusStrip.Items.AddRange(new ToolStripItem[] { - label, - comboBox, - }); - - view.MouseClick += new MouseEventHandler(onMouseClick); - } + view.MouseClick += new MouseEventHandler(onMouseClick); + Controls.Add(statusStrip); Controls.Add(statusStrip); @@ -138,66 +101,144 @@ private void onMouseClick(object sender, MouseEventArgs e) } } - private void InitializeComboBox(IEnumerable dataSource) + /// + /// Method to add a combobox with a label to the status strip. + /// Requires a string label, an enumerable data source, a selected index, and a callback method for the selected index changed event. + /// + public void AddComboBoxWithLabel(string label, IEnumerable dataSource, int selectedIndex, EventHandler onComboBoxSelectionChanged) { - label = new ToolStripLabel - { - Text = "State component:", - AutoSize = true, - }; - - comboBox = new ToolStripComboBox() - { - Name = "stateComponent", - AutoSize = true, - }; + ToolStripLabel toolStripLabel = new ToolStripLabel(label); + ToolStripComboBox toolStripComboBox = new ToolStripComboBox(); foreach (var value in dataSource) { - comboBox.Items.Add(value); + toolStripComboBox.Items.Add(value); } - - comboBox.SelectedIndexChanged += ComboBoxSelectedIndexChanged; - comboBox.SelectedIndex = _selectedIndex; + + toolStripComboBox.SelectedIndexChanged += onComboBoxSelectionChanged; + toolStripComboBox.SelectedIndex = selectedIndex; + + statusStrip.Items.AddRange(new ToolStripItem[] { + toolStripLabel, + toolStripComboBox + }); + } - private void ComboBoxSelectedIndexChanged(object sender, EventArgs e) + /// + /// Method to add a new line series to the data plot. + /// Requires a string for the name of the line series + /// Color of the line series is optional. + /// + public LineSeries AddNewLineSeries(string lineSeriesName, OxyColor? color = null) { - if (comboBox.SelectedIndex != _selectedIndex) - { - _selectedIndex = comboBox.SelectedIndex; - ComboBoxValueChanged?.Invoke(this, e); - } + OxyColor _color = color.HasValue ? color.Value : defaultLineSeriesColor; + LineSeries lineSeries = new LineSeries { + Title = lineSeriesName, + Color = _color + }; + model.Series.Add(lineSeries); + return lineSeries; } - public void AddToLineSeries(DateTime time, double mean) + /// + /// Method to add a new area series to the data plot. + /// Requires a string for the name of the area series + /// Optional parameters are color of the lines, fill color, and opacity. + /// Returns the new line series. + /// + public AreaSeries AddNewAreaSeries(string areaSeriesName, OxyColor? color = null, OxyColor? fill = null, byte opacity = 100) { - lineSeries.Points.Add(new DataPoint(DateTimeAxis.ToDouble(time), mean)); + OxyColor _color = color.HasValue ? color.Value : defaultAreaSeriesColor; + OxyColor _fill = fill.HasValue? fill.Value : OxyColor.FromArgb(opacity, _color.R, _color.G, _color.B); + AreaSeries areaSeries = new AreaSeries { + Title = areaSeriesName, + Color = _color, + Fill = _fill + }; + model.Series.Add(areaSeries); + return areaSeries; } - public void AddToAreaSeries(DateTime time, double mean, double variance) + /// + /// Method to add data to a line series. + /// Requires the line series, time, and value. + /// + public void AddToLineSeries(LineSeries lineSeries, DateTime time, double value) { - areaSeries.Points.Add(new DataPoint(DateTimeAxis.ToDouble(time), mean + variance)); - areaSeries.Points2.Add(new DataPoint(DateTimeAxis.ToDouble(time), mean - variance)); + if (!BufferData) + { + var timeCap = DateTimeAxis.ToDouble(time.AddSeconds(-Capacity)); + lineSeries.Points.RemoveAll(dataPoint => dataPoint.X < timeCap); + } + lineSeries.Points.Add(new DataPoint(DateTimeAxis.ToDouble(time), value)); } + /// + /// Method to add data to an area series. + /// Requires the area series, time, value1, and value2. + /// + public void AddToAreaSeries(AreaSeries areaSeries, DateTime time, double value1, double value2) + { + if (!BufferData) + { + var timeCap = DateTimeAxis.ToDouble(time.AddSeconds(-Capacity)); + areaSeries.Points.RemoveAll(dataPoint => dataPoint.X < timeCap); + areaSeries.Points2.RemoveAll(dataPoint => dataPoint.X < timeCap); + } + var curTime = DateTimeAxis.ToDouble(time); + areaSeries.Points.Add(new DataPoint(curTime, value1)); + areaSeries.Points2.Add(new DataPoint(curTime, value2)); + } + + /// + /// Set the minimum and maximum values to show along the x axis. + /// Requires the minTime and maxTime. + /// public void SetAxes(DateTime minTime, DateTime maxTime) { xAxis.Minimum = DateTimeAxis.ToDouble(minTime); xAxis.Maximum = DateTimeAxis.ToDouble(maxTime); } + /// + /// Method to update the plot. + /// public void UpdatePlot() { model.InvalidatePlot(true); } - public void ResetSeries() + /// + /// Method to reset the line series. + /// + public void ResetLineSeries(LineSeries lineSeries) { lineSeries.Points.Clear(); + } + + /// + /// Method to reset the area series. + /// + public void ResetAreaSeries(AreaSeries areaSeries) + { areaSeries.Points.Clear(); areaSeries.Points2.Clear(); + } + /// + /// Method to reset all series in the current PlotModel. + /// + public void ResetModelSeries() + { + model.Series.Clear(); + } + + /// + /// Method to reset the x and y axes to their default. + /// + public void ResetAxes() + { xAxis.Reset(); yAxis.Reset(); From 9ed4c7721a0dd4880926c87813d22252b8ad3548 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 10 May 2024 16:34:50 +0100 Subject: [PATCH 02/14] Updated kinematic component visualizer for new time series --- .../KinematicComponentVisualizer.cs | 68 ++++++++----------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs index 31ba029d..045d5752 100644 --- a/src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs @@ -9,6 +9,7 @@ using Bonsai.ML.LinearDynamicalSystems.Kinematics; using System.Drawing; using System.Reactive; +using OxyPlot.Series; [assembly: TypeVisualizer(typeof(KinematicComponentVisualizer), Target = typeof(KinematicComponent))] @@ -28,6 +29,10 @@ public class KinematicComponentVisualizer : BufferedVisualizer private TimeSeriesOxyPlotBase Plot; + private LineSeries lineSeries; + + private AreaSeries areaSeries; + /// /// The selected index of the state component to be visualized /// @@ -43,28 +48,31 @@ public class KinematicComponentVisualizer : BufferedVisualizer /// public int Capacity { get; set; } = 10; + /// + /// Buffer the data beyond the capacity. + /// + public bool BufferData { get; set; } = true; + /// public override void Load(IServiceProvider provider) { - var stateComponents = GetStateComponents(); - stateComponentProperty = typeof(KinematicComponent).GetProperty(stateComponents[selectedIndex]); - - Plot = new TimeSeriesOxyPlotBase( - lineSeriesName: "Mean", - areaSeriesName: "Variance", - dataSource: stateComponents, - selectedIndex: selectedIndex - ) + Plot = new TimeSeriesOxyPlotBase() { Size = Size, Capacity = Capacity, Dock = DockStyle.Fill, - StartTime = DateTime.Now + StartTime = DateTime.Now, + BufferData = BufferData }; - Plot.ResetSeries(); + lineSeries = Plot.AddNewLineSeries("Mean"); + areaSeries = Plot.AddNewAreaSeries("Variance"); - Plot.ComboBoxValueChanged += ComponentChanged; + Plot.ResetLineSeries(lineSeries); + Plot.ResetAreaSeries(areaSeries); + Plot.ResetAxes(); + + Plot.AddComboBoxWithLabel("State component:", KinematicsHelper.GetStateComponents(), selectedIndex, ComponentChanged); var visualizerService = (IDialogTypeVisualizerService)provider.GetService(typeof(IDialogTypeVisualizerService)); if (visualizerService != null) @@ -85,7 +93,8 @@ protected override void Show(DateTime time, object value) { _startTime = time; Plot.StartTime = _startTime.Value; - Plot.ResetSeries(); + // Plot.ResetSeries(); + } KinematicComponent kinematicComponent = (KinematicComponent)value; @@ -94,14 +103,16 @@ protected override void Show(DateTime time, object value) double variance = stateComponent.Variance; Plot.AddToLineSeries( + lineSeries: lineSeries, time: time, - mean: mean + value: mean ); Plot.AddToAreaSeries( + areaSeries: areaSeries, time: time, - mean: mean, - variance: variance + value1: mean + variance, + value2: mean - variance ); Plot.SetAxes(minTime: time.AddSeconds(-Capacity), maxTime: time); @@ -118,24 +129,6 @@ protected override void ShowBuffer(IList> values) } } - /// - /// Gets the names of the state components defined in the kinematic component class - /// - private List GetStateComponents() - { - List stateComponents = new List(); - - foreach (PropertyInfo property in typeof(KinematicComponent).GetProperties()) - { - if (property.PropertyType == typeof(StateComponent)) - { - stateComponents.Add(property.Name); - } - } - - return stateComponents; - } - /// public override void Unload() { @@ -146,18 +139,15 @@ public override void Unload() } } - /// - /// Callback function to update the visualizer when the selected component has changed - /// private void ComponentChanged(object sender, EventArgs e) { - var comboBox = Plot.ComboBox; + ToolStripComboBox comboBox = sender as ToolStripComboBox; selectedIndex = comboBox.SelectedIndex; var selectedName = comboBox.SelectedItem.ToString(); stateComponentProperty = typeof(KinematicComponent).GetProperty(selectedName); _startTime = null; - Plot.ResetSeries(); + Plot.ResetAxes(); } } } From 51c87f5234dccc55959ba020499641996764bd82 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 10 May 2024 16:35:41 +0100 Subject: [PATCH 03/14] Added visualizers for state component --- .../StateComponentVisualizer.cs | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs b/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs index fbdaf333..8e5a3afb 100644 --- a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs @@ -7,6 +7,7 @@ using Bonsai.ML.LinearDynamicalSystems; using System.Drawing; using System.Reactive; +using OxyPlot.Series; [assembly: TypeVisualizer(typeof(StateComponentVisualizer), Target = typeof(StateComponent))] @@ -22,31 +23,37 @@ public class StateComponentVisualizer : BufferedVisualizer private TimeSeriesOxyPlotBase Plot; - /// - /// Size of the window when loaded - /// - public Size Size { get; set; } = new Size(320, 240); + private LineSeries lineSeries; + + private AreaSeries areaSeries; /// /// Capacity or length of time shown along the x axis of the plot during automatic updating /// public int Capacity { get; set; } = 10; + /// + /// Buffer the data beyond the capacity. + /// + public bool BufferData { get; set; } = true; + /// public override void Load(IServiceProvider provider) { - Plot = new TimeSeriesOxyPlotBase( - lineSeriesName: "Mean", - areaSeriesName: "Variance" - ) + Plot = new TimeSeriesOxyPlotBase() { - Size = Size, Capacity = Capacity, Dock = DockStyle.Fill, - StartTime = DateTime.Now + StartTime = DateTime.Now, + BufferData = BufferData }; - Plot.ResetSeries(); + lineSeries = Plot.AddNewLineSeries("Mean"); + areaSeries = Plot.AddNewAreaSeries("Variance"); + + Plot.ResetLineSeries(lineSeries); + Plot.ResetAreaSeries(areaSeries); + Plot.ResetAxes(); var visualizerService = (IDialogTypeVisualizerService)provider.GetService(typeof(IDialogTypeVisualizerService)); if (visualizerService != null) @@ -67,7 +74,7 @@ protected override void Show(DateTime time, object value) { _startTime = time; Plot.StartTime = _startTime.Value; - Plot.ResetSeries(); + Plot.ResetAxes(); } StateComponent stateComponent = (StateComponent)value; @@ -75,14 +82,16 @@ protected override void Show(DateTime time, object value) double variance = stateComponent.Variance; Plot.AddToLineSeries( + lineSeries: lineSeries, time: time, - mean: mean + value: mean ); Plot.AddToAreaSeries( + areaSeries: areaSeries, time: time, - mean: mean, - variance: variance + value1: mean + variance, + value2: mean - variance ); Plot.SetAxes(minTime: time.AddSeconds(-Capacity), maxTime: time); From 8435542e4966a6205f5afa4cde1bad011c0cc013 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 10 May 2024 16:36:35 +0100 Subject: [PATCH 04/14] Added base visualizer for kinematic state which also serves as base for mashup --- .../KinematicStateVisualizer.cs | 203 ++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs diff --git a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs new file mode 100644 index 00000000..38138825 --- /dev/null +++ b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs @@ -0,0 +1,203 @@ +using Bonsai.Design; +using Bonsai; +using Bonsai.ML.LinearDynamicalSystems; +using Bonsai.ML.LinearDynamicalSystems.Kinematics; +using Bonsai.ML.Visualizers; +using System.Collections.Generic; +using System; +using System.Windows.Forms; +using System.Xml.Serialization; +using System.Reactive.Linq; +using OxyPlot.Series; +using System.Linq; +using System.Drawing; +using System.Reflection; + +[assembly: TypeVisualizer(typeof(KinematicStateVisualizer), Target = typeof(KinematicState))] + +namespace Bonsai.ML.Visualizers +{ + + /// + /// Provides a type visualizer to display the state components of a Kalman Filter Kinematics model. + /// + public class KinematicStateVisualizer : MashupVisualizer + { + + private int selectedStateIndex = 0; + private int selectedKinematicIndex = 0; + private DateTime? _startTime; + private TimeSpan updateFrequency = TimeSpan.FromSeconds(1/30); + private LineSeries lineSeries; + private AreaSeries areaSeries; + + /// + /// The selected state component property of the Kinematic State object being visualized. + /// + [XmlIgnore()] + public PropertyInfo stateComponentProperty { get; private set; } + + /// + /// The selected kinematic component property of the Kinematic State object being visualized. + /// + [XmlIgnore()] + public PropertyInfo kinematicComponentProperty { get; private set; } + + /// + /// The underlying plot used for visualization. + /// + // [XmlIgnore()] + internal TimeSeriesOxyPlotBase Plot { get; private set; } + + /// + /// The selected index of the state component to be visualized + /// + public int SelectedStateIndex { get => selectedStateIndex; set => selectedStateIndex = value; } + + /// + /// The selected index of the kinematic component to be visualized + /// + public int SelectedKinematicIndex { get => selectedKinematicIndex; set => selectedKinematicIndex = value; } + + /// + /// Size of the window when loaded + /// + public Size Size { get; set; } = new Size(320, 240); + + /// + /// Capacity or length of time shown along the x axis of the plot during automatic updating + /// + public int Capacity { get; set; } = 10; + + /// + /// Buffer the data beyond the capacity. + /// + public bool BufferData { get; set; } = true; + + /// + public override void Load(IServiceProvider provider) + { + Plot = new TimeSeriesOxyPlotBase() + { + Dock = DockStyle.Fill, + StartTime = DateTime.Now, + Capacity = Capacity, + Size = Size, + BufferData = BufferData + }; + + lineSeries = Plot.AddNewLineSeries("Mean"); + areaSeries = Plot.AddNewAreaSeries("Variance"); + + Plot.ResetLineSeries(lineSeries); + Plot.ResetAreaSeries(areaSeries); + Plot.ResetAxes(); + + List stateComponents = KinematicsHelper.GetStateComponents(); + List kinematicComponents = KinematicsHelper.GetKinematicComponents(); + + Plot.AddComboBoxWithLabel("State component:", stateComponents, selectedStateIndex, StateComponentChanged); + Plot.AddComboBoxWithLabel("Kinematic component:", kinematicComponents, selectedKinematicIndex, KinematicComponentChanged); + + stateComponentProperty = typeof(KinematicComponent).GetProperty(stateComponents[selectedStateIndex]); + kinematicComponentProperty = typeof(KinematicState).GetProperty(kinematicComponents[selectedKinematicIndex]); + + var visualizerService = (IDialogTypeVisualizerService)provider.GetService(typeof(IDialogTypeVisualizerService)); + if (visualizerService != null) + { + visualizerService.AddControl(Plot); + } + _startTime = null; + + base.Load(provider); + } + + + /// + public override void Show(object value) + { + var time = DateTime.Now; + if (!_startTime.HasValue) + { + _startTime = time; + Plot.StartTime = _startTime.Value; + Plot.ResetAxes(); + } + + KinematicState kinematicState = (KinematicState)value; + KinematicComponent kinematicComponent = (KinematicComponent)kinematicComponentProperty.GetValue(kinematicState); + StateComponent stateComponent = (StateComponent)stateComponentProperty.GetValue(kinematicComponent); + + double mean = stateComponent.Mean; + double variance = stateComponent.Variance; + + Plot.AddToLineSeries( + lineSeries: lineSeries, + time: time, + value: mean + ); + + Plot.AddToAreaSeries( + areaSeries: areaSeries, + time: time, + value1: mean + variance, + value2: mean - variance + ); + + if (MashupSources.Count == 0) Plot.SetAxes(minTime: time.AddSeconds(-Capacity), maxTime: time); + + } + + /// + public override IObservable Visualize(IObservable> source, IServiceProvider provider) + { + var mashupSourceStreams = MashupSources.Select(mashupSource => + mashupSource.Visualizer.Visualize(mashupSource.Source.Output, provider) + .Do(value => mashupSource.Visualizer.Show(value))); + + var mergedMashupSources = Observable.Merge(mashupSourceStreams); + + var processedSource = base.Visualize(source, provider); + + return Observable.Merge(mergedMashupSources, processedSource) + .Sample(updateFrequency) + .Do(_ => Plot.UpdatePlot()); + } + + /// + public override void Unload() + { + _startTime = null; + if (!Plot.IsDisposed) + { + Plot.Dispose(); + } + } + + private void StateComponentChanged(object sender, EventArgs e) + { + ToolStripComboBox comboBox = sender as ToolStripComboBox; + selectedStateIndex = comboBox.SelectedIndex; + var selectedName = comboBox.SelectedItem.ToString(); + stateComponentProperty = typeof(KinematicComponent).GetProperty(selectedName); + _startTime = null; + + Plot.ResetLineSeries(lineSeries); + Plot.ResetAreaSeries(areaSeries); + Plot.ResetAxes(); + } + + private void KinematicComponentChanged(object sender, EventArgs e) + { + ToolStripComboBox comboBox = sender as ToolStripComboBox; + selectedKinematicIndex = comboBox.SelectedIndex; + var selectedName = comboBox.SelectedItem.ToString(); + kinematicComponentProperty = typeof(KinematicState).GetProperty(selectedName); + _startTime = null; + + Plot.ResetLineSeries(lineSeries); + Plot.ResetAreaSeries(areaSeries); + Plot.ResetAxes(); + } + } +} From 1e59d134d4b55a3cde15f4546f75e25b3c60a23e Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Wed, 22 May 2024 15:14:38 +0100 Subject: [PATCH 05/14] Removed unnecessary combobox --- src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs b/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs index 0b494c8e..9256364e 100644 --- a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs +++ b/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs @@ -31,8 +31,6 @@ internal class TimeSeriesOxyPlotBase : UserControl /// public int Capacity { get; set; } - public ToolStripComboBox ComboBox => comboBox; - public StatusStrip StatusStrip => statusStrip; /// From 4b51df3f9d66473c1cf70c9aad5fa432000fc1d7 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Thu, 23 May 2024 11:29:13 +0100 Subject: [PATCH 06/14] Updated xml comments --- src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs b/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs index 9256364e..b321b05a 100644 --- a/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs +++ b/src/Bonsai.ML.Visualizers/TimeSeriesOxyPlotBase.cs @@ -22,24 +22,27 @@ internal class TimeSeriesOxyPlotBase : UserControl private StatusStrip statusStrip; /// - /// DateTime value that determines the starting time of the data values. + /// Gets or sets the datetime value that determines the starting time of the data values. /// public DateTime StartTime { get; set; } /// - /// Integer value that determines how many data points should be shown along the x axis. + /// Gets or sets the integer value that determines how many data points should be shown along the x axis. /// public int Capacity { get; set; } + /// + /// Gets the status strip control. + /// public StatusStrip StatusStrip => statusStrip; /// - /// Buffer the data beyond the capacity. + /// Gets or sets a boolean value that determines whether to buffer the data beyond the capacity. /// public bool BufferData { get; set; } /// - /// Constructor of the TimeSeriesOxyPlotBase class. + /// Initializes a new instance of the class /// public TimeSeriesOxyPlotBase() { From 6ec476588df46ff39dca8825575c7eb557cf3dfd Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 24 May 2024 15:40:05 +0100 Subject: [PATCH 07/14] Removed KinematicComponent visualizer --- .../KinematicComponentVisualizer.cs | 153 ------------------ 1 file changed, 153 deletions(-) delete mode 100644 src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs diff --git a/src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs deleted file mode 100644 index 045d5752..00000000 --- a/src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs +++ /dev/null @@ -1,153 +0,0 @@ -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.Kinematics; -using System.Drawing; -using System.Reactive; -using OxyPlot.Series; - -[assembly: TypeVisualizer(typeof(KinematicComponentVisualizer), Target = typeof(KinematicComponent))] - -namespace Bonsai.ML.Visualizers -{ - /// - /// Provides a type visualizer to display the state components of a Kalman Filter kinematics model. - /// - public class KinematicComponentVisualizer : BufferedVisualizer - { - - private PropertyInfo stateComponentProperty; - - private int selectedIndex = 0; - - private DateTime? _startTime; - - private TimeSeriesOxyPlotBase Plot; - - private LineSeries lineSeries; - - private AreaSeries areaSeries; - - /// - /// The selected index of the state component to be visualized - /// - public int SelectedIndex { get => selectedIndex; set => selectedIndex = value; } - - /// - /// Size of the window when loaded - /// - public Size Size { get; set; } = new Size(320, 240); - - /// - /// Capacity or length of time shown along the x axis of the plot during automatic updating - /// - public int Capacity { get; set; } = 10; - - /// - /// Buffer the data beyond the capacity. - /// - public bool BufferData { get; set; } = true; - - /// - public override void Load(IServiceProvider provider) - { - Plot = new TimeSeriesOxyPlotBase() - { - Size = Size, - Capacity = Capacity, - Dock = DockStyle.Fill, - StartTime = DateTime.Now, - BufferData = BufferData - }; - - lineSeries = Plot.AddNewLineSeries("Mean"); - areaSeries = Plot.AddNewAreaSeries("Variance"); - - Plot.ResetLineSeries(lineSeries); - Plot.ResetAreaSeries(areaSeries); - Plot.ResetAxes(); - - Plot.AddComboBoxWithLabel("State component:", KinematicsHelper.GetStateComponents(), selectedIndex, ComponentChanged); - - var visualizerService = (IDialogTypeVisualizerService)provider.GetService(typeof(IDialogTypeVisualizerService)); - if (visualizerService != null) - { - visualizerService.AddControl(Plot); - } - } - - /// - public override void Show(object value) - { - } - - /// - protected override void Show(DateTime time, object value) - { - if (!_startTime.HasValue) - { - _startTime = time; - Plot.StartTime = _startTime.Value; - // Plot.ResetSeries(); - - } - - KinematicComponent kinematicComponent = (KinematicComponent)value; - StateComponent stateComponent = (StateComponent)stateComponentProperty.GetValue(kinematicComponent); - double mean = stateComponent.Mean; - double variance = stateComponent.Variance; - - Plot.AddToLineSeries( - lineSeries: lineSeries, - time: time, - value: mean - ); - - Plot.AddToAreaSeries( - areaSeries: areaSeries, - time: time, - value1: mean + variance, - value2: mean - variance - ); - - Plot.SetAxes(minTime: time.AddSeconds(-Capacity), maxTime: time); - - } - - /// - protected override void ShowBuffer(IList> values) - { - base.ShowBuffer(values); - if (values.Count > 0) - { - Plot.UpdatePlot(); - } - } - - /// - public override void Unload() - { - _startTime = null; - if (!Plot.IsDisposed) - { - Plot.Dispose(); - } - } - - private void ComponentChanged(object sender, EventArgs e) - { - ToolStripComboBox comboBox = sender as ToolStripComboBox; - selectedIndex = comboBox.SelectedIndex; - var selectedName = comboBox.SelectedItem.ToString(); - stateComponentProperty = typeof(KinematicComponent).GetProperty(selectedName); - _startTime = null; - - Plot.ResetAxes(); - } - } -} From cfd2be50ff8e948a96b2e5f193e41da378982a16 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 24 May 2024 15:41:15 +0100 Subject: [PATCH 08/14] Updated StateComponent to better support reuse --- .../StateComponentVisualizer.cs | 61 ++++++++++++++----- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs b/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs index 8e5a3afb..af6b3784 100644 --- a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs @@ -5,9 +5,10 @@ using Bonsai.Design; using Bonsai.ML.Visualizers; using Bonsai.ML.LinearDynamicalSystems; -using System.Drawing; +using OxyPlot; using System.Reactive; using OxyPlot.Series; +using System.Linq; [assembly: TypeVisualizer(typeof(StateComponentVisualizer), Target = typeof(StateComponent))] @@ -19,24 +20,41 @@ namespace Bonsai.ML.Visualizers public class StateComponentVisualizer : BufferedVisualizer { - private DateTime? _startTime; + internal DateTime? startTime { get; set; } - private TimeSeriesOxyPlotBase Plot; + internal TimeSeriesOxyPlotBase Plot; - private LineSeries lineSeries; + internal LineSeries lineSeries { get; private set; } - private AreaSeries areaSeries; + internal AreaSeries areaSeries { get; private set; } + + private bool resetAxes = true; /// - /// Capacity or length of time shown along the x axis of the plot during automatic updating + /// Gets or sets the amount of time in seconds that should be shown along the x axis. /// public int Capacity { get; set; } = 10; /// - /// Buffer the data beyond the capacity. + /// Gets or sets a boolean value that determines whether to buffer the data beyond the capacity. /// public bool BufferData { get; set; } = true; + /// + /// Gets or sets the optional label to prepend to the line and area series names. + /// + public string Label { get; set; } + + /// + /// Gets or sets the color to use for the line series. + /// + public OxyColor? LineSeriesColor { get; set; } = null; + + /// + /// Gets or sets the color to use for the area series. + /// + public OxyColor? AreaSeriesColor { get; set; } = null; + /// public override void Load(IServiceProvider provider) { @@ -48,8 +66,11 @@ public override void Load(IServiceProvider provider) BufferData = BufferData }; - lineSeries = Plot.AddNewLineSeries("Mean"); - areaSeries = Plot.AddNewAreaSeries("Variance"); + var lineSeriesName = string.IsNullOrEmpty(Label) ? "Mean" : $"{Label} Mean"; + lineSeries = Plot.AddNewLineSeries(lineSeriesName, color: LineSeriesColor); + + var areaSeriesName = string.IsNullOrEmpty(Label) ? "Variance" : $"{Label} Variance"; + areaSeries = Plot.AddNewAreaSeries(areaSeriesName, color: AreaSeriesColor); Plot.ResetLineSeries(lineSeries); Plot.ResetAreaSeries(areaSeries); @@ -70,10 +91,10 @@ public override void Show(object value) /// protected override void Show(DateTime time, object value) { - if (!_startTime.HasValue) + if (!startTime.HasValue) { - _startTime = time; - Plot.StartTime = _startTime.Value; + startTime = time; + Plot.StartTime = startTime.Value; Plot.ResetAxes(); } @@ -93,9 +114,6 @@ protected override void Show(DateTime time, object value) value1: mean + variance, value2: mean - variance ); - - Plot.SetAxes(minTime: time.AddSeconds(-Capacity), maxTime: time); - } /// @@ -104,14 +122,25 @@ protected override void ShowBuffer(IList> values) base.ShowBuffer(values); if (values.Count > 0) { + if (resetAxes) + { + var time = values.LastOrDefault().Timestamp.DateTime; + Plot.SetAxes(minTime: time.AddSeconds(-Capacity), maxTime: time); + } Plot.UpdatePlot(); } } + internal void ShowDataBuffer(IList> values, bool resetAxes = true) + { + this.resetAxes = resetAxes; + ShowBuffer(values); + } + /// public override void Unload() { - _startTime = null; + startTime = null; if (!Plot.IsDisposed) { Plot.Dispose(); From e4519d6d8dd1754f518d5398412465a64336a803 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 24 May 2024 15:42:26 +0100 Subject: [PATCH 09/14] Removed controls and modified to use state component visualizer in table layout panel --- .../KinematicStateVisualizer.cs | 240 ++++++++---------- 1 file changed, 107 insertions(+), 133 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs index 38138825..0beaf667 100644 --- a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs @@ -12,6 +12,7 @@ using System.Linq; using System.Drawing; using System.Reflection; +using System.Reactive; [assembly: TypeVisualizer(typeof(KinematicStateVisualizer), Target = typeof(KinematicState))] @@ -23,91 +24,61 @@ namespace Bonsai.ML.Visualizers /// public class KinematicStateVisualizer : MashupVisualizer { - - private int selectedStateIndex = 0; - private int selectedKinematicIndex = 0; - private DateTime? _startTime; - private TimeSpan updateFrequency = TimeSpan.FromSeconds(1/30); - private LineSeries lineSeries; - private AreaSeries areaSeries; - - /// - /// The selected state component property of the Kinematic State object being visualized. - /// - [XmlIgnore()] - public PropertyInfo stateComponentProperty { get; private set; } - - /// - /// The selected kinematic component property of the Kinematic State object being visualized. - /// - [XmlIgnore()] - public PropertyInfo kinematicComponentProperty { get; private set; } - - /// - /// The underlying plot used for visualization. - /// - // [XmlIgnore()] - internal TimeSeriesOxyPlotBase Plot { get; private set; } - - /// - /// The selected index of the state component to be visualized - /// - public int SelectedStateIndex { get => selectedStateIndex; set => selectedStateIndex = value; } - - /// - /// The selected index of the kinematic component to be visualized - /// - public int SelectedKinematicIndex { get => selectedKinematicIndex; set => selectedKinematicIndex = value; } - - /// - /// Size of the window when loaded - /// - public Size Size { get; set; } = new Size(320, 240); - - /// - /// Capacity or length of time shown along the x axis of the plot during automatic updating - /// - public int Capacity { get; set; } = 10; - - /// - /// Buffer the data beyond the capacity. - /// - public bool BufferData { get; set; } = true; + internal int RowCount { get; set; } = 3; + internal int ColumnCount { get; set; } = 2; + internal List componentVisualizers = new(); + private TableLayoutPanel container; + private int updateFrequency = 1000 / 50; + private bool resetAxes = true; + + internal string[] Labels = new string[] { + "Position X", + "Position Y", + "Velocity X", + "Velocity Y", + "Acceleration X", + "Acceleration Y" + }; /// public override void Load(IServiceProvider provider) { - Plot = new TimeSeriesOxyPlotBase() + container = new TableLayoutPanel { - Dock = DockStyle.Fill, - StartTime = DateTime.Now, - Capacity = Capacity, - Size = Size, - BufferData = BufferData + ColumnCount = ColumnCount, + RowCount = RowCount, + Dock = DockStyle.Fill }; - lineSeries = Plot.AddNewLineSeries("Mean"); - areaSeries = Plot.AddNewAreaSeries("Variance"); - - Plot.ResetLineSeries(lineSeries); - Plot.ResetAreaSeries(areaSeries); - Plot.ResetAxes(); - - List stateComponents = KinematicsHelper.GetStateComponents(); - List kinematicComponents = KinematicsHelper.GetKinematicComponents(); + for (int i = 0; i < container.RowCount; i++) + { + container.RowStyles.Add(new RowStyle(SizeType.Percent, 100f / RowCount)); + } - Plot.AddComboBoxWithLabel("State component:", stateComponents, selectedStateIndex, StateComponentChanged); - Plot.AddComboBoxWithLabel("Kinematic component:", kinematicComponents, selectedKinematicIndex, KinematicComponentChanged); + for (int i = 0; i < container.ColumnCount; i++) + { + container.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f / ColumnCount)); + } - stateComponentProperty = typeof(KinematicComponent).GetProperty(stateComponents[selectedStateIndex]); - kinematicComponentProperty = typeof(KinematicState).GetProperty(kinematicComponents[selectedKinematicIndex]); + for (int i = 0 ; i < RowCount; i++) + { + for (int j = 0; j < ColumnCount; j++) + { + var StateComponentVisualizer = new StateComponentVisualizer() { + Label = Labels[i * ColumnCount + j] + }; + StateComponentVisualizer.Load(provider); + container.Controls.Add(StateComponentVisualizer.Plot, j, i); + componentVisualizers.Add(StateComponentVisualizer); + } + } var visualizerService = (IDialogTypeVisualizerService)provider.GetService(typeof(IDialogTypeVisualizerService)); + if (visualizerService != null) { - visualizerService.AddControl(Plot); + visualizerService.AddControl(container); } - _startTime = null; base.Load(provider); } @@ -116,88 +87,91 @@ public override void Load(IServiceProvider provider) /// public override void Show(object value) { - var time = DateTime.Now; - if (!_startTime.HasValue) + } + + /// + public void ShowBuffer(IList> values) + { + List> positionX = new(); + List> positionY = new(); + List> velocityX = new(); + List> velocityY = new(); + List> accelerationX = new(); + List> accelerationY = new(); + + foreach (var value in values) { - _startTime = time; - Plot.StartTime = _startTime.Value; - Plot.ResetAxes(); + 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)); } - KinematicState kinematicState = (KinematicState)value; - KinematicComponent kinematicComponent = (KinematicComponent)kinematicComponentProperty.GetValue(kinematicState); - StateComponent stateComponent = (StateComponent)stateComponentProperty.GetValue(kinematicComponent); - - double mean = stateComponent.Mean; - double variance = stateComponent.Variance; - - Plot.AddToLineSeries( - lineSeries: lineSeries, - time: time, - value: mean - ); - - Plot.AddToAreaSeries( - areaSeries: areaSeries, - time: time, - value1: mean + variance, - value2: mean - variance - ); - - if (MashupSources.Count == 0) Plot.SetAxes(minTime: time.AddSeconds(-Capacity), maxTime: time); - + componentVisualizers[0].ShowDataBuffer(positionX, resetAxes); + componentVisualizers[1].ShowDataBuffer(positionY, resetAxes); + componentVisualizers[2].ShowDataBuffer(velocityX, resetAxes); + componentVisualizers[3].ShowDataBuffer(velocityY, resetAxes); + componentVisualizers[4].ShowDataBuffer(accelerationX, resetAxes); + componentVisualizers[5].ShowDataBuffer(accelerationY, resetAxes); } /// public override IObservable Visualize(IObservable> source, IServiceProvider provider) { + if (provider.GetService(typeof(IDialogTypeVisualizerService)) is not Control visualizerControl) + { + return source; + } + + var visualizerSource = VisualizeSource(source, visualizerControl); + + if (MashupSources.Count == 0) + { + resetAxes = true; + return visualizerSource; + } + + resetAxes = false; + var mashupSourceStreams = MashupSources.Select(mashupSource => mashupSource.Visualizer.Visualize(mashupSource.Source.Output, provider) .Do(value => mashupSource.Visualizer.Show(value))); var mergedMashupSources = Observable.Merge(mashupSourceStreams); - var processedSource = base.Visualize(source, provider); - - return Observable.Merge(mergedMashupSources, processedSource) - .Sample(updateFrequency) - .Do(_ => Plot.UpdatePlot()); + return Observable.Merge(mergedMashupSources, visualizerSource); } - /// - public override void Unload() + private IObservable VisualizeSource(IObservable> source, Control visualizerControl) { - _startTime = null; - if (!Plot.IsDisposed) - { - Plot.Dispose(); - } + return Observable.Using( + () => new Timer(), + timer => + { + timer.Interval = updateFrequency; + var timerTick = Observable.FromEventPattern( + handler => timer.Tick += handler, + handler => timer.Tick -= handler); + timer.Start(); + var mergedSource = source.SelectMany(xs => xs.Do( + _ => { }, + () => visualizerControl.BeginInvoke((Action)SequenceCompleted))); + return mergedSource + .Timestamp(HighResolutionScheduler.Default) + .Buffer(() => timerTick) + .Do(ShowBuffer) + .Finally(timer.Stop); + }); } - private void StateComponentChanged(object sender, EventArgs e) - { - ToolStripComboBox comboBox = sender as ToolStripComboBox; - selectedStateIndex = comboBox.SelectedIndex; - var selectedName = comboBox.SelectedItem.ToString(); - stateComponentProperty = typeof(KinematicComponent).GetProperty(selectedName); - _startTime = null; - - Plot.ResetLineSeries(lineSeries); - Plot.ResetAreaSeries(areaSeries); - Plot.ResetAxes(); - } - - private void KinematicComponentChanged(object sender, EventArgs e) + /// + public override void Unload() { - ToolStripComboBox comboBox = sender as ToolStripComboBox; - selectedKinematicIndex = comboBox.SelectedIndex; - var selectedName = comboBox.SelectedItem.ToString(); - kinematicComponentProperty = typeof(KinematicState).GetProperty(selectedName); - _startTime = null; - - Plot.ResetLineSeries(lineSeries); - Plot.ResetAreaSeries(areaSeries); - Plot.ResetAxes(); + foreach (var componentVisualizer in componentVisualizers) componentVisualizer.Unload(); + if (componentVisualizers.Count > 0) componentVisualizers.Clear(); + if (!container.IsDisposed) container.Dispose(); } } } From 0dbab7922d994582f60066313874193ae8effe7b Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 24 May 2024 22:45:39 +0100 Subject: [PATCH 10/14] Ensure component visualizers are reset on unload --- .../KinematicStateVisualizer.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs index 0beaf667..6dae993b 100644 --- a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs @@ -1,17 +1,12 @@ using Bonsai.Design; using Bonsai; -using Bonsai.ML.LinearDynamicalSystems; using Bonsai.ML.LinearDynamicalSystems.Kinematics; using Bonsai.ML.Visualizers; using System.Collections.Generic; using System; using System.Windows.Forms; -using System.Xml.Serialization; using System.Reactive.Linq; -using OxyPlot.Series; using System.Linq; -using System.Drawing; -using System.Reflection; using System.Reactive; [assembly: TypeVisualizer(typeof(KinematicStateVisualizer), Target = typeof(KinematicState))] @@ -26,7 +21,7 @@ public class KinematicStateVisualizer : MashupVisualizer { internal int RowCount { get; set; } = 3; internal int ColumnCount { get; set; } = 2; - internal List componentVisualizers = new(); + internal List componentVisualizers { get; private set; } = new(); private TableLayoutPanel container; private int updateFrequency = 1000 / 50; private bool resetAxes = true; @@ -169,8 +164,15 @@ private IObservable VisualizeSource(IObservable> sou /// public override void Unload() { - foreach (var componentVisualizer in componentVisualizers) componentVisualizer.Unload(); - if (componentVisualizers.Count > 0) componentVisualizers.Clear(); + foreach (var componentVisualizer in componentVisualizers) + { + componentVisualizer.Unload(); + } + if (componentVisualizers.Count > 0) + { + componentVisualizers.Clear(); + componentVisualizers = new(); + } if (!container.IsDisposed) container.Dispose(); } } From 7fddc3c9c7b50e48cdfd04099b4c039ec1302dfc Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Mon, 3 Jun 2024 10:20:57 +0100 Subject: [PATCH 11/14] Changed to camel case --- .../KinematicStateVisualizer.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs index 6dae993b..7ea4e963 100644 --- a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs @@ -21,7 +21,7 @@ public class KinematicStateVisualizer : MashupVisualizer { internal int RowCount { get; set; } = 3; internal int ColumnCount { get; set; } = 2; - internal List componentVisualizers { get; private set; } = new(); + internal List ComponentVisualizers { get; private set; } = new(); private TableLayoutPanel container; private int updateFrequency = 1000 / 50; private bool resetAxes = true; @@ -64,7 +64,7 @@ public override void Load(IServiceProvider provider) }; StateComponentVisualizer.Load(provider); container.Controls.Add(StateComponentVisualizer.Plot, j, i); - componentVisualizers.Add(StateComponentVisualizer); + ComponentVisualizers.Add(StateComponentVisualizer); } } @@ -104,12 +104,12 @@ public void ShowBuffer(IList> values) accelerationY.Add(new Timestamped(((KinematicState)value.Value).Acceleration.Y, value.Timestamp)); } - componentVisualizers[0].ShowDataBuffer(positionX, resetAxes); - componentVisualizers[1].ShowDataBuffer(positionY, resetAxes); - componentVisualizers[2].ShowDataBuffer(velocityX, resetAxes); - componentVisualizers[3].ShowDataBuffer(velocityY, resetAxes); - componentVisualizers[4].ShowDataBuffer(accelerationX, resetAxes); - componentVisualizers[5].ShowDataBuffer(accelerationY, resetAxes); + ComponentVisualizers[0].ShowDataBuffer(positionX, resetAxes); + ComponentVisualizers[1].ShowDataBuffer(positionY, resetAxes); + ComponentVisualizers[2].ShowDataBuffer(velocityX, resetAxes); + ComponentVisualizers[3].ShowDataBuffer(velocityY, resetAxes); + ComponentVisualizers[4].ShowDataBuffer(accelerationX, resetAxes); + ComponentVisualizers[5].ShowDataBuffer(accelerationY, resetAxes); } /// @@ -164,14 +164,14 @@ private IObservable VisualizeSource(IObservable> sou /// public override void Unload() { - foreach (var componentVisualizer in componentVisualizers) + foreach (var componentVisualizer in ComponentVisualizers) { componentVisualizer.Unload(); } - if (componentVisualizers.Count > 0) + if (ComponentVisualizers.Count > 0) { - componentVisualizers.Clear(); - componentVisualizers = new(); + ComponentVisualizers.Clear(); + ComponentVisualizers = new(); } if (!container.IsDisposed) container.Dispose(); } From 61776821763e2bc4e7a12b1fac0da2b2df90b009 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Mon, 3 Jun 2024 10:25:35 +0100 Subject: [PATCH 12/14] Updated internal properties to private --- .../KinematicStateVisualizer.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs index 7ea4e963..9a5f5736 100644 --- a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs @@ -19,14 +19,14 @@ namespace Bonsai.ML.Visualizers /// public class KinematicStateVisualizer : MashupVisualizer { - internal int RowCount { get; set; } = 3; - internal int ColumnCount { get; set; } = 2; internal List ComponentVisualizers { get; private set; } = new(); private TableLayoutPanel container; private int updateFrequency = 1000 / 50; private bool resetAxes = true; + private int rowCount = 3; + private int columnCount = 2; - internal string[] Labels = new string[] { + private string[] labels = new string[] { "Position X", "Position Y", "Velocity X", @@ -40,27 +40,27 @@ public override void Load(IServiceProvider provider) { container = new TableLayoutPanel { - ColumnCount = ColumnCount, - RowCount = RowCount, + ColumnCount = columnCount, + RowCount = rowCount, Dock = DockStyle.Fill }; for (int i = 0; i < container.RowCount; i++) { - container.RowStyles.Add(new RowStyle(SizeType.Percent, 100f / RowCount)); + container.RowStyles.Add(new RowStyle(SizeType.Percent, 100f / rowCount)); } for (int i = 0; i < container.ColumnCount; i++) { - container.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f / ColumnCount)); + container.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100f / columnCount)); } - for (int i = 0 ; i < RowCount; i++) + for (int i = 0 ; i < rowCount; i++) { - for (int j = 0; j < ColumnCount; j++) + for (int j = 0; j < columnCount; j++) { var StateComponentVisualizer = new StateComponentVisualizer() { - Label = Labels[i * ColumnCount + j] + Label = labels[i * columnCount + j] }; StateComponentVisualizer.Load(provider); container.Controls.Add(StateComponentVisualizer.Plot, j, i); From 87570273d3379145b36fbea5c81137ba991ae50d Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Mon, 3 Jun 2024 12:47:40 +0100 Subject: [PATCH 13/14] Updated internal and private variables --- src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs index 9a5f5736..8409eab1 100644 --- a/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/KinematicStateVisualizer.cs @@ -19,14 +19,15 @@ namespace Bonsai.ML.Visualizers /// public class KinematicStateVisualizer : MashupVisualizer { - internal List ComponentVisualizers { get; private set; } = new(); private TableLayoutPanel container; private int updateFrequency = 1000 / 50; private bool resetAxes = true; private int rowCount = 3; private int columnCount = 2; - private string[] labels = new string[] { + internal List ComponentVisualizers { get; private set; } = new(); + + internal string[] Labels = new string[] { "Position X", "Position Y", "Velocity X", @@ -60,7 +61,7 @@ public override void Load(IServiceProvider provider) for (int j = 0; j < columnCount; j++) { var StateComponentVisualizer = new StateComponentVisualizer() { - Label = labels[i * columnCount + j] + Label = Labels[i * columnCount + j] }; StateComponentVisualizer.Load(provider); container.Controls.Add(StateComponentVisualizer.Plot, j, i); From 14c90a7b83fd0f72d8013acdca6b17c82371def7 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Mon, 3 Jun 2024 12:48:22 +0100 Subject: [PATCH 14/14] Updated casing and changed variable to private --- .../StateComponentVisualizer.cs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs b/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs index af6b3784..f75e5a1c 100644 --- a/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs +++ b/src/Bonsai.ML.Visualizers/StateComponentVisualizer.cs @@ -19,17 +19,16 @@ namespace Bonsai.ML.Visualizers /// public class StateComponentVisualizer : BufferedVisualizer { - - internal DateTime? startTime { get; set; } - internal TimeSeriesOxyPlotBase Plot; - internal LineSeries lineSeries { get; private set; } + internal LineSeries LineSeries { get; private set; } - internal AreaSeries areaSeries { get; private set; } + internal AreaSeries AreaSeries { get; private set; } private bool resetAxes = true; + private DateTime? startTime; + /// /// Gets or sets the amount of time in seconds that should be shown along the x axis. /// @@ -67,13 +66,13 @@ public override void Load(IServiceProvider provider) }; var lineSeriesName = string.IsNullOrEmpty(Label) ? "Mean" : $"{Label} Mean"; - lineSeries = Plot.AddNewLineSeries(lineSeriesName, color: LineSeriesColor); + LineSeries = Plot.AddNewLineSeries(lineSeriesName, color: LineSeriesColor); var areaSeriesName = string.IsNullOrEmpty(Label) ? "Variance" : $"{Label} Variance"; - areaSeries = Plot.AddNewAreaSeries(areaSeriesName, color: AreaSeriesColor); + AreaSeries = Plot.AddNewAreaSeries(areaSeriesName, color: AreaSeriesColor); - Plot.ResetLineSeries(lineSeries); - Plot.ResetAreaSeries(areaSeries); + Plot.ResetLineSeries(LineSeries); + Plot.ResetAreaSeries(AreaSeries); Plot.ResetAxes(); var visualizerService = (IDialogTypeVisualizerService)provider.GetService(typeof(IDialogTypeVisualizerService)); @@ -103,13 +102,13 @@ protected override void Show(DateTime time, object value) double variance = stateComponent.Variance; Plot.AddToLineSeries( - lineSeries: lineSeries, + lineSeries: LineSeries, time: time, value: mean ); Plot.AddToAreaSeries( - areaSeries: areaSeries, + areaSeries: AreaSeries, time: time, value1: mean + variance, value2: mean - variance