C#实时绘制多个图表
C# Drawing multiple charts in real time
我有一个采集设备,可以读取数据并将其添加到缓冲区。这是在一个单独的线程中完成的。一旦这些数据出队,我设置了一个引发事件 OnDataRead() 的委托。
在我的信号监视器中,当接收到事件时,我想在多个图表中绘制数据(总共 16 个)。我成功绘制了第一个样本,但随后图表停止绘制数据,从第 16 个开始并逐步停止所有样本。这样做的正确方法是什么?我需要一个单独的线程吗?
接收带有数据的事件
public void OnDataRead(object source, DataEventArgs e)
{
if (e.rawData.Length > 0)
{
AddData(e.rawData, e.numChannels, e.triggerEnabled);
}
}
在适当的图表中添加数据点
private void AddData(float[] rawData, int numChannels, bool triggerEnabled)
{
//for (int i=0; i<chChannels.Count; i++)
// {
if (this.InvokeRequired)
{
SetAddDataCallback d = new SetAddDataCallback(AddData);
this.Invoke(d, new object[] {rawData, numChannels, triggerEnabled})
;
}
else
{
DateTime timeStamp = DateTime.Now;
// Find the channel selected
int channelIdx = 0; //boxChannelSelection.SelectedIndex;
// Add new data points for the selected channel
for (int sampleIdx = 0; sampleIdx < rawData.Length; sampleIdx++)
{
channelIdx = sampleIdx %(numChannels + 1);
if (triggerEnabled && (channelIdx != numChannels))
{
foreach (Series ptSeries in chChannels[channelIdx].Series)
{
AddNewPoint(timeStamp, rawData[sampleIdx], channelIdx, ptSeries);
}
}
else if (!triggerEnabled)
{
foreach (Series ptSeries in chChannels[channelIdx].Series)
{
AddNewPoint(timeStamp, rawData[sampleIdx], channelIdx, ptSeries);
}
}
}
}
// }
}
在图表中绘制新数据点
public void AddNewPoint(DateTime timeStamp, float yValue, int channel, System.Windows.Forms.DataVisualization.Charting.Series ptSeries)
{
ptSeries.Points.AddXY(timeStamp.ToOADate(), yValue);
// Remove old datapoints if needed
double removeBefore = timeStamp.AddSeconds((double)(8) * (-1)).ToOADate();
while (ptSeries.Points[0].XValue < removeBefore)
{
ptSeries.Points.RemoveAt(0);
}
chChannels[channel].ChartAreas[0].AxisX.Minimum = ptSeries.Points[0].XValue;
chChannels[channel].ChartAreas[0].AxisX.Maximum = DateTime.FromOADate(ptSeries.Points[0].XValue).AddSeconds(10).ToOADate();
chChannels[channel].Invalidate();
在不同的线程中绘制图表中的数据是一种很好的方法。
读取新数据时,数据存储在列表或数组中。由于是实时数据,所以这里也会生成时间戳。使用采集数据的采样率:timeStamp = timeStamp + sampleIdx/sampleRate;
public void OnDataRead(object source, EEGEventArgs e)
{
if ((e.rawData.Length > 0) && (!_shouldStop))
{
lock (_bufferRawData)
{
for (int sampleIdx = 0; sampleIdx < e.rawData.Length; sampleIdx++)
{
// Append data
_bufferRawData.Add(e.rawData[sampleIdx]);
// Calculate corresponding timestamp
secondsToAdd = (float) sampleIdx/e.sampleRate;
// Append corresponding timestamp
_bufferXValues.Add( e.timeStamp.AddSeconds(secondsToAdd));
}
}
然后,创建一个线程,每N毫秒休眠一次(100毫秒适合我显示2秒的数据,但如果我想显示10秒,我需要增加线程的休眠时间到500毫秒)
//Create thread
//define a thread to add values into chart
ThreadStart addDataThreadObj = new ThreadStart(AddDataThreadLoop);
_addDataRunner = new Thread(addDataThreadObj);
addDataDel += new AddDataDelegate(AddData);
//Start thread
_addDataRunner.Start();
最后,更新图表并让线程每 N 毫秒休眠一次
private void AddDataThreadLoop()
{
while (!_shouldStop)
{
chChannels[1].Invoke(addDataDel);
// Sleeep thread for 100ms
Thread.Sleep(100);
}
}
数据将每 100 毫秒添加到图表中
private void AddData()
{
// Copy data stored in lists to arrays
float[] rawData;
DateTime[] xValues;
if (_bufferRawData.Count > 0)
{
// Copy buffered data in thread-safe manner
lock (_bufferRawData)
{
rawData = _bufferRawData.ToArray();
_bufferRawData.Clear();
xValues = _bufferXValues.ToArray();
_bufferXValues.Clear();
}
for (int sampleIdx = 0; sampleIdx < rawData.Length; sampleIdx++)
{
foreach (Series ptSeries in chChannels[channelIdx].Series)
// Add new datapoint to the corresponding chart (x, y, chartIndex, seriesIndex)
AddNewPoint(xValues[sampleIdx], rawData[sampleIdx], ptSeries);
}
}
}
我有一个采集设备,可以读取数据并将其添加到缓冲区。这是在一个单独的线程中完成的。一旦这些数据出队,我设置了一个引发事件 OnDataRead() 的委托。
在我的信号监视器中,当接收到事件时,我想在多个图表中绘制数据(总共 16 个)。我成功绘制了第一个样本,但随后图表停止绘制数据,从第 16 个开始并逐步停止所有样本。这样做的正确方法是什么?我需要一个单独的线程吗?
接收带有数据的事件
public void OnDataRead(object source, DataEventArgs e)
{
if (e.rawData.Length > 0)
{
AddData(e.rawData, e.numChannels, e.triggerEnabled);
}
}
在适当的图表中添加数据点
private void AddData(float[] rawData, int numChannels, bool triggerEnabled)
{
//for (int i=0; i<chChannels.Count; i++)
// {
if (this.InvokeRequired)
{
SetAddDataCallback d = new SetAddDataCallback(AddData);
this.Invoke(d, new object[] {rawData, numChannels, triggerEnabled})
;
}
else
{
DateTime timeStamp = DateTime.Now;
// Find the channel selected
int channelIdx = 0; //boxChannelSelection.SelectedIndex;
// Add new data points for the selected channel
for (int sampleIdx = 0; sampleIdx < rawData.Length; sampleIdx++)
{
channelIdx = sampleIdx %(numChannels + 1);
if (triggerEnabled && (channelIdx != numChannels))
{
foreach (Series ptSeries in chChannels[channelIdx].Series)
{
AddNewPoint(timeStamp, rawData[sampleIdx], channelIdx, ptSeries);
}
}
else if (!triggerEnabled)
{
foreach (Series ptSeries in chChannels[channelIdx].Series)
{
AddNewPoint(timeStamp, rawData[sampleIdx], channelIdx, ptSeries);
}
}
}
}
// }
}
在图表中绘制新数据点
public void AddNewPoint(DateTime timeStamp, float yValue, int channel, System.Windows.Forms.DataVisualization.Charting.Series ptSeries)
{
ptSeries.Points.AddXY(timeStamp.ToOADate(), yValue);
// Remove old datapoints if needed
double removeBefore = timeStamp.AddSeconds((double)(8) * (-1)).ToOADate();
while (ptSeries.Points[0].XValue < removeBefore)
{
ptSeries.Points.RemoveAt(0);
}
chChannels[channel].ChartAreas[0].AxisX.Minimum = ptSeries.Points[0].XValue;
chChannels[channel].ChartAreas[0].AxisX.Maximum = DateTime.FromOADate(ptSeries.Points[0].XValue).AddSeconds(10).ToOADate();
chChannels[channel].Invalidate();
在不同的线程中绘制图表中的数据是一种很好的方法。
读取新数据时,数据存储在列表或数组中。由于是实时数据,所以这里也会生成时间戳。使用采集数据的采样率:timeStamp = timeStamp + sampleIdx/sampleRate;
public void OnDataRead(object source, EEGEventArgs e)
{
if ((e.rawData.Length > 0) && (!_shouldStop))
{
lock (_bufferRawData)
{
for (int sampleIdx = 0; sampleIdx < e.rawData.Length; sampleIdx++)
{
// Append data
_bufferRawData.Add(e.rawData[sampleIdx]);
// Calculate corresponding timestamp
secondsToAdd = (float) sampleIdx/e.sampleRate;
// Append corresponding timestamp
_bufferXValues.Add( e.timeStamp.AddSeconds(secondsToAdd));
}
}
然后,创建一个线程,每N毫秒休眠一次(100毫秒适合我显示2秒的数据,但如果我想显示10秒,我需要增加线程的休眠时间到500毫秒)
//Create thread
//define a thread to add values into chart
ThreadStart addDataThreadObj = new ThreadStart(AddDataThreadLoop);
_addDataRunner = new Thread(addDataThreadObj);
addDataDel += new AddDataDelegate(AddData);
//Start thread
_addDataRunner.Start();
最后,更新图表并让线程每 N 毫秒休眠一次
private void AddDataThreadLoop()
{
while (!_shouldStop)
{
chChannels[1].Invoke(addDataDel);
// Sleeep thread for 100ms
Thread.Sleep(100);
}
}
数据将每 100 毫秒添加到图表中
private void AddData()
{
// Copy data stored in lists to arrays
float[] rawData;
DateTime[] xValues;
if (_bufferRawData.Count > 0)
{
// Copy buffered data in thread-safe manner
lock (_bufferRawData)
{
rawData = _bufferRawData.ToArray();
_bufferRawData.Clear();
xValues = _bufferXValues.ToArray();
_bufferXValues.Clear();
}
for (int sampleIdx = 0; sampleIdx < rawData.Length; sampleIdx++)
{
foreach (Series ptSeries in chChannels[channelIdx].Series)
// Add new datapoint to the corresponding chart (x, y, chartIndex, seriesIndex)
AddNewPoint(xValues[sampleIdx], rawData[sampleIdx], ptSeries);
}
}
}