Core Plot: Should I add CPTPlotSpaceAnnotation for plotting so the whole plot is redrawn?

I am using Core Plot to display price time series. When the user taps the graph, I show a draggable vertical line at that point. Both the time series and the drag line are CPTScatterPlot

objects within CPTXYGraph

. This works pretty well - the performance when dragging a line across the time series plot is acceptable.

The next step is to display the price and date at the point chosen by the user. The Yahoo Stocks app has a nice feature that displays the price in a label that moves as if it's attached to the top of a dragged line. I tried to reproduce this using the text displayed in CPTPlotSpaceAnnotation

. It works, but it has a huge performance impact. After some digging, I found that it CPTLayer drawInContext:

gets called multiple times - it looks like the entire graph is redrawn every time I redraw the text label (actually my logs imply it is redrawn twice).

Here is the code that draws the label (work in progress). It is called plotSpace:shouldHandlePointingDeviceDraggedEvent:atPoint:


- (void)displayPriceAndDateForIndex:(NSUInteger)index atPoint:(CGPoint)pointInPlotArea
  NSNumber * theValue = [[self.graphDataSource.timeSeries objectAtIndex:index] observationValue];

  // if the annotations already exist, remove them
  if ( self.valueTextAnnotation ) {
    [self.graph.plotAreaFrame.plotArea removeAnnotation:self.valueTextAnnotation];
    self.valueTextAnnotation = nil;

  // Setup a style for the annotation
  CPTMutableTextStyle *annotationTextStyle = [CPTMutableTextStyle textStyle];
  annotationTextStyle.color = [CPTColor whiteColor];
  annotationTextStyle.fontSize = 14.0f;
  annotationTextStyle.fontName = @"Helvetica-Bold";

  // Add annotation
  // First make a string for the y value
  NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
  [formatter setMaximumFractionDigits:2];
  NSString *currentValue = [formatter stringFromNumber:theValue];

  NSNumber *x            = [NSNumber numberWithDouble:[theDate timeIntervalSince1970]];
  NSNumber *y            = [NSNumber numberWithFloat:self.graphDataSource.maxValue];
  NSArray *anchorPoint = [NSArray arrayWithObjects:x, y, nil];

  // Then add the value annotation to the plot area
  float valueLayerWidth = 50.0f;
  float valueLayerHeight = 20.0f;
  CPTTextLayer *valueLayer = [[CPTTextLayer alloc] initWithFrame:CGRectMake(0,0,valueLayerWidth,valueLayerHeight)];

  valueLayer.text = currentValue;
  valueLayer.textStyle = annotationTextStyle;
  valueLayer.backgroundColor = [UIColor blueColor].CGColor;

  self.valueTextAnnotation  = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:self.graph.defaultPlotSpace anchorPlotPoint:anchorPoint];

  self.valueTextAnnotation.contentLayer = valueLayer;

  // modify the displacement if we are close to either edge
  float xDisplacement = 0.0;
  self.valueTextAnnotation.displacement = CGPointMake(xDisplacement, 8.0f);

  [self.graph.plotAreaFrame.plotArea addAnnotation:self.valueTextAnnotation];

  // now do the date field


Is the expected full redraw behavior? And is there a better way to manage the annotation without destroying it and recreating it every time the method is called?


source to share

1 answer

You don't have to destroy and create annotations every time. Once it has been created, just update anchorPoint

. Removing and adding annotation is probably due to constant redrawing.



All Articles