CPTPlotDataSource プロトコル対応

CPTPlotDataSource プロトコルに対応するには、まずこれが必ず必要

(NSUInteger) - numberOfRecordsForPlot:

この部分は今回はこんな感じ。

-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot {
	return 5;
}

単純にグラフには何個レコードがありますか?という確認なので、今回は決め打ちで 5個にしてある。
実際に使う場合には、例えば横軸が日付になるなら何日分か?を返すとかすれば良い。


で、次に必要なのは以下の中のどれか1つ

(NSArray *) - numbersForPlot:field:recordIndexRange:
(NSNumber *) - numberForPlot:field:recordIndex:
(double *) - doublesForPlot:field:recordIndexRange:
(double) - doubleForPlot:field:recordIndex:
(CPTNumericData *) - dataForPlot:field:recordIndexRange:

今回は (NSNumber *) - numberForPlot:field:recordIndex: を使用してみてこんな感じに。

-(NSNumber *)numberForPlot:(CPTPlot *)plot 
                           field:(NSUInteger)fieldEnum 
                  recordIndex:(NSUInteger)index 
{
	if(fieldEnum == CPTBarPlotFieldBarLocation)
		return [NSNumber numberWithDouble:index+1];
	else
	{ 
		if(plot.identifier == @"Bar Plot 1")
			return [NSNumber numberWithDouble:(index+1)*2.0f];
		else
			return 0;
	}
}

まず、(NSNumber *) - numberForPlot:field:recordIndex: は、そのプロット(CPTPlot)の field の recordIndex 番目のレコードの値を返すというメソッド。


今回は CPTPlot が棒グラフ1つしかないから CPTPlot の確認は行ってない。
けど、もしも複数の CPTPlot を乗せるなら確認が必要になる。


次の field はプロットのどの部分の値が必要なのかを示している。
これはそれぞれの CPTPlot(CPTBarPlot や CPTScatterPlot 等)で用意されていて、CPTBarPlot の場合はこんなのがある。

typedef enum _CPTBarPlotField {
    CPTBarPlotFieldBarLocation = 2,  ///< Bar location on independent coordinate axis.
    CPTBarPlotFieldBarTip   	  = 3,	///< Bar tip value.
    CPTBarPlotFieldBarBase     = 4	///< Bar base (used only if barBasesVary is YES).
} CPTBarPlotField;

そして CPTScatterPlot ではこんなんがある。

typedef enum _CPTScatterPlotField {
    CPTScatterPlotFieldX,		///< X values.
    CPTScatterPlotFieldY 		///< Y values.
} CPTScatterPlotField;

今回の CPTBarPlot の場合は CPTBarPlotFieldBarLocation が来たら「そのレコードは何番目の棒か?」を返せば良い。
今回は recordIndex の値に 1 をプラスしている。これは最初のレコードを 0番目でなく 1番目の場所から描く様にしたため。
ちなみに 1を加えずにそのまま index を返すとこんな感じのグラフになる。

最初の棒の位置が 0なので、Y軸に重なっちゃう…。
これ、Y軸の交差する位置を変えたり、棒を描く位置をずらしたり、方法は色々とあるのだけど、今回はとりあえずこんな感じで。


今回は CPTBarPlotFieldBarLocation でなければ実際のレコードの値の問い合わせなので、(index+1)*2.0f で右肩上がりの棒グラフになるようにしている。


で、これを最初に示したサンプル(+Y軸の目盛線)にするにはもう少しだけ修正をしている。

	// First bar plot
	CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor redColor] horizontalBars:NO];
	barPlot.baseValue = CPTDecimalFromString(@"0");
	barPlot.dataSource = self;
	barPlot.barWidth = CPTDecimalFromFloat(1.0f);
	barPlot.identifier = @"Bar Plot 1";
	barPlot.barOffset = CPTDecimalFromString(@"3");
	[graph addPlot:barPlot toPlotSpace:plotSpace];
  1. barPlot.barWidth = CPTDecimalFromFloat(1.0f); で棒の幅を1にしている。これで棒の間の隙間が無くなった。
  2. barPlot.barOffset = CPTDecimalFromString(@"3"); で描く位置を右に3ずらしている。小数点でもいけるので 0.5 だと棒の半分ずれる。

以上の修正で最初のサンプル(+Y軸の目盛線)になる。


取り敢えず簡単な棒グラフならこれで作れるようになったはず!
UITableView みたいに datasource に値を問い合わせてくるので、CoreData を使ってグラフを描くのは結構簡単。
というわけで、明日は X軸を日付にしてみる!