&tag(CorePlot); *目次 [#pb478f69] #contents *参考情報 [#s9129797] -[[core-plot - Cocoa plotting framework for OS X and iOS - Google Project Hosting:https://code.google.com/p/core-plot/]] *概要 [#m295d9f5] -iOSで使えるグラフ描画ライブラリ *セットアップ [#hc37bca0] **CocoaPodsを使用 [#mec69c07] -hgが必要なので事前にインストールしておく。 -Podfileを編集 #pre{{ platform :ios pod 'CorePlot' }} -インストール $ pod install *サンプル作成 [#j2cf4f07] **基礎知識 [#t8983e95] -公式サイトからダウンロードできるzipファイルの中にサンプルあり。 -iPhone用はCPTTestApp-iPhoneというフォルダにある。 **ヘッダーのインクルード [#ge67bd5c] -プロジェクト.pchでインクルードしておくと便利。 #import "CorePlot-CocoaTouch.h" *棒グラフの描画 [#d5c0021c] **初めての棒グラフ [#fbefb0cf] ***前置き [#mbd68f86] -サンプルアプリと同様の棒グラフをさらのUIViewControllerのサブクラスに描画してみる。 -サンプルはxibを使ってviewを入れ替えているが以下のコードではコードでviewを置き換えている。 -ソースはARC対応で作成(releaseなどはなし)。 ***ヘッダーの修正 [#a23e6579] -データを提供するために、CPTPlotDataSourceを実装する。 @interface CPTTestAppBarChartController : UIViewController<CPTPlotDataSource> ***ソースファイルの編集[#z43f4213] -CPTXYGraphをプライベートプロパティとして保持 #pre{{ @interface DemoFirstViewController () @property(nonatomic, strong) CPTXYGraph *barChart; @end }} -viewDidLoadを次のように修正する。 #pre{{ - (void)viewDidLoad { [super viewDidLoad]; //viewを置き換える必要がある CPTGraphHostingView *hostingView = [[CPTGraphHostingView alloc] init]; hostingView.collapsesLayers = NO; // Setting to YES reduces GPU memory usage, but can slow drawing/scrolling self.view = hostingView; // Create barChart from theme self.barChart = [[CPTXYGraph alloc] initWithFrame:CGRectZero]; CPTTheme *theme = [CPTTheme themeNamed:kCPTDarkGradientTheme]; [self.barChart applyTheme:theme]; hostingView.hostedGraph = self.barChart; // Border self.barChart.plotAreaFrame.borderLineStyle = nil; self.barChart.plotAreaFrame.cornerRadius = 0.0f; // Paddings self.barChart.paddingLeft = 0.0f; self.barChart.paddingRight = 0.0f; self.barChart.paddingTop = 0.0f; self.barChart.paddingBottom = 0.0f; self.barChart.plotAreaFrame.paddingLeft = 70.0; self.barChart.plotAreaFrame.paddingTop = 20.0; self.barChart.plotAreaFrame.paddingRight = 20.0; self.barChart.plotAreaFrame.paddingBottom = 80.0; // Graph title self.barChart.title = @"Graph Title\nLine 2"; CPTMutableTextStyle *textStyle = [CPTTextStyle textStyle]; textStyle.color = [CPTColor grayColor]; textStyle.fontSize = 16.0f; textStyle.textAlignment = CPTTextAlignmentCenter; self.barChart.titleTextStyle = textStyle; self.barChart.titleDisplacement = CGPointMake(0.0f, -20.0f); self.barChart.titlePlotAreaFrameAnchor = CPTRectAnchorTop; // Add plot space for horizontal bar charts CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.barChart.defaultPlotSpace; plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(300.0f)]; plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(16.0f)]; CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.barChart.axisSet; CPTXYAxis *x = axisSet.xAxis; x.axisLineStyle = nil; x.majorTickLineStyle = nil; x.minorTickLineStyle = nil; x.majorIntervalLength = CPTDecimalFromString(@"5"); x.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0"); x.title = @"X Axis"; x.titleLocation = CPTDecimalFromFloat(7.5f); x.titleOffset = 55.0f; // Define some custom labels for the data elements x.labelRotation = M_PI / 4; x.labelingPolicy = CPTAxisLabelingPolicyNone; NSArray *customTickLocations = [NSArray arrayWithObjects:[NSDecimalNumber numberWithInt:1], [NSDecimalNumber numberWithInt:5], [NSDecimalNumber numberWithInt:10], [NSDecimalNumber numberWithInt:15], nil]; NSArray *xAxisLabels = [NSArray arrayWithObjects:@"Label A", @"Label B", @"Label C", @"Label D", @"Label E", nil]; NSUInteger labelLocation = 0; NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:[xAxisLabels count]]; for ( NSNumber *tickLocation in customTickLocations ) { CPTAxisLabel *newLabel = [[CPTAxisLabel alloc] initWithText:[xAxisLabels objectAtIndex:labelLocation++] textStyle:x.labelTextStyle]; newLabel.tickLocation = [tickLocation decimalValue]; newLabel.offset = x.labelOffset + x.majorTickLength; newLabel.rotation = M_PI / 4; [customLabels addObject:newLabel]; } x.axisLabels = [NSSet setWithArray:customLabels]; CPTXYAxis *y = axisSet.yAxis; y.axisLineStyle = nil; y.majorTickLineStyle = nil; y.minorTickLineStyle = nil; y.majorIntervalLength = CPTDecimalFromString(@"50"); y.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0"); y.title = @"Y Axis"; y.titleOffset = 45.0f; y.titleLocation = CPTDecimalFromFloat(150.0f); // First bar plot CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor darkGrayColor] horizontalBars:NO]; barPlot.baseValue = CPTDecimalFromString(@"0"); barPlot.dataSource = self; barPlot.barOffset = CPTDecimalFromFloat(-0.25f); barPlot.identifier = @"Bar Plot 1"; [self.barChart addPlot:barPlot toPlotSpace:plotSpace]; // Second bar plot barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor blueColor] horizontalBars:NO]; barPlot.dataSource = self; barPlot.baseValue = CPTDecimalFromString(@"0"); barPlot.barOffset = CPTDecimalFromFloat(0.25f); barPlot.barCornerRadius = 2.0f; barPlot.identifier = @"Bar Plot 2"; [self.barChart addPlot:barPlot toPlotSpace:plotSpace]; } }} -CPTPlotDataSourceのメソッドを実装 #pre{{ #pragma mark - #pragma mark Plot Data Source Methods -(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot { return 16; } -(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index { NSDecimalNumber *num = nil; if ( [plot isKindOfClass:[CPTBarPlot class]] ) { switch ( fieldEnum ) { case CPTBarPlotFieldBarLocation: num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:index]; break; case CPTBarPlotFieldBarTip: num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:(index + 1) * (index + 1)]; if ( [plot.identifier isEqual:@"Bar Plot 2"] ) { num = [num decimalNumberBySubtracting:[NSDecimalNumber decimalNumberWithString:@"10"]]; } break; } } return num; } }} ***以上で一応完成 [#z2c10baf] -実行すればグレーと青の2種類の棒グラフが画面に表示される。 -以下ポイントの説明など。 ***タイトル・パディングなどの設定 [#z22a223e] -タイトルやPaddingなどは以下の部分で設定されている。試行錯誤してみればどこがどれに該当しているかは比較的わかりやすい。 #pre{{ // Border self.barChart.plotAreaFrame.borderLineStyle = nil; self.barChart.plotAreaFrame.cornerRadius = 0.0f; // Paddings self.barChart.paddingLeft = 0.0f; self.barChart.paddingRight = 0.0f; self.barChart.paddingTop = 0.0f; self.barChart.paddingBottom = 0.0f; self.barChart.plotAreaFrame.paddingLeft = 70.0; self.barChart.plotAreaFrame.paddingTop = 20.0; self.barChart.plotAreaFrame.paddingRight = 20.0; self.barChart.plotAreaFrame.paddingBottom = 80.0; // Graph title self.barChart.title = @"Graph Title\nLine 2"; CPTMutableTextStyle *textStyle = [CPTTextStyle textStyle]; textStyle.color = [CPTColor grayColor]; textStyle.fontSize = 16.0f; textStyle.textAlignment = CPTTextAlignmentCenter; self.barChart.titleTextStyle = textStyle; self.barChart.titleDisplacement = CGPointMake(0.0f, -20.0f); self.barChart.titlePlotAreaFrameAnchor = CPTRectAnchorTop; }} ***プロット間隔の設定 [#pa446239] -開始、終了時点の値の情報は、CPTXYPlotSpaceを使って指定する。 #pre{{ CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.barChart.defaultPlotSpace; //Y軸の範囲(0〜300) plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(300.0f)]; //X軸の範囲(0〜16) plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(16.0f)]; }} ***X軸のメモリ・ラベルなどの設定 [#h9b68714] -CPTXYAxisに設定する。サンプルではX方向にカスタムしたラベルを表示するためコードが長くなっている。axisLineStyle(X軸のラインスタイル)、majorTickLineStyle(大目盛りのラインスタイル)、minorTickLineStyle(小目盛りのラインスタイル)がnilに設定されているため、横方向の線自体はまったく書かれない事に注意。 #pre{{ CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.barChart.axisSet; CPTXYAxis *x = axisSet.xAxis; x.axisLineStyle = nil; x.majorTickLineStyle = nil; x.minorTickLineStyle = nil; x.majorIntervalLength = CPTDecimalFromString(@"5"); x.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0"); x.title = @"X Axis"; x.titleLocation = CPTDecimalFromFloat(7.5f); x.titleOffset = 55.0f; // Define some custom labels for the data elements x.labelRotation = M_PI / 4; x.labelingPolicy = CPTAxisLabelingPolicyNone; NSArray *customTickLocations = [NSArray arrayWithObjects:[NSDecimalNumber numberWithInt:1], [NSDecimalNumber numberWithInt:5], [NSDecimalNumber numberWithInt:10], [NSDecimalNumber numberWithInt:15], nil]; NSArray *xAxisLabels = [NSArray arrayWithObjects:@"Label A", @"Label B", @"Label C", @"Label D", @"Label E", nil]; NSUInteger labelLocation = 0; NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:[xAxisLabels count]]; for ( NSNumber *tickLocation in customTickLocations ) { CPTAxisLabel *newLabel = [[CPTAxisLabel alloc] initWithText:[xAxisLabels objectAtIndex:labelLocation++] textStyle:x.labelTextStyle]; newLabel.tickLocation = [tickLocation decimalValue]; newLabel.offset = x.labelOffset + x.majorTickLength; newLabel.rotation = M_PI / 4; [customLabels addObject:newLabel]; } x.axisLabels = [NSSet setWithArray:customLabels]; }} ***Y軸のメモリ・ラベル [#ydb46dba] -同様に設定。こっちは独自ラベルの設定はないので数字が描画される。 #pre{{ CPTXYAxis *y = axisSet.yAxis; y.axisLineStyle = nil; y.majorTickLineStyle = nil; y.minorTickLineStyle = nil; y.majorIntervalLength = CPTDecimalFromString(@"50"); y.orthogonalCoordinateDecimal = CPTDecimalFromString(@"0"); y.title = @"Y Axis"; y.titleOffset = 45.0f; y.titleLocation = CPTDecimalFromFloat(150.0f); }} ***CPTPlotDataSourceの実装 [#nc022189] -numberOfRecordsForPlotでデータの個数(棒の数)を返す。16を返しているので16個の棒がかかれる。 #pre{{ -(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot { return 16; } }} -numberForPlot:field:recordIndexはデータを返す。plotが複数存在する場合はその考慮も必要。 #pre{{ -(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index { NSDecimalNumber *num = nil; // if ( [plot isKindOfClass:[CPTBarPlot class]] ) { switch ( fieldEnum ) { case CPTBarPlotFieldBarLocation: //X方向の位置を返す num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:index]; break; case CPTBarPlotFieldBarTip: //棒の高さを返す(サンプルでは機械的に計算してかえしているだけ) num = (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:(index + 1) * (index + 1)]; if ( [plot.identifier isEqual:@"Bar Plot 2"] ) { num = [num decimalNumberBySubtracting:[NSDecimalNumber decimalNumberWithString:@"10"]]; } break; } } return num; } }} * トラブルシューティング [#q4f31589] **CorePlot/framework/Source/CPTAxis.m:41:1: Property attribute in class extension does not match the primary class という警告が表示される [#o1bb8c49] -[[Issue 519 - core-plot - cpt_weak breaking when target > 5 but not using arc - Cocoa plotting framework for OS X and iOS - Google Project Hosting:https://code.google.com/p/core-plot/issues/detail?id=519]]にある現象か。 -CPTDefinitions.hの最初のCPT_SDK_SUPPORTS_WEAK 1をCPT_SDK_SUPPORTS_WEAK 0にすればとりあえずエラーはけせる。 #pre{{ #if TARGET_OS_IPHONE && defined(__IPHONE_5_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_5_0) && __clang__ && (__clang_major__ >= 3) #define CPT_SDK_SUPPORTS_WEAK 1 #elif TARGET_OS_MAC && defined(__MAC_10_7) && (MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7) && __clang__ && (__clang_major__ >= 3) #define CPT_SDK_SUPPORTS_WEAK 1 #else #define CPT_SDK_SUPPORTS_WEAK 0 #endif }} -CorePlot 1.1をPodfileで次のように利用すると発生する。 #pre{{ platform :ios, "5.0" pod 'CorePlot' }}