This probably has a really simple fix, but I have a UITableViewController that calls a UIViewController in a normal list/detail configuration.
Since I added 2 subviews to the detail viewcontroller the app has been crashing on the second time I display the detail view controller.
I do lots of setup etc. when the view is loaded, but I have gone through and I can't find anything that has been set to null etc. None of the initialising functions crash the app. It's only once they are done that the app falls over. I assume the detail view controller is going through the same initialization each time...
Has anyone encountered this before?
Here is where the detail view controller is called:
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
/***************************************************************************************
The detail view is just sent the tank object for the selected tank. The detail view
loads the labels and gauge with the appropriate information
***************************************************************************************/
self.detailViewController = [[tankDetailViewController alloc] init];
self.detailViewController = segue.destinationViewController;
[segue.destinationViewController setTankToShow:self.selectedTank];
}
and the following is the code for the detailviewcontroller:
#interface tankDetailViewController () <iTanksV2ListViewControllerDelegate>
//#property (nonatomic, strong) tankReleasedProductListTVCViewController* releasedProductList;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *tankGaugeHeightConstraint;
#property (weak, nonatomic) IBOutlet UIView *tankDetailView;
#property (weak, nonatomic) IBOutlet UIView *tankTrendView;
#property (nonatomic, strong) CPTGraphHostingView* hostView;
#property (strong, nonatomic) CPTGraph* graph;
#property BOOL isFirstValue;
#property double startValue;
#property double lastValue;
#end
#implementation tankDetailViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
/*************************************************************************************
All we need to do here, is to display all the information from the tank object in the
labels in the view.
The only thing of note is that we convert the volumes to doubles, and then use them to
calculate the percentFilled property of the tankGauge object.
************************************************************************************/
[super viewDidLoad];
self.isFirstValue = YES;
self.tankNumberLabel.text = [#"T" stringByAppendingString: self.tankToShow.tankNumber];
self.tankAvailableProductLabel.text = self.tankToShow.tankPumpableVolume;
self.tankProductLabel.text = self.tankToShow.tankProduct.name;
self.tankMaxVolumeLabel.text = self.tankToShow.tankMaxVolume;
self.tankGaugeHeightConstraint.constant = ([self.tankToShow.tankTotalVolume doubleValue]/[self.tankToShow.tankMaxVolume doubleValue]) * self.tankGaugeScaleView.frame.size.height;
self.tankTotalVolumeLabel.text = self.tankToShow.tankTotalVolume;
self.tankProductCode.text = self.tankToShow.tankProduct.code;
self.tankStatusLabel.text = self.tankToShow.tankStatus;
if([self.tankToShow.tankStatus isEqualToString:#"Process"])
{
[self.tankStatusLED setImage:[UIImage imageNamed:#"red_btn.png"] forState:UIControlStateNormal];
}
else if([self.tankToShow.tankStatus isEqualToString:#"Release"])
{
[self.tankStatusLED setImage:[UIImage imageNamed:#"green_btn.png"] forState:UIControlStateNormal];
}
else if([self.tankToShow.tankStatus isEqualToString:#"For Test"])
{
[self.tankStatusLED setImage:[UIImage imageNamed:#"amber_btn.png"] forState:UIControlStateNormal];
} else
{
[self.tankStatusLED setImage:[UIImage imageNamed:#"grey_btn.png"] forState:UIControlStateNormal];
}
[self.view bringSubviewToFront:self.tankDetailView];
self.graphData = [TrendData getTrendDataForTank];
[self initPlot];
}
- (void)viewWillAppear:(BOOL)animated
{
[self.view bringSubviewToFront:self.tankDetailView];
}
-(void) viewDidDisappear:(BOOL)animated
{
}
- (void) initPlot
{
[self configureHost];
[self configureGraph];
[self configurePlots];
[self configureAxes];
}
- (void) configureHost
{
self.hostView = [(CPTGraphHostingView*) [CPTGraphHostingView alloc] initWithFrame:self.tankTrendView.bounds];
self.hostView.allowPinchScaling = NO;
[self.tankTrendView addSubview:self.hostView];
}
- (void) configureGraph
{
self.graph = [[CPTXYGraph alloc] initWithFrame:self.hostView.bounds];
[self.graph applyTheme:[CPTTheme themeNamed:kCPTPlainWhiteTheme]];
self.hostView.hostedGraph = self.graph;
self.graph.title = [#"Trend Graph for " stringByAppendingString:self.tankNumberLabel.text];
CPTMutableTextStyle* titleStyle = [CPTMutableTextStyle textStyle];
titleStyle.color = [CPTColor blackColor];
titleStyle.fontName = #"Helvetica-Neue Light";
titleStyle.fontSize = 10.0f;
self.graph.titleTextStyle = titleStyle;
self.graph.titlePlotAreaFrameAnchor = CPTRectAnchorTop;
self.graph.titleDisplacement = CGPointMake(0.0f, 20.0f);
[self.graph.plotAreaFrame setPaddingLeft:50.0f];
[self.graph.plotAreaFrame setPaddingBottom:90.0f];
CPTXYPlotSpace* plotSpace = (CPTXYPlotSpace*) self.graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
self.graph.defaultPlotSpace.delegate = self;
self.graph.delegate = self;
}
- (void) configurePlots
{
CPTGraph* graph = self.hostView.hostedGraph;
CPTXYPlotSpace* plotSpace = (CPTXYPlotSpace*) graph.defaultPlotSpace;
CPTScatterPlot* aaplPlot = [[CPTScatterPlot alloc] init];
aaplPlot.dataSource = self;
CPTColor *aaplColor = [CPTColor redColor];
aaplPlot.delegate = self;
aaplPlot.plotLineMarginForHitDetection = 10;
aaplPlot.plotSymbolMarginForHitDetection = 10;
[graph addPlot:aaplPlot toPlotSpace:plotSpace];
[plotSpace scaleToFitPlots: [NSArray arrayWithObjects:aaplPlot, nil]];
CPTMutablePlotRange* xRange = [plotSpace.xRange mutableCopy];
[xRange expandRangeByFactor:CPTDecimalFromCGFloat(1.2f)];
plotSpace.xRange = xRange;
CPTMutablePlotRange* yRange = [plotSpace.yRange mutableCopy];
[xRange expandRangeByFactor:CPTDecimalFromCGFloat(1.2f)];
plotSpace.yRange = yRange;
CPTMutableLineStyle* aapleLineStyle = [aaplPlot.dataLineStyle mutableCopy];
aapleLineStyle.lineWidth = 2.5;
aapleLineStyle.lineColor = aaplColor;
aaplPlot.dataLineStyle = aapleLineStyle;
}
- (void) configureAxes
{
NSDate* refDate = [NSDate dateWithTimeIntervalSince1970:0];
CPTGraph* graph = self.hostView.hostedGraph;
CPTXYAxisSet* axes = (id)graph.axisSet;
CPTXYPlotSpace* plotSpace = (CPTXYPlotSpace*) self.graph.defaultPlotSpace;
axes.xAxis.minorTicksPerInterval = 0;
NSValue* firstValue = [self.graphData objectAtIndex:0];
NSValue* lastValue = [self.graphData objectAtIndex:self.graphData.count -1];
CGPoint firstPoint = [firstValue CGPointValue];
CGPoint lastPoint = [lastValue CGPointValue];
axes.yAxis.orthogonalCoordinateDecimal = CPTDecimalFromDouble(plotSpace.xRange.minLimitDouble);
axes.yAxis.majorIntervalLength = CPTDecimalFromDouble(plotSpace.yRange.lengthDouble/5);
axes.yAxis.minorTicksPerInterval = 0;
axes.xAxis.orthogonalCoordinateDecimal = CPTDecimalFromDouble(plotSpace.yRange.minLimitDouble);
axes.xAxis.majorIntervalLength = CPTDecimalFromDouble((lastPoint.x - firstPoint.x)/3);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.locale = [NSLocale currentLocale];
dateFormatter.dateFormat = #"dd/MM/yyyy HH:mm:ss";
CPTTimeFormatter *timeFormatter = [[CPTTimeFormatter alloc] initWithDateFormatter:dateFormatter];
timeFormatter.referenceDate = refDate;
axes.xAxis.labelFormatter = timeFormatter;
}
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (fromInterfaceOrientation==UIInterfaceOrientationPortrait || fromInterfaceOrientation==UIInterfaceOrientationPortraitUpsideDown)
{
self.hostView.frame = self.view.bounds;
[self.graph reloadData];
[self.view bringSubviewToFront:self.tankTrendView];
}
else
{
self.hostView.frame = self.view.bounds;
[self.graph reloadData];
[self.view bringSubviewToFront:self.tankDetailView];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)didPressTankStatusLED:(UIButton *)sender {
//if([self.tankToShow.tankStatus isEqualToString:#"Release"])
//{
/*self.releasedProductList = [[tankReleasedProductListTVCViewController alloc] initWithStyle:UITableViewStylePlain];
Product* releasedProduct = [[Product alloc] init];
releasedProduct.name = self.tankProductLabel.text;
releasedProduct.code = self.tankProductCode.text;
self.releasedProductList.productList = [NSArray arrayWithObjects:releasedProduct, nil];
FPPopoverController* popoverController = [[FPPopoverController alloc]initWithViewController:self.releasedProductList];
self.releasedProductList.delegate = self;
popoverController.contentSize = CGSizeMake(250, 85 * self.releasedProductList.productList.count);
[popoverController presentPopoverFromView:self.tankStatusLED];*/
//}
}
- (NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
return self.graphData.count;
}
- (id)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)idx
{
NSValue *value = [self.graphData objectAtIndex:idx];
CGPoint point = [value CGPointValue];
// FieldEnum determines if we return an X or Y value.
if ( fieldEnum == CPTScatterPlotFieldX )
{
return [NSNumber numberWithFloat:point.x];
}
else // Y-Axis
{
return [NSNumber numberWithFloat:point.y];
}
}
- (void)scatterPlot:(CPTScatterPlot *)plot plotSymbolWasSelectedAtRecordIndex:(NSUInteger)index
{
}
//This function is here to lock the graph and prevent it from being panned so I can use the the drag event for my own purposes
-(CGPoint)plotSpace:(CPTPlotSpace *)space willDisplaceBy:(CGPoint)displacement {
return CGPointMake(0, 0);
}
- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDownEvent:(UIEvent *)event atPoint:(CGPoint)point
{
return NO;
}
- (BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDraggedEvent:(UIEvent *)event atPoint:(CGPoint)point
{
CPTGraph* graph = self.hostView.hostedGraph;
CPTXYAxisSet* axes = (id)graph.axisSet;
double percentAcrossScreen = point.x/self.view.frame.size.width;
if (self.isFirstValue==YES)
{
self.startValue = percentAcrossScreen;
self.isFirstValue = NO;
}
else
{
self.lastValue = percentAcrossScreen;
}
NSValue *firstValue = [self.graphData objectAtIndex:[[NSNumber numberWithDouble:self.startValue * self.graphData.count] integerValue]];
CGPoint firstPoint = [firstValue CGPointValue];
NSValue *lastValue = [self.graphData objectAtIndex:[[NSNumber numberWithDouble:self.lastValue * self.graphData.count] integerValue]];
CGPoint lastPoint = [lastValue CGPointValue];
double difference = lastPoint.x - firstPoint.x;
CPTPlotRange *range = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(firstPoint.x)
length:CPTDecimalFromDouble(difference)];
CPTFill *bandFill = [CPTFill fillWithColor:[CPTColor blueColor]];
[axes.yAxis addBackgroundLimitBand:[CPTLimitBand limitBandWithRange:range
fill:bandFill]];
NSLog([[NSNumber numberWithDouble:firstPoint.x] stringValue]);
NSLog([[NSNumber numberWithDouble:lastPoint.x] stringValue]);
return YES;
}
Related
The h file for the relevant view controller
#import <UIKit/UIKit.h>
#import "StudentModel.h"
#import "CorePlot-CocoaTouch.h"
#interface AttendenceViewController : UIViewController <UITabBarDelegate,UITableViewDataSource,CPTLegendDelegate,CPTPieChartDataSource,CPTPieChartDelegate>
#property (strong,nonatomic) StudentModel *studentA;
#property (strong,nonatomic) NSDictionary *studentAttendanceDetails;
#property (weak, nonatomic) IBOutlet UIView *graphContainer;
The m file for the relevant view controller
#import "AttendenceViewController.h"
#interface AttendenceViewController ()
#property (nonatomic,strong) CPTGraphHostingView *hostView;
#property (nonatomic,strong) CPTTheme *selectedTheme;
-(void)initPlot;
-(void)configureHost;
-(void)configureGraph;
-(void)configureChart;
-(void)configureLegend;
#end
#implementation AttendenceViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// float attendanceTotal = [self.studentA.percentageAttendance floatValue];
// float authorisedAbsences = [self.studentA.authorisedAbsences floatValue];
// float unathorisedAbsences = [self.studentA.unautherisedAbsences floatValue];
self.studentAttendanceDetails = [NSDictionary dictionaryWithObjectsAndKeys:self.studentA.percentageAttendance,#"totalAttendance",self.studentA.authorisedAbsences,#"authorisedAbsences",self.studentA.unautherisedAbsences,#"unauthorisedAbsences", nil];
NSLog(#"%#",self.studentAttendanceDetails);
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self initPlot];
}
#pragma mark Core Plot Initialisation Methods
-(void)initPlot
{
[self configureHost];
[self configureGraph];
[self configureChart];
[self configureLegend];
}
-(void)configureHost;
{
CGRect parentRect = self.graphContainer.bounds;
self.hostView = [(CPTGraphHostingView*)[CPTGraphHostingView alloc]initWithFrame:parentRect];
self.hostView.allowPinchScaling=NO;
[self.graphContainer addSubview:self.hostView];
}
-(void)configureGraph;
{
//create and initialise the graph
CPTGraph *graph = [[CPTXYGraph alloc]initWithFrame:self.hostView.bounds];
self.hostView.hostedGraph=graph;
graph.paddingLeft=0.0f;
graph.paddingTop=0.0f;
graph.paddingRight=0.0f;
graph.paddingBottom=0.0f;
graph.axisSet=nil;
//set up the text styles
CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
textStyle.color= [CPTColor grayColor];
textStyle.fontName =#"Helvetica-Bold";
textStyle.fontSize=16.0f;
//configure the title
NSString *title = #"Student Attendance";
graph.title=title;
graph.titleTextStyle=textStyle;
graph.titlePlotAreaFrameAnchor= CPTRectAnchorTop;
graph.titleDisplacement= CGPointMake(0.0f, -12.0f);
self.selectedTheme = [CPTTheme themeNamed:kCPTPlainWhiteTheme];
[graph applyTheme:self.selectedTheme];
}
-(void)configureChart;
{
//get reference to graph
CPTGraph *graph = self.hostView.hostedGraph;
//create chart
CPTPieChart *pieChart = [[CPTPieChart alloc]init];
pieChart.delegate=self;
pieChart.dataSource=self;
pieChart.pieRadius=(self.hostView.bounds.size.height*0.9)/3;
pieChart.identifier= graph.title;
pieChart.startAngle = M_PI_4;
pieChart.sliceDirection=CPTPieDirectionClockwise;
//gradient
CPTGradient *overlayGradient = [[CPTGradient alloc]init];
overlayGradient.gradientType=CPTGradientTypeRadial;
overlayGradient=[overlayGradient addColorStop:[[CPTColor blackColor]colorWithAlphaComponent:0.0] atPosition:0.9];
overlayGradient=[overlayGradient addColorStop:[[CPTColor blackColor]colorWithAlphaComponent:0.4] atPosition:1.0];
pieChart.overlayFill = [CPTFill fillWithGradient:overlayGradient];
[graph addPlot:pieChart];
}
-(void)configureLegend;
{
}
#pragma mark Core Plot Datasource Methods
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
return [self.studentAttendanceDetails count];
}
-(NSNumber*)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)idx
{
if (CPTPieChartFieldSliceWidth == fieldEnum)
{
NSArray *values = [self.studentAttendanceDetails allValues];
return [values objectAtIndex:idx];
}
return [NSDecimalNumber zero];
}
-(CPTLayer*)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)idx
{
static CPTMutableTextStyle *labelText = nil;
if (!labelText) {
labelText= [[CPTMutableTextStyle alloc] init];
labelText.color = [CPTColor grayColor];
}
NSString *labelValue = nil;
switch (idx) {
case 0:{
NSString *unauthorised= [self.studentAttendanceDetails objectForKey:#"unauthorisedAbsences"];
NSLog(#"%#",unauthorised);
if ([unauthorised isEqualToString:#"0.00"]) {
labelText=nil;
}
labelValue = [NSString stringWithFormat:#"%#",[self.studentAttendanceDetails objectForKey:#"unauthorisedAbsences"]];
}
break;
case 1:
labelValue = [NSString stringWithFormat:#"%#",[self.studentAttendanceDetails objectForKey:#"totalAttendance"]];
break;
case 2:
labelValue = [NSString stringWithFormat:#"%#",[self.studentAttendanceDetails objectForKey:#"authorisedAbsences"]];
break;
}
return [[CPTTextLayer alloc] initWithText:labelValue style:labelText];
}
-(NSString*)legendTitleForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)idx
{
return #"Student Attendance";
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
Image of result when simulator is set to iPhone 5 and run (i.e. 32 bit)
Image of result when simulator is set to iPhone 5s or later (i.e 64bit)
The problem is how to I adjust the code in the implementation file for the view controller to ensure the output is the same for 32 bit and 64 bit runs?
Dictionaries don't have a defined ordering. The allValues array is probably different on each platform. For this application, you don't need to stash the values in a dictionary at all. Just return authorisedAbsences or unautherisedAbsences from the datasource based on the index.
I would like to be able to add a legend to a graph slice. How can I do this?
I tried to implement the following two methods but I don't think is right;
- (NSString *) legendTitleForPieChart:(CPTPieChart *)pieChart
recordIndex:(NSUInteger)idx{
return #"Legend";
}
- (NSAttributedString *) attributedLegendTitleForPieChart: (CPTPieChart *) pieChart
recordIndex: (NSUInteger) idxv{
return [[NSAttributedString alloc] initWithString:#"Attributed"];
}
Here is the official CorePlot protocol documentation:
https://core-plot.googlecode.com/hg/documentation/html/iOS/protocol_c_p_t_pie_chart_data_source-p.html#a6a85e1a9e613eb65267abfb8a884434a
EDIT: my code
// .h
#interface MyViewController : UIViewController<CPTPlotSpaceDelegate,CPTPieChartDelegate,CPTLegendDelegate,CPTPlotDataSource>
- (void) initializeAll;
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil data:(NSMutableArray*)dataPoints;
// .m
#import “MyViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet CPTGraphHostingView * pieChartgraphHostView;
#property (strong, nonatomic) CPTGraph* pieChartGraph;
#property (strong, nonatomic) CPTPieChart* pieChart;
#end
#implementation MyViewController
#synthesize data;
#synthesize pieChart, pieChartGraph;
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil data:(NSMutableArray*)dataPoints{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.data = dataPoints;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self initializeGraph];
[self updateViewData];
[self configureChart];
}
- (void) initializeGraph{
if (self.data == nil) {
NSLog(#"Error, should not use this without assigning data");
}
// Create a CPTGraph object and add to hostView
self.graph = [[CPTXYGraph alloc] initWithFrame:self.graphHostView.bounds];
self.graphHostView.hostedGraph = self.graph;
////////////////////
CPTMutableTextStyle *titleStyle = [CPTMutableTextStyle textStyle];
titleStyle.color = [CPTColor blackColor];
titleStyle.fontName = #"Helvetica";
titleStyle.fontSize = 12.0f;
// Axes
// Label x axis with a fixed interval policy
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
x.separateLayers = NO;
x.title = #"X Axis";
x.titleTextStyle = titleStyle;
x.delegate = self;
CPTXYAxis *y = axisSet.yAxis;
y.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
y.separateLayers = YES;
y.majorTickLocations = [NSSet setWithObjects:
[NSDecimalNumber numberWithDouble:0],
[NSDecimalNumber numberWithDouble:300],
nil];
y.title = #"Y Axis";
y.titleTextStyle = titleStyle;
y.delegate = self;
CPTFill *whitebandFill = [CPTFill fillWithColor:[[CPTColor whiteColor] colorWithAlphaComponent:0.5]];
CPTFill *greenbandFill = [CPTFill fillWithColor:[[CPTColor greenColor] colorWithAlphaComponent:0.5]];
CPTFill *redbandFill = [CPTFill fillWithColor:[[CPTColor redColor] colorWithAlphaComponent:0.75]];
[y addBackgroundLimitBand:[CPTLimitBand limitBandWithRange:[CPTPlotRange plotRangeWithLocationDecimal:CPTDecimalFromDouble(0.0) lengthDecimal:CPTDecimalFromDouble(500.0)] fill:whitebandFill]];
[y addBackgroundLimitBand:[CPTLimitBand limitBandWithRange:[CPTPlotRange plotRangeWithLocationDecimal:CPTDecimalFromDouble(500.0) lengthDecimal:CPTDecimalFromDouble(750.0)] fill:greenbandFill]];
[y addBackgroundLimitBand:[CPTLimitBand limitBandWithRange:[CPTPlotRange plotRangeWithLocationDecimal:CPTDecimalFromDouble(750.0) lengthDecimal:CPTDecimalFromDouble(1024.0)] fill:redbandFill]];
// Add the y2 axis to the axis set
self.graph.axisSet.axes = #[x, y];
/////////////////////
// Get the (default) plotspace from the graph so we can set its x/y ranges
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) self.graph.defaultPlotSpace;
// Note that these CPTPlotRange are defined by START and LENGTH (not START and END) !!
[plotSpace setYRange: [CPTPlotRange plotRangeWithLocation:[NSNumber numberWithInt:0] length:[NSNumber numberWithInt:1024]]];
NSLog(#"creating x range for %lu data points", (unsigned long)[self.data count]);
[plotSpace setXRange: [CPTPlotRange plotRangeWithLocation:[NSNumber numberWithInt:0] length:[NSNumber numberWithInt:[self.data count]]]];
// Create the plot (we do not define actual x/y values yet, these will be supplied by the datasource...)
self.plot = [[CPTScatterPlot alloc] initWithFrame:CGRectZero];
// Let's keep it simple and let this class act as datasource (therefore we implemtn <CPTPlotDataSource>)
self.plot.dataSource = self;
self.plot.delegate = self;
// Finally, add the created plot to the default plot space of the CPTGraph object we created before
[self.graph addPlot:self.plot toPlotSpace:self.graph.defaultPlotSpace];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)configureChart {
// 1 - Get reference to graph
pieChartGraph = [[CPTXYGraph alloc] initWithFrame:self.pieChartgraphHostView.bounds];
self.pieChartgraphHostView.hostedGraph = pieChartGraph;
pieChartGraph.plotAreaFrame.masksToBorder = NO;
pieChartGraph.axisSet = nil;
pieChart.title = #"My pie chart";
// 2 - Create chart
pieChart = [[CPTPieChart alloc] init];
pieChart.dataSource = self;
pieChart.delegate = self;
pieChart.pieRadius = (self.pieChartgraphHostView.bounds.size.height * 0.9) / 2;
pieChartGraph.delegate = self;
pieChart.identifier = pieChartGraph.title;
pieChart.startAngle = CPTFloat(M_PI_4);
pieChart.sliceDirection = CPTPieDirectionClockwise;
pieChart.borderLineStyle = [CPTLineStyle lineStyle];
// 3 - Create gradient
CPTGradient *overlayGradient = [[CPTGradient alloc] init];
overlayGradient.gradientType = CPTGradientTypeRadial;
overlayGradient = [overlayGradient addColorStop:[[CPTColor blackColor] colorWithAlphaComponent:0.0] atPosition:0.9];
overlayGradient = [overlayGradient addColorStop:[[CPTColor blackColor] colorWithAlphaComponent:0.4] atPosition:1.0];
pieChart.overlayFill = [CPTFill fillWithGradient:overlayGradient];
// 4 - Add chart to graph
pieChart.pieRadius = pieChart.pieRadius / 2.3;
[pieChartGraph addPlot:pieChart];
self.dataForChart = [#[#20.0, #30.0, #25.0, #25.0] mutableCopy];
}
-(void)setRoundedView:(UIView *)roundedView toDiameter:(float)newSize;
{
CGPoint saveCenter = roundedView.center;
CGRect newFrame = CGRectMake(roundedView.frame.origin.x, roundedView.frame.origin.y, newSize, newSize);
roundedView.frame = newFrame;
roundedView.layer.cornerRadius = newSize / 2.0;
roundedView.center = saveCenter;
}
-(void)configureLegend {
// 1 - Get graph instance
CPTGraph *graph = self.graphHostView.hostedGraph;
// 2 - Create legend
CPTLegend *theLegend = [CPTLegend legendWithGraph:graph];
// 3 - Configure legen
theLegend.numberOfColumns = 1;
theLegend.fill = [CPTFill fillWithColor:[CPTColor whiteColor]];
theLegend.borderLineStyle = [CPTLineStyle lineStyle];
theLegend.cornerRadius = 5.0;
// 4 - Add legend to graph
graph.legend = theLegend;
graph.legendAnchor = CPTRectAnchorRight;
CGFloat legendPadding = -(self.view.bounds.size.width / 8);
graph.legendDisplacement = CGPointMake(legendPadding, 0.0);
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#pragma mark -
#pragma mark Plot Data Source Methods
- (NSString *) legendTitleForPieChart:(CPTPieChart *)pieChart
recordIndex:(NSUInteger)idx{
return #"Legend";
}
/**
- (NSAttributedString *) attributedLegendTitleForPieChart: (CPTPieChart *) pieChart
recordIndex: (NSUInteger) idxv{
return [[NSAttributedString alloc] initWithString:#"Attributed"];
}**/
-(NSAttributedString *)attributedLegendTitleForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
UIColor *sliceColor = [CPTPieChart defaultPieSliceColorForIndex:index].uiColor;
UIFont *labelFont = [UIFont fontWithName:#"Helvetica" size:12.0 * CPTFloat(0.5)];
#else
NSColor *sliceColor = [CPTPieChart defaultPieSliceColorForIndex:index].nsColor;
NSFont *labelFont = [NSFont fontWithName:#"Helvetica" size:12.0 * CPTFloat(0.5)];
#endif
NSMutableAttributedString *title = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:#"Pie Slice %lu", (unsigned long)index]];
[title addAttribute:NSForegroundColorAttributeName
value:sliceColor
range:NSMakeRange(4, 5)];
[title addAttribute:NSFontAttributeName
value:labelFont
range:NSMakeRange(0, title.length)];
return title;
}
#end
Title, legend and labels won't show.
You only need one of those methods. Use the attributed title if you need styled text like in the example image, otherwise either method will work. These methods should be implemented in the plot's datasource.
I am trying to follow the tutorial at http://www.raywenderlich.com/13269/how-to-draw-graphs-with-core-plot-part-1
I am working on ios 7 and latest core chart library (1.3)
I am trying to draw a pie chart. My example compiles fine, I get the title header but I do not get any pie chart drawn. What I see is shown below:
My main source code that contains the logic is given below. Kindly help
//
// CPDFirstViewController.m
// CorePlotDemo
//
// Created by R Menon on 9/19/13.
// Copyright (c) 2013 4stepfinance Inc. All rights reserved.
//
#import "CPDPieChartViewController.h"
#interface CPDPieChartViewController ()
#property (weak, nonatomic) IBOutlet UIToolbar *toolbar;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *themeButton;
#property (strong, nonatomic) CPTGraphHostingView *hostView;
#property (strong, nonatomic) CPTTheme *selectedTheme;
- (void)initPlot;
-(void)configureHost;
-(void)configureGraph;
-(void)configureChart;
-(void)configureLegend;
#end
#implementation CPDPieChartViewController
#pragma mark - Chart behavior
- (void)initPlot {
[self configureHost];
[self configureChart];
[self configureGraph];
[self configureLegend];
}
-(void)configureHost {
// Set up view frame
CGRect parentRect = self.view.bounds;
CGSize toolbarSize = self.toolbar.bounds.size;
parentRect = CGRectMake(parentRect.origin.x, (parentRect.origin.y + toolbarSize.height), parentRect.size.width, (parentRect.size.height - toolbarSize.height));
// Create host view
self.hostView = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:parentRect];
self.hostView.allowPinchScaling = NO;
[self.view addSubview:self.hostView];
}
-(void)configureGraph {
//Create and initialize graph
CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:self.hostView.bounds];
self.hostView.hostedGraph = graph;
graph.paddingLeft = 0.0f;
graph.paddingTop = 0.0f;
graph.paddingRight = 0.0f;
graph.paddingBottom = 0.0f;
graph.axisSet = nil;
// Set up text stile
CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
textStyle.color = [CPTColor grayColor];
textStyle.fontName = #"Helvetica-Bold";
textStyle.fontSize = 16.0f;
// Configure title
NSString *title = #"Portfolio Prices: May 1, 2012";
graph.title = title;
graph.titleTextStyle = textStyle;
graph.titlePlotAreaFrameAnchor = CPTRectAnchorTop;
graph.titleDisplacement = CGPointMake(0.0f, -12.0f);
// Set theme
self.selectedTheme = [CPTTheme themeNamed:kCPTPlainWhiteTheme];
[graph applyTheme:self.selectedTheme];
}
-(void)configureChart {
// 1 - Get reference to graph
CPTGraph *graph = self.hostView.hostedGraph;
// 2 - Create chart
CPTPieChart *pieChart = [[CPTPieChart alloc] init];
pieChart.dataSource = self;
pieChart.delegate = self;
pieChart.pieRadius = (self.hostView.bounds.size.height * 0.7) / 2;
pieChart.identifier = graph.title;
pieChart.startAngle = M_PI_4;
pieChart.sliceDirection = CPTPieDirectionClockwise;
// 3 - Create gradient
CPTGradient *overlayGradient = [[CPTGradient alloc] init];
overlayGradient.gradientType = CPTGradientTypeRadial;
overlayGradient = [overlayGradient addColorStop:[[CPTColor blackColor] colorWithAlphaComponent:0.0] atPosition:0.9];
overlayGradient = [overlayGradient addColorStop:[[CPTColor blackColor] colorWithAlphaComponent:0.4] atPosition:1.0];
pieChart.overlayFill = [CPTFill fillWithGradient:overlayGradient];
// 4 - Add chart to graph
[graph addPlot:pieChart];
}
-(void)configureLegend {
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:YES];
[self initPlot];
}
- (IBAction)themeTapped:(id)sender {
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - CPTPlotDataSource methods
- (NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
return [[[CPDStockPriceStore sharedInstance] tickerSymbols] count];
}
- (NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)idx
{
if (CPTPieChartFieldSliceWidth == fieldEnum)
{
return [[[CPDStockPriceStore sharedInstance] dailyPortfolioPrices] objectAtIndex:idx];
}
return [NSDecimalNumber zero];
}
- (CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)idx {
static CPTMutableTextStyle *labelText = nil;
if (!labelText) {
labelText= [[CPTMutableTextStyle alloc] init];
labelText.color = [CPTColor grayColor];
}
// 2 - Calculate portfolio total value
NSDecimalNumber *portfolioSum = [NSDecimalNumber zero];
for (NSDecimalNumber *price in [[CPDStockPriceStore sharedInstance] dailyPortfolioPrices]) {
portfolioSum = [portfolioSum decimalNumberByAdding:price];
}
// 3 - Calculate percentage value
NSDecimalNumber *price = [[[CPDStockPriceStore sharedInstance] dailyPortfolioPrices] objectAtIndex:idx];
NSDecimalNumber *percent = [price decimalNumberByDividingBy:portfolioSum];
// 4 - Set up display label
NSString *labelValue = [NSString stringWithFormat:#"$%0.2f USD (%0.1f %%)", [price floatValue], ([percent floatValue] * 100.0f)];
// 5 - Create and return layer with label text
return [[CPTTextLayer alloc] initWithText:labelValue style:labelText];
}
-(NSString *)legendTitleForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index {
return #"";
}
#pragma mark - UIActionSheetDelegate methods
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
}
#end
Never mind. I had a typo:
Following method definition
- (void)initPlot {
[self configureHost];
[self configureChart];
[self configureGraph];
[self configureLegend];
}
should change to
- (void)initPlot {
[self configureHost];
[self configureGraph];
[self configureChart];
[self configureLegend];
}
In other words, I should invoke configureGraph before configureChart method.
I'm new in IOS developpement and I have a problem drawing the legend of a pieChart with Core-Plot.The pie chart is well displayed but it doesn't display its legend. I've already read a lot about this issue (StackOverFlowResponseTopic) but I can't find why it doesn't work with me.
I've created a PieChartView that I initialse in my second ViewController of a tabBar application.
This is the code of my pie chart view:
//
// PieChartView.m
// ExerciceRecap
//
// Created by Alex on 02/03/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "PieChartView.h"
#import "ModeleDeDonnes.h"
#import "CorePlot-CocoaTouch.h"
#implementation PieChartView
#synthesize graph=_graph;
#synthesize hostingView = _hostingView;
#synthesize graphData = _graphData;
#synthesize myLabels = _myLabels;
- (id) initWithHostingView:(CPTGraphHostingView *)hostingView andData:(NSMutableArray *)data{
self = [super init];
if (self != nil){
self.hostingView = hostingView;
self.graph = nil;
// Manage data from dataController
_myLabels = [[[NSMutableArray alloc]init]autorelease];
NSMutableArray *myValues = [[[NSMutableArray alloc]init]autorelease];
for (NSUInteger i = 0; i < [data count]; i++) {
ModeleDeDonnes *theObject = [data objectAtIndex:i];
[_myLabels addObject:theObject.nom];
[myValues addObject:theObject.montant];
}
self.graphData = myValues;
}
return self;
}
-(void)initialisePieChart{
if ([_graphData count] == 0 ){
NSLog(#"No data");
return;
}
if((self.hostingView == nil) || (self.graphData == nil)){
NSLog(#" Cannot initialse hostingView");
return;
}
if (self.graph != nil){
NSLog(#" graph already exists");
return;
}
CGRect frame = [self.hostingView bounds];
self.graph = [[[CPTXYGraph alloc] initWithFrame:frame] autorelease];
//Tie the graph we have created with the hosting view
self.hostingView.hostedGraph = self.graph;
CPTPieChart * pieChart = [[[CPTPieChart alloc]init]autorelease];
pieChart.dataSource = self;
pieChart.pieRadius = 100.0;
pieChart.identifier = #"pieChart1";
pieChart.startAngle = M_PI_2;
pieChart.sliceDirection = CPTPieDirectionCounterClockwise;
_graph.title=#"My PieChart";
// Add legend
CPTLegend *theLegend = [CPTLegend legendWithGraph:_graph];
theLegend.numberOfColumns = 2;
theLegend.fill = [CPTFill fillWithColor:[CPTColor redColor]];
//theLegend.borderLineStyle = [CPTLineStyle lineStyle];
theLegend.cornerRadius = 5.0;
_graph.legend = theLegend;
_graph.legendAnchor = CPTRectAnchorBottom;
_graph.legendDisplacement = CGPointMake(0.0, 30.0);
[self.graph addPlot:pieChart];
}
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot{
return [self.graphData count];
}
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index{
return [self.graphData objectAtIndex:index];
}
-(NSString *)legendTitleForPieChart:(CPTPieChart *)pieChart
recordIndex:(NSUInteger)index{
NSLog(#"LegendTitleForPieChart");
return [NSString stringWithFormat:#"Ma légende", index];
}
#end
And this is the code of the viewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.pieChart =[[PieChartView alloc] initWithHostingView:_myGraphView andData:_dataController.masterDataList];
[self.pieChart initialisePieChart];
}
Thanks a lot and sry for my bad english.
if you can't get CorePlot to do what you want it to, there are several alternatives you might consider:
What are the alternatives to Core-Plot for drawing graphs in iPhone SDK
I'd recommend ShinobiCharts personally, but admittedly I am biased!
Hope this helps :)
Try to reload data of the hosting view in the viewWillAppear method of your viewController:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.pieChart =[[PieChartView alloc] initWithHostingView:_myGraphView andData:_dataController.masterDataList];
[self.pieChart initialisePieChart];
[self.pieChart.hostingView reloadData];
}
I have a problem with my code, core plot gives a SIGBRT.
can someone help me ?
Thanks..
header:
#interface CorePLotTestAppDelegate : NSObject <CPPlotDataSource>
{
IBOutlet CPLayerHostingView *view;
CPXYGraph *graph;
NSMutableArray *xvalues;
NSMutableArray *yvalues;
}
-(void)clear;
-(void)addPointFloat:(float)x y:(float)y;
-(void)addPointNumber:(NSNumber*)x y:(NSNumber*)y;
// CPPlotDataSource protocol:
-(NSUInteger)numberOfRecordsForPlot:(CPPlot*)plot;
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum
recordIndex:(NSUInteger)index;
main:
#implementation CorePLotTestAppDelegate
-(id)init
{
if ([super init]) {
xvalues = [[NSMutableArray alloc] init];
yvalues = [[NSMutableArray alloc] init];
}
return self;
}
-(void)dealloc
{
[xvalues release];
[yvalues release];
[graph release];
[super dealloc];
}
-(void)clear
{
[xvalues removeAllObjects];
[yvalues removeAllObjects];
}
-(void)addPointFloat:(float)x y:(float)y
{
[xvalues addObject:[NSNumber numberWithFloat:x]];
[yvalues addObject:[NSNumber numberWithFloat:y]];
}
-(void)addPointNumber:(NSNumber*)x y:(NSNumber*)y
{
[xvalues addObject:x];
[yvalues addObject:y];
}
-(NSUInteger)numberOfRecordsForPlot:(CPPlot*)plot
{
return [xvalues count];
}
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum
recordIndex:(NSUInteger)index
{
if (fieldEnum == CPScatterPlotFieldX)
return [xvalues objectAtIndex:index];
else
return [yvalues objectAtIndex:index];
}
- (void) awakeFromNib
{
//Daten YAchse
NSString *filePath = #"pegel";//file path...
NSString *fileRoot = [[NSBundle mainBundle] pathForResource:filePath ofType:#"txt"];
// read everything from text
NSString *fileContents = [NSString stringWithContentsOfFile:fileRoot encoding:NSUTF8StringEncoding error:nil];
// first, separate by new line
NSArray *allLinedStrings = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
// then break down even further
NSString *strsInOneLine;
int d;
for (d=0; d < [allLinedStrings count]; d=d+1) {
strsInOneLine = [allLinedStrings objectAtIndex:d];
// choose whatever input identity you have decided. in this case ;
NSArray *workingArray = [strsInOneLine componentsSeparatedByString:#";"];
NSMutableArray *pegel = [workingArray lastObject];
yvalues = pegel;
xvalues = pegel;
NSLog(#"%#", pegel);
}
// Create graph and set a theme
graph = [[CPXYGraph alloc] initWithFrame:CGRectZero];
CPTheme *theme = [CPTheme themeNamed:kCPDarkGradientTheme];
[graph applyTheme:theme];
view.hostedLayer = graph;
// Setup plot space
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-3) length:CPDecimalFromFloat(20.0)];
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-3.5) length:CPDecimalFromFloat(10.0)];
// ScatterPlot
CPScatterPlot *linePlot = [[[CPScatterPlot alloc] init] autorelease];
linePlot.identifier = #"LinienDiagramm";
linePlot.dataLineStyle.lineWidth = 3.f;
linePlot.dataLineStyle.lineColor = [CPColor blueColor];
linePlot.dataSource = self;
[graph addPlot: linePlot];
// linien effekt
CPGradient *areaGradient =
[CPGradient gradientWithBeginningColor:[CPColor blueColor]
endingColor:[CPColor blackColor]];
areaGradient.angle = -90.0f;
linePlot.areaFill = [CPFill fillWithGradient:areaGradient];
linePlot.areaBaseValue = CPDecimalFromString(#"0");
// X und Y achse einstellungen
CPXYAxisSet *axisSet = (CPXYAxisSet *)graph.axisSet;
CPXYAxis *x = axisSet.xAxis;
CPXYAxis *y = axisSet.yAxis;
// x-achse
x.minorTicksPerInterval = 5;
x.minorTickLength = 2.0f;
x.majorTickLength = 7.0f;
x.labelOffset = 2.0f;
x.labelRotation = 45;
x.majorIntervalLength = CPDecimalFromFloat(5.0f);
// y-achse
y.minorTicksPerInterval = 5;
y.minorTickLength = 2.0f;
y.majorTickLength = 7.0f;
y.labelOffset = 5.0f;
y.majorIntervalLength = CPDecimalFromFloat(5.0f);
NSLog(#"%#", graph);
}
In -awakeFromNib, you're setting xvalues and yvalues to the object retrieved from workingArray. You're leaking the original value arrays, you're setting both xvalues and yvalues to the same object, and--just guessing without seeing the actual error message--the new object is not an array.