Note that there are some explanatory texts on larger screens.

plurals
  1. POUpdating X axis on scrolling real-time CorePlot Scatterplot
    text
    copied!<p>I'm trying to implement a real-time scatter plot using CorePlot 1.0 on an iPad with iOS 5.1. Things are working well with a couple of issues and one major exception - axis redraw.</p> <p>When enough data is collected, I adjust the range in the plotSpace thus:</p> <pre><code>CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace; plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(self.graphMinX) length:CPTDecimalFromFloat(self.graphRangeX)]; </code></pre> <p>When I do this, the plots on the graph adjust as if the axis had changed, <em>but the axis doesn't adjust</em> - so the plots of the data display correctly against an incorrect axis. The axis will correctly update 5 seconds after I stop the data source.</p> <p>I have reviewed the code in <a href="http://code.google.com/p/core-plot/source/browse/examples/CorePlotGallery/src/plots/RealTimePlot.m" rel="nofollow">RealTimePlot</a> (RTP) from the CorePlot iOS Plot Gallery and I can't find any <em>significant</em> difference (though one surely exists).</p> <p>One difference between my code and RTP:</p> <p>I capture the new data in a background GCD queue, which is then "distributed" by attaching it to a custom notification in <code>[NSNotificationCenter defaultCenter]</code></p> <p><strong>Update:</strong> A simplified view of the architecture hierarchy is something like this:</p> <ul> <li>SplitViewController</li> <li><ul> <li>DetailViewController</li> </ul></li> <li><ul> <li><ul> <li><code>TreatmentGraph</code> object (managing the <code>CPTXYGraph</code>)</li> </ul></li> </ul></li> <li><ul> <li><ul> <li><ul> <li>[Collection of] <code>TreatmentChannel</code> objects (each managing a <code>CPTXYPlot</code>)</li> </ul></li> </ul></li> </ul></li> </ul> <p>The <code>DetailViewController</code> has an observer for the data notification which looks like this:</p> <pre><code>- (void)dataArrived:(NSNotification *)notification { FVMonitoredSignal *sig = [notification object]; NSValue *currValue = [sig.dataPoints lastObject]; CGPoint point = [currValue CGPointValue]; [self.treatmentGraph addPoint:point toChannelWithIdentifier:sig.signalName]; dispatch_async(dispatch_get_main_queue(), ^{ [self.graphHostingView.hostedGraph reloadData]; }); return; } </code></pre> <p>(Note that I force a reload of the data using a GCD post to the UI queue - the example in RTP did not seem to require this) This is a red flag, but of what?</p> <p>Within the <code>TreatmentGraph</code> we check whether a X Axis adjustment is needed and the data is dispatched to the appropriate <code>TreatmentChannel</code>.</p> <pre><code>- (void)addPoint:(CGPoint)point toChannelWithIdentifier:(NSString *)identifier { // Check for a graph shift if (point.x &gt;= (self.graphMinX + self.graphRangeX)) { [self shiftGraphX]; } FVTreatmentChannel *channel = [self.channels objectForKey:identifier]; [channel addPoint:point]; return; } - (void)shiftGraphX { CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace; plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(self.graphMinX) length:CPTDecimalFromFloat(self.graphRangeX)]; } </code></pre> <p>My guess is the axis isn't updated until the main queue is idle, but since I'm already forcing a reload when new data arrives, I'm perplexed why the axis redraw doesn't happen then.</p> <p>The <code>TreatmentChannel</code> accepts the new data like this:</p> <pre><code>- (void)addPoint:(CGPoint)point { [self.plotData addObject:[NSValue valueWithCGPoint:point]]; // cache it [self.plot insertDataAtIndex:self.plotData.count-1 numberOfRecords:1]; [self.plot reloadData]; } </code></pre> <p>Note that I'm using <code>-insertDataAtIndex:numberOfRecords:</code> to add just the new data and calling <code>-reloadData</code> specifically on the <code>CPTXYPlot</code>. This is not causing a display update - it's not until the <code>-reloadData</code> is called in the data notification handler in the <code>DetailViewController</code> that I get a display update.</p> <p>Questions:</p> <ol> <li>What can I do to cause my axis to update in a more timely manner?</li> <li>Any clues why I don't get plots on my graph unless I force a reload when data arrives?</li> </ol> <p>Item 1 was addressed by making sure any updates to the axis and/or plotspace were wrapped to put them back on the GCD main queue.</p> <p>Item 2 was addressed by wrapping the calls to <code>-insertDataAtIndex:numberOfRecords:</code> allowed the removal of many of the <code>-reloadData</code> calls that were bothering me.</p> <p><strong>Moral of the story</strong>: consider interaction with CorePlot equivalent to UIKit calls - in terms of making sure they all happen on the main queue.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload