3
votes

I am using core plot to draw graphs. So far it seems to be a great framework but I have encountered some performance issues when I enable user interaction and perform a scroll.

At first I thought this was due to the number of points being plotted so I wrote a simple test app with very few points. Scrolling was still quite jerky despite the plot being as simple as possible. I get around 20-25 fps on an iPhone 4 with this plot.

Am I doing something wrong or is this just as fast as it gets with core plot?

My sample code is below:

- (void)viewDidLoad
{
    [super viewDidLoad];

    graph = [(CPTXYGraph *)[CPTXYGraph alloc] initWithFrame:CGRectZero];

    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0) length: CPTDecimalFromDouble(5)];
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0) length:CPTDecimalFromDouble(5)];
    plotSpace.allowsUserInteraction = YES;
    plotSpace.globalYRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(-10) length:CPTDecimalFromDouble(100)];
    plotSpace.globalXRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(-10) length:CPTDecimalFromDouble(20)];

    // Axes
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *x          = axisSet.xAxis;
    x.majorIntervalLength         = CPTDecimalFromInt(1);
    x.orthogonalCoordinateDecimal = CPTDecimalFromInt(0);
    x.axisConstraints = [CPTConstraints constraintWithLowerOffset:30];

    CPTXYAxis *y = axisSet.yAxis;
    y.majorIntervalLength         = CPTDecimalFromInt(1);
    y.minorTicksPerInterval       = 0;
    y.orthogonalCoordinateDecimal = CPTDecimalFromDouble(0);
    y.axisConstraints = [CPTConstraints constraintWithLowerOffset:30];

    // Create a plot that uses the data source method
    CPTScatterPlot *dataSourceLinePlot = [[CPTScatterPlot alloc] init];
    dataSourceLinePlot.identifier = @"1";

    CPTMutableLineStyle *lineStyle = [dataSourceLinePlot.dataLineStyle mutableCopy];
    lineStyle.lineWidth              = 3.f;
    lineStyle.lineColor              = [CPTColor redColor];
    dataSourceLinePlot.dataLineStyle = lineStyle;
    dataSourceLinePlot.dataSource = self;
    dataSourceLinePlot.delegate = self;
    [graph addPlot:dataSourceLinePlot];

    hostView.hostedGraph = graph;
}

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

-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    return [NSNumber numberWithInt:index];
}
2

2 Answers

1
votes

Its best if you perform plotting in the background.

You are probably trying to plot/process these graphs on the main queue which is bad. What is happening is all your rendering, processing and your user touch events are all being backed up on the main queue,like below. So what you are getting is the plotting, processing and touch events are happening in the order they are being received (FIFO). If you put the processing on the background touch events will be handled without waiting. (Please watch the video referenced below)

BAD (what you are probably doing)
MainQueue: Process/Plot -> TouchEvent(scroll) -> Render -> Plot/Process -> Plot/Process -> TouchEvent(scroll) -> Update UI -> TouchEvent

GOOD
MainQueue: TouchEvent(scroll) -> TouchEvent(scroll) -> Update UI -> TouchEvent
ProcessingQueue: Process/Plot -> Plot/Process -> Plot/Process 

Its best to let the MainQueue only handle rendering (UI updates) and touch events and put everything else on background queues.

NSOperationQueue *q = [NSOperationQueue alloc] init];
[q setName:@"Plotting Queue"];
[q addOperationWithBlock:^{ plotGraph(); }];
[q addOperationWithBlock:^{ 
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        updateTheUI();
     }];
}];

plotGraph method would be all your plotting code above. updateTheUI method would be your hostView.hostedGraph = graph; line plus any code to make the UI re-render itself.

Check out WWDC 2012 video called "Building Concurrent User Interfaces on iOS"

0
votes

I had huge performance problems with my scatter plot until I set the axis labeling policies. Setting the labeling policy to either Automatic or None eliminated 5 seconds of lag I was having.

CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
CPTXYAxis *y = axisSet.yAxis;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
y.labelingPolicy = CPTAxisLabelingPolicyNone;