Skip to content

Instantly share code, notes, and snippets.

@VisualMelon
Created March 14, 2021 09:49
Show Gist options
  • Save VisualMelon/ea288e012923e5e94cb27c9001c35536 to your computer and use it in GitHub Desktop.
Save VisualMelon/ea288e012923e5e94cb27c9001c35536 to your computer and use it in GitHub Desktop.
SignalSeries
[Example("EndlessSignals")]
public static PlotModel EndlessSignal()
{
var model = new PlotModel { Title = "Endless Signals" };
var signals = new SignalSeries[3];
for (int i = 0; i < signals.Length; i++)
{
signals[i] = new SignalSeries();
signals[i].MarkerType = MarkerType.Diamond; // just to show where the datapoint are
signals[i].PushValue(0, i);
model.Series.Add(signals[i]);
}
System.Threading.Tasks.Task.Run(async () =>
{
var rnd = new Random();
var sw = new System.Diagnostics.Stopwatch();
sw.Start();
while (true)
{
await System.Threading.Tasks.Task.Delay(50);
lock (model.SyncRoot)
{
var t = sw.Elapsed.TotalSeconds;
for (int i = 0; i < signals.Length; i++)
{
var v = signals[i].Points.Last().Y;
if (rnd.NextDouble() < 0.1)
v = 0.5 - (v - i) + i;
// Updates the EndX value, and adds more points as necessary
signals[i].PushValue(t, v);
// or, if we just wanted to inform it of the time, and not any change in value:
signals[i].EndX = t;
}
model.InvalidatePlot(true);
}
}
});
return model;
}
using OxyPlot;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
namespace ExampleLibrary
{
// StairStepSeries might make more sense
public class SignalSeries : LineSeries
{
/// <summary>
/// Gets or sets the x-value to which the signal should be extended.
/// </summary>
public double EndX { get; set; }
public SignalSeries()
{
this.EndX = double.NaN;
}
protected override void RenderLine(IRenderContext rc, IList<ScreenPoint> pointsToRender)
{
bool removeLast = false;
if (pointsToRender.Count != 0 && !double.IsNaN(this.EndX))
{
// assumes left-to-right data and axis, should really check this.XAxis.IsReversed
var sx = this.XAxis.Transform(EndX);
var last = pointsToRender[pointsToRender.Count - 1];
if (last.X < sx)
{
pointsToRender.Add(new ScreenPoint(sx, last.Y));
}
}
base.RenderLine(rc, pointsToRender);
if (removeLast)
{
pointsToRender.RemoveAt(pointsToRender.Count - 1);
}
}
protected override void UpdateMaxMin()
{
base.UpdateMaxMin();
this.MaxX = Math.Max(this.MaxX, this.EndX);
}
/// <summary>
/// Pushes a sample to the series.
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
public void PushValue(double x, double y)
{
if (Points.Count != 0 && !double.IsNaN(EndX))
{
var lastPoint = Points[Points.Count - 1];
if (lastPoint.Y != y)
{
// if the value has changed, we may need to inject a value for the 'last' value
// really make any sense, but works for an example)
if (EndX > lastPoint.X)
Points.Add(new DataPoint(EndX, lastPoint.Y));
Points.Add(new DataPoint(x, y));
}
}
else
{
Points.Add(new DataPoint(x, y));
}
this.EndX = x;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment