3D円グラフは、使うと死が待っています。
その錯視が、どんなものか分からないと殺せるものも殺せないので、3D円グラフを描いてみることにします。
IncanterはClojureの統計解析ライブラリですが、肝心の3D円グラフは描けません。
ですが、中で使われているJFreeChartは、3D円グラフReadyです。(サイトのロゴが3D円グラフなのは皮肉なものです)
これを拡張します。通常の円グラフは以下のように書けます。
(view (pie-chart ["a" "b" "c"] [10 20 30]))
なので同じ感じで、pie-chart-3d
関数を追加します。
ソースはpie-chartをまるっとコピーし、ChartFactoryでChartオブジェクトを作るところだけ、createPieChart
からcreatePieChart3D
に書き換えます。
(ChartFactory/createPieChart3D
title
dataset
legend?
false
false)
これで3D円グラフのチャートが生成されます。
(view (pie-chart-3d ["a" "b" "c"] [10 20 30]))
IncanterではSwingを使ってグラフを表示するのにview
関数を、画像ファイルに出力するのにsave
関数をそれぞれ使います。せっかくの3D円グラフなので、錯視が如何ほどのものか、その3Dの視点をグリグリ動かしてみたいですよね!
そこで、view
関数を再定義してみます。
(defmethod view org.jfree.chart.JFreeChart
([chart & options]
(let [opts (when options (apply assoc {} options))
window-title (or (:window-title opts) "Incanter Plot")
width (or (:width opts) 500)
height (or (:height opts) 400)
frame (ChartFrame. window-title chart)]
(doto frame
(.setSize width height)
(.setVisible true))
frame)))
viewの定義はマルチメソッドになっていて、JFreeChartクラスのインスタンスだったらこのview関数で処理されます。JFreeChartのオブジェクト構成は、グラフの種類はJFreeChartのオブジェクトがもつPlotで区別されます。グラフの種類によらずChartFactoryで生成されるオブジェクトは、すべてJFreeChartクラスのインスタンスになります。したがって、このようにJFreeChartクラスでディスパッチされると"3D円グラフだけ特別な処理をする"ということができないのです。
この挙動を変えるには、次のようにします。
(when-let [original-view-fn (get-method view org.jfree.chart.JFreeChart)]
(defmethod view org.jfree.chart.JFreeChart [chart & options]
(let [view (apply original-view-fn chart options)]
(when (= (type (.getPlot chart)) org.jfree.chart.plot.PiePlot3D)
(pie-slider view))
view)))
基本的にはdefmethod
で再定義するのですが、元のメソッドをget-method
関数で取り出しておくのがポイントです。そしてPlotがPiePlot3Dのときだけ、右側にスライダーをつけるようにしています。
同様にsave
も再定義して、3D円グラフでファイル拡張子がGIFのときだけ、アニメーションGIFを出力するようにしました。ぜひお使いください。
incanter-charts-3d
https://github.com/kawasima/incanter-charts-3d