倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

関数をプロットする

JFreeChart で関数をプロットする方法を紹介。

チャートを生成する大雑把な手順は

  1. Function2D オブジェクトを生成する
  2. Dataset オブジェクトを生成する
  3. JFreeChart オブジェクトを生成して表示する

です。

Function2D インターフェース


JFreeChart で関数を表すには、 org.jfree.data.function.Function2D インターフェースを用います。 このインターフェースは引数から値を計算して返す getValue() メソッドのみ定義されています:

package org.jfree.data.function;

public interface Function2D{
    double getValue(double x);
}

このインターフェースを実装するクラスであれば、以下で見る方法でチャートを表示することができます:

import static java.lang.Math.*

// サブクラス
class HyperbolicSineFunction implements Function2D{
    @Override
    public double getValue(double x){
        return (exp(x) - exp(x))/2.0;
    }
}

// 無名クラス
Function2D cosh = new Function2D(){
    @Override
    public double getValue(double x){
        return (exp(x) + exp(x))/2.0;
    };
}

Groovy ではメソッドが1つしかないインターフェースはクロージャを用いて簡単にインスタンスを生成できます:

import static java.lang.Math.*

def tanh = { x -> (exp(2d*x) - 1) / (exp(2d*x) + 1) } as Function2D

Dataset オブジェクトの生成


Function2D オブジェクトから Dataset オブジェクトを生成するには org.jfree.data.general.DatasetUtilities#sampleFunction2D() メソッドを用います:

Function2D f = ...
double xmin = -1.0d;
double xmax = 1.0d;
int sampleCount = 1000;
String seriesKey = "Function"

XYDataset dataset = DatasetUtilities.sampleFunction2D(f, xmin, xmax, sampleCount, seriesKey);

この結果返される XYDataset オブジェクトは(JFreeChart 1.0.12 では) XYSeriesCollection クラスのインスタンスで、sampleCount で指定された個数のデータを持つ離散的なデータになっています*1

JFreeChart 1.0.13 からは DatasetUtilities クラスに XYDataset オブジェクトを生成する sampleFunction2D() メソッドに加えて、XYSeries オブジェクトを生成する sampleFunction2DToSeries() メソッドも定義されています(Maven2リポジトリには今のところ 1.0.12 までしか配備されていないので、拙者はあまり使ってませんが)。 他のデータも同時に扱いたい場合にはこちらを使うと便利かと。

チャートの生成(と表示)


上記の方法で生成された XYDataset オブジェクトは離散的なデータの単なる XYDataset なので、ChartFactory#createXxxx() メソッドで JFreeChart オブジェクトを生成すれば普通にチャートが生成できます(詳細割愛)。

JFreeChart chart = ChartFactory.createXYLineChart("Function Plot", "X", "Y", dataset, PlotOrientation.VERTICAL, true, true, false);

ちなみに、ChartFactory.createScatterPlot() などでチャートを生成すると、跳び跳びのグラフが表示されます。

とりあえず、これで関数のプロットは完了。

ビルドイン関数


JFreeChart にはもともと定義されている関数が3つあります(1.0.12)

LineFunction2D
1次関数。 new LineFunction2D(a, b) によって1次関数 a+bx が生成される(ax+b ではない!)
PowerFunction2D
冪関数。 new PowerFunction2D(a, b) によって a*x^b (x^b は x の b 乗の意)が生成される。 b が負の値や非整数でも可。 ただし、b が非整数の場合は x は非負でないといけない(NaN が返される)。
NormalDistribution2D
正規分布関数。 wikipedia:正規分布参照。 new NormalDistribution2D(μ, σ) は、平均値が μ、標準偏差が σ の正規分布

で、それぞれチャート作ってみました。

LineFunction2D


PowerFunction2D


NormalDistribution2D

追記


JFreeChart 1.0.12 では Function2D から XYSeries を直接生成できませんが、DatasetUtilities#sampleFunction2D() メソッドで返される XYDataset が XYSeriesCollection オブジェクトなので、XYSeriesCollection の API を使って

XYSeriesCollection dataset = (XYSeriesCollection)DatasetUtilities.sampleFunction2D(...)
XYSeries series = dataset.getSeries(0)

とすれば XYSeries オブジェクトを取得することができます。

Groovyイン・アクション

Groovyイン・アクション


関数とはなんだろう―三角関数から複素関数・超関数まで (ブルーバックス)

関数とはなんだろう―三角関数から複素関数・超関数まで (ブルーバックス)

*1:sampleFunction2D() メソッドの名前は 「Function2D をサンプリングする」という意味なので当然といえば当然ですが。