开发者

Chart Control Y axis auto-scale on scrolling

开发者 https://www.devze.com 2023-02-17 16:55 出处:网络
I\'ve been searching the net for some time now yet still haven\'t found any good solution to my problem. I want to make MS Chart to automatically rescale Y axis on scrolling to make sure that all data

I've been searching the net for some time now yet still haven't found any good solution to my problem. I want to make MS Chart to automatically rescale Y axis on scrolling to make sure that all data points are visible. The twist here is that I need to have the ability to exclude certain series from being used for auto scale. So far I only found solutions that offer to iterate through the entire point collection on AxisViewChanged event, which doesn't work well when you have large col开发者_StackOverflow中文版lections of points and a few series to iterate through. I was wondering if there was any way to narrow the search by obtaining data points that are between currently visible min and max X values. Any help would be appreciated.

Edit Heres the image. As you can see the candlesticks in the middle aren't entirely visible.

Chart Control Y axis auto-scale on scrolling


you can try this code

        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;

Chart Control Y axis auto-scale on scrolling


Use a query to find out which series you want to use for finding ymin and ymax in the code.

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


This is a minor improvement on the excellent submission from Shivaram K R, to prevent open, close and low dropping off the bottom for the lowest points on financial charts with four Y values: high, low, open close.

// 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; 
    } 
} 


Based on previous answers

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

It could be you have more series in the chartarea. In this case you pick the high and low of all series in the area instead of just one.

regards,

Matthijs


Above answers were very helpful for me. However, I have a chart with multiple charting areas. I have adapted the code to scale up to all chart areas:

    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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号