-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from bonsai-rx/lds-timeseries-visualizers
Updated timeseries visualizers for kinematics model and mashup visualizers
- Loading branch information
Showing
4 changed files
with
364 additions
and
268 deletions.
There are no files selected for viewing
163 changes: 0 additions & 163 deletions
163
src/Bonsai.ML.Visualizers/KinematicComponentVisualizer.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
using Bonsai.Design; | ||
using Bonsai; | ||
using Bonsai.ML.LinearDynamicalSystems.Kinematics; | ||
using Bonsai.ML.Visualizers; | ||
using System.Collections.Generic; | ||
using System; | ||
using System.Windows.Forms; | ||
using System.Reactive.Linq; | ||
using System.Linq; | ||
using System.Reactive; | ||
|
||
[assembly: TypeVisualizer(typeof(KinematicStateVisualizer), Target = typeof(KinematicState))] | ||
|
||
namespace Bonsai.ML.Visualizers | ||
{ | ||
|
||
/// <summary> | ||
/// Provides a type visualizer to display the state components of a Kalman Filter Kinematics model. | ||
/// </summary> | ||
public class KinematicStateVisualizer : MashupVisualizer | ||
{ | ||
private TableLayoutPanel container; | ||
private int updateFrequency = 1000 / 50; | ||
private bool resetAxes = true; | ||
private int rowCount = 3; | ||
private int columnCount = 2; | ||
|
||
internal List<StateComponentVisualizer> ComponentVisualizers { get; private set; } = new(); | ||
|
||
internal string[] Labels = new string[] { | ||
"Position X", | ||
"Position Y", | ||
"Velocity X", | ||
"Velocity Y", | ||
"Acceleration X", | ||
"Acceleration Y" | ||
}; | ||
|
||
/// <inheritdoc/> | ||
public override void Load(IServiceProvider provider) | ||
{ | ||
container = new TableLayoutPanel | ||
{ | ||
ColumnCount = columnCount, | ||
RowCount = rowCount, | ||
Dock = DockStyle.Fill | ||
}; | ||
|
||
for (int i = 0; i < container.RowCount; i++) | ||
{ | ||
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)); | ||
} | ||
|
||
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(container); | ||
} | ||
|
||
base.Load(provider); | ||
} | ||
|
||
|
||
/// <inheritdoc/> | ||
public override void Show(object value) | ||
{ | ||
} | ||
|
||
/// <inheritdoc/> | ||
public void ShowBuffer(IList<Timestamped<object>> values) | ||
{ | ||
List<Timestamped<object>> positionX = new(); | ||
List<Timestamped<object>> positionY = new(); | ||
List<Timestamped<object>> velocityX = new(); | ||
List<Timestamped<object>> velocityY = new(); | ||
List<Timestamped<object>> accelerationX = new(); | ||
List<Timestamped<object>> accelerationY = new(); | ||
|
||
foreach (var value in values) | ||
{ | ||
positionX.Add(new Timestamped<object>(((KinematicState)value.Value).Position.X, value.Timestamp)); | ||
positionY.Add(new Timestamped<object>(((KinematicState)value.Value).Position.Y, value.Timestamp)); | ||
velocityX.Add(new Timestamped<object>(((KinematicState)value.Value).Velocity.X, value.Timestamp)); | ||
velocityY.Add(new Timestamped<object>(((KinematicState)value.Value).Velocity.Y, value.Timestamp)); | ||
accelerationX.Add(new Timestamped<object>(((KinematicState)value.Value).Acceleration.X, value.Timestamp)); | ||
accelerationY.Add(new Timestamped<object>(((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); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override IObservable<object> Visualize(IObservable<IObservable<object>> 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); | ||
|
||
return Observable.Merge(mergedMashupSources, visualizerSource); | ||
} | ||
|
||
private IObservable<object> VisualizeSource(IObservable<IObservable<object>> source, Control visualizerControl) | ||
{ | ||
return Observable.Using( | ||
() => new Timer(), | ||
timer => | ||
{ | ||
timer.Interval = updateFrequency; | ||
var timerTick = Observable.FromEventPattern<EventHandler, EventArgs>( | ||
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); | ||
}); | ||
} | ||
|
||
/// <inheritdoc/> | ||
public override void Unload() | ||
{ | ||
foreach (var componentVisualizer in ComponentVisualizers) | ||
{ | ||
componentVisualizer.Unload(); | ||
} | ||
if (ComponentVisualizers.Count > 0) | ||
{ | ||
ComponentVisualizers.Clear(); | ||
ComponentVisualizers = new(); | ||
} | ||
if (!container.IsDisposed) container.Dispose(); | ||
} | ||
} | ||
} |
Oops, something went wrong.