CorePlotを理解可能なレベルに噛み砕きたい件

私のような初心者がライブラリを使ったとき、ある程度まではとんとんびょうしに作業が進み、調子にのってしまうことがよくある。  
そして「さー、少しカスタマイズしてみようか」ととりかかって数時間。数日。。挫折。。。
残念ながらPNChartも類にもれずそのような形になった。まず、ライブラリの構造がわからない。どこをどうすればよいのか、レファレンスもあまりない。  
そこで、自分でもカスタマイズ可能なライブラリを利用すべしと観点を変え、CorePlotを選定した。

##まず最初につまずいたこと

* ColePlotの構成がよくわからず、全体像が見えない
* 目的を実現するための作業の見通しが立たない
* 自分が独自に実現したいことと、実装のポイントとが結びつかない

これはPNChartでも同じようにつまずいている。
手軽で楽しいサンプルで遊ぶのもいいが、やがて立ちふさがるだろう課題に向き合わなくてはならない。

##ゆえに噛み砕かなければならないこと
何らかのオリジナルな機能の実現のためにCorePlotを使って作業するなら、基礎の部分・今後使いまわせる共通の部分は事前に整理・理解して、生産性をある程度上げておきたい。

* CorePlotライブラリの概念
* グラフを作成するための基本的なアプローチ

くらいは事前に整理して、自分なりに表現できていないとダメだ。

###CorePlotライブラリの概念
イメージがつきやすいように、コンポーネントの位置づけをひとことで言ってみる。

|コンポーネント|位置づけ|
|-----|-----|
|Graphs|実装すべきグラフ機能の全体像|
|Plot Area|全てのプロットが描かれる領域で、軸やタイトルは含まない|
|Plot Spaces|データを表現するための範囲と、実際に描画する空間を対応づけている（これはまだ難解な表現）|
|Plots|データを表現したもの（日本ではグラフと呼ばれるイメージ）で、Plot Areaに複数描ける|
|Axes|軸。折れ線グラフではX軸やY軸など|
[参考](https://github.com/core-plot/core-plot/wiki/High-Level-Design-Overview)


###グラフを作成するための基本的なアプローチ
まず、viewDidApper:時に、下記４つの設定を行う。

* ホスト設定
* グラフ設定
* プロット設定
* 軸設定


次にdataSourceメソッドで、プロットを作成する。

* `-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot`
* `-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index `


####ホスト設定
グラフを表示するビューに、グラフをホストするビューを追加する。

```objc
- (void)configureHost
{
    //ホストビューの作成
    self.hostview = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:CGRectMake(0.0f, 110.0f, 320.0f, 400.0f)];
    [self.view addSubview:self.hostview];
}
```
####グラフ設定
グラフ（全体像）に関する情報を設定する

```objc
- (void)configureGraph
{
    //グラフを作る
    CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:CGRectZero];
    graph.paddingTop = 10.0f;
    graph.paddingLeft = 10.0f;
    graph.paddingRight = 10.0f;
    graph.paddingBottom = 10.0f;
    [graph applyTheme:[CPTTheme themeNamed:kCPTSlateTheme]];
    self.hostview.hostedGraph = graph;
    //グラフタイトルを作る
    NSString *title = @"hogeTitle";
    graph.title = title;
    //テキストスタイルの作成と設定
    CPTMutableTextStyle *titleStyle = [CPTMutableTextStyle textStyle];
    titleStyle.color = [CPTColor blackColor];
    titleStyle.fontName = @"Helvetica-Bold";
    titleStyle.fontSize = 12.0f;
    graph.titleTextStyle = titleStyle;
    graph.titlePlotAreaFrameAnchor = CPTRectAnchorTop;
    graph.titleDisplacement = CGPointMake(0.0f, -10.0f);
    //プロットエリアのパディング設定
    [graph.plotAreaFrame setPaddingLeft:60.0f];
    [graph.plotAreaFrame setPaddingRight:30.0f];
    [graph.plotAreaFrame setPaddingTop:30.0f];
    [graph.plotAreaFrame setPaddingBottom:30.0f];
}
```

####プロット設定
プロットスペースとプロットを対応付け、プロットスペースにどのくらいの情報を表示したいか設定する。

```objc
- (void)configurePlots
{
    //グラフとプロットスペースを用意する
    CPTGraph *graph = self.hostview.hostedGraph;
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    //プロットを作成する
    CPTScatterPlot *scatterPlot = [[CPTScatterPlot alloc] init];
    scatterPlot.dataSource = self;
    scatterPlot.identifier = @"identifier";
    scatterPlot.interpolation = CPTScatterPlotInterpolationCurved;
    CPTColor *scatterColor = [CPTColor yellowColor];
    [graph addPlot:scatterPlot toPlotSpace:plotSpace];
    //プロットスペースをセットアップする
    [plotSpace scaleToFitPlots:[NSArray arrayWithObjects:scatterPlot, nil]];
    CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
    xRange  = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(31.0f)];
    plotSpace.xRange = xRange;
    CPTMutablePlotRange *yRange = [plotSpace.yRange mutableCopy];
    yRange  = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(180.0f)];
    plotSpace.yRange = yRange;
    //スタイルとシンボル作成
    CPTMutableLineStyle *scatterLineStyle = [scatterPlot.dataLineStyle mutableCopy];
    scatterLineStyle.lineWidth = 2.5;
    scatterLineStyle.lineColor = scatterColor;
    scatterPlot.dataLineStyle = scatterLineStyle;
    CPTMutableLineStyle *scatterSymbolLineStyle = [CPTMutableLineStyle lineStyle];
    scatterSymbolLineStyle.lineColor = scatterColor;
    CPTPlotSymbol *scatterSymbol = [CPTPlotSymbol ellipsePlotSymbol];
    scatterSymbol.fill = [CPTFill fillWithColor:scatterColor];
    scatterSymbol.lineStyle = scatterSymbolLineStyle;
    scatterSymbol.size = CGSizeMake(6.0f, 6.0f);
    scatterPlot.plotSymbol = scatterSymbol;
}
```

####軸設定
X軸、Y軸にそれぞれの目盛りに関する情報を設定する。

```objc
- (void)configureAxes
{
    CPTGraph *graph = self.hostview.hostedGraph;
    //1. スタイル作成
    CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
    lineStyle.lineColor = [CPTColor brownColor];
    lineStyle.lineWidth = 2.0f;
    CPTMutableTextStyle *axisTextStyle = [[CPTMutableTextStyle alloc] init];
    axisTextStyle.color = [CPTColor blackColor];
    axisTextStyle.fontName = @"Helvetica-Bold";
    axisTextStyle.fontSize = 11.0f;
    
    
    //2. Axes Setを取得
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    
    //3. X軸の設定
    CPTXYAxis *x = axisSet.xAxis;
    x.majorIntervalLength = CPTDecimalFromString(@"7");
    x.minorTicksPerInterval = 6;
    x.majorTickLineStyle = lineStyle;
    x.minorTickLineStyle = lineStyle;
    x.axisLineStyle = lineStyle;
    x.minorTickLength = 5.0f;
    x.majorTickLength = 9.0f;
    x.labelTextStyle = axisTextStyle;
    
    //4. Y軸の設定
    CPTXYAxis *y = axisSet.yAxis;
    y.majorIntervalLength = CPTDecimalFromString(@"20");
    y.minorTicksPerInterval = 4;
    y.majorTickLineStyle = lineStyle;
    y.minorTickLineStyle = lineStyle;
    y.axisLineStyle = lineStyle;
    y.minorTickLength = 5.0f;
    y.majorTickLength = 9.0f;
    y.labelTextStyle = axisTextStyle;
    y.title = @"推移";
    y.titleOffset = 35.0f;
    lineStyle.lineWidth = 0.5f;
    y.majorGridLineStyle = lineStyle;
}
```


####`-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot`
表示するデータの個数を設定する。CoreDataなどのモデルオブジェクトがあれば、動的に設定する。

```objc
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
    return [self.calendarData count];
}
```

####`-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index `
X軸、Y軸それぞれの座標を設定する。今回はX軸に日付を設定しているため、`index`に`oneDay`を乗じている。Y軸に対するデータは、TableViewでdatasourceメソッドを使って値を取得するのと特にかわらない。

```objc
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
    NSUInteger valueCount = [self.calendarData count];

    switch (fieldEnum) {
        case CPTScatterPlotFieldX:
            if (index < valueCount) {
                return [NSNumber numberWithUnsignedInteger:index * oneDay]; //ondDayは一日を秒で表した定数(60.0f * 24.0f * 24.0f)
            }
            break;
        case CPTScatterPlotFieldY:
            if ([plot.identifier isEqual:kData] == YES) {
                NSNumber *numberForPlot = [[self.calendarData objectAtIndex:index] valueForKey:@"max"];
                return numberForPlot;
            }
        default:
            break;
    }
    return [NSDecimalNumber zero];
}
```
[参考](http://www.raywenderlich.com/13271/how-to-draw-graphs-with-core-plot-part-2)

##つづく
ここまでは基本的なことであり、グラフ（折れ線グラフ）を作成したくなったら今後も使い回しができるだろう。
サンプルコードコピペ状態より少しだけ勉強したのでちょっと落ち着いた。
次の記事ではやりたいことを実現するにあたって、手間取ったり工夫した点を整理してみる。

* X軸を日付にする
* 元となるデータをユーザが指定してグラフを作成する
* [連続しないデータ間を補完したプロットはないのか](https://groups.google.com/forum/#!searchin/coreplot-discuss/scatter/coreplot-discuss/8ulsY6MUqMU/oFaf7-kY5GoJ
)