C# Chartで散布図を描く

# はじめに

C#でグラフを描ける[Chart](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.chart?view=netframework-4.8.1)コントロールを利用して、散布図を描く方法です。ここでいう散布図は時系列データの折れ線グラフなども含みます。  

**Chartコントロールについて**   

* .NET Frameworkに標準搭載されているため、追加のライブラリを導入せず利用可能。但し.NET系では使えないようです。  

* 使用する場合は`System.Windows.Forms.DataVisualization`を参照に追加します。[プロジェクト]→[参照の追加]を選択し、アセンブリの中にある`System.Windows.Forms.DataVisualization`にチェックを入れて[OK]を押します。  

* Chartコントロールは[ツールボックス]の[データ]の中にあります。  
   ![chart100.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/66efb426-583d-00ce-e93a-8437801f422e.png)  

* Chartコントロール関連の主要リンク  

|項目|説明|
|:----|:----|
|[System.Windows.Forms.DataVisualization.Charting 名前空間](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting?view=netframework-4.8.1)|名前空間|
|[Chart クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.chart?view=netframework-4.8.1)|グラフ|
|[ChartArea クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.chartarea?view=netframework-4.8.1)|グラフエリア|
|[Legend クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.legend?view=netframework-4.8.1)|凡例|
|[Axis クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.axis?view=netframework-4.8.1)|軸|
|[Series クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.series?view=netframework-4.8)|データ系列|
|[DataPoint クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.datapoint?view=netframework-4.8)|データ点|
|[AxisScaleView クラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.axisscaleview?view=netframework-4.8.1)|グラフの拡大/縮小されたビュー|


# グラフを描く

:::note warn
本記事に記載のソースコードは、Form上にChartコントロールを1つ配置している（Name=chart1）前提です。またプロジェクト名（名前空間）はWindowsFormsApp1としています。  
:::

## とりあえず描いてみる

![chart101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/99d2b9e9-1a77-79bc-56a9-824d80123985.png)  

.NETでは使用できないので、プロジェクトとして「Windows フォーム アプリケーション(.NET Framewrok)」を使用します。`System.Windows.Forms.DataVisualization`を参照に追加し、Chartコントロールを1つForm上に配置したら、以下のソースを記述します。  

```cs
using System.Windows.Forms;

//Chartコントロールを使用するために必要。
//System.Windows.Forms.DataVisualizationを参照に追加必要。
using System.Windows.Forms.DataVisualization.Charting;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //ChartコントロールをForm上に配置すると、
            //自動で仮のグラフデータが設定されるのでクリアしておく。
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;//フォームいっぱいに表示

            //グラフエリアと凡例を作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア
            chart1.Legends.Add(new Legend());//凡例

            //データ系列を作成
            Series series = new Series();

            //データ系列のグラフの種類を散布図（点のみ）とする
            series.ChartType = SeriesChartType.Point;

            //データ系列にプロットデータ(y=x^2 x範囲-10～10)を追加
            for (int i = -10; i <= 10; i++)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);
        }
    }
}
```

## データ系列を追加する

Chartコントロールの`Series`にデータ系列を追加することで、グラフに表示するデータ系列を追加することができます。  
![chart102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/e4c99f40-db7c-2019-17fe-5ffb72ebdcfa.png)  

```cs
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアと凡例を作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア
            chart1.Legends.Add(new Legend());//凡例

            //データ系列を作成
            Series series = new Series();

            //データ系列のグラフの種類を散布図（点のみ）とする
            series.ChartType = SeriesChartType.Point;

            //データ系列にプロットデータ(y=x^2 x範囲-10～10)を追加
            for (int i = -10; i <= 10; i++)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);

            //データ系列2個目
            Series series2 = new Series();
            series2.ChartType = SeriesChartType.Point;

            //プロットデータ(y=x x範囲-20～20)を追加
            for (int i = -20; i <= 20; i += 2)
            {
                series2.Points.AddXY(i, i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series2);
        }
    }
}
```

## グラフの種類を変更する

設定を変えることでデータ系列のグラフの種類を変更することができます。下記では上から順番に設定を追加していっています。  

|設定|結果|
|:----|:----|
|//グラフの種類を線に変更<br>series.ChartType = [SeriesChartType](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.seriescharttype?view=netframework-4.8).Line;|![chart103a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/bdca9e10-b08b-12e0-6166-c8563cb74649.png)|
|//線の太さ<br>series.BorderWidth = 3;|![chart103b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/b5e7b564-9008-8eb2-3100-1aa367c8ad6e.png)|
|//線の色<br>series.Color = Color.Blue;|![chart103c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/630de485-ee21-7363-6cf8-813b6b9afe60.png)|
|//線の種類<br>series.BorderDashStyle = [ChartDashStyle](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.chartdashstyle?view=netframework-4.8).Dash;|![chart103d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/c1294e8b-91d0-6e62-187b-db05a2548bcb.png)|
|//マーカー追加<br>series.MarkerStyle = [MarkerStyle](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.markerstyle?view=netframework-4.8).Circle;<br>series.MarkerSize = 8;//マーカーサイズ|![chart103e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/83c4fe7f-0e54-fd26-672b-82bd42f4f0d8.png)|
|//マーカーのプロパティ変更<br>series.MarkerColor = Color.White;//色<br>series.MarkerBorderColor = Color.Green;//外枠色<br>series.MarkerBorderWidth = 2;//外枠の太さ|![chart103f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/e6e9993b-02e6-f22e-23ed-fc65a14b581f.png)|
|//凡例文字列の変更<br>series.LegendText = "y = x^2";|![chart103g.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/25a15756-e873-7e22-5bc7-b63212e3c5e8.png)|
|//グラフ上に値ラベルを表示<br>series.IsValueShownAsLabel = true;|![chart103h.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/167deaa1-51a8-926f-d560-b3d1cd54f2d9.png)|

以下は設定変更のサンプルです。「凡例の非表示」や「カスタムラベルの表示」なども併せて実施しています。  

![chart103i.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/426ae887-abc3-5410-7681-c297e0427154.png)  

```cs
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアと凡例を作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア
            chart1.Legends.Add(new Legend());//凡例

            //データ系列を作成
            Series series = new Series();

            //データ系列のグラフの種類を設定
            series.ChartType = SeriesChartType.Line;//線
            series.BorderWidth = 2;//線の太さ
            series.Color = Color.Blue;//線の色
            series.BorderDashStyle = ChartDashStyle.Solid;//線の種類
            series.MarkerStyle = MarkerStyle.Circle;//丸マーカー
            series.MarkerSize = 6;//マーカーサイズ
            series.MarkerColor = Color.White;//マーカーの色
            series.MarkerBorderColor = Color.Blue;//マーカー外枠の色
            series.MarkerBorderWidth = 1;//マーカー外枠の太さ
            series.LegendText = "y = x^2";//凡例文字列の変更

            //データ系列にプロットデータ(y=x^2 x範囲-10～10)を追加
            for (int i = -10; i <= 10; i++)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);

            //データ系列2個目
            Series series2 = new Series();

            //データ系列のグラフの種類を設定
            series2.ChartType = SeriesChartType.Line;//線の種類
            series2.BorderWidth = 2;//線の太さ
            series2.Color = Color.Red;//線の色
            series2.MarkerStyle = MarkerStyle.Triangle;//マーカー種類
            series2.MarkerSize = 8;//マーカーサイズ
            series2.IsVisibleInLegend = false;//凡例を非表示

            //プロットデータ(y=x*2 x範囲-20～20)を追加
            for (int i = -20; i <= 20; i += 5)
            {
                //プロットデータの値を設定
                DataPoint dataPoint = new DataPoint(i, i * 2);

                //プロットデータのラベルを設定
                dataPoint.Label = "(" + i.ToString() + "," + (i * 2).ToString() + ")";

                //系列にプロットデータを追加
                series2.Points.Add(dataPoint);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series2);
        }
    }
}
```

## 第2軸を使用する

`Series`の`XAxisType` `YAxisType`を変更することで、データ系列ごとに主軸を使用するか、第2軸を使用するかを設定できます。以下の例では2個目のデータ系列をX,Y軸とも第2軸に設定しています。  
![chart104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/2ea25fdd-46a8-5a33-177e-4ee5fb8bb84b.png)  

```cs
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアと凡例を作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア
            chart1.Legends.Add(new Legend());//凡例

            //データ系列を作成
            Series series1 = new Series { ChartType = SeriesChartType.Line, Color = Color.Blue };
            Series series2 = new Series { ChartType = SeriesChartType.Line, Color = Color.Red };

            //データ系列にプロットデータを追加
            for (int i = -10; i <= 10; i++)
            {
                series1.Points.AddXY(i, i * i);//y=x^2 x範囲-10～10
                series2.Points.AddXY(i * 2, i * 2);//y=x x範囲-20～20
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series1);
            chart1.Series.Add(series2);

            //データ系列series2の軸を第2軸に設定
            series2.XAxisType = AxisType.Secondary;//X軸として第2軸を使用
            series2.YAxisType = AxisType.Secondary;//Y軸として第2軸を使用
        }
    }
}
```

## 軸の目盛や範囲などを変更する

X軸である`AxisX`を対象として説明をしていますが、他の軸も同様です。  
Y軸の場合は`AxisY`、第2軸の場合は`AxisX2` `AxisY2`となります。  

### Minimum、Maximum、Interval、IntervalOffset、MinorGrid

例えば以下のコードを実行すると、目盛が中途半端な値となります。  

![chart105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/0710261c-8e3c-7627-585b-76f9900fcefc.png)  

```cs
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series { ChartType = SeriesChartType.Line, BorderWidth = 2 };

            //データ系列にプロットデータを追加
            for (double i = -13.15; i <= 20; i++)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);
        }
    }
}
```

軸設定を変えることで、グラフの見た目を変更してみます。  

|設定|結果|
|:----|:----|
|//最小値、最大値を変更<br>chart1.ChartAreas[0].AxisX.Minimum = -15.0;<br>chart1.ChartAreas[0].AxisX.Maximum = 20.0;|![chart105a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/59e5fe17-1d94-469d-e877-28ea49a91763.png)|
|//目盛間隔を10に設定<br>chart1.ChartAreas[0].AxisX.Interval = 10;|![chart105b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/9444bfca-93c5-0a98-be23-73736d0518bb.png)|
|//目盛のオフセットを設定。-15に対して5を足して-10から目盛を表示<br>chart1.ChartAreas[0].AxisX.IntervalOffset = 5;|![chart105c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/ea3e1fbe-4778-25b6-18b0-0b45abbe4ffe.png)|
|//補助目盛を追加<br>chart1.ChartAreas[0].AxisX.MinorGrid.Enabled = true;<br>chart1.ChartAreas[0].AxisX.MinorGrid.Interval = 2;<br>chart1.ChartAreas[0].AxisX.MinorGrid.IntervalOffset = 1;|![chart105d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/dd878718-e357-871a-f601-0d3b2c485337.png)|
|//X軸の値0の点でY軸と交差する<br>chart1.ChartAreas[0].AxisX.Crossing = 0;|![chart105e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/51682c12-f23d-20ab-f192-e33b18a00413.png)|

以下は設定変更のサンプルです。上記以外の設定も変更しています。  

![chart106.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/369dfe1b-dc2b-19bc-3be4-4579bda8db6d.png)  


```cs
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series { ChartType = SeriesChartType.Line, BorderWidth = 2 };

            //データ系列にプロットデータを追加
            for (double i = -13.15; i <= 20; i++)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);

            //コードが長くなるので軸を変数に代入
            Axis AxisX = chart1.ChartAreas[0].AxisX;
            Axis AxisY = chart1.ChartAreas[0].AxisY;

            //X軸の設定を変更
            AxisX.Minimum = -15.0;//最小値
            AxisX.Maximum = 20.0;//最大値
            AxisX.Interval = 10;//間隔
            AxisX.IntervalOffset = 5;//間隔のオフセット
            AxisX.LineWidth = 2;//軸の太さ

            //X軸の補助目盛を設定
            AxisX.MinorGrid.Enabled = true;//補助目盛を使用
            AxisX.MinorGrid.Interval = 2;//間隔
            AxisX.MinorGrid.IntervalOffset = 1;//間隔のオフセット
            AxisX.MinorGrid.LineColor = Color.FromArgb(200, 200, 200);//色
            AxisX.MinorGrid.LineDashStyle = ChartDashStyle.Dash;//線の種類

            //X軸のTickMarkを設定
            AxisX.MinorTickMark.Enabled = true;
            AxisX.MinorTickMark.TickMarkStyle = TickMarkStyle.InsideArea;
            AxisX.MinorTickMark.LineWidth = 1;
            AxisX.MinorTickMark.Size = 3;
            AxisX.MinorTickMark.Interval = AxisX.MinorGrid.Interval;
            AxisX.MinorTickMark.IntervalOffset = AxisX.MinorGrid.IntervalOffset;

            //目盛の書式設定
            AxisX.LabelStyle.Format = "0.0";

            //Y軸との交差位置を変更
            AxisX.Crossing = 0;

            //軸のタイトルを設定
            AxisX.Title = "X軸タイトル";
            AxisY.Title = "Y軸タイトル";
        }
    }
}
```
### IsMarginVisible

`IsMarginVisible`により軸の目盛範囲にマージン（余白）を持たせるかどうかを設定できます。  

* `true`（既定値）  
   データ範囲-5～5に対し、左端、右端にマージンが追加され表示範囲が-6～6となっています。  
   ![chart107a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/3d8dd386-f736-32a2-3143-5a7a82107fc0.png)  
* `false`  
   データ範囲がそのまま表示範囲となっています。  
   ![chart107b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/cb32cb53-1b14-6ab3-d61b-e58f4ea0c0eb.png)  

以下は`false`の場合のソースコードです。  

```cs
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series { ChartType = SeriesChartType.Line, BorderWidth = 2 };

            //データ系列にプロットデータを追加
            for (int i = -5; i <= 5; i++)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);

            //軸のマージンを設定
            chart1.ChartAreas[0].AxisX.IsMarginVisible = false;//マージンなしで設定

            //グラフタイトル
            chart1.Titles.Add("IsMarginVisible=" + chart1.ChartAreas[0].AxisX.IsMarginVisible.ToString());
        }
    }
}
```

### IntervalAutoMode

`IntervalAutoMode`により軸の目盛間隔を固定とするか、軸の長さに応じて可変とするかを設定します。  
* `FixedCount`（既定値）  
   サイズを大きくしても目盛間隔は変わりません。  
   ![chart108a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/6d103230-606a-4213-54c0-d412ca01d24f.png)  
* `VariableCount`  
   サイズの大小に応じて目盛間隔が変わります。  
   ![chart108b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/cc5f2be0-7cca-85e4-dda6-e85b66b47821.png)  

以下は`VariableCount`の場合のソースコードです。  

```cs
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series { ChartType = SeriesChartType.Line, BorderWidth = 2 };

            //データ系列にプロットデータを追加
            for (int i = -100; i <= 100; i += 10)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);

            //軸のマージンをなしに設定
            chart1.ChartAreas[0].AxisX.IsMarginVisible = false;

            //目盛の数を固定にするか可変にするか
            chart1.ChartAreas[0].AxisX.IntervalAutoMode = IntervalAutoMode.VariableCount;//可変

            //グラフタイトル
            chart1.Titles.Add("IntervalAutoMode=" + chart1.ChartAreas[0].AxisX.IntervalAutoMode.ToString());
        }
    }
}
```

### ScaleView

グラフの一部を拡大して見たい場合、軸の最大最小値を変更する方法もありますが、表示範囲外を見ることができないため不便です。そのようなときは[`ScaleView`](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.axisscaleview?view=netframework-4.8.1)を使います。下記はデータの範囲が-100～100に対して、-50～50の部分を拡大して表示しています。またスクロールバーにより表示範囲を変更できます。  

![chart109.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/a4d17605-6b77-5593-b87e-ab1ac6e199f3.png)  

```cs
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series { ChartType = SeriesChartType.Line, BorderWidth = 2 };

            //データ系列にプロットデータを追加
            for (int i = -100; i <= 100; i += 1)
            {
                series.Points.AddXY(i, i * i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);

            //Zoomしたとき引数の値をそのまま表示範囲にしたいのでマージンをなしにする。
            //マージンありで、Zoom(-50.0, 50.0)とした場合-51～51のように左右にマージンが作られてしまう。
            chart1.ChartAreas[0].AxisX.IsMarginVisible = false;

            //ScaleViewでグラフを拡大
            chart1.ChartAreas[0].AxisX.ScaleView.Zoom(-50.0, 50.0);
        }
    }
}
```


## 時系列(日時)データを表示する

### X軸データを日時にする
`Series.XValueType = ChartValueType.DateTime`とすると、データ系列のX軸データが日時データとして扱われます。また軸目盛の書式を`yyyy/MM/dd`や`HH:mm:ss`のような[カスタム日時形式文字列](https://learn.microsoft.com/ja-jp/dotnet/standard/base-types/custom-date-and-time-format-strings)で指定することで目盛表記を変更できます。  

![chart110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/8e291d98-b468-9092-7566-a473fd769d6b.png)  

```cs
using System;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series { ChartType = SeriesChartType.Line, BorderWidth = 2 };

            //データ系列のX軸データを日時データとする
            series.XValueType = ChartValueType.DateTime;

            //X軸の目盛の書式設定
            chart1.ChartAreas[0].AxisX.LabelStyle.Format = "yyyy/M/d";

            //データ系列にプロットデータを追加
            for (int i = 1; i <= 180; i++)
            {
                series.Points.AddXY(new DateTime(2015, 5, 1).AddHours(i), Math.Sin((double)(i * 5) / 360 * 2 * Math.PI));
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);
        }
    }
}
```

### 日時をシリアル値に変換する

[`AddXY`](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.datapointcollection.addxy?view=netframework-4.8)には[`AddXY(Double, Double)`](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.datapointcollection.addxy?view=netframework-4.8#system-windows-forms-datavisualization-charting-datapointcollection-addxy(system-double-system-double))だけでなく[`AddXY(Object, Object[])`](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.datapointcollection.addxy?view=netframework-4.8#system-windows-forms-datavisualization-charting-datapointcollection-addxy(system-object-system-object()))といったオーバーロードが存在するためX軸データとして[`DateTime`](https://learn.microsoft.com/ja-jp/dotnet/api/system.datetime?view=net-7.0)をそのまま指定できます。但し軸の最小値[`Axis.Minimum`](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.axis.minimum?view=netframework-4.8.1#system-windows-forms-datavisualization-charting-axis-minimum)や最大値[`Axis.Maximum`](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting.axis.maximum?view=netframework-4.8.1#system-windows-forms-datavisualization-charting-axis-maximum)はDouble型のため、例えば最小値を2051/5/1のように日時で指定したい場合は、[`DateTime.ToOADate`](https://learn.microsoft.com/ja-jp/dotnet/api/system.datetime.tooadate?view=net-7.0)メソッドを使って日時をDouble型（Excelでいうシリアル値）に変換する必要があります。  


![chart111.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/f12dca26-c4f2-7e7c-d653-ec03e46b28e2.png)  

```cs
using System;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series { ChartType = SeriesChartType.Line, BorderWidth = 2 };

            //データ系列のX軸データを日時データとする
            series.XValueType = ChartValueType.DateTime;

            //X軸の目盛の書式設定
            chart1.ChartAreas[0].AxisX.LabelStyle.Format = "M/d HH:mm";

            //データ系列にプロットデータを追加
            for (int i = 1; i <= 180; i++)
            {
                series.Points.AddXY(new DateTime(2015, 5, 1).AddHours(i), Math.Sin((double)(i * 5) / 360 * 2 * Math.PI));
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);

            //X軸の最小最大値を指定
            chart1.ChartAreas[0].AxisX.Minimum = new DateTime(2015, 5, 2, 0, 0, 0).ToOADate();
            chart1.ChartAreas[0].AxisX.Maximum = new DateTime(2015, 5, 2, 20, 0, 0).ToOADate();
        }
    }
}
```
### 日時文字列をDateTimeに変換する

データ系列のX軸データが日時文字列の場合は、[`DateTime.Parse`](https://learn.microsoft.com/ja-jp/dotnet/api/system.datetime.parse?view=net-7.0)によって[`DateTime`](https://learn.microsoft.com/ja-jp/dotnet/api/system.datetime?view=net-7.0)に変換してから使用します。ここでは省略していますが通常は例外処理が必要です。  

![chart112.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/a93b9e42-8079-27ff-6f3b-047f3c9f25d8.png)  

```cs
using System;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series
            {
                ChartType = SeriesChartType.Line,
                BorderWidth = 2,
                MarkerStyle = MarkerStyle.Circle,
                MarkerSize = 8
            };

            //データ系列のX軸データを日時データとする
            series.XValueType = ChartValueType.DateTime;

            //X軸の目盛の書式設定
            chart1.ChartAreas[0].AxisX.LabelStyle.Format = "M/d";

            //データ系列のX軸データ（日時文字列）
            string[] dates = {
                "2015/5/1 10:00:00",
                "2015/5/3 14:00:00",
                "2015/5/3 16:00:00",
                "2015/5/4  9:00:00",
                "2015/5/6 10:00:00",
            };

            int i = 0;
            foreach (string date in dates)
            {
                i++;
                series.Points.AddXY(DateTime.Parse(date), i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);
        }
    }
}
```

### ミリ秒データを表示する

ミリ秒データの場合、目盛が表示されない場合があります。その場合は目盛間隔を明示的に設定するか`IntervalAutoMode`を`VariableCount`にします。  
![chart113.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/552366f0-cdab-aa1b-6d19-66a11e89294e.png)  

```cs
using System;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアを作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア

            //データ系列を作成
            Series series = new Series
            {
                ChartType = SeriesChartType.Line,
                BorderWidth = 2,
                MarkerStyle = MarkerStyle.Circle,
                MarkerSize = 8
            };

            //データ系列のX軸データを日時データとする
            series.XValueType = ChartValueType.DateTime;

            //X軸の目盛の書式設定
            chart1.ChartAreas[0].AxisX.LabelStyle.Format = "mm:ss.fff";
            chart1.ChartAreas[0].AxisX.LabelStyle.Angle = -90;//目盛の表示角度

            //どちらかを設定しないと目盛が表示されない
            chart1.ChartAreas[0].AxisX.IntervalAutoMode = IntervalAutoMode.VariableCount;
            //chart1.ChartAreas[0].AxisX.Interval = (1.0 / 24.0 / 60.0 / 60.0 / 1000.0) * 100.0;//100msec間隔

            //データ系列のX軸データ（日時文字列）
            string[] dates = {
                "2015/5/1 0:00:00.110",
                "2015/5/1 0:00:00.204",
                "2015/5/1 0:00:00.334",
                "2015/5/1 0:00:00.412",
                "2015/5/1 0:00:00.501",
                "2015/5/1 0:00:00.640",
                "2015/5/1 0:00:00.767",
                "2015/5/1 0:00:00.878"
            };

            int i = 0;
            foreach (string date in dates)
            {
                i++;
                series.Points.AddXY(DateTime.Parse(date), i);
            }

            //データ系列をChartコントロールに追加
            chart1.Series.Add(series);
        }
    }
}
```

## CSVファイルのデータを表示する

CSVファイルの内容を読み込むにあたって[`TextFieldParser`](https://learn.microsoft.com/ja-jp/dotnet/api/microsoft.visualbasic.fileio.textfieldparser?view=net-7.0)を使用しています。`TextFieldParser`を使用すると`a,"b,b",c`や`a,"b\n(改行)b",c`などようなデータも問題なくパースできます。使用するためには`Microsoft.VisualBasic`を参照に追加する必要があります。  

![chart114.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3193449/76d73a83-5ffc-8af1-3140-9113706e9614.png)  

CSVファイル  
```:C:\work\sample.csv
日時,データ1,データ2
2015/5/1 0:00,1,1
2015/5/1 12:00,5,2
2015/5/2 0:00,4,3
2015/5/2 12:00,3,4
2015/5/3 0:00,7,
2015/5/3 12:00,6,6
2015/5/4 0:00,2,7
2015/5/4 12:00,4,8
```

ソースコード  
```cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;//グラフ用
using Microsoft.VisualBasic.FileIO;//TextFieldParserを使用するために必要。Microsoft.VisualBasicを参照に追加必要

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //初期化
            chart1.ChartAreas.Clear();
            chart1.Series.Clear();
            chart1.Legends.Clear();
            chart1.Dock = DockStyle.Fill;

            //グラフエリアと凡例を作成
            chart1.ChartAreas.Add(new ChartArea());//グラフエリア
            chart1.Legends.Add(new Legend());//凡例

            //X軸の目盛の書式設定
            chart1.ChartAreas[0].AxisX.LabelStyle.Format = "M/d H:mm";

            //読み込むファイル
            string filepath = @"C:\work\sample.csv";

            //ファイルの全データ
            List<List<string>> allDatas = new List<List<string>>();

            //ファイルの内容を読み込んで配列に格納
            using (TextFieldParser textFieldParser = new TextFieldParser(filepath, Encoding.GetEncoding(932)))
            {
                //区切り文字としてカンマを設定
                textFieldParser.TextFieldType = FieldType.Delimited;
                textFieldParser.SetDelimiters(",");

                while (!textFieldParser.EndOfData)
                {
                    try
                    {
                        string[] cells = textFieldParser.ReadFields();
                        allDatas.Add(new List<string>(cells));
                    }
                    catch (Exception)
                    {
                        ;
                    }
                }
            }

            //データ系列の作成
            List<Series> series = new List<Series>();

            bool firstline = true;//1行目かどうか
            foreach (var cells in allDatas)
            {
                if (firstline)//1行目はデータ系列の項目名とする
                {
                    firstline = false;

                    //データ系列の作成
                    for (int i = 1; i < cells.Count; i++)
                    {
                        //X軸データを日時データとして、データ系列を作成
                        Series s = new Series
                        {
                            ChartType = SeriesChartType.Line,
                            BorderWidth = 2,
                            XValueType = ChartValueType.DateTime
                        };

                        //項目名を凡例とする
                        s.LegendText = cells[i];

                        //配列に追加
                        series.Add(s);
                    }
                }
                else//2行目以降はデータ系列のデータ値とする
                {
                    if (series.Count + 1 == cells.Count)//データはX軸データも含むので系列の数+1
                    {
                        DateTime dt;
                        if (DateTime.TryParse(cells[0], out dt))//1列目が日時変換できる場合
                        {
                            for (int i = 0; i < series.Count; i++)
                            {
                                //プロットデータ
                                DataPoint dataPoint = new DataPoint();

                                //プロットデータに値を設定。数値変換できない場合は空データとする
                                double value;
                                dataPoint.IsEmpty = !double.TryParse(cells[i + 1], out value);
                                dataPoint.SetValueXY(dt, value);

                                //データ系列に追加
                                series[i].Points.Add(dataPoint);
                            }
                        }
                    }
                }
            }

            //データ系列をChartコントロールに追加
            foreach (Series s in series)
            {
                chart1.Series.Add(s);
            }
        }
    }
}
```

# 参考URL

* [System.Windows.Forms.DataVisualization.Charting 名前空間](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.datavisualization.charting?view=netframework-4.8.1)  
* [Chart | Tech and Investment](https://tech-and-investment.com/category/c-sharp/graph-c-sharp/chart-graph-c-sharp/)