图表控件Y轴滚动时自动缩放

11

我已经在网上搜索了一段时间,但仍然没有找到解决我的问题的好方法。我想让MS Chart在滚动时自动重新调整Y轴,以确保所有数据点都可见。这里的关键是,我需要有能力排除某些系列用于自动缩放。到目前为止,我只发现了提供在AxisViewChanged事件上迭代整个点集合的解决方案,但当您具有大量点和要迭代的几个系列时,效果不佳。我想知道是否有任何方法可以通过获取当前可见的最小和最大X值之间的数据点来缩小搜索范围。任何帮助都将不胜感激。

编辑 这里是图像。正如您所看到的,中间的蜡烛并不完全可见。 enter image description here


1
嗯,我不太清楚...你是想在滚动X轴的同时重新调整Y轴吗?否则这对我来说没有意义。顺便问一下,你能给出一个你需要的视觉示例吗? - digEmAll
@digEmAll 是的,没错 - L.E.O
5个回答

6
你可以尝试这段代码。
        DateTime date = DateTime.Now;
        chart1.ChartAreas[0].AxisX.Minimum = 0;
        chart1.ChartAreas[0].AxisX.Maximum = 20;
        Random r = new Random((int)date.Ticks);

        chart1.Series[0].ChartType = SeriesChartType.Candlestick;
        chart1.Series[0].Color = Color.Green;
        chart1.Series[0].XValueType = ChartValueType.Time;
        chart1.Series[0].IsXValueIndexed = true;
        chart1.Series[0].YValuesPerPoint = 4;
        chart1.Series[0].CustomProperties = "MaxPixelPointWidth=10";
        for (int i = 0; i < 100; i++ )
        {
            DataPoint point = new DataPoint(date.AddHours(i).ToOADate(), new double[] { r.Next(10, 20), r.Next(30, 40), r.Next(20, 30), r.Next(20, 30) });
            chart1.Series[0].Points.Add(point);
        }

        int min = (int)chart1.ChartAreas[0].AxisX.Minimum;
        int max = (int)chart1.ChartAreas[0].AxisX.Maximum;

        if (max > chart1.Series[0].Points.Count)
            max = chart1.Series[0].Points.Count;

        var points = chart1.Series[0].Points.Skip(min).Take(max - min);

        var minValue = points.Min(x => x.YValues[0]);
        var maxValue = points.Max(x => x.YValues[1]);

        chart1.ChartAreas[0].AxisY.Minimum = minValue;
        chart1.ChartAreas[0].AxisY.Maximum = maxValue;

enter image description here


@Stecya。我的X值是DateTime类型,这使得最大值远低于最小值,因此点集变成了一个空集合。 - L.E.O
如果使用 chart1.Series[0].IsXValueIndexed = true;,则 X 值将为整数,标签仍将为日期时间。 - Stecya
@Stecya。但这会删除X轴上的所有空白间隙,不是吗? - L.E.O
是的,它会有空隙,但我从屏幕上看到你正在开发一些金融图表,周六/周日没有数据,所以会出现一个巨大的空白间隔。 - Stecya
@Stecya。对我来说,AxisX.Minimum始终返回1,而AxisX.Maximum始终返回点数,因此它最终会搜索整个集合,但我认为我可以获取滚动条的位置。 - L.E.O
显示剩余2条评论

6

使用查询语句查找要在代码中用于查找ymin和ymax的系列。

private void chart1_AxisViewChanged(object sender, ViewEventArgs e)
    {
        if (e.Axis.AxisName == AxisName.X)
        {
            int start = (int)e.Axis.ScaleView.ViewMinimum;
            int end = (int)e.Axis.ScaleView.ViewMaximum;

            // Series ss = chart1.Series.FindByName("SeriesName");
            // use ss instead of chart1.Series[0]

            double[] temp = chart1.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToArray();
            double ymin = temp.Min();
            double ymax = temp.Max();

            chart1.ChartAreas[0].AxisY.ScaleView.Position = ymin;
            chart1.ChartAreas[0].AxisY.ScaleView.Size = ymax - ymin;
        }
    }

3

这是对Shivaram K R出色提交的微小改进,旨在防止具有四个Y值(高、低、开盘和收盘)的金融图表上最低点的开盘价、收盘价和最低价掉落到底部。

// The following line goes in your form constructor
this.chart1.AxisViewChanged += new EventHandler<ViewEventArgs> (this.chart1_AxisViewChanged);


private void chart1_AxisViewChanged(object sender, ViewEventArgs e)
{ 
    if (e.Axis.AxisName == AxisName.X) 
    { 
        int start = (int)e.Axis.ScaleView.ViewMinimum; 
        int end = (int)e.Axis.ScaleView.ViewMaximum; 
        // Use two separate arrays, one for highs (same as temp was in Shavram's original)
        // and a new one for lows which is used to set the Y axis min.
        double[] tempHighs = chart1.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToArray();
        double[] tempLows = chart1.Series[0].Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[1]).ToArray();
        double ymin = tempLows.Min();
        double ymax = tempHighs.Max();

        chart1.ChartAreas[0].AxisY.ScaleView.Position = ymin; 
        chart1.ChartAreas[0].AxisY.ScaleView.Size = ymax - ymin; 
    } 
} 

0

以上的回答对我非常有帮助。然而,我有一个包含多个图表区域的图表。我已经修改了代码,使其能够适应所有的图表区域:

    foreach (ChartArea area in chart1.ChartAreas)
    {
      List<double> allNumbers = new List<double>();

      foreach (Series item in chart1.Series)
        if (item.ChartArea == area.Name)
          allNumbers.AddRange(item.Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToList());

      double ymin = allNumbers.Min();
      double ymax = allNumbers.Max();

      if (ymax > ymin)
      {
        double offset = 0.02 * (ymax - ymin);
        area.AxisY.Maximum = ymax + offset;
        area.AxisY.Minimum = ymin - offset;
      }
    }

0

根据之前的答案

private void chart1_AxisViewChanged(object sender, ViewEventArgs e)
    {
        if(e.Axis.AxisName == AxisName.X)
        {
            int start = (int)e.Axis.ScaleView.ViewMinimum;
            int end = (int)e.Axis.ScaleView.ViewMaximum;

            List<double> allNumbers = new List<double>();

            foreach(Series item in chart1.Series)
                allNumbers.AddRange(item.Points.Where((x, i) => i >= start && i <= end).Select(x => x.YValues[0]).ToList());

            double ymin = allNumbers.Min();
            double ymax = allNumbers.Max();

            chart1.ChartAreas[0].AxisY.ScaleView.Position = ymin;
            chart1.ChartAreas[0].AxisY.ScaleView.Size = ymax - ymin;
        }
    }

可能您的图表区域中有更多的系列。在这种情况下,您选择该区域中所有系列的高点和低点,而不仅仅是一个。

敬礼,

Matthijs


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接