2

I have the following code in a method for setting up a CPTBarPlot:

CPTGraphHostingView *chartView = [[CPTGraphHostingView alloc] initWithFrame:CGRectMake(10, 100, 290, 330)];
    [self.view addSubview:chartView];

    CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:chartView.bounds];
    graph.plotAreaFrame.masksToBorder = NO;
    chartView.hostedGraph = graph;

    graph.paddingLeft = 20.0f;
    graph.paddingTop = 0.0f;
    graph.paddingRight = 0.0f;
    graph.paddingBottom = 20.0f;

    CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
    textStyle.color = [CPTColor grayColor];
    textStyle.fontName = @"Helvetica-Bold";
    textStyle.fontSize = 8.0f;;

    CPTMutableTextStyle *axisTitleStyle = [CPTMutableTextStyle textStyle];
    axisTitleStyle.color = [CPTColor grayColor];
    axisTitleStyle.fontName = @"Helvetica-Bold";
    axisTitleStyle.fontSize = 12.0f;
    CPTMutableLineStyle *axisLineStyleX = [CPTMutableLineStyle lineStyle];
    axisLineStyleX.lineWidth = 2.0f;
    axisLineStyleX.lineColor = [CPTColor grayColor];
    CPTMutableLineStyle *axisLineStyleY = [CPTMutableLineStyle lineStyle];
    axisLineStyleY.lineWidth = 2.0f;
    axisLineStyleY.lineColor = [CPTColor grayColor];

    CPTXYAxisSet *axisSet = (CPTXYAxisSet *) chartView.hostedGraph.axisSet;

    axisSet.xAxis.labelingPolicy = CPTAxisLabelingPolicyFixedInterval;
    axisSet.xAxis.title = @"Ferientage pro Jahr";
    axisSet.xAxis.titleTextStyle = axisTitleStyle;
    axisSet.xAxis.titleOffset = 10.0f;
    axisSet.xAxis.axisLineStyle = axisLineStyleX;
    axisSet.xAxis.labelTextStyle = textStyle;
    axisSet.xAxis.labelOffset = -7.0f;
    axisSet.xAxis.majorIntervalLength = CPTDecimalFromFloat(10.0f);
    axisSet.xAxis.labelFormatter.maximumFractionDigits = 0;

    axisSet.yAxis.labelingPolicy = CPTAxisLabelingPolicyNone;
    axisSet.yAxis.title = @"Bundesländer";
    axisSet.yAxis.titleTextStyle = axisTitleStyle;
    axisSet.yAxis.titleOffset = 5.0f;
    axisSet.yAxis.axisLineStyle = axisLineStyleY;

    CPTXYPlotSpace *plotspace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
            plotspace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0) length:CPTDecimalFromFloat(110)];
    plotspace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0) length:CPTDecimalFromFloat(17)];
    [graph addPlotSpace:plotspace];

    CPTBarPlot *plot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor redColor] horizontalBars:YES];
    plot.plotRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.5) length:CPTDecimalFromFloat(16)];
    plot.labelTextStyle = textStyle;
    plot.labelFormatter.maximumFractionDigits = 0;
    plot.labelOffset = -3.0f;
    plot.identifier = @"bl";
    plot.dataSource = self;
    plot.delegate = self;
    [graph addPlot:plot];

    plot.anchorPoint = CGPointMake(0.0, 0.0);
    CABasicAnimation *scaling = [CABasicAnimation
                                         animationWithKeyPath:@"transform.scale.x"];
    scaling.fromValue = [NSNumber numberWithFloat:0.0];
    scaling.toValue = [NSNumber numberWithFloat:1.0];
    scaling.duration = 1.0f;
    scaling.removedOnCompletion = NO;
    scaling.fillMode = kCAFillModeForwards;
    [plot addAnimation:scaling forKey:@"scaling"];

Loading it takes about 4 seconds on an iPhone 5 and twice the time on an iPhone 4. Is that normal?

I also tried to circumvent that by detaching that method from the main thread and using aUIActivityIndicatorView, however there's a second strange behavior:

Sometimes it shows the spinner and the plot gets animated after a while, sometimes the spinner doesn't show up and the plot is displayed without an animation.

So as you can see I'm actually struggling with two issues, but maybe the second one is intertwined with the first one.


Maybe I show you other methods that are in conjunction with the Core Plot work:

-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot {
return 16;
}

-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
Ferien *ferien = [[Ferien alloc] init];

NSNumber *num = nil;
if ([plot isKindOfClass:[CPTBarPlot class]]) {
    NSArray *reversedArrayCount = [[ferien.getToplist reverseObjectEnumerator] allObjects];
    num = (NSNumber *)[NSNumber numberWithFloat:[[reversedArrayCount objectAtIndex:index] floatValue]];
    }
return num;

}

-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index {
if ( [plot.identifier isEqual: @"bl"] ) {
    Ferien *ferien = [[Ferien alloc] init];
    CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
    textStyle.fontName = @"Helvetica-Bold";
    textStyle.fontSize = 8.0f;
    textStyle.color = [CPTColor blackColor];

    NSArray *reversedArrayBl = [[ferien.bundeslandListWithManagedObjects reverseObjectEnumerator] allObjects];
    NSArray *reversedArrayCount = [[ferien.getToplist reverseObjectEnumerator] allObjects];

    CPTTextLayer *label = [[CPTTextLayer alloc] initWithText:[NSString stringWithFormat:@"%@ (%@)", [reversedArrayBl objectAtIndex:index], [reversedArrayCount objectAtIndex:index]]];
    label.textStyle = textStyle;

    return label;
}

CPTTextLayer *defaultLabel = [[CPTTextLayer alloc] initWithText:@"Label"];
return defaultLabel;

}

-(CPTFill *)barFillForBarPlot:(CPTBarPlot *)barPlot recordIndex:(NSUInteger)index {
if ([barPlot.identifier isEqual:@"bl"] ) {
    Ferien *ferien = [[Ferien alloc] init];

    NSMutableArray *colors = [[NSMutableArray alloc] initWithObjects:[UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], [UIColor lightGrayColor], nil];

    [colors replaceObjectAtIndex:15-ferien.currentBundesland withObject:[UIColor orangeColor]];

    for (int i = 0; i < 16; i++) {
        CPTGradient *gradient = [CPTGradient gradientWithBeginningColor:[colors objectAtIndex:index]
                                                        endingColor:[CPTColor whiteColor]
                                                  beginningPosition:0.0 endingPosition:1.5 ];
        [gradient setGradientType:CPTGradientTypeAxial];
        [gradient setAngle:320.0];

        CPTFill *fill = [CPTFill fillWithGradient:gradient];

        return fill;
    }
}
return [CPTFill fillWithColor:[CPTColor colorWithComponentRed:1.0 green:1.0 blue:1.0 alpha:1.0]];

}

- (void)initView {
self.labelFerienName.text = self.ferienName;
self.labelFeriendauer.text = self.feriendauer;

}

- (void)mergeChanges:(NSNotification *)notification {
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *mainContext = [delegate managedObjectContext];

// Merge changes into the main context on the main thread
[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                              withObject:notification
                           waitUntilDone:YES];

}

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Tobias Frischholz
  • 331
  • 1
  • 3
  • 4
  • Remove the animation while testing to isolate Core Plot issues from something else in the app. How many bars are you trying to display (what value is returned from `-numberOfRecordsForPlot:`)? – Eric Skroch Feb 17 '13 at 13:13
  • Removing the animation didn't change anything.`numberOfRecordsForPlot:`returns 16. – Tobias Frischholz Feb 17 '13 at 15:34
  • Definitely not normal. 16 bars should display almost instantly. Keep all of your Core Plot code on the main thread. Does your datasource have to do a lot of calculation while providing the data? I don't see anything in the code you posted that would cause a big delay. – Eric Skroch Feb 17 '13 at 20:38
  • Well, that's the point: I didn't implement the Core Plot code on the main thread **because** it was that slow. This resulted in the implementation of a UIActivityViewController and the following code: `- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [NSThread detachNewThreadSelector:@selector(initGraph) toTarget:self withObject:nil]; }` `-(void)initGraph`is the above mentioned code. – Tobias Frischholz Feb 19 '13 at 12:32

1 Answers1

1

You can do the data calculations anywhere, including other threads, but the graph setup and all other Core Plot interaction must be on the main thread. Call -initGraph when you're ready to display the graph, even if the data isn't ready yet. Do the data calculations on a background thread and cache the results in a structure that can be accessed quickly by the datasource. Call -reloadData on the plot (from the main thread) when the data is ready to force the plot to read the new data from the datasource.

Eric Skroch
  • 27,381
  • 3
  • 29
  • 36