[英]Adding points to the left side of a chart
在WinForms中,我正在嘗試創建一個交互式圖表,但我遇到了一個方面的困難。 我正在使用System.Windows.Forms.DataVisualization.Charting.Chart作為圖表,並使用FastLine系列來呈現數據。
在此圖表中,您可以縮放/平移/更改通道,並根據需要動態添加/刪除新點。 原因是這些點的來源是一個大的二進制文件,可以超過一千兆字節,我使用MemoryMappedFile來提取盡可能少的數據來提高性能。
當向右平移時,一切正常 - 新的點被添加到列表的末尾,你甚至不能說它們在一秒鍾之前就不存在了。
但是,當我向左平移時,圖表以非常奇怪的方式顯示。 整條地方都有線路。 我知道這里發生了什么,我無法弄清楚如何解決它。
原因是當添加一個點時,從添加到新點的最后一個點繪制一條線。 因此,如果最后一個點被添加到右側,並且新點被添加到左側,則一條線將穿過圖形。
以下是為圖表添加點的代碼:
for (var i = scanStart; i + _step <= scanEnd; i += _step)
{
var sample = _expeData.ReadSample(channel, i);
Series[0].Points.AddXY(i, sample);
}
有沒有辦法防止這種情況發生? 這是一個屏幕截圖,顯示向左平移后的樣子:
我決定嘗試使用LINQ來處理排序。
// Suspend updates prior to insertion to speed everything up
chart1.Series[0].Points.SuspendUpdates();
// Do a quicky population for testing purposes
for (int i = 0; i < 100; i++)
{
chart1.Series[0].Points.AddXY(i, i);
}
for (int i = -100; i < 0; i++)
{
chart1.Series[0].Points.AddXY(i, -i * 2);
}
// Sort the data points
var newDataPoints =
(from d in chart1.Series[0].Points
orderby d.XValue
select new { XValue = d.XValue, YValue = d.YValues[0] }).ToList();
// Replace the datapoints
chart1.Series[0].Points.DataBind(newDataPoints, "XValue", "YValue", "");
// Turn updates back on
chart1.Series[0].Points.ResumeUpdates();
這是一個很酷的控制,我以前從未注意過。 請不要將我的帖子標記為答案。 它只是大聲說話。
你能清除圖表並在LEFT PAN上重新分配數據嗎?
您可以向您的類聲明一些全局變量:
private int x_index;
private DataTable m_dataTable;
在Chart的構造函數中,連接AxisViewChanging和AxisViewChanged事件處理程序:
public Form1() {
InitializeComponent();
x_index = -1;
if (graph1.Series == null) {
graph1.Series = new SeriesCollection();
}
graph1.AxisViewChanging += new EventHandler<ViewEventArgs>(graph1_AxisViewChanging);
graph1.AxisViewChanged += new EventHandler<ViewEventArgs>(graph1_AxisViewChanged);
}
現在,修改Get Data例程以將數據收集到新的DataTable中:
private void GetData(string channel, int scanStart, int step, int scanEnd) {
m_dataTable = new DataTable();
var col1 = m_dataTable.Columns.Add("Index", typeof(int));
var col2 = m_dataTable.Columns.Add("Data", typeof(Series));
for (var i = scanStart; i + step <= scanEnd; i += step) {
var sample = _expeData.ReadSample(channel, i);
var row = m_dataTable.NewRow();
row[col1] = i;
row[col2] = new Series(sample);
m_dataTable.Rows.Add(row);
}
}
下面的更改處理程序只記錄您當前的索引:
private void graph1_AxisViewChanging(object sender, ViewEventArgs e) {
// below is probably wrong, but basically, get the x_axis before the data changes
x_index = Convert.ToInt32(graph1.Series[0].XValueMember);
}
下面的Changed處理程序用於顯示您在上面收集的x_index
之前的數據:
private void graph1_AxisViewChanged(object sender, ViewEventArgs e) {
var index = Convert.ToInt32(graph1.Series[0].XValueMember);
if (index < x_index) {
graph1.Series.Clear();
for (int i = index; i < index + 50; i++) {
var pt = (Series)m_dataTable.Rows[i]["Data"];
graph1.Series.Add(pt);
}
}
}
在上面,值50
將是您想要計算的任何值。 它應該在代碼中的某處確定為變量或常量,以使其看起來不像幻數。
我不確定這是否符合您的要求。
如果是這樣的話,當有人平移時,需要調整它來計算你的價值 - 因為我的代碼可能會破壞這個功能。 ;)
您是否嘗試過使用InsetXY方法?
chart.Series[0].Points.InsertXY(0, i, sample)
有了它,你將始終添加到第一個位置。
不知道這是否適合你的問題。
我發現解決方案是使用Series [0] .Sort()函數。 我修改了原始代碼如下:
for (var i = scanStart; i + _step <= scanEnd; i += _step)
{
var sample = _expeData.ReadSample(_channel, i);
Series[0].Points.AddXY(i, sample);
}
Series[0].Sort(new PointComparer());
我添加了一個私有類來處理排序:
private class PointComparer : IComparer<DataPoint>
{
public int Compare(DataPoint x, DataPoint y)
{
return (int)(x.XValue - y.XValue);
}
}
這基於XValue對點進行排序。 當點數開始增長到大約40,000以上時,會有輕微的性能損失。 但是,我可以通過僅加載屏幕上可見的點(在現代寬屏顯示器上最多大約2,000點)然后在超過一定量(我使用20,000)時修剪來減輕這種情況。 這導致在相對大量的搖攝后偶爾出現打嗝,但這不是很明顯。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.