VisualStudioの2010ではグラフを表示するために、Chartコントロールというものが追加されています。
このコントロールを使用すると、手軽にグラフを作成する事が出来るのですが、デフォルトのプロパティ値ではデザインがいまいちなグラフが出来上がってしまいます。
コントロールをフォームに貼った直後のデザインは、以下のような感じになっています。
今回は、Chartコントロールを使用して、主に見た目に関するプロパティを確認しつつ、
Windowsのタスクマネージャー風のグラフを作成してみました。
[今回作成したプログラムによるグラフの表示]
情報を見える形にする技術
今回のサンプルプログラムです。
まずは、チャートの初期化処理です。
private void initChart( Chart chart ) { // チャート全体の背景色を設定 chart.BackColor = Color.Black; chart.ChartAreas[0].BackColor = Color.Transparent; // チャート表示エリア周囲の余白をカットする chart.ChartAreas[0].InnerPlotPosition.Auto = false; chart.ChartAreas[0].InnerPlotPosition.Width = 100; // 100% chart.ChartAreas[0].InnerPlotPosition.Height = 90; // 90%(横軸のメモリラベル印字分の余裕を設ける) chart.ChartAreas[0].InnerPlotPosition.X = 8; chart.ChartAreas[0].InnerPlotPosition.Y = 0; // X,Y軸情報のセット関数を定義 Action<Axis> setAxis = (axisInfo) => { // 軸のメモリラベルのフォントサイズ上限値を制限 axisInfo.LabelAutoFitMaxFontSize = 8; // 軸のメモリラベルの文字色をセット axisInfo.LabelStyle.ForeColor = Color.White; // 軸タイトルの文字色をセット(今回はTitle未使用なので関係ないが...) axisInfo.TitleForeColor = Color.White; // 軸の色をセット axisInfo.MajorGrid.Enabled = true; axisInfo.MajorGrid.LineColor = ColorTranslator.FromHtml("#008242"); axisInfo.MinorGrid.Enabled = false; axisInfo.MinorGrid.LineColor = ColorTranslator.FromHtml("#008242"); }; // X,Y軸の表示方法を定義 setAxis( chart.ChartAreas[0].AxisY ); setAxis( chart.ChartAreas[0].AxisX ); chart.ChartAreas[0].AxisX.MinorGrid.Enabled = true; chart.ChartAreas[0].AxisY.Maximum = 100; // 縦軸の最大値を100にする chart.AntiAliasing = AntiAliasingStyles.None; // 折れ線グラフとして表示 chart.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine; // 線の色を指定 chart.Series[0].Color = ColorTranslator.FromHtml( "#00FF00" ); // 凡例を非表示,各値に数値を表示しない chart.Series[0].IsVisibleInLegend = false; chart.Series[0].IsValueShownAsLabel = false; // チャートに表示させる値の履歴を全て0クリア while ( countHistory.Count <= MAX_HISTORY ) { countHistory.Enqueue( 0 ); } } |
上記の初期化処理は、実際にはGUIからプロパティの指定を行っても問題ありませんが、今回は説明のためにコードから設定しています。
それでは、メソッド内の処理を順に確認してきます。
// チャート全体の背景色を設定 chart.BackColor = Color.Black; chart.ChartAreas[0].BackColor = Color.Transparent; |
まずは、背景を黒にします。chart.BackColorで背景色が指定できますが、これを黒にするだけでは、下記のようにグラフ表示エリアの周囲だけが黒くなってしまいます。

グラフの表示エリア内も同じ色にする為にchart.ChartAreasの背景色を透明にすると、下記のように全体が黒くなります。

// チャート表示エリア周囲の余白をカットする chart.ChartAreas[0].InnerPlotPosition.Auto = false; chart.ChartAreas[0].InnerPlotPosition.Width = 100; // 100% chart.ChartAreas[0].InnerPlotPosition.Height = 90; // 90%(横軸のメモリラベル印字分の余裕を設ける) chart.ChartAreas[0].InnerPlotPosition.X = 8; chart.ChartAreas[0].InnerPlotPosition.Y = 0; |
次に、グラフを表示している周囲の余白を微調整します。
下記の赤枠の部分です。

今回の例では、縦横軸のメモリ数値を表示させるため、HeightとXに余白を残しました。これをもし、Width,Heightを100にして、X,Yを共に0にすると完全に余白が無くなり、以下のような表示となります。

// X,Y軸情報のセット関数を定義 Action<Axis> setAxis = (axisInfo) => { // 軸のメモリラベルのフォントサイズ上限値を制限 axisInfo.LabelAutoFitMaxFontSize = 8; // 軸のメモリラベルの文字色をセット axisInfo.LabelStyle.ForeColor = Color.White; // 軸タイトルの文字色をセット(今回はTitle未使用なので関係ないが...) axisInfo.TitleForeColor = Color.White; // 軸の色をセット axisInfo.MajorGrid.Enabled = true; axisInfo.MajorGrid.LineColor = ColorTranslator.FromHtml("#008242"); axisInfo.MinorGrid.Enabled = false; axisInfo.MinorGrid.LineColor = ColorTranslator.FromHtml("#008242"); }; // X,Y軸の表示方法を定義 setAxis( chart.ChartAreas[0].AxisY ); setAxis( chart.ChartAreas[0].AxisX ); |
次に、縦横軸の表示を変更します。
縦軸と横軸で同じ処理をする箇所が多いので、共通部を無名関数のsetAxis()として定義してしまいます。
この処理を実行する事で、グリッドの線が緑色で、メモリ数値の文字が白色になりました。

chart.ChartAreas[0].AxisX.MinorGrid.Enabled = true; chart.ChartAreas[0].AxisY.Maximum = 100; // 縦軸の最大値を100にする |
縦軸と横軸で個別の設定を行います。
見栄え向上のため、横軸側は補助メモリのグリッドを追加します。
また、縦軸はCPU負荷を想定して、メモリの最大値を100にしてみました。

chart.AntiAliasing = AntiAliasingStyles.None; |
軸メモリの数値にアンチエイリアスを掛けないようにします。
// 折れ線グラフとして表示 chart.Series[0].ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.FastLine; // 線の色を指定 chart.Series[0].Color = ColorTranslator.FromHtml( "#00FF00" ); |
グラフを折れ線にし、緑色で表示させます。
だいぶタスクマネージャーのグラフっぽくなってきました。

// 凡例を非表示 chart.Series[0].IsVisibleInLegend = false; |
最後に、右上に表示されている凡例を非表示します。
これで、デザインの指定は完了です。

次は、グラフの描画処理です。
//*************************************************************************** /// <summary> チャートを描画する /// </summary> /// <param name="chart"></param> //*************************************************************************** private void showChart( Chart chart ) { //----------------------- // チャートに値をセット //----------------------- chart.Series[0].Points.Clear(); foreach( int value in countHistory ) { // データをチャートに追加 chart.Series[0].Points.Add( new DataPoint( 0, value ) ); } } |
こちらは、コレクションに登録されている値を全部chartコントロールに追加しなおしているだけなので簡単です。
上記の例では、countHistoryコレクションに入っている変数を全てAdd()しなおしていますが、新規データを取得の都度Add()し、チャートに表示させる履歴件数を一定にしたい場合はAdd()した後RemoveAt()で最初の要素を削除させても、タスクマネージャ風の最新履歴をスクロールさせる様なグラフが作成できます。
最後に、上記2メソッドの呼び出し側を作ります。
今回はCPU負荷をタイマーで表示させています。
// 取得データの履歴 const int MAX_HISTORY = 40; Queue<int> countHistory = new Queue<int>(); // CPU使用率の取得用カウンタ PerformanceCounter pc = new PerformanceCounter("Processor", "% Processor Time", "_Total", true); public Form1() { InitializeComponent(); // チャートの表示を初期化 initChart( chart1 ); // 1秒周期でチャートを再描画 timer1.Interval = 1000; timer1.Enabled = true; } //*************************************************************************** /// <summary> タイマー処理 /// CPU負荷を一定周期で取得する /// </summary> /// <param name="sender"></param> /// <param name="e"></param> //*************************************************************************** private void timer1_Tick( object sender, EventArgs e ) { //--------------------------------- // CPUの使用率を取得し、履歴に登録 //--------------------------------- int value = (int)pc.NextValue(); countHistory.Enqueue( value ); //------------------------------------------------ // 履歴の最大数を超えていたら、古いものを削除する //------------------------------------------------ while ( countHistory.Count > MAX_HISTORY ) { countHistory.Dequeue(); } //------------------------------------------------ // グラフを再描画する //------------------------------------------------ showChart( chart1 ); } |
以上で、今回のプログラム作成は完了です。
プログラムを実行し、タスクマネージャの表示と並べてみました。(画像クリックで拡大します)

データビジュアライゼーションのデザインパターン20 混沌から意味を見つける可視化の理論と導入
関連記事
当方初心者で見よう見まねで、こちらのページを参考にさせて頂いております。ありがとうございます。
ちなみに、こちらはtimer1_Tickを呼び出すところがないように見えますが、これをどのように呼んだらいいでしょうか?
ご教授頂けますと幸いです。よろしくお願い致します。
度々失礼いたします。理解てきました。タイマーというコントロールを使うのですね。失礼しました。
参考にさせていただきます。ありがとうございます!