web-dev-qa-db-ja.com

チャートコントロールY軸のスクロール時の自動スケール

私はしばらくの間ネットを検索してきましたが、それでも私の問題に対する良い解決策は見つかりませんでした。すべてのデータポイントが表示されるように、スクロール時にY軸を自動的に再スケーリングするMSチャートを作成したいと思います。ここでのひねりは、特定のシリーズを自動スケールの使用から除外する機能が必要なことです。これまでのところ、AxisViewChangedイベントでポイントコレクション全体を反復処理することを提案するソリューションのみが見つかりました。これは、反復するポイントの大規模なコレクションといくつかのシリーズがある場合はうまく機能しません。現在表示されている最小X値と最大X値の間にあるデータポイントを取得して検索を絞り込む方法があるかどうか疑問に思いました。どんな助けでもいただければ幸いです。

編集画像はこちらです。ご覧のとおり、真ん中のローソク足は完全には見えません。 enter image description here

10
L.E.O

このコードを試すことができます

        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

6
Stecya

クエリを使用して、コード内の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;
        }
    }
5
Shivaram K R

これは、Shivaram K Rからの優れた提出物のマイナーな改善であり、4つの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; 
    } 
} 
3
Chris J

上記の回答は私にとって非常に役に立ちました。ただし、複数のグラフ領域があるグラフがあります。すべてのグラフ領域にスケールアップするようにコードを調整しました。

    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
Boris Zinchenko

以前の回答に基づく

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

チャートエリアにもっとシリーズがあるかもしれません。この場合、1つだけではなく、エリア内のすべてのシリーズの高低を選択します。

よろしく、

Matthijs

0
user369122