将点添加到图表的左侧

时间:2013-12-13 23:28:47

标签: c# .net winforms

在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);
}

有没有办法防止这种情况发生?这是一个屏幕截图,显示向左平移后的样子:

enter image description here

4 个答案:

答案 0 :(得分:0)

我决定尝试使用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();

答案 1 :(得分:0)

这是一个很酷的控制,我以前从未注意过。请不要将我的帖子标记为答案。它只是大声说话。

你能清除图表并在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将是您想要计算的任何值。它应该在代码中的某处确定为变量或常量,以使它看起来不像幻数。

我不确定这是否符合您的要求。

如果确实如此,当有人向右移动时,需要调整它来计算您的值 - 因为我的代码可能会破坏该功能。 ;)

答案 2 :(得分:0)

您是否尝试过使用InsetXY方法?

chart.Series[0].Points.InsertXY(0, i, sample)

通过这种方式,您将始终添加到第一个位置。

不知道这是否适合你的问题。

答案 3 :(得分:0)

我发现解决方案是使用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)时修剪来减轻这种情况。这会导致在相对大量的平移后偶尔出现打嗝,但这并不是很明显。