LoginSignup
7
7

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-03-04

前回の続きも記録しておく。

X軸を日付にする

X軸、Y軸ともに通常は数字が軸ラベルとして用いられる。今回私が作りたいのは時系列の情報の推移なので、X軸を数字から日付にする必要がある。

前回記載したように、CorePlotを使う場合の基本的なアプローチで下記のような設定を行った。

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

それに加えてconfigureCalendarというカレンダー用設定処理を追加した。

NSTimeInterval const oneDay = 60.0f * 60.0f * 24.0f;
- (void)configureCalendar
{
    CPTGraph *graph = self.hostview.hostedGraph;
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;

    //プロットスペースのX軸表示範囲設定
    CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
    xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(oneDay * 30)];
    plotSpace.xRange = xRange;


    //30日前の日付を取得する
    NSDate *today = [NSDate date];
    NSDate *startDate = [NSDate dateWithTimeInterval:-(oneDay * 30) sinceDate:today];
    //グラフのX軸に描かれる日付を設定する
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"MM-dd"];
    [formatter setLocale:[NSLocale systemLocale]];
    [formatter setTimeZone:[NSTimeZone systemTimeZone]];
    CPTTimeFormatter *timeFormatter = [[CPTTimeFormatter alloc] initWithDateFormatter:formatter];
    timeFormatter.referenceDate = startDate;

    //X軸のラベルを日付形式に設定
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *x = axisSet.xAxis;
    x.labelFormatter = timeFormatter;
    x.majorIntervalLength = CPTDecimalFromFloat(7*oneDay);
    x.minorTicksPerInterval = 6;

}
  1. プロットスペースのX軸表示範囲は、当日を最新として30日間分としたい。軸のlabelFormatterにはCPTimeFomartterのオブジェクトを設定するため、表示の範囲としては30 × [1日の秒換算]をlengthに設定する。これは、CPTimeFomatterが秒数を使って日付を管理しているため。
  2. 時間的な範囲を30日前〜本日、と定義したいため、30日前の日付を取得し、CPTimeFormatterの開始日referenceDateプロパティに設定している。
  3. このグラフのX軸のラベルを日付形式に設定している。インターバルは7日間なので、この場合は7*oneDay秒となり、それをx.minorTicksPerInterval=6とすることで6分割(1日ごとに目盛表示される)した。

続いて、DataSourceメソッドにてX軸の値を返却する場合も、日付フォーマットであることを考慮してindex * oneDayとしている。

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

    switch (fieldEnum) {
        case CPTScatterPlotFieldX:
            //index * 1日分の秒数
            if (index < valueCount) {
                return [NSNumber numberWithUnsignedInteger:index * oneDay]; //<- here
            }
            break;
        case CPTScatterPlotFieldY:
            if ([plot.identifier isEqual:kData] == YES) {
                NSNumber *numberForPlot = [[self.calendarData objectAtIndex:index] valueForKey:@"max"];
                return numberForPlot;
            }
        default:
            break;
    }
    return [NSDecimalNumber zero];
}

元となるデータをユーザが指定してグラフを作成する

通常、グラフはviewDidLoadまたはviewDidAppear:のタイミングで描画されることが多いように思う。
私の実現したかったことは、グラフ表示させるプロットをユーザが動的に選択(テキストフィールドで条件を指定)することだったので、UITextFieldDelegateプロトコルを実装し、textFieldDidEndEditing:メソッド内にて、グラフ更新処理を記述した。

#pragma mark - UITextFieldDelegate
- (void)textFieldDidEndEditing:(UITextField *)textField
{
    if (![self.nameTextField.text isEqualToString:@""]) {
        //グラフ表示させるためのモデルデータ作成
        ......

        //グラフ更新処理
       [self reloadGraphData:self.hostview.hostedGraph];
    }
}

ちなみにreloadGraphData:は内部のメソッドで、下記のように実装。

- (void) reloadGraphData:(CPTGraph*)graph
{
    // データ取得の各種delegateが実行される。
    [graph reloadData];
}

連続しないデータ間を補完したプロットは作れないのか

これについては、現在調査中・・・、もとい、調査凍結中。
X軸に設定した目盛り単位にY軸の値をプロットできればその2点間は線で結ばれるが、間の値が欠落しているとそれを補完して最も近い2点間を結んでくれるわけではない。
折れ線グラフという体裁において、これはかなり違和感がある。間の値はNSNULL nullを設定していると上述のようになるのだが、@0を設定すると一応折れ線の体は維持してくれる(本質的な解決ではない)。
iOSシミュレータのスクリーンショット 2014.03.05 0.18.18.png
iOSシミュレータのスクリーンショット 2014.03.05 0.16.57.png

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7