C#

【WPF】Live Chartsを使って棒グラフを作成する方法

Windows Form には グラフを作成する Chart コントロールが標準で搭載されています。

この Chart コントロールに興味がある方はリンクを見てみて下さい。

【C#】Chartコントロールを使ってグラフを作成する方法C#には.NET用のChartコントロールが標準搭載されています。Chartを使うことで棒グラフや折れ線グラフを簡単に作成することができます。SeriesやAxisをプロパティを設定して、グラフの種類や凡例、目盛り領域をカスタマイズできます。...

しかし、Windows Form には Chart コントロールがあるのに WPF にはありません。

WPF の場合はライブラリを Nuget から別途ダウンロードして、そのライブラリを使用してグラフを作成する方法があります。フリーで使える有名なライブラリーは、LiveCharts・OxyPlot・ScottPlotの3種類があります。

今回はその3種類の中からアニメーションが豊富でビジュアルに特化した「Live Charts」を使って、WPF にグラフを描画する方法をご紹介します。

Live Charts

Live Charts は、.NET 向けのグラフ作成用のライブラリーです。そのため WPF および Windows Forms 、Core に対応しています。(2022年5月現在)

\Live Chartsの公式サイトを見る/

 

特徴

特徴としてグラフを描画した時などにアニメーション処理が施されており、とても見やすくデータを可視化してくれます。また、マウスカーソルをグラフの上に移動させると、グラフのプロット情報がカーソルの近くに表示されます。Material Designもアニメーションが豊富なので相性が良さそうです。

下図は LiveCharts を使って実際に作成したグラフです。

マウスホバーした時にプロット情報を ToolTips で表示します。この ToolTips は好きなように表示内容をカスタマイズすることが可能です。

興味ある方は次のサイトでカスタマイズする方法を紹介していますので、確認してみてください。

【C#】LiveChartsのToolTipsをカスタマイズしてみたC#のWindowsFormやWPFで利用できるグラフ作成ライブラリのLiveCharts。グラフにマウスホバーした時に表示されるToolTipsをカスタマイズしてみた。LiveChartsの使い方を更に知りたい方や興味ある方は、ぜひ最後まで読んでみてください。...

 

グラフの種類

さまざまなグラフを作成できます。普段よく使われる折れ線グラフや縦棒グラフをはじめ、散布図や円グラフなど多彩なグラフを作成することができるのでとても便利ですね。

下の図は、公式ホームページにサンプルで載っているグラフの一部です。グラフの種類が多いので、どんなニーズにも対応できそうです。

公式ホームページの『Tutorial and samples』にグラフ毎のサンプルソースが記載されています。サンプルも充実していますね。

\Live Chartsのチュートリアルを見る/

 

欠点

グラフで表示するデータ件数が1万件を超えると、他のチャートコントロールと比べると描画速度が速度が遅くなってしまうというデメリットがあります。アニメーション処理を無しにすることで多少マシになるかもしれませんが、限界があるでしょう。

この問題に関しては、有料版を購入することで解決できます。ライセンスは約7,000円です。

有料版を購入することで『High performance series』が解禁されるので描画速度が速くなるようです。大量のデータ件数を扱う場合に、グラフの表示時間にストレスを感じたら、無料版から有料版に切り替えることを検討するといいでしょう。

Live Chartsのインストール

この記事では次の開発環境でプログラムを作成します。

  • OS:Windows 10 Home
  • 開発環境:Visual Studio 2019
  • 言語:C#
  • 開発プラットフォーム:WPF

ソリューションエクスプローラーを開いて、プロジェクト名の上にカーソルを移動させて右クリックします。Nugetの管理画面を開いて検索欄に『LiveCharts』を入力します。

検索結果の一覧から『LiveCharts.Wpf』を選択して、インストールを行います。関連パッケージである『LiveCharts』も同時にインストールされます。最新の安定版は2017年6月20日公開されている 0.9.7 でした。

プログラムの実装

前回作成したメニュー画面にユーザーコントロールを追加して、グラフを描画するまで実装をします。下準備として前回の記事を参考に『UserControlChart』というユーザーコントロールを追加しておきます。前回の記事は以下のURLからアクセスできます。

【WPF】Material Designでオシャレなメニュー画面を作成する方法−PART2WPFでUserControlを切り替える方法を紹介しています。メインメニューで押下したボタンに応じて、ユーザーコントロールを切り替えするサンプルがあります。どのボタンが押下されたかを判定する為に識別子(Uid)を使っています。...

さっそく XAML とコードをそれぞれ記述します。

XAML実装

XAMLファイルを開いて、ファイルのヘッダー部分に LiveCharts 参照先を指定する1行を追加します。

xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"

 

次にコントロールを定義します。

SeriesCollection クラスや AxisX クラスなどの各種プロパティに対して Binding をするコードを実装します。

また、X 軸のラベルの感覚が狭いと、全てのラベルが表示されずに歯抜けになってしまいます。グラフの幅が相当広くないと全てのX軸のラベルが表示されません。

この問題を解決する方法として、Axis クラスの Seqarator プロパティの Step を”1”にします。

こうすることで、全ての X 軸ラベルを表示することができます。注意点としてグラフの幅が小さすぎると、軸ラベルが重なってしまいますので、充分な感覚を取る必要があります。

<lvc:CartesianChart
    x:Name="lvChart"
    Series="{Binding seriesCollection}">
    <lvc:CartesianChart.AxisX>
        <lvc:Axis Labels="{Binding labels}">
            <lvc:Axis.Separator>
                <lvc:Separator IsEnabled="False" Step="1" />
            </lvc:Axis.Separator>
        </lvc:Axis>
    </lvc:CartesianChart.AxisX>
    <lvc:CartesianChart.AxisY>
        <lvc:Axis MaxValue="10.0" MinValue="0.0" />
    </lvc:CartesianChart.AxisY>
</lvc:CartesianChart>

 

UserControlChart の UI 画面にグラフ更新ボタンやテキストを配置します。コントロールを追加し、位置調整をした XAML が以下になります。

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
        <materialDesign:PackIcon
            Width="35"
            Height="35"
            Margin="10"
            VerticalAlignment="Center"
            Foreground="{StaticResource PrimaryHueMidBrush}"
            Kind="ChartBar" />
        <TextBlock
            Margin="0,0,40,0"
            HorizontalAlignment="Center"
            Style="{StaticResource MaterialDesignHeadline4TextBlock}"
            Text="Chart" />
        <Button
            x:Name="btnUpdate"
            Width="100"
            Margin="10,9"
            HorizontalAlignment="Right"
            VerticalAlignment="Center"
            Click="btnUpdate_Click"
            Style="{StaticResource MaterialDesignOutlinedButton}">
            <StackPanel Orientation="Horizontal">
                <materialDesign:PackIcon VerticalAlignment="Center" Kind="Update" />
                <TextBlock Text="Update" />
            </StackPanel>
        </Button>
    </StackPanel>
    <lvc:CartesianChart
        x:Name="lvChart"
        Grid.Row="1"
        Margin="10,10"
        Series="{Binding seriesCollection}">
        <lvc:CartesianChart.AxisX>
            <lvc:Axis Labels="{Binding labels}">
                <lvc:Axis.Separator>
                    <lvc:Separator IsEnabled="False" Step="1" />
                </lvc:Axis.Separator>
            </lvc:Axis>
        </lvc:CartesianChart.AxisX>
        <lvc:CartesianChart.AxisY>
            <lvc:Axis MaxValue="10.0" MinValue="0.0" />
        </lvc:CartesianChart.AxisY>
    </lvc:CartesianChart>
</Grid>

 

コードの実装

C#のソースコードの先頭に LiveCharts の名前空間を参照する為のコードを記述します。

using LiveCharts;
using LiveCharts.Wpf;

 

グラフのプロパティが変更されたことを View に通知するために INotifyPropertyChanged を使った ViewModel という名前のクラスを新たに作成します。

ViewModel クラスは、INotifyPropertyChanged を継承します。このクラスをつくることで、SeriesCollection と AxisX の各種プロパティに値のセットと画面の反映を行うことができるようになります。

public class ViewModel : INotifyPropertyChanged
{
    // INotifyPropertyChanged を実装するためのイベントハンドラ
    public event PropertyChangedEventHandler PropertyChanged;
    // プロパティ名によって自動的にセットされる
    private void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    SeriesCollection _seriesCollectiont;
    public SeriesCollection seriesCollection
    {
        get { return _seriesCollectiont; }
        // 値をセットした後、画面側でも値が反映されるように通知する
        set { if (_seriesCollectiont != value) { _seriesCollectiont = value; RaisePropertyChanged(); } }
    }

    List<string> _labels;
    public List<string> labels
    {
        get { return _labels; }
        // 値をセットした後、画面側でも値が反映されるように通知する
        set { if (_labels != value) { _labels = value; RaisePropertyChanged(); } }
    }
}

 

LiveCharts で利用できるグラフの種類は以下の通りです。

クラスグラフの種類
ColumnSeries縦棒グラフ
RowSeries横棒グラフ
StackedColumnSeries積み上げ縦棒グラフ
StackedRowSeries積み上げ横棒グラフ
LineSeries折れ線グラフ
PieSeries円グラフ
StackedAreaSeries面グラフ

 

ColumnSeries クラスを使って縦棒グラフを描画する独自メソッドを作成します。引数を2つにして、第一引数に X 軸ラベルの項目の配列を、第二引数に描画データの配列を渡すとグラフを描画するようになっています。

//グラフを描く関数
private void DarwChart(string[] labels, double[] values)
{
    //X軸のラベル
    vm.labels = new List<string>(labels);

    //グラフの値
    vm.seriesCollection = new SeriesCollection
    {
        new ColumnSeries
        {
            Values = new ChartValues<double>(values),
            Fill = Brushes.DarkOrange
        }
    };
}

 

LiveCharts では複数の Series (データ系列) をこの SeriesCollection クラスで管理します。ColumnSeries クラスにグラフの値と色の設定パラメーターを渡します。

UserControlChart の初期処理時は、グラフの値は全て0にします。更新ボタンが押下されたらランダムで値を算出して、グラフに描画する値の配列を作成します。その配列を描画メソッドに渡してグラフの描画を行います。

vm.labels や vm.seriesCollection の値を更新すると、グラフも自動で再描画されます。

ソースコードは次の様になっています。

/// <summary>
/// UserControlChart.xaml の相互作用ロジック
/// </summary>
public partial class UserControlChart : UserControl
{
    // ViewModel のインスタンス
    ViewModel vm = new ViewModel();

    public UserControlChart()
    {
        InitializeComponent();
        DataContext = vm;

        //グラフの描画
        var labels = new string[] { "Apple", "Banana", "Grapes", "Kiwi", "Melon", "Orange" };
        var values = new double[] { 0, 0, 0, 0, 0, 0 };
        DarwChart(labels, values);
    }

    //グラフを描く関数
    private void DarwChart(string[] labels, double[] values)
    {
        //X軸のラベル
        vm.labels = new List<string>(labels);

        //グラフの値
        vm.seriesCollection = new SeriesCollection
            {
                new ColumnSeries
                {
                    Values = new ChartValues<double>(values),
                    Fill = Brushes.DarkOrange
                }
            };
    }

    private void btnUpdate_Click(object sender, System.Windows.RoutedEventArgs e)
    {
        //ランダムでグラフの値をリスト化
        var values = new double[6];
        for (int i = 0; i < values.Length; i++)
        {
            var seed = Convert.ToInt32(Guid.NewGuid().ToString("N").Substring(0, 8), 16);
            values[i] = new Random(seed).Next(1, 10);
        }

        //グラフの描画
        var labels = new string[] { "Apple", "Banana", "Grapes", "Kiwi", "Melon", "Orange" };
        DarwChart(labels, values);
    }
}

 

アプリケーションの起動

さっそく、実装したプログラムをデバックしてみましょう。デバックしたイメージ画像がこちらです。

WPF でもグラフが描画できましたね。LiveChartsの縦棒グラフのアニメーションは下からグッと指定のパラメーターまで上昇します。

個人的にはMaterial Desginとマッチしていて、結構いい感じだと思っています。

アニメーションの制御方法

描画時のアニメーションを無くして、描画速度を少しでも速くしたいと思う方もいらっしゃるかもしれません。そのような場合は、以下の方法でアニメーションの ON / OFF を切り替えることができます。

方法は、WPF内にあるのタブの中にDisableAnimationsプロパティを追加し、そのプロパティへ True を代入することで、アニメーション処理を OFF にすることができます。

DisableAnimations="True"

 

アニメーションの描画をOFFにした場合が以下です。用途によって使い分けをしましょう。

最後に

今回は LiveCharts で簡単に描画するための方法について解説しました。

グラフの描画件数が多い場合は遅延が発生してしまいますが、それ以外の不満はなく比較的扱いやすいライブラリーだと感じました。

描画時の遅延が気になる方は、有料版を使うことで解決ができますので検討してみるといいでしょう。

個人的には、グラフの種類も十分ですし、操作した時のアニメーションもあり Material Design との相性がいい所も気に入っています。今後グラフ使う機会あれば、積極的に LiveCharts を使っていこうと思います。

WPF でグラフを書く際の参考になれば幸いです。

以上、最後まで読んで頂きありがとうございました。

プログラミングを学習したいなら…

プログラミングスキルを身に付けるなら、プログラミングを効率良く学べる
プログラミングスクール」がオススメです。

特にこんな方にオススメ!!
これからエンジニアを目指したい
プログラミングの専門性を高めたい
プログラミングを学んで副業をしたい
エンジニアに転職して年収をアップさせたい

プログラミングを触ったことがない未経験からでも、プログラミングスクールで学習すれば、エンジニアへ就職・転職することも可能です。

あなたの「行動力」と「やる気」で、あなたの人生を大きく変えるチャンスになることでしょう。

プログラミングスクールに興味がある方は是非チェックしてみてください。

> プログラミングを学ぶ <

COMMENT

メールアドレスが公開されることはありません。

CAPTCHA