C#でグラフを描く OxyPlotのFunctionSeriesによる方法

.NETフレームワーク用のグラフ描画ライブラリであるOxyPlotを使ってグラフを描く.
その中でもFunctionSeriesクラスを使って与えられた関数のグラフを描く方法を記す.

OxyPlotはWindows Formアプリケーションだけでなく,WPF,Silverlight,Windows8等様々な環境で使える.

Chartコントロールとの比較

Chartコントロールによるグラフの描画方法は以下の別の記事で紹介したことがあるが,比較してOxyPlotの方が良いなと思っている点をあげる.

  • 関数を渡してこの範囲を表示するとかが楽(今回の記事のメイン.詳細は後述.たとえば

y=x^3+2x^2-3-2\le x\le 2の範囲のグラフを描画とか)

  • マウス操作によるグラフの拡大・縮小,移動等の機能が最初からついている
  • ベクター画像できれいにグラフを保存できる(ChartコントロールでもEMFで保存できるがグラフの種類によっては汚い)
  • 配列データ等にバインディングさせて,複数のグラフを描画するとき便利な気がする(今度記事にまとめようと思います)

OxyPlotのインストール

NuGet経由でインストール可能.プロジェクトを右クリックして「NuGetパッケージの管理」を選択する.オンラインから「OxyPlot」を検索.自分に合った環境のパッケージをインストール.(この記事ではOxyPlot.WindowsFormsを使った)

f:id:whoopsidaisies:20140210110630p:plain

Plotコントロールの追加

グラフ描画用のPlotというコントロールが用意されているので使う.

ツールボックスの適当なところで右クリックして「アイテムの選択(I)...」を選択.「.NET Framework コンポーネント」タブの「参照(B)...」ボタンを押して,「(ソリューションフォルダ)\packages\OxyPlot.WindowsForms.yyyy.x.xxx.x\lib\NET45\OxyPlot.WindowsForms.dll」を選択したらOK.

すると,ツールボックスに「Plot」ができるので,Formに配置する.

f:id:whoopsidaisies:20140210111336p:plain

FunctionSeries

OxyPlotには,Func<double, double>のメソッドのグラフを描画してくれるFunctionSeriesクラスがあるのでその使い方を記す.
Func<double, double>という書き方になじみがない人もいるかもしれないので,とりあえず標準正規分布
f\(x\)=\frac{1}{\sqrt{2\pi}}exp\(-\frac{x^{2}}{2}\)
を描くサンプルを以下に示す.

private static double StandardNormalDistribution(double x)
{
    return 1 / Math.Sqrt(2 * Math.PI) * Math.Exp(-x * x / 2);
}

private void Form1_Load(object sender, EventArgs e)
{
    plot1.Model = new OxyPlot.PlotModel { PlotType = OxyPlot.PlotType.XY };
    var series = new OxyPlot.Series.FunctionSeries(
        StandardNormalDistribution,     // 引数double,戻り値doubleの関数
        -3,                             // x座標の最小値
        3,                              // x座標の最大値
        0.01,                           // x座標の刻み幅
        "標準正規分布");                // グラフタイトル
    plot1.Model.Series.Add(series);
}

実行すると以下のようなグラフが表示される.

f:id:whoopsidaisies:20140210114639p:plain

StandardNormalDistributionという引数がdouble型,戻り値もdouble型の関数を定義している.これがFunc<double, double>のメソッドである.
これと,グラフ描画をしたい範囲をFunctionSeriesクラスのコンストラクタに渡してやるだけでグラフを描画してくれて非常に便利である.

ラムダ式による方法

メソッドの部分をラムダ式で表現することも当然出来るので,StandardNormalDistributionメソッドをわざわざ定義しないでも以下のように書くこともできる.(ここではラムダ式の説明は省略.わからない人はここらのへんのページを参照)

    var series = new OxyPlot.Series.FunctionSeries(
        x => 1 / Math.Sqrt(2 * Math.PI) * Math.Exp(-x * x / 2),     // 引数double,戻り値doubleの関数
        -3,                             // x座標の最小値
        3,                              // x座標の最大値
        0.01,                           // x座標の刻み幅
        "標準正規分布");                // グラフタイトル

媒介変数表示された関数のグラフ描画

これも簡単に出来るので例を示す.例として以下のカージオイドを表示させてみる.
x=a\(2\cos\theta - \cos2\theta\)
y=a\(2\sin\theta - \sin2\theta\)

ソースコードは以下のようになる.(ラムダ式使用)

= new OxyPlot.PlotModel { PlotType = OxyPlot.PlotType.XY };
var series = new OxyPlot.Series.FunctionSeries(
    t => 2 * Math.Cos(t) - Math.Cos(2 * t), // x座標の関数
    t => 2 * Math.Sin(t) - Math.Sin(2 * t), // y座標の関数
    0,                                      // tの最小値
    2 * Math.PI,                            // tの最大値
    Math.PI / 32,                           // tの刻み幅
    "カージオイド");                        // グラフタイトル
plot1.Model.Series.Add(series);

実行すると以下のようなグラフが表示される.

f:id:whoopsidaisies:20140210122606p:plain

その他

PlotTypeの設定によって極座標表示とかもできるがそれはまたの機会に.