2

我正在尝试在装有 iOS 5.1 的 iPad 上使用 CorePlot 1.0 实现实时散点图。有几个问题和一个主要的例外 - 轴重绘,事情进展顺利。

当收集到足够的数据时,我会调整 plotSpace 中的范围:

CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(self.graphMinX)
                                                length:CPTDecimalFromFloat(self.graphRangeX)];    

当我这样做时,图表上的图会调整,就好像轴已经改变一样,但轴没有调整- 所以数据图正确显示在不正确的轴上。停止数据源后,轴将正确更新 5 秒。

我已经查看了 CorePlot iOS Plot Gallery 中RealTimePlot (RTP) 中的代码,但我找不到任何显着差异(尽管肯定存在)。

我的代码和 RTP 之间的一个区别:

我在后台 GCD 队列中捕获新数据,然后通过将其附加到[NSNotificationCenter defaultCenter]

更新: 架构层次结构的简化视图是这样的:

  • 拆分视图控制器
    • 细节视图控制器
      • TreatmentGraph对象(管理CPTXYGraph
        • [集合]TreatmentChannel对象(每个管理一个CPTXYPlot

有一个数据通知的DetailViewController观察者,如下所示:

- (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;
}

(请注意,我使用 GCD 将数据强制重新加载到 UI 队列 - RTP 中的示例似乎不需要这样做)这是一个危险信号,但是什么?

TreatmentGraph我们检查是否需要调整 X 轴并将数据发送到适当的TreatmentChannel.

- (void)addPoint:(CGPoint)point toChannelWithIdentifier:(NSString *)identifier
{
    // Check for a graph shift
    if (point.x >= (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)];
}

我的猜测是在主队列空闲之前轴不会更新,但是由于我已经在新数据到达时强制重新加载,所以我很困惑为什么轴重绘不会发生。

接受这样的TreatmentChannel新数据:

- (void)addPoint:(CGPoint)point
{
    [self.plotData addObject:[NSValue valueWithCGPoint:point]]; // cache it
    [self.plot insertDataAtIndex:self.plotData.count-1 numberOfRecords:1];
    [self.plot reloadData];
}

请注意,我-insertDataAtIndex:numberOfRecords:用于仅添加新数据并-reloadData专门在CPTXYPlot. 这不会导致显示更新 - 直到-reloadData在数据通知处理程序中调用DetailViewController我才获得显示更新。

问题:

  1. 我该怎么做才能使我的轴更及时地更新?
  2. 除非我在数据到达时强制重新加载,否则为什么我没有在图表上显示图表的任何线索?

通过确保对轴和/或绘图空间的任何更新都被包装以将它们放回 GCD 主队列来解决第 1 项。

第 2 项通过包装调用来解决,以-insertDataAtIndex:numberOfRecords:允许删除许多-reloadData困扰我的调用。

故事的寓意:考虑与 UIKit 调用等效的 CorePlot 交互 - 确保它们都发生在主队列上。

4

1 回答 1

2
  1. 每当绘图空间范围发生变化时,轴都应重新标记和重绘。您何时根据新数据更新绘图空间?

  2. 您必须告诉绘图有新数据可用。-reloadData是做到这一点的一种方法,尽管对于这个应用程序,有更快的方法来做到这一点。实时绘图示例使用-insertDataAtIndex:numberOfRecords:and-deleteDataInIndexRange:添加新点并删除滚动到视图之外的点。这比每次发生变化时重新加载绘图的所有数据要快。-reloadData如果您有多个绘图,则调用图表而不是受影响的绘图会更慢,因为它将重新加载所有绘图的数据。

于 2012-06-03T00:26:46.603 回答