WPF(Windows Presentation Foundation)を使ってグラフを表示させるときに使える『ScottPlot』というライブラリの使い方を解説します。
なお、WPFについて詳細を以下の記事で解説していますので、気になる方はご参照ください。
この記事を読むと・・・?
この記事を読むと、WPFでこんな感じのグラフを描画することができます。
興味のある方は是非ご一読ください。

WPFでのグラフの描き方
UI(ユーザーインターフェース)を開発しているときに、グラフを表示させたいことがあるかもしれません。
このとき、昔ながらのWindows.Formsであれば『Chartコントロール』があるのですが、残念ながらWPFには用意されていません。
- ほんとにWPFにChartコントロールはないの?
- はい。ただ、厳密にはWindows.Formsをusing句を使ってインポートすると使うことはできるようです。
ただそうは言っても、「せっかくWindows.Formsから離れてWPFでUIを作ろうとしているのにまたWindows.Forms!?」と思われる方には、今回の記事が参考になるかもしれません。
このことから、WPFでグラフを表示させたいときは、グラフ描画のためのライブラリを使用することが一般的です。
WPFで使用できるグラフ描画のライブラリは『ScottPlot』や『OxyPlot』、『LiveChart』、『MSChart』が代表的ですが、その中でも本記事ではScottPlotの使い方をご説明します。
ScottPlotが持つ特長は以下のとおりです。
- グラフの描画が高速である
- 大量のデータの描画が得意である
ScottPlotのインストール
ScottPlotは、VisualStudioのNuGetパッケージマネージャーでインストールできます。
パッケージ名 | バージョン |
---|---|
ScottPlot.WPF | 5.0.39 |
WPFでグラフを表示させる
基本的な使い方は、ScottPlotのインスタンスをXAMLで生成し、このインスタンスに対してコードビハインドで色々設定するやり方かと思います。
XAML
ScottPlotのインスタンスをWPF_GraphとしてViewに配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<Window x:Class="ScottPlot_Sample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF" 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:ScottPlot_Sample" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <ScottPlot:WpfPlot x:Name="WPF_Graph" /> </Grid> </Window> |
コードビハインド
ViewのLoadイベント発生時にLoadEvent()に処理が飛んできます。
ここでグラフのデータ設定が行われて再描画されます。
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 |
using System.Windows; namespace ScottPlot_Sample { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow( ) { InitializeComponent( ); Loaded += LoadEvent; } private void LoadEvent( object sender, RoutedEventArgs e ) { int[] dataX = { 1, 2, 3, 4, 5 }; int[] dataY = { 1, 4, 9, 16, 25 }; WPF_Graph.Plot.Add.Scatter( dataX, dataY ); WPF_Graph.Plot.Axes.SetLimits( 0, 10, 0, 30 ); WPF_Graph.Plot.Axes.Left.Label.Text = "Y軸"; WPF_Graph.Plot.Axes.Bottom.Label.Text = "X軸"; WPF_Graph.Plot.Axes.Left.Label.FontName = "BIZ UDゴシック"; WPF_Graph.Plot.Axes.Bottom.Label.FontName = "BIZ UDゴシック"; WPF_Graph.Plot.Axes.Left.Label.FontSize = 24; WPF_Graph.Plot.Axes.Bottom.Label.FontSize = 24; WPF_Graph.Plot.Axes.Left.TickLabelStyle.FontSize = 24; WPF_Graph.Plot.Axes.Bottom.TickLabelStyle.FontSize = 24; ScottPlot.TickGenerators.NumericAutomatic l_TickGenY = new ScottPlot.TickGenerators.NumericAutomatic(); l_TickGenY.TargetTickCount = 10; WPF_Graph.Plot.Axes.Left.TickGenerator = l_TickGenY; ScottPlot.TickGenerators.NumericAutomatic l_TickGenX = new ScottPlot.TickGenerators.NumericAutomatic(); l_TickGenX.TargetTickCount = 10; WPF_Graph.Plot.Axes.Bottom.TickGenerator = l_TickGenX; WPF_Graph.Refresh( ); } } } |
ScottPlotのグラフ設定
ScottPlotのグラフ設定としてよく使いそうなものをまとめておきます。
1 |
WPF_Graph.Plot.Add.Scatter([X軸系列データ], [Y軸系列データ]); |
1 |
WPF_Graph.Plot.Add.Bars([X軸系列データ], [Y軸系列データ]); |
1 |
WPF_Graph.Plot.FigureBackground.Color = Color.FromHex("[16進数カラーコード]"); |
1 |
WPF_Graph.Plot.DataBackground.Color = Color.FromHex("[16進数カラーコード]"); |
1 |
WPF_Graph.Plot.Axes.SetLimits( [X軸最小値], [X軸最大値], [Y軸最小値], [Y軸最大値] ); |
1 |
WPF_Graph.Plot.Axes.AutoScale(); |
1 |
WPF_Graph.Plot.Axes.Left.TickLabelStyle.FontSize = "[フォントサイズ]"; |
1 |
WPF_Graph.Plot.Axes.Bottom.TickLabelStyle.FontSize = "[フォントサイズ]"; |
1 2 3 |
ScottPlot.TickGenerators.NumericAutomatic l_TickGenY = new ScottPlot.TickGenerators.NumericAutomatic(); l_TickGenY.TargetTickCount = 10; WPF_Graph.Plot.Axes.Left.TickGenerator = l_TickGenY; |
1 2 3 |
ScottPlot.TickGenerators.NumericAutomatic l_TickGenX = new ScottPlot.TickGenerators.NumericAutomatic(); l_TickGenX.TargetTickCount = 10; WPF_Graph.Plot.Axes.Bottom.TickGenerator = l_TickGenX; |
1 |
WPF_Graph.Plot.Axes.Left.Label.Text = "[Y軸ラベル名]"; |
1 |
WPF_Graph.Plot.Axes.Bottom.Label.Text = "[X軸ラベル名]"; |
1 |
WPF_Graph.Plot.Axes.Left.Label.FontName = "[フォント名]"; |
1 |
WPF_Graph.Plot.Axes.Bottom.Label.FontName = "[フォント名]"; |
1 |
WPF_Graph.Plot.Axes.Left.Label.FontSize = "[フォントサイズ]"; |
1 |
WPF_Graph.Plot.Axes.Bottom.Label.FontSize = "[フォントサイズ]"; |
1 |
WPF_Graph.Refresh(); |
なお、ScottPlotで設定できる項目はまだまだありますので、詳細は公式HPのCookbookをご参照ください。
こちらはどうしてもというとき用です。
WPFとセットでよく扱われるMVVMでも使いたいところですが、ScottPlotはMVVMに対応していません。
なので、Model側でインスタンスを生成して、それをViewModelに受け渡し、Viewとバインドする、という手法にムリやりはめ込んでみます。
なお、MVVMについて詳しく知りたい方は以下の記事もご覧ください。
Model
WpfPlotクラスのインスタンスであるScottPlotGraphを生成し保持します。
ただし、今回のようにムリやりバインディングする場合、インスタンスのパラメータ変更ではsetterに処理が移ってくれず、setterに処理を移すにはインスタンス生成のようにインスタンス自体の変化が必要になります。
つまり、従来のMVVMで行うようなRaisePropertyChanged()による変更通知をトリガーに、Viewを更新していくことはできないということです。
そのため、RaisePropertyChanged()やNotifyChangedはコメントアウトしています。
RaisePropertyChanged()が使えない以上、自動的に再描画はしてくれないので、自分で描画のリフレッシュを行う必要がありますので、最後にRefresh()で再描画しています。
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 48 49 50 51 52 53 |
using ScottPlot.WPF; namespace ScottPlot_MVVM_Sample { public class GraphModel /*: NotifyChanged*/ { #region メンバ変数 private WpfPlot? m_ScottPlotGraph = null; #endregion #region プロパティ public WpfPlot? ScottPlotGraph { get { return m_ScottPlotGraph; } set { if( m_ScottPlotGraph != value ) { m_ScottPlotGraph = value; //RaisePropertyChanged( ); } } } #endregion #region コンストラクタ public GraphModel( ) { ScottPlotGraph = new WpfPlot( ); int[] dataX = { 1, 2, 3, 4, 5 }; int[] dataY = { 1, 4, 9, 16, 25 }; ScottPlotGraph.Plot.Add.Scatter( dataX, dataY ); ScottPlotGraph.Plot.Axes.SetLimits( 0, 10, 0, 30 ); ScottPlotGraph.Plot.Axes.Left.Label.Text = "Y軸"; ScottPlotGraph.Plot.Axes.Bottom.Label.Text = "X軸"; ScottPlotGraph.Plot.Axes.Left.Label.FontName = "BIZ UDゴシック"; ScottPlotGraph.Plot.Axes.Bottom.Label.FontName = "BIZ UDゴシック"; ScottPlotGraph.Plot.Axes.Left.Label.FontSize = 24; ScottPlotGraph.Plot.Axes.Bottom.Label.FontSize = 24; ScottPlotGraph.Plot.Axes.Left.TickLabelStyle.FontSize = 24; ScottPlotGraph.Plot.Axes.Bottom.TickLabelStyle.FontSize = 24; ScottPlot.TickGenerators.NumericAutomatic l_TickGenY = new ScottPlot.TickGenerators.NumericAutomatic(); l_TickGenY.TargetTickCount = 10; ScottPlotGraph.Plot.Axes.Left.TickGenerator = l_TickGenY; ScottPlot.TickGenerators.NumericAutomatic l_TickGenX = new ScottPlot.TickGenerators.NumericAutomatic(); l_TickGenX.TargetTickCount = 10; ScottPlotGraph.Plot.Axes.Bottom.TickGenerator = l_TickGenX; ScottPlotGraph.Refresh( ); } #endregion } } |
ViewModel
コンストラクタでModelのインスタンスを生成するだけです。
なお、起動時のコンストラクタ処理後にはScottPlotGraphのgetterが働くので、Model側からインスタンスを取得します。
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 |
using ScottPlot.WPF; namespace ScottPlot_MVVM_Sample { public class MainViewModel /*: NotifyChanged*/ { #region メンバ変数 private GraphModel m_GraphModel; #endregion #region プロパティ public WpfPlot? ScottPlotGraph { get { return m_GraphModel.ScottPlotGraph; } set { m_GraphModel.ScottPlotGraph = value; } } #endregion #region コンストラクタ public MainViewModel( ) { m_GraphModel = new GraphModel( ); //m_GraphModel.PropertyChanged += ( sender, e ) => RaisePropertyChanged( ); } #endregion } } |
View
XAML上でDataContextにViewModelを設定してバインディングの準備をしてから、ContentControlのContentプロパティにViewModelのScottPlotGraphのインスタンスをバインディングします。
これによりViewにグラフが表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<Window x:Class="ScottPlot_MVVM_Sample.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:ScottPlot="clr-namespace:ScottPlot.WPF;assembly=ScottPlot.WPF" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ScottPlot_MVVM_Sample" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:MainViewModel /> </Window.DataContext> <Grid> <ContentControl Content="{ Binding ScottPlotGraph }" /> </Grid> </Window> |