WPFで使えるグラフ描画コントロールとして、ScottPlot、LiveCharts、OxyPlot、MSChart の4種類がありますが、LiveChartsはビジュアルに特化したチャートコントロールと言えます。
今回は、LiveCharts の基本的な使い方について、WPFのサンプルプログラムを交えて説明したいと思います。
グラフ描画の手順についてはWindowsFormと同じなので、この記事が参考になると思います。
LiveCharsの概要
LiveChartsはアニメーションに力を入れたチャートコントロールです。
下記の画面キャプチャを見て頂くと分かる通り、「一瞬でパッと表示」ではなく、「ヌルっと表示」されていることがお分かりいただけると思います。
またマウスカーソルを移動させると、そこにプロットの情報が浮き出して表示されることも特徴の一つです。
公式サイトも充実しており、Tutorial and Examples には、描画できるグラフ毎のサンプルソースが掲載されています。
サンプルソースはWPFで書かれていますが、メソッドやプロパティの使い方は、WPF版とWindowsForm版でほとんど共通なので、WindowsFormで使う上でも参考になります。
また、WindowsForm版では、標準のMSChartコントロールと同様、手軽にツールボックスからドラッグ&ドロップで画面に張り付けて使う事も可能です。
描画速度が遅のが弱点
100件以下のデータを表示するには問題ありませんが、1万件を超えるプロットを描画する場合は他のチャートコントロールに比べて速度が極めて遅くなります。
例えば1万件のデータで単一の折れ線グラフを描画するだけでも、Core i-5搭載のPCでさえ数十秒も掛かってしまうので、データ件数が多い場合は他のチャートコントロールを利用した方が良いでしょう。
有料版なら1千万ポイントでも1秒以下
Live Charts は有料版があり、約7000円(開発者1名分のライセンス)で購入可能です。
サンプルプログラムが公開されているので、こちらから段ロード可能です。
さすがにヌルっとしたアニメーションはありませんが、数万件程度なら一瞬で描画できるので、大量データを扱ったグラフ描画でScottやMSChartの速度に満足できない場合、有料版を購入してみては如何でしょうか。
インストール方法
Nuget から Live chart で検索すると、WPF版とWindows Formが表示されるので、どちらか必要な方をインストールして下さい。
Nugetの使い方に関しては、こちらの記事に記載しています。
使い方
インストールに成功すると、WindowsFormの場合はツールボックスにコントロールが表示されます。
WPFの場合は、残念ながらツールボックスには表示されないので、XAMLでコードを記述する必要があります。
LiveCharts の構造
LiveChartsは用途に応じた5つのコントロールで構成されています。
ScottPlot、OxyPlot、MsChartはいずれもコントロールが1種類しかなく、グラフの種類(折れ線、散布図、バー、円など)を選ぶことによって様々なグラフを表示できましたが、LiveChartsはコントロールを選ぶ必要がある点が他と異なります。
コントロールは異なっても基本的な構造は同じなので、ここでは一番良く利用されるであろう CartesianChart を例に、クラスの構造を図で説明したいと思います。
コントロールのプロパティには、凡例の表示位置やアニメーションの禁止など、チャート全体に関するプロパティと、縦軸、横軸を登録するAxisYプロパティ、描画するグラフの種類とプロットデータを登録する Series プロパティが用意されています。
他のチャートコントロールだと縦軸と横軸を1つのAxisプロパティに登録する仕様が多いですが、LiveCharts の場合は縦軸と横軸が独立して用意されています。
描画のタイミングですが、SeriesプロパティにSeriesを追加したタイミングで、グラフが表示されます。
尚、CartesianChartコントロールで使えるSeriesには次のものが有ります。
ちなみに、ヒートマップも存在しますが、私自身が使ったことが無いので、今回は割愛しました。
種類 | シリーズ | プロットデータの型 |
---|---|---|
折れ線グラフ | LineSeries | ChartValues<ObservalePoint> |
散布図 | ScatterSeries | ChartValues<ObservalePoint> |
縦棒グラフ | ColumnSeries | ChartValues<double> |
積み上げグラフ | StackedColumnSeries | ChartValues<double> |
横棒グラフ | RowSeries | ChartValues<double> |
サンプルソース
それでは、次の線グラフを描画するためのサンプルソースを使って、実際のコードをもう少し詳しく解説していきましょう。
今回は、コントロールに "uxChart1" という名前を付けました。
XAMLのソースコード
以下がXAMLのソースコードになります。
1 2 3 4 5 6 7 8 9 10 11 12 |
<Window x:Class="LiveChartsTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:LiveChartsTest" xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" mc:Ignorable="d" Title="MainWindow" Height="450" Width="1320"> <Grid> <lvc:CartesianChart x:Name="uxChart1" Zoom="Xy" LegendLocation="Right" /> </Grid> |
まず、参照設定として次の1行が必要です。
1 |
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf" |
そして、コントロールの定義は次の様になります。
1 |
<lvc:CartesianChart x:Name="uxChart1" Zoom="Xy"/> |
ちなみに、Zoom は、XとY方向に対して、マウスによる拡大/縮小を行うための設定なので、C#のプログラム上で設定しても構いません。
では、C#側のソースコードを見ていきましょう。
C#のソースコード
こちらの方も最初に参照設定が必要になります。
1 2 3 |
using LiveCharts; using LiveCharts.Defaults; using LiveCharts.Wpf; |
折れ線グラフのデータを作る部分、LiveChartの初期化部分、折れ線グラフを描画するという3つの構成になっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
//--------------------------------------------------- //折れ線グラフのデータ作成 //--------------------------------------------------- Random rand = new Random(); double[] xs = Enumerable.Range(0, 100).Select(i => (double)i).ToArray(); double[] ys1 = Enumerable.Range(0, 100).Select(i => Math.Sin(i * 0.1)).ToArray(); double[] ys2 = Enumerable.Range(0, 100).Select(i => 2 + Math.Cos(i * 0.1)).ToArray(); double[] ys3 = Enumerable.Range(0, 100).Select(i => 4 + Math.Sin(i * 0.1) * Math.Cos(i * 0.1)).ToArray(); //--------------------------------------------------- //LiveChartsの初期化 //--------------------------------------------------- uxChart1.Series.Clear(); //描画領域のクリア uxChart1.DisableAnimations = true; //アニメーション禁止 //--------------------------------------------------- //折れ線グラフの描画 //--------------------------------------------------- //1つ目の折れ線用のシリーズを作成 LineSeries seri = new LineSeries(); seri.Title = "A"; //凡例名 var plots = Enumerable.Range(0, ys1.Length).Select(i => new ObservablePoint(xs[i], ys1[i])); //描画データ登録 seri.Values = new ChartValues<ObservablePoint>(plots); uxChart1.Series.Add(seri); //LiveChartsにシリーズを登録 //2つ目の折れ線用のシリーズを作成 seri = new LineSeries(); seri.Title = "B"; //凡例名 plots = Enumerable.Range(0, ys2.Length).Select(i => new ObservablePoint(xs[i], ys2[i])); //描画データ登録 seri.Values = new ChartValues<ObservablePoint>(plots); uxChart1.Series.Add(seri); //LiveChartsにシリーズを登録 //3つ目の折れ線用のシリーズを作成 seri = new LineSeries(); seri.Title = "C"; //凡例名 plots = Enumerable.Range(0, ys3.Length).Select(i => new ObservablePoint(xs[i], ys3[i])); //描画データ登録 seri.Values = new ChartValues<ObservablePoint>(plots); uxChart1.Series.Add(seri); //LiveChartsにシリーズを登録 |
Axisは特に設定していないので、デフォルトのAxisが使用されています。
それから、DisableAnimations を true にすると、アニメーションしなくなりますので、描画速度が向上します。
今回は速度優先ということで、DisableAnimations=true にして、アニメーションを禁止にしています。
プロットデータの渡し方については少しだけ複雑で、配列をそのまま設定できません。
ObservalePoint の引数にXとYの座標を渡してオブジェクトを生成し、ChartValues にセットしています。
CharValuesの引数の型が IEnumerable<double> になっているので、Enumerabel.Range で生成した ObservalePoint をそのまま渡しています。
1 2 3 4 5 |
//描画データを作成 var plots = Enumerable.Range(0, ys1.Length).Select(i => new ObservablePoint(xs[i], ys1[i])); //描画データをSeries に登録 seri.Values = new ChartValues<ObservablePoint>(plots); |
そして、最後にSeriesをコントロールにAddすることで、グラフが表示される。
1 |
uxChart1.Series.Add(seri) |
今回は3つの折れ線を描画したいので、上記のことを3回繰り返しています。
軸の表記が省略されてしまう事への対応
棒グラフを描画する際、グラフの横幅が十分大きくないと、軸のラベルが省略されてしまいます。
次の例では、X軸のラベルがA、B、C、D、Eという短い文字で、それぞれの棒グラフの幅も十分太いため、全てのラベルが表示されても良さそうです。
しかし、実際にはA以外は省略されてしまっています。
つまり、グラフの幅が相当広くないと、全ての軸ラベルが表示されないのです。
これを解決するには、Axisクラスの Separator プロパティに、Step 1 を設定します。
次が棒グラフのソースコードです。
AxisX プロパティに new Axsis() {Labels = labels, Separator = new LiveCharts.Wpf.Separator() { Step = 1 } } を代入していますが、このようにして Step=1 を指定することで、全ての軸ラベルが表示出来ます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
double[] values = { 778, 43, 283, 76, 184 }; string[] labels = { "A", "B", "C", "D", "E" }; uxChart1.Series.Clear(); uxChart1.AxisX.Clear(); uxChart1.AxisY.Clear(); uxChart1.DisableAnimations = true; uxChart1.AxisX.Add(new Axis() { Labels = labels, Separator = new LiveCharts.Wpf.Separator() { Step = 1 } }); ColumnSeries seri = new ColumnSeries(); seri.Values = new ChartValues<double>(values); uxChart1.Series.Add(seri); |
但し、グラフの幅が小さい場合、軸ラベルが重なってしまいますので、その点はご注意ください。
まとめ
今回は フリーのグラフ(チャート)描画コントロールであるLiveCharts について、その構造とサンプルを交えた使い方の解説を行いました。
デザインは美しいのですが、描画速度が遅いという弱点があります。
プロットデータが1000点以下だと問題ありませんが、10000件を超えると極端に速度が落ちますので、その場合は7000円の有料版の導入するか、別のチャートコントロールを検討する必要があります。
製品ごとに得意、不得意がありますので、自分の用途に合ったものを見極めるのに、この記事が参考になれば幸いです。