読者です 読者をやめる 読者になる 読者になる

ニペブ - iPhone / iOSアプリ開発

iPhone / iOS アプリ開発方法と技術情報、入門レベルの初心者向けの記事を書いています。

(iOS/iPhoneアプリ開発) グラフ描画ライブラリ CorePlot でX軸に日付や月を表示させる方法

完成イメージ

棒グラフが表示され、X軸に月が表示されています。
f:id:nipe880324:20131227134126p:plain:w320

環境

xcodeのプロジェクトにCorePlotを導入する

毎度のことですが導入していない人のために、記載しておきます。
次のサイト参考にして、導入しました。
core-plotでグラフを描いてみよう。-入門編- | Developers.IO
現在は「Downloads -> CorePlot_1.4.zip」でした。

X軸に日付や月を表示させる

まずは、ViewController.h を作成します。上記の過去記事の棒グラフと同じですが再掲します。
CorePlotのヘッダを追加し、必要な変数を宣言しておきます。ここは、こうなるんだなぐらいで特に説明はないです。

#import <UIKit/UIKit.h>
#import "CorePlot-CocoaTouch.h"

@interface BarChartViewController : UIViewController
<CPTPlotDataSource, CPTBarPlotDelegate>
{
@private
    // グラフ表示領域(この領域に棒グラフを追加する)
    CPTGraph *graph;
}

// 棒グラフで表示するデータを保持する配列
@property(nonatomic, strong) NSMutableArray *dataForBar;    //1つめの棒グラフ用
@property(nonatomic, strong) NSMutableArray *dataForBar2;   //2つめの棒グラフ用

@end



次に、ViewController.m を作成します。
基本は「CorePlotの過去記事」の棒グラフです。
細かくコメントを記載してますのでそれを見れば大体分かると思います。

X軸に日付や月を表示させるためには、CPTXYAxisSetに表示させたい日付や月をラベルとして設定する必要があります。
次のメソッドで設定しています。今回は月を表示させていますが、ラベルとして日付を設定させればX軸に日付を表示させる事が可能です。

- (void) arbitraryLabels:(CPTGraph*)cptGraph;

そこを中心に見れば難しくないので実装ができると思います。
実際のソースコードです。

#import "BarChartViewController.h"

@interface BarChartViewController ()

@end

@implementation BarChartViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // グラフに表示するデータを生成
    // 1つめの棒グラフ用のデータ。12ヶ月の棒グラフのX軸データ
    self.dataForBar = [NSMutableArray arrayWithObjects:
                       [NSNumber numberWithDouble:-2.0],[NSNumber numberWithDouble:-1.0],[NSNumber numberWithDouble:0.0],
                       [NSNumber numberWithDouble:1.0],[NSNumber numberWithDouble:2.0],[NSNumber numberWithDouble:3.0],
                       [NSNumber numberWithDouble:4.0],[NSNumber numberWithDouble:5.0],[NSNumber numberWithDouble:6.0],
                       [NSNumber numberWithDouble:7.0],[NSNumber numberWithDouble:8.0],[NSNumber numberWithDouble:9.0],
                       nil];
    // 2つめの棒グラフ用のデータ。12ヶ月の棒グラフのX軸データ
    self.dataForBar2 = [NSMutableArray arrayWithObjects:
                       [NSNumber numberWithDouble:9.0],[NSNumber numberWithDouble:8.0],[NSNumber numberWithDouble:7.0],
                       [NSNumber numberWithDouble:6.0],[NSNumber numberWithDouble:5.0],[NSNumber numberWithDouble:4.0],
                       [NSNumber numberWithDouble:3.0],[NSNumber numberWithDouble:2.0],[NSNumber numberWithDouble:1.0],
                       [NSNumber numberWithDouble:0.0],[NSNumber numberWithDouble:-1.0],[NSNumber numberWithDouble:-2.0],
                       nil];
    
    
    // ホスティングビューを生成する
    CPTGraphHostingView *hostingView =
    [[CPTGraphHostingView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];
    hostingView.collapsesLayers = NO;
    // 画面にホスティングビューを追加
    [self.view addSubview:hostingView];

    // グラフを生成
    graph = [[CPTXYGraph alloc] initWithFrame:hostingView.bounds];
    hostingView.hostedGraph = graph;
    
    // グラフのテーマを作成して、設定
    // その他のテーマ名 kCPTPlainBlackTheme:黒いテーマ, kCPTDarkGradientTheme:グレーなテーマ
    //                kCPTSlateTheme:グレーなテーマ, kCPTStocksTheme
    CPTTheme *theme = [CPTTheme themeNamed:kCPTPlainWhiteTheme];    // シンプルな白いテーマ
    [graph applyTheme:theme];

    // グラフのボーダー設定
    graph.plotAreaFrame.borderLineStyle = nil;
    graph.plotAreaFrame.cornerRadius    = 0.0f;
    graph.plotAreaFrame.masksToBorder   = NO;
    
    // パディング
    graph.paddingLeft   = 0.0f;
    graph.paddingRight  = 0.0f;
    graph.paddingTop    = 0.0f;
    graph.paddingBottom = 0.0f;
    
    graph.plotAreaFrame.paddingLeft   = 60.0f;
    graph.plotAreaFrame.paddingTop    = 60.0f;
    graph.plotAreaFrame.paddingRight  = 20.0f;
    graph.plotAreaFrame.paddingBottom = 65.0f;

    //プロット間隔の設定
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    //Y軸は-3〜10の値で設定
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(-3) length:CPTDecimalFromInt(13)];
    //X軸は0〜7の値で設定
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(0) length:CPTDecimalFromInt(12)];
     
    // テキストスタイル
    CPTMutableTextStyle *textStyle = [CPTTextStyle textStyle];
    textStyle.color                = [CPTColor colorWithComponentRed:0.447f green:0.443f blue:0.443f alpha:1.0f];
    textStyle.fontSize             = 13.0f;
    textStyle.textAlignment        = CPTTextAlignmentCenter;
    
    // ラインスタイル
    CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
    lineStyle.lineColor            = [CPTColor colorWithComponentRed:0.788f green:0.792f blue:0.792f alpha:1.0f];
    lineStyle.lineWidth            = 2.0f;
    
    // X軸のメモリ・ラベルなどの設定
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *x          = axisSet.xAxis;
    x.axisLineStyle               = lineStyle;
//    x.majorTickLineStyle          = lineStyle;                // ラベルを設定しているため無効ぽい
//    x.minorTickLineStyle          = lineStyle;                // ラベルを設定しているため無効ぽい
    x.majorIntervalLength         = CPTDecimalFromString(@"2"); // X軸ラベルの表示間隔
    x.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0"); // X軸のY位置
    x.title                       = @"X軸";
    x.titleTextStyle = textStyle;
    x.titleLocation               = CPTDecimalFromFloat(5.0f);
    x.titleOffset                 = 36.0f;
//    x.minorTickLength = 5.0f;                   // X軸のメモリの長さ ラベルを設定しているため無効ぽい
//    x.majorTickLength = 9.0f;                   // X軸のメモリの長さ ラベルを設定しているため無効ぽい
    x.labelTextStyle = textStyle;
    
    // Y軸のメモリ・ラベルなどの設定
    CPTXYAxis *y = axisSet.yAxis;
    y.axisLineStyle               = lineStyle;
    y.minorTickLength = 5.0f;                   // Y軸のメモリの長さ
    y.majorTickLength = 9.0f;                   // Y軸のメモリの長さ
    y.majorTickLineStyle          = lineStyle;
    y.minorTickLineStyle          = lineStyle;
    y.majorIntervalLength         = CPTDecimalFromFloat(1.0f);  // Y軸ラベルの表示間隔
    y.orthogonalCoordinateDecimal = CPTDecimalFromFloat(0.0f);  // Y軸のX位置
    y.title                       = @"Y軸";
    y.titleTextStyle = textStyle;
    y.titleRotation = M_PI*2;
    y.titleLocation               = CPTDecimalFromFloat(10.5f);
    y.titleOffset                 = 25.0f;
    lineStyle.lineWidth = 0.5f;
    y.majorGridLineStyle = lineStyle;
    y.labelTextStyle = textStyle;

    // 2つめの棒グラフの作成と設定
    // horizontalBars:BOOL => YESの場合、横棒グラフ。NOの場合、縦棒グラフ。
    CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor colorWithComponentRed:1.0f green:1.0f blue:0.88f alpha:1.0f] horizontalBars:NO];
    barPlot.fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:0.573f green:0.82f blue:0.831f alpha:0.50f]]; // バーの色を設定。上記のカラーが上塗りされる。
    barPlot.identifier = @"Plot1";                      // 1つめの棒グラフの識別子を設定
    barPlot.lineStyle = lineStyle;                      // ラインスタイルを設定
    barPlot.baseValue  = CPTDecimalFromString(@"0");    // グラフのベースの値を設定
    barPlot.dataSource = self;                          // データソースを設定
    barPlot.delegate = self;
    barPlot.barWidth = CPTDecimalFromFloat(0.3f);       // 各棒の幅を設定
    barPlot.barOffset  = CPTDecimalFromFloat(0.3f);     // 各棒の横軸からのオフセット値を設定
    [graph addPlot:barPlot toPlotSpace:plotSpace];      // グラフに棒グラフを追加

    // 2つめの棒グラフの作成と設定
    CPTBarPlot *barPlot2 = [CPTBarPlot tubularBarPlotWithColor:[CPTColor colorWithComponentRed:1.0f green:1.0f blue:0.88f alpha:1.0f] horizontalBars:NO];
    barPlot2.fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:0.780f green:0.50f blue:0.531f alpha:0.50f]]; // バーの色を設定。上記のカラーが上塗りされる。
    barPlot2.identifier = @"Plot2";                      // 2つめの棒グラフの識別子を設定
    barPlot2.lineStyle = lineStyle;                      // ラインスタイルを設定
    barPlot2.baseValue  = CPTDecimalFromString(@"0");    // グラフのベースの値を設定
    barPlot2.dataSource = self;                          // データソースを設定
    barPlot2.delegate = self;
    barPlot2.barWidth = CPTDecimalFromFloat(0.3f);       // 各棒の幅を設定
    barPlot2.barOffset  = CPTDecimalFromFloat(0.6f);     // 各棒の横軸からのオフセット値を設定
    [graph addPlot:barPlot2 toPlotSpace:plotSpace];      // グラフに棒グラフを追加

    
    // 任意の文字列のラベルを表示する
    [self arbitraryLabels:graph];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark -
// 任意の文字列のラベルを表示する
- (void) arbitraryLabels:(CPTGraph*)cpgGraph
{
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)cpgGraph.axisSet;
    
    NSMutableArray *labels = [NSMutableArray arrayWithCapacity:12];
    int idx = 1;
    for (NSString *year in @[@"1月",@"2月",@"3月",@"4月",@"5月",@"6月",@"7月",@"8月",@"9月",@"10月",@"11月",@"12月"]) // ラベルの文字列
    {
        CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:year
                                                       textStyle:axisSet.xAxis.labelTextStyle];
        label.tickLocation = CPTDecimalFromInt(idx); // ラベルを追加するレコードの位置
        label.offset = 5.0f; // 軸からラベルまでの距離
        [labels addObject:label];
        ++idx;
    }
    // X軸に設定
    axisSet.xAxis.axisLabels = [NSSet setWithArray:labels];
    axisSet.xAxis.labelingPolicy = CPTAxisLabelingPolicyNone; // これ重要
    axisSet.xAxis.labelRotation  = M_PI / 3;                // 表示角度

}


#pragma mark Plot Data Source Methods

// グラフに使用する棒グラフのデータ数を返す
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
    return [self.dataForBar count];
}

// 各棒の設定値を返す
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    NSDecimalNumber *num = nil;
    
    if ( [plot isKindOfClass:[CPTBarPlot class]] ) {
        
        switch ( fieldEnum ) {
            //X軸のラベルをNSNumberで指定(Formatterとか
            case CPTBarPlotFieldBarLocation:
                num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:index];
                break;
                
            //棒の高さを指定
            case CPTBarPlotFieldBarTip:
                if ([plot.identifier isEqual:@"Plot1"]) {
                    num = [self.dataForBar objectAtIndex:index];
                } else if ([plot.identifier isEqual:@"Plot2"]) {
                    num = [self.dataForBar2 objectAtIndex:index];
                }
                break;
        }
    }
    return num;
}


#pragma mark Plot Delegate Methods

// 各棒をタップしたときに発生するイベント
- (void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index
{
    // グラフタイトルにタップされた各項目のインデックス番号を設定
    graph.title = [NSString stringWithFormat:@"Selected index: %lu", (unsigned long)index];
}

@end


円グラフや棒グラフなどCorePlotのサンプルのソースコードGithubに置いてあります。よろしければ、覗いてみてください。
yanagi0324/test-core-plot · GitHub

参考情報

分かりづらい箇所やご質問などありましたら、 コメントやメールアドレスにご連絡いただけると嬉しいです。