Core-Plotをじっくり使ってみる(X軸を日付にする)
昨日で簡単な棒グラフは描けたので、今日は X軸を日付にしてみる。
Core-Plot のサンプルにあったのを真似しただけだけど、なんかちょっとびっくりした。
X軸を日付にするための設定
まずは最終的なグラフはこんな感じ
横軸を 31日分の日付にして、2週間毎にラベルで日付を書いてる。
各レコードの値は適当に計算してリニアに増える様にしてある。
viewDidLoad の昨日までのコードとの違い
// Graph data prepare NSDate *refDate = [NSDate date]; NSTimeInterval oneDay = 24.0f * 60.0f * 60.0f; plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(oneDay * -1.0f) length:CPTDecimalFromFloat(oneDay*32.0f)]; x.majorIntervalLength = CPTDecimalFromFloat(oneDay*14.0f); x.minorTicksPerInterval = 13; NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [dateFormatter setDateFormat:@"yyyy/MM/dd"]; CPTTimeFormatter *timeFormatter = [[[CPTTimeFormatter alloc] initWithDateFormatter:dateFormatter] autorelease]; timeFormatter.referenceDate = refDate; x.labelFormatter = timeFormatter; y.orthogonalCoordinateDecimal = CPTDecimalFromFloat(-24.0f*60.0f*60.0f/4.0f*3.0f); barPlot.barWidth = CPTDecimalFromFloat(oneDay);
Graph data prepare
refDate は NSDate の今日の日付。とりあえず、今日から 31日分のデータを表示するグラフを描くための元になる日付。
oneDay は NSTimeInterval の1日の長さ。とっても大きな数時になるけど、横軸は秒で計算されてる。
xRange
X軸の範囲を 秒で設定している。Location が 0でないのは、0の時のグラフが Y軸にかかるのが嫌だから。oneDay * -1 で1日分古い日付から X軸が始まる。そして範囲は 31日 + マイナスした1日分なので onDay*32.0f になる。
major/minar Interval
X軸が短いので隔週で目盛を描くことにした。というわけで、majorIntervalLength は 14で、補助目盛の minorTicksPerInterval は 13に。
labelFormatter
X,Y軸に labelFormatter を設定することでラベルのフォーマットを指定できる。
今回 X軸は日付にしたので CPTTimeFormatter を使って日付をラベルに描くことにする。
で、この CPTTimeFormatter は結局 NSDateFormatter とリファレンスになる NSDate でできてて、リファレンスになる日付はさっき求めた refDate を使う。
表示されるラベルは、refDate + 0 の今日の日付、refDate + 14*oneDay の2週間後の日付、refDate + 28*oneDay の4週間後の日付になる。それぞれの NSDate値が NSDateFormatter でフォーマットされて描かれる。
orthogonalCoordinateDecimal
これは Y軸が X軸と交わる X軸の場所。デフォルトは 0で交わってるのだけど、それだとグラフの棒と Y軸が重なって嫌なので、Y軸の交わる場所をマイナス方向に1日分の 3/4 移動している。X軸の範囲を−1日分広げているからまるまる1日移動しても良いのだけど、なんとなく 3/4移動したらピッタリだったので。
ちなみに xRange の Location を 0にして、orthogonalCoordinateDecimal も 0にするとこんな感じになる。
barPlot.barWidth
棒グラフの棒の太さを1日分の太さにした。
これを設定しなかったり、1にしたりすると描いてあるんだかわからない位の細い線になっちゃう!
CPTPlotDataSource プロトコル
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot { return 31; } -(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index { if(fieldEnum == CPTBarPlotFieldBarLocation) return [NSNumber numberWithDouble:index*24.0*60.0*60.0]; else { if(plot.identifier == @"Bar Plot 1") return [NSNumber numberWithDouble:(index/2.0f+1.0f)*1.5f]; else return 0; } }
numberOfRecordsForPlot
決め打ちで 31。31日分のデータを描くよ!
numberForPlot:field:recordIndex:
まず、CPTBarPlotFieldBarLocation の場合。これはそのレコードの X軸での位置だから、index*oneDay になるんだけど、oneDay はここで定義されてなかった…。定数にしとくべき。
で、実際の値は適当に indexが 31の時に 24に近くなる様な計算をしてみただけ。
今回の X軸を日付にしたサンプルはBitBucket からダウンロードできます。
画面右の「Download」で zip, gz, bz2 からフォーマットを選んでください。
というわけで、X軸を日付にするのは思いのほか簡単だった。
日付を横向きに描くと横幅がかなり広いので、iPhone 縦だと今回みたいな隔週とかで描くのがギリギリ。label の rotation を使って斜めや縦に書くこともできるけど、自分的にはあれは格好悪いと思うので使っていない。