scott系列:
绘图初步
????
多个图像
单击移动
在了解ScottPlot的绘图逻辑之后,在WPF中生成动态图像简直轻而易举,只需不断地删除旧图而绘制新图即可。
新建一个按钮,绑定下面的函数
ScatterPlot dynSinPlot;
int dynClick = 0;
private void btnDynSin_Click(object sender, RoutedEventArgs e)
{
var xs = Enumerable.Range(0, 100).Select(x => x / 10.0).ToArray();
double shift = dynClick / 10.0;
var ys = xs.Select(x => Math.Sin(x+shift)).ToArray();
dynClick += 1;
plt.Plot.Remove(dynSinPlot);
dynSinPlot = plt.Plot.AddScatter(xs, ys, label: "sin");
plt.Plot.Legend();
plt.Refresh();
}
其中,dynClick用于计数,以调整正弦函数的相位,这个函数的功能为,每点击一次按钮,正弦图像便相左移动
0.1
0.1
0.1
弧度。效果如下
多线程
这种需要通过单击才能更改图像的方案,显然不是我们所希望的,但自动的动态绘图函数,其实并不属于scottPlot的功能,而需要使用C#的多线程。
首先,新建一个动态余弦绘制函数,其相位取决于当前的时间戳。考虑到我们将在新的线程中调用这个函数,所以函数中在使用WPF对象时,需要在Dispatchar.Invoke中以委托的形式进行。
ScatterPlot dynCosPlot;
private void dynCos()
{
double t = DateTime.Now.Ticks/1000000.0;
Console.WriteLine(t);
var xs = Enumerable.Range(0, 100).Select(x => x / 10.0).ToArray();
var ys = xs.Select(x => Math.Cos(x + t)).ToArray();
Dispatcher.Invoke(() =>
{
plt.Plot.Remove(dynCosPlot);
dynCosPlot = plt.Plot.AddScatter(xs, ys, label: "cos");
plt.Plot.Legend();
plt.Refresh();
});
}
然后把这个函数放在一个循环中,为了能够自由控制动态绘图,这个函数需要传入一个tocken,并写在循环的判断条件中。
private void TaskDynCosLoop(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
dynCos();
Task.Delay(10);
}
}
最后添加一个按钮,绑定下列动态绘图函数,每次点击,都翻转一次布尔型的drawDynCos,若翻转后drawDynCos为True,则开启动态绘图,通过工厂方法开启一个新的线程;若反转后为False,则取消Tocken,从而中止绘图。
bool drawDynCos = false;
CancellationTokenSource dynCts;
private void btnDynCos_Click(object sender, RoutedEventArgs e)
{
drawDynCos = ! drawDynCos;
if (drawDynCos)
{
dynCts = new CancellationTokenSource();
Task.Factory.StartNew(
()=> TaskDynCosLoop(dynCts.Token));
}
else
{
dynCts.Cancel();
}
}
效果如下