1

Currently, I am using Coreplot's graphical framework to implement bar graphs.

I pulled the tutorial projects from http://www.raywenderlich.com/13271/how-to-draw-graphs-with-core-plot-part-2 .

I changed the tutorial slightly to pull web service data rather than static data.

Now when I load the view into a view controller, everything good - the BAR graph displays perfectly and everything.

Also I took the scatter plot graph in the example, did the same with the data - pulled web services data, and displayed the graph in its own view controller.

Now, I wanted to add both the scatter plot and bar graph to a subview of a view controller.

Understand both are able to be viewed within a viewcontroller whose subclass is a UINavigationController (hopefully my terminology is correct :/).

Anyways, I am able to display the SCATTER PLOT graph in a subview.... no problem....

But the most frustrating part is whenever I do the same for the Bar Graph... BOOM CRASH CRASH CRASH!!!!

And it crashes on the line where I add a bar plot to the bar graph's view...

        [graph addPlot:plot toPlotSpace:graph.defaultPlotSpace];

Without this line... the app runs but no bars are visible....

Now I don't add the graph to my subview and go to the view controller where it displays the graph, NO CRASH.... but at the point of me adding the BAR GRAPH to a subview of a uiviewcontroller where more content lies.... CRASH CRASH CRASH...

What is making me so frustrated is everything is good with the scatter plot graph..... NOT the bar graph plot....

I will provide more information if needed.... I would just like to know HOW to add a bar graph to a uiview

This is what I do....

UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 140, 320, 150)];
view.backgroundColor = [UIColor clearColor];
[scroller addSubview:view];

_0DGraphViewController *BarGraphView = [[_0DGraphViewController alloc] init];
BarGraphView.hostView.frame = CGRectMake(view.bounds.origin.x, view.bounds.origin.y, view.bounds.size.width , view.bounds.size.height);
[view addSubview:BarGraph.view];

And heres my bar graph class

#import "30DGraphViewController.h"
#define graphData30DRequest [NSURL URLWithString:url]

@implementation _0DGraphViewController

@synthesize hostView = hostView_;

@synthesize priceAnnotation = priceAnnotation_;

CGFloat const _0DBarWidth = 0.25f;
CGFloat const _0DBarInitialX = 0.25f;

-(void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - UIViewController lifecycle methods
//-(void)viewDidAppear:(BOOL)animated {

//    [super viewDidAppear:animated];

//}

- (void)viewDidLoad
{

    //[super viewDidLoad];

    graphData = [[PullEasyViewData alloc] init];



    SWRevealViewController *revealController = [self revealViewController];

    [self.navigationController.navigationBar addGestureRecognizer:revealController.panGestureRecognizer];

    UIBarButtonItem *revealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"reveal-icon.png"]
                                                                         style:UIBarButtonItemStyleBordered target:revealController action:@selector(revealToggle:)];

    self.navigationItem.leftBarButtonItem = revealButtonItem;

    UIBarButtonItem *rightRevealButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"reveal-icon.png"]
                                                                              style:UIBarButtonItemStyleBordered target:revealController action:@selector(rightRevealToggle:)];

    self.navigationItem.rightBarButtonItem = rightRevealButtonItem;


    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *startDate = @"20130514";
        NSString *endDate = @"20130613";

        NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
        [graphData performSelectorOnMainThread:@selector(fetchGraphDataRequestData30D:) withObject:data waitUntilDone:YES];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self initPlot];
        });

    });
}

#pragma mark - Rotation
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

#pragma mark - Chart behavior
-(void)initPlot {
    self.hostView.allowPinchScaling = NO;
    [self configureHost];
    [self configureGraph];
    [self configurePlots];
    [self configureAxes];
}

-(void)configureHost {
    //self.hostView = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:self.view.bounds];
    self.hostView = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:CGRectMake(0, 0, 320, 170)];

    self.hostView.allowPinchScaling = YES;
    [self.view addSubview:self.hostView];
}

-(void)configureGraph {
    // 1 - Create the graph
    CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:self.hostView.bounds];
    graph.plotAreaFrame.masksToBorder = NO;
    self.hostView.hostedGraph = graph;

    // 2 - Configure the graph
    [graph applyTheme:[CPTTheme themeNamed:kCPTPlainBlackTheme]];
    graph.paddingBottom = 30.0f;
    graph.paddingLeft  = 30.0f;
    graph.paddingTop    = -1.0f;
    graph.paddingRight  = -5.0f;

    // 3 - Set up styles
    CPTMutableTextStyle *titleStyle = [CPTMutableTextStyle textStyle];
    titleStyle.color = [CPTColor whiteColor];
    titleStyle.fontName = @"Helvetica-Bold";
    titleStyle.fontSize = 16.0f;

    // 4 - Set up title
    NSString *title = @"Portfolio Prices: April 23 - 27, 2012";
    graph.title = title;
    graph.titleTextStyle = titleStyle;
    graph.titlePlotAreaFrameAnchor = CPTRectAnchorTop;
    graph.titleDisplacement = CGPointMake(0.0f, -16.0f);

    // 5 - Set up plot space
    CGFloat xMin = 0.0f;
    CGFloat xMax = [[graphData getGraphDates30D] count];//[[[CPDStockPriceStore sharedInstance] datesInWeek] count];
    CGFloat yMin = 0.0f;
    CGFloat yMax = 20.0f;  // should determine dynamically based on max price
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(xMin) length:CPTDecimalFromFloat(xMax)];
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(yMin) length:CPTDecimalFromFloat(yMax)];
}

-(void)configurePlots {

    // 1 - Set up the three plots
    CPTBarPlot *aaplPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor redColor] horizontalBars:NO];
    aaplPlot.identifier = CPDTickerSymbolAAPL;
    //CPTBarPlot *googPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor greenColor] horizontalBars:NO];
    //googPlot.identifier = CPDTickerSymbolGOOG;
    //CPTBarPlot *msftPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor blueColor] horizontalBars:NO];
    //msftPlot.identifier = CPDTickerSymbolMSFT;

    // 2 - Set up line style
    CPTMutableLineStyle *barLineStyle = [[CPTMutableLineStyle alloc] init];
    barLineStyle.lineColor = [CPTColor lightGrayColor];
    barLineStyle.lineWidth = 0.5;

    // 3 - Add plots to graph
    CPTGraph *graph = self.hostView.hostedGraph;
    CGFloat barX = _0DBarInitialX;
    //NSArray *plots = [NSArray arrayWithObjects:aaplPlot, googPlot, msftPlot, nil];
    NSArray *plots = [NSArray arrayWithObjects:aaplPlot, nil];
    for (CPTBarPlot *plot in plots) {
        plot.dataSource = self;
        plot.delegate = self;
        plot.barWidth = CPTDecimalFromDouble(_0DBarWidth);
        plot.barOffset = CPTDecimalFromDouble(barX);
        plot.lineStyle = barLineStyle;
        [graph addPlot:plot toPlotSpace:graph.defaultPlotSpace];
        barX += _0DBarWidth;
    }
}

-(void)configureAxes {

    // 1 - Configure styles
    CPTMutableTextStyle *axisTitleStyle = [CPTMutableTextStyle textStyle];
    axisTitleStyle.color = [CPTColor whiteColor];
    axisTitleStyle.fontName = @"Helvetica-Bold";
    axisTitleStyle.fontSize = 12.0f;
    CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
    axisLineStyle.lineWidth = 2.0f;
    axisLineStyle.lineColor = [[CPTColor whiteColor] colorWithAlphaComponent:1];

    // 2 - Get the graph's axis set
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *) self.hostView.hostedGraph.axisSet;

    // 3 - Configure the x-axis
    axisSet.xAxis.labelingPolicy = CPTAxisLabelingPolicyNone;
    axisSet.xAxis.title = @"Days of Week (Mon - Fri)";
    axisSet.xAxis.titleTextStyle = axisTitleStyle;
    axisSet.xAxis.titleOffset = 10.0f;
    axisSet.xAxis.axisLineStyle = axisLineStyle;

    // 4 - Configure the y-axis
    axisSet.yAxis.labelingPolicy = CPTAxisLabelingPolicyNone;
    axisSet.yAxis.title = @"Price";
    axisSet.yAxis.titleTextStyle = axisTitleStyle;
    axisSet.yAxis.titleOffset = 5.0f;
    axisSet.yAxis.axisLineStyle = axisLineStyle;
}

-(void)hideAnnotation:(CPTGraph *)graph {
    if ((graph.plotAreaFrame.plotArea) && (self.priceAnnotation)) {
        [graph.plotAreaFrame.plotArea removeAnnotation:self.priceAnnotation];
        self.priceAnnotation = nil;
    }
}

#pragma mark - CPTPlotDataSource methods
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot {
    //return [[[CPDStockPriceStore sharedInstance] datesInWeek] count];

    return [[graphData getGraphDates30D] count];
}

-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
    //if ((fieldEnum == CPTBarPlotFieldBarTip) && (index < [[[CPDStockPriceStore sharedInstance] datesInWeek] count])) {
    if ((fieldEnum == CPTBarPlotFieldBarTip) && (index < [[graphData getGraphDates30D] count])) {
        if ([plot.identifier isEqual:CPDTickerSymbolAAPL]) {

            return [[graphData getGraphValues30D] objectAtIndex:index];
            //return [[[CPDStockPriceStore sharedInstance] weeklyPrices:CPDTickerSymbolAAPL] objectAtIndex:index];
        } else if ([plot.identifier isEqual:CPDTickerSymbolGOOG]) {
            //return [[[CPDStockPriceStore sharedInstance] weeklyPrices:CPDTickerSymbolGOOG] objectAtIndex:index];
        } else if ([plot.identifier isEqual:CPDTickerSymbolMSFT]) {
            //return [[[CPDStockPriceStore sharedInstance] weeklyPrices:CPDTickerSymbolMSFT] objectAtIndex:index];
        }
    }
    return [NSDecimalNumber numberWithUnsignedInteger:index];
}

#pragma mark - CPTBarPlotDelegate methods
-(void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index {

    // 1 - Is the plot hidden?
    if (plot.isHidden == YES) {
        return;
    }

    // 2 - Create style, if necessary
    static CPTMutableTextStyle *style = nil;
    if (!style) {
        style = [CPTMutableTextStyle textStyle];
        style.color= [CPTColor yellowColor];
        style.fontSize = 16.0f;
        style.fontName = @"Helvetica-Bold";
    }

    // 3 - Create annotation, if necessary
    NSNumber *price = [self numberForPlot:plot field:CPTBarPlotFieldBarTip recordIndex:index];
    if (!self.priceAnnotation) {
        NSNumber *x = [NSNumber numberWithInt:0];
        NSNumber *y = [NSNumber numberWithInt:0];
        NSArray *anchorPoint = [NSArray arrayWithObjects:x, y, nil];
        self.priceAnnotation = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:plot.plotSpace anchorPlotPoint:anchorPoint];
    }

    // 4 - Create number formatter, if needed
    static NSNumberFormatter *formatter = nil;
    if (!formatter) {
        formatter = [[NSNumberFormatter alloc] init];
        [formatter setMaximumFractionDigits:2];
    }

    // 5 - Create text layer for annotation
    NSString *priceValue = [formatter stringFromNumber:price];
    CPTTextLayer *textLayer = [[CPTTextLayer alloc] initWithText:priceValue style:style];
    self.priceAnnotation.contentLayer = textLayer;

    // 6 - Get plot index based on identifier
    NSInteger plotIndex = 0;
    if ([plot.identifier isEqual:CPDTickerSymbolAAPL] == YES) {
        plotIndex = 0;
    } else if ([plot.identifier isEqual:CPDTickerSymbolGOOG] == YES) {
        plotIndex = 1;
    } else if ([plot.identifier isEqual:CPDTickerSymbolMSFT] == YES) {
        plotIndex = 2;
    }

    // 7 - Get the anchor point for annotation
    CGFloat x = index + _0DBarInitialX + (plotIndex * _0DBarWidth);
    NSNumber *anchorX = [NSNumber numberWithFloat:x];
    CGFloat y = [price floatValue] + 40.0f;
    NSNumber *anchorY = [NSNumber numberWithFloat:y];
    self.priceAnnotation.anchorPlotPoint = [NSArray arrayWithObjects:anchorX, anchorY, nil];

    // 8 - Add the annotation
    [plot.graph.plotAreaFrame.plotArea addAnnotation:self.priceAnnotation];
}

@end

Please help!!!! Scatter plot class works when adding to a uiview within a uiviewcontroller..... BUT NOT THIS BAR GRAPH!!!!

EDIT

The crash doesn't give me any information other than this

0x1a3209f:  movl   (%edi), %esi Thread 1: EXC_BAD_ACCESS (code=1, address=0x5489c855)
jsetting32
  • 1,632
  • 2
  • 20
  • 45
  • The graph is probably trying to pull data from `graphData` before it is completely set up. Can you get a stack trace? What gets printed if you add logging statements to the datasource methods? – Eric Skroch Jun 14 '13 at 01:18

1 Answers1

1

With a few days of waiting and some help from Coreplot members.... the issue was resolved....

Apparently, for the bar graphs, I have to ensure the plots are NOT RELEASED throughout the lifetime of the graph's lifetime....

Adding this ONE line of code after I allocate and instantiate space for a CPTBarplot ensured such,

[barplot.datasource retain];

One line of code always helps :).....

This made my day seeing my graphs in my subview.... now to make the axes look nice .....

jsetting32
  • 1,632
  • 2
  • 20
  • 45