視覚化ライブラリ Axiis

最近、仕事2割:趣味8割ぐらいでFlex/Airをいじっている。
Flex Builderを買う余裕が無いので、フリーのEclipse plugin Air Gearを使って開発しているが、Flexの標準グラフ化APIFlex Builderを買わないと使用できないらしい。(つか、それって"標準"APIか?)

そこで、Airアプリケーション上ででグラフ(散布図)を作成するために、Flexのフリー(MITライセンス)視覚化ライブラリ Axiisにトライしてみた。現時点では日本語で書かれたAxiisコーディングについてのBlog等が少ないようなので(「こんなにきれいなグラフが表示できる!」系の記事は多いが、コード内容まで触れられているものは少ない)、公開作業メモを残してみる。

公式サイトのExamplesの中に散布図グラフmxmlソースがあったので、ほぼそれを流用する感じで作成。

表示内容について

以下のようなオブジェクトの配列を散布図のデータ元として使用する。

public class Hoge {
/*オブジェクト名*/
[Bindable]
public var name:String;
/*X軸の値*/
[Bindable]
public var xValue:Number;
/*Y軸の値*/
[Bindable]
public var yValue:Number;
/*オブジェクトの値*/
[Bindable]
public var value:Number;
}

このオブジェクトの集合(ArrayCollection)は、Airの組み込みDB上から以下のようにSingletonなDaoクラスのプロパティを通じて取得する。

HogeDao.getInstance().hogeList;

mxmlファイルについて

色の設定などを除き、グラフの表示に最低限必要不可欠なXMLタグは以下のもの

  • axiis:LinearScale
  • axiis:DataCanvas
  • view:PlotGroup
  • axis:VAxis
  • axis:HAxis
axiis:LinearScale

オブジェクトのプロパティ値と画面表示時のサイズを変換するためのオブジェクト。

dataProvider="{HogeDao.getInstance().hogeList}"
dataField="xValue"
minValue="0"
minLayout="0"
maxValue = "{Math.floor(hScale.maxValue + 1)}"
maxLayout="{plotGroup.width}"
/>

minLayout/maxLayout属性で画面表示上のピクセルサイズの最小・最大値を指定。minValue/maxValue属性でHogeクラスのxValueプロパティの最小・最大値を指定する。上の例は、X軸を描画するためのScale。同様にY軸を描画するためのScale(id="hScale")も作成する必要が有る。

axiis:DataCanvas

グラフの描画に使用するキャンバスのサイズや位置を指定。

view:PlotGroup

グラフのプロット部分を描画する。

上の例では、

  • dataProvider:"HogeDao.getInstance().hogeList"を使ってグラフ作成
  • vertivalScale: LinearScale(id={vScale})を使用して、Y軸の値と画面上の大きさを変換する。
  • horizontalScale: LinearScale(id={hScale})を使用して、X軸の値と画面上の大きさを変換する。
  • verticalField: X軸の値として、HogeクラスのyValueプロパティを使用する。
  • horizontalField: Y軸の値として、HogeクラスのxValueプロパティを使用する。
  • dataField: DataTipsを表示する際の値として、Hogeクラスのvalueプロパティを使用する。
  • labelField: DataTipsを表示する際の表示名として、Hogeクラスのnameプロパティを使用する。
axis:VAxis
axis:HAxis

exampleのmxmlソースどおりで問題ないはず。

詰まった箇所

DataTipの表示場所が微妙にずれる。

何故かバルーンチップ(Axiis風に言うとDataTip)の表示場所がずれてしまう。とりあえずはmxmlから参照されるActionScriptに以下のような処理を加える。

//グラフの初期化時に呼ばれるメソッド。
private function initChart():void{
plotGroup.addEventListener("itemMouseOver", itemMouseOverHandler);
}

//itemMouseOverのハンドラメソッド
private function itemMouseOverHandler(event:LayoutItemEvent):void{
var selected:Hoge = event.item.data as Hoge;
var x:Number = hScale.valueToLayout(selected.xValue);
var y:Number = vScale.valueToLayout(vScale.maxValue - selected.yValue);
plotGroup.dataTipAnchorPoint = new Point(x, y);
event.item.dataTipAnchorPoint = new Point(x, y);
}

Hoge#valueプロパティの値によってプロットの色を変えたい

例えば、Hoge#valueの値によってプロットの色を以下のように変えたい場合

value < 0.5の場合・・・・・・・青色
0.5 =< value =< 1.5の場合・・・緑色
value >1.5の場合 ・・・・・・・赤色


PlotGroupクラスを継承し、preIterationメソッドをoverrideする。

public class CustomPlotGroup extends PlotGroup{

private const red:Number = 0xFF0000;
private const blue:Number = 0x0000CD;
private const green:Number = 0x99FF33;

public function CustomPlotGroup() {
super();
}

override protected function preIteration():void{

super.preIteration();
var rgf:RadialGradientFill = new RadialGradientFill();
var hoge:Hoge = this.currentDatum as Hoge;

for each (var gs:GradientStop in (plotFill as RadialGradientFill).gradientStops)
{
var currentColor:Number;
if(hoge.value > 2){
currentColor = red;
} else if(0.5 > hoge.value){
currentColor = blue;
} else {
currentColor = green;
}
var gstop:GradientStop = new GradientStop(currentColor,gs.alpha, gs.ratio);
rgf.gradientStops.push(gstop);
}
super.plotFill = rgf;

}
}

あとはmxmlファイルのPlotGroupタグをCustomPlotGroupタグに置き換えるだけ。
最終的にはこんな感じの表示になる。

f:id:ka-ka_xyz:20100131140537p:image