では、WEBで見つけたサンプルを組み合せて作った、Visual Srudioを使わない、MSCompAss用の折れ線、棒、円グラフのサンプルを載せますが、コード自体の説明はコメントを読んでいただくとして、以下はMSCompAssを使う場合(Visual Studioを使わない場合)のポイントを書きます。
1.MSCompAss使用の際に注意すること
Visual Studioを使うと、ユーザーが知ると否とにかかわらず、勝手に必要なコードを作ってくれるので便利である反面、WEBに載っているサンプルでは想像力を働かせて細くしなければなりません。
(1)先ず、サンプルでは(Visual Studio上で貼り付けたコントロールのインスタンス生成、初期設定等をInitControls()関数ですべてまとめてやっちゃうのですが、それは通常表示されていませんので)コントロールはクラスインスタンスが出来上がった状態から書かれていますので、初期設定を行わなければなりません。
(2)今回のMS Chartで問題となったのは、まず"using System.Windows.Forms.DataVisualization.Charting;"と書いても"using System.Windows.FormsにはDataVisualization.Chartingは見当たりません"というようなエラーが出たことです。これは↓のコードの/*~*/にあるように、csc.exeが検索するように指定されたシステムDLLが入っている場所にSystem.Windows.Forms.DataVisualization.Charting.dllがないので、コンパイラーにDLL参照指示を与える必要があるということです。ご自身のPC環境でどこにあるか調べてオプションの「DLL参照」に加える必要があります。ご参考までに末尾に私の環境におけるサンプルのoptファイルを載せておきます。
(3)また、Chartクラスのインスタンスを作ってグラフが表示されても「凡例」が表示されないことに気が付き、調べた結果、凡例を表示するにはCharクラスインスタンスのLegendプロパティにAdd()メソッドを使って凡例を作ってやることが必要であることが分かりました。"chart.Legends.Add("Legend1");"
2.MS Chartの使い方
C#でMS Chartを使うのは極めて簡単です。いろいろなサンプルで記述が一様ではないのですが、私は以下のように統一的な書き方にしてみました。
(1)まず参照できる範囲にChartクラスインスタンスを作成する
C#では"Chart chart;"とクラスインスタンスを宣言してもその段階では必要なメモリー領域が確保できていないのでエラーになります。(エラーにはなりませんが、C++の"Chart* chart;"なんだ、と理解するとよいと思います。)したがって可視範囲にクラスインスタンスを宣言したらその段階で"new Chart();"としてインスタンスを確保するか、↓のコードのようにコンストラクターやWM_CREATEの段階で確保する必要があります。
なお、C++では"new したら、delete"ですが、C#ではマネージされたリソースは"dispose"メソッドで開放する必要がありませんが、マネージされていないリソースを使うとユーザーでdisopseによる開放を行う必要があります。Chartのサンプルでは特印disopse()していなかったのでマネージされたリソースになるのかな、と思っていましたが、Microsoft Docsではdispose(bool)メソッドがあり、「trueはマネージされたリソース、マネージされていないリソースの両方、falseはマネージされていないリソースのみ開放」と書かれています。まぁ、サンプルでも使っていなかったのでマニュアル開放はしていませんが、気になる方はdispose()してください。(ここがC#のやりにくいところなんですが...)
(2)(凡例を使いたい場合)作ったChartインスタンスに凡例(Legend)を追加(Add)する
上記↑1.(3)参照。
(3)MS Chartの初期化
最初のまっさらなChartインスタンスでは問題ないのですが、一度使ったインスタンスは再初期化する必要があります。一般的な初期化対象はChartインスタンスの(以下に述べる)「領域」、その「名称」(タイトル)と「系列」になります。
(4)(タイトルが必要であれば)タイトル設定
次に述べるグラフを描く「領域」にタイトルが設定できます。
(5)チャートエリア作成(複数可)
MS Chartは丁度「グラフを描くキャンバス」のようなものだと考えてください。このキャンバスは最初一つですが、複数のグラフ領域(チャートエリア-ChartArea )に分割することもでき、それぞれに個別のタイトルを与えることが出来ます。
(6)系列の作成(複数可)
チャートエリアが決まったら、それぞれに描くグラプとなる「系列-Series」を作り、グラフ種類を決めてそれぞれのグラフ種類に合わせた設定を行ってゆきます。
一つのチャートエリアに複数のグラフを書くことも可能(Sample 2)ですし、チャートエリアを分けて複数のグラフを書くことも可能(Sample 4)です。
(7)(グラフの)データ設定
データは系列のPoints配列(コレクション)に追加(Addメソッド)してゆけばよく、チャートに凡例(Legend)を作成しおればそれに反映されます。
(8)チャート設定
最後にChartインスタンスに名前、領域、系列をAdd()メソッドで設定します。また個別のグラフについて背景色等、Chart自体の設定を行うこともできます。
3.MS Chartのサンプルについて
以下のコードは、MS Chartの上でマウスクリックを行うと、
(1)単純な折れ線グラフ(Sample 1)
(2)折れ線グラフと棒グラフの混合(Sample 2)
(3)円グラフ(Sample 3)
(4)領域を区分した折れ線グラフと棒グラフの混合(Sample 4)
を表示するサンプルです。
さて、いかがでしたか?C++プログラミングでは考えられないような簡単さで、矢張りVisual Basicを髣髴とさせます。しかし、如何にMS Chartが簡単に使えても、家庭でグラフを見て分析するような問題は余り考えられず、これならExcelでやった方が簡単、ということも事実ですね!同様にDataGridも使えますが、これも矢張り完成されているExcelの方が簡単なので余り食指が動きません。「【.NET】C# や VB で使う全コントロール一覧(サンプル画像付き)」というサイトも見ましたが、見慣れたコントロールばかりですね。また、何か面白いネタを考えてみましょう。
【SampleMSChart.cs】
//Visual Studioで行われる一般的Windowsプログラム用クラス宣言
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
//MS Chart利用の為追加される宣言
using System.Windows.Forms.DataVisualization.Charting;
/*
但し、DataVisualizationクラスは一般的なクラスが入っているフォールダー
C:\Windows\Microsoft.NET\assembly\GAC_32(64)
ではなく、csc.exeがデフォルトでは参照しないフォールダーである
C:\Windows\Microsoft.NET\assembly\GAC_MSIL
に入っているため、Visual Studioではプロジェクトの「参照」で行うcsc.exe
のオプションに以下を与える必要がある。
"RefFile=C:\Windows\Microsoft.NET\assembly\GAC_MSIL\...\System.Windows.Forms.DataVisualization.dll"
(注:私のシステムで...は"System.Windows.Forms.DataVisualization\v4.0_4.0.0.0__31bf3856ad364e35")
*/
namespace SampleMSChart
{
public partial class SampleChart : Form
{
//MS Charコントロールインスタンス(ポインター)
Chart chart;
//エントリーポイント
[STAThread]
public static void Main()
{
Application.Run(new SampleChart());
}
//コンストラクター
public SampleChart()
{
//フォームの設定
this.Size = new Size(800, 480);
this.MinimumSize = new Size(320, 190);
this.Text = "Sample - MS Chart";
this.Load += Form_Load; //WM_CREATE処理
}
//WM_CREATE処理
private void Form_Load(object sender, EventArgs e)
{
//Visual Studioでは以下の処理が InitControls(); で行われる
//MS Chart インスタンスの生成と設定
chart = new Chart();
chart.Location = new Point(10, 10);
chart.Size = new Size(ClientSize.Width - 20, ClientSize.Height - 20);
chart.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
chart.Legends.Add("Legend1"); //Addしないと「凡例」が表示されない
/*
//凡例の幅と高さを設定
chart.Legends[0].Position.Auto = false;
chart.Legends[0].Position.Width = 20.0f;
chart.Legends[0].Position.Height = 20.0f;
//凡例の位置を設定します
chart.Legends[0].Position.X = 80.0f;
chart.Legends[0].Position.Y = 90.0f;
*/
this.Controls.Add(chart);
//MS Chart上でマウスクリックした場合の処理を追加
chart.Click += Chart_Click;
}
//MS Chart上でマウスクリックした場合の処理
private void Chart_Click(object sender, System.EventArgs e)
{
//Sample 1
MessageBox.Show("最初のサンプルです", "サンプル1", MessageBoxButtons.OK, MessageBoxIcon.Information);
Sample1();
//Sample 2
MessageBox.Show("二番目ののサンプルです", "サンプル2", MessageBoxButtons.OK, MessageBoxIcon.Information);
Sample2();
//Sample 3
MessageBox.Show("三番目のサンプルです", "サンプル3", MessageBoxButtons.OK, MessageBoxIcon.Information);
Sample3();
//Sample 4
MessageBox.Show("最後のサンプルです", "サンプル4", MessageBoxButtons.OK, MessageBoxIcon.Information);
Sample4();
}
//Sample 1
private void Sample1()
{
//サンプル用データ
double[] pointX = { 1.0, 2.0, 3.0, 4.0, 5.0 };
double[] pointY = { 1.0, 2.0, 3.0, 4.0, 5.0 };
//MS Chartの初期化
chart.Series.Clear();
chart.ChartAreas.Clear();
chart.Titles.Clear();
//タイトル作成
Title title = new Title("サンプル1");
//チャートエリアの作成
ChartArea chartAria = new ChartArea("Area1");
//系列(Series)の作成
Series series = new Series();
series.ChartType = SeriesChartType.Line; //系列の種類を折れ線グラフ(Line)に設定
series.LegendText = "凡例"; //系列の凡例を設置
series.IsVisibleInLegend = true;
//ポイントデータを設定
for (int i = 0; i < 5; i++)
{
series.Points.AddXY(pointX[i], pointY[i]);
}
//チャートの設定
chart.Titles.Add(title);
chart.ChartAreas.Add(chartAria);
chart.Series.Add(series);
}
//Sample 2
private void Sample2()
{
//MS Chartの初期化
chart.Series.Clear();
chart.ChartAreas.Clear();
chart.Titles.Clear();
//タイトル設定
Title title = new Title("サンプル2");
//チャートエリアの作成
ChartArea chartAria = new ChartArea("Area1");
chartAria.AxisX.Title = "X軸";
chartAria.AxisY.Title = "Y軸";
//系列の作成
Series series = new Series();
series.ChartType = SeriesChartType.Line; //系列の種類を折れ線グラフ(Line)に設定
series.LegendText = "凡例:折れ線グラフ"; //系列の凡例を設置
series.BorderWidth = 3; //系列の境界線太さ
series.MarkerStyle = MarkerStyle.Circle; //系列のポイントマークの形状
series.MarkerSize = 12; //系列のポイントマークの大きさ
series.Color = Color.BlueViolet;
//系列の追加とデータ作成
Series seriesColumn = new Series();
seriesColumn.LegendText = "凡例:棒グラフ";
seriesColumn.ChartType = SeriesChartType.Column;
seriesColumn.Color = Color.DeepSkyBlue;
//乱数を使ったデータ作成
Random rdm = new Random();
for (int i = 0; i < 10; i++)
{
series.Points.Add(new DataPoint(i, rdm.Next(0, 210)));
}
for (int i = 0; i < 10; i++)
{
seriesColumn.Points.Add(new DataPoint(i, rdm.Next(0, 210)));
}
//チャート設定
chart.Titles.Add(title);
chart.ChartAreas.Add(chartAria);
chart.Series.Add(seriesColumn);
chart.Series.Add(series);
}
//Sample 3
private void Sample3()
{
//MS Chartの初期化
chart.Series.Clear();
chart.ChartAreas.Clear();
chart.Titles.Clear();
//タイトル設定
Title title = new Title("サンプル3");
//チャートエリア作成
ChartArea chartAria = new ChartArea("Area1");
//系列の作成
string legend = "PieGraph";
Series series = new Series(legend);
// series.ChartType = SeriesChartType.Pie; //系列の種類を円グラフ(Pie)に設定
series.ChartType = SeriesChartType.Doughnut; //系列の種類を円グラフ(Doughnut)に設定
series.LegendText = "凡例:円グラフ"; //系列の凡例を設置
series.BorderWidth = 2; //系列の境界線太さ
//乱数を使ったデータ作成
Random rdm = new Random();
double[] values = new double[5];
double total = 0.0;
for(int i = 0; i < values.Length; i++)
{
values[i] = (double)rdm.Next(0, 20);
total += values[i];
}
//系列にデータを設定
for(int i = 0; i < values.Length; i++)
{
double rate = (int)(values[i] * 10000.0 / total) / 100.0; //小数点以下2桁にする
series.Points.Add(new DataPoint(rate, rate));
series.Points[i].LegendText = "製品" + i.ToString() + ": " + rate.ToString();
}
//チャート設定
chart.Titles.Add(title);
chart.ChartAreas.Add(chartAria);
chart.Series.Add(series);
chart.ChartAreas["Area1"].BackColor = Color.SeaShell; //背景色を変更
}
//Sample 4
private void Sample4()
{
//MS Chartの初期化
chart.Series.Clear();
chart.ChartAreas.Clear();
chart.Titles.Clear();
//タイトル設定
Title title = new Title("サンプル4");
Title title1 = new Title("グラフ1");
Title title2 = new Title("グラフ2");
title1.DockedToChartArea = "Area1"; // ChartAreaとの紐付
title2.DockedToChartArea = "Area2"; // ChartAreaとの紐付
//チャートエリア作成
ChartArea chartAria = new ChartArea("Area1");
chartAria.AxisX.Title = "X軸";
chartAria.AxisY.Title = "Y軸";
ChartArea chartAria2 = new ChartArea("Area2");
chartAria2.AxisX.Title = "X軸";
chartAria2.AxisY.Title = "Y軸";
//系列の作成
Series series = new Series();
series.ChartType = SeriesChartType.Line; //系列の種類を折れ線グラフ(Line)に設定
series.LegendText = "凡例:折れ線グラフ"; //系列の凡例を設置
series.BorderWidth = 2; //系列の境界線太さ
series.MarkerStyle = MarkerStyle.Circle; //系列のポイントマークの形状
series.MarkerSize = 12; //系列のポイントマークの大きさ
//乱数を使ったデータ作成
Random rdm = new Random();
for (int i = 0; i < 10; i++)
{
series.Points.Add(new DataPoint(i, rdm.Next(0, 210)));
}
series.ChartArea = "Area1"; // ChartAreaとの紐付
//系列の追加とデータ作成
Series seriesColumn = new Series();
seriesColumn.LegendText = "凡例:棒グラフ";
seriesColumn.ChartType = SeriesChartType.Column;
for (int i = 0; i < 10; i++)
{
seriesColumn.Points.Add(new DataPoint(i, rdm.Next(0, 210)));
}
seriesColumn.ChartArea = "Area2"; // ChartAreaとの紐付
//チャート設定
chart.Titles.Add(title);
chart.Titles.Add(title1);
chart.Titles.Add(title2);
chart.ChartAreas.Add(chartAria);
chart.ChartAreas.Add(chartAria2);
chart.Series.Add(series);
chart.Series.Add(seriesColumn);
chart.ChartAreas["Area1"].BackColor = Color.WhiteSmoke; //背景色を変更
}
}
}
【SampleMSChart.opt】
[Compile Option]
Target=2
Resource=0
RscFile=
IconFile=C:\Users\ysama\Programing\C# Programing\Samples\Resources\resources\CatFace.ico
DbgOpt=0
WarnErr=5
RefFile=C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Windows.Forms.DataVisualization\v4.0_4.0.0.0__31bf3856ad364e35\System.Windows.Forms.DataVisualization.dll
Others=