【问题标题】:Updating X axis on scrolling real-time CorePlot Scatterplot在滚动实时 CorePlot 散点图上更新 X 轴
【发布时间】:2012-06-01 13:49:31
【问题描述】:

我正在尝试在装有 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] 中的自定义通知来“分发”它

更新: 架构层次结构的简化视图如下所示:

  • SplitViewController
    • DetailViewController
      • 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: 仅添加新数据并专门在CPTXYPlot 上调用-reloadData。这不会导致显示更新 - 直到在 DetailViewController 的数据通知处理程序中调用 -reloadData 后,我才会获得显示更新。

问题:

  1. 我可以做些什么来使我的轴更及时地更新?
  2. 有什么线索可以解释为什么除非我在数据到达时强制重新加载,否则我的图表上没有图表?

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

第 2 项已通过包装对 -insertDataAtIndex:numberOfRecords: 的调用得到解决,从而可以删除许多困扰我的 -reloadData 调用。

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

【问题讨论】:

    标签: ios ipad core-plot


    【解决方案1】:
    1. 每当绘图空间范围发生变化时,轴都应重新标记和重新绘制。您什么时候根据新数据更新绘图空间?

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

    【讨论】:

    • 您好 Eric,我将更详细地更新问题,但很快:新数据通过 TreatmentGraph 对象发送 - 如果需要,对轴和 plotSpace 进行调整 - 并传递给从它们的集合中正确的 TreatmentChannel 对象。 TreatmentChannel 中的 -addPoint: 方法缓存特定于绘图的数据,使用 -insertDataAtIndex:numberOfRecords: 更新绘图并在该绘图上调用 -reloadData。 (这不会导致更新)感谢您的帮助。
    • 您不需要-insertDataAtIndex:numberOfRecords:-reloadData。我认为这个问题与不同的线程有关。尝试在主线程上调用-insertDataAtIndex:numberOfRecords:
    • 在主队列中调用-insertDataAtIndex:numberOfRecords: 确实减少了对-reloadData 的需求。很好的电话。我仍在尝试找出除非我停止数据馈送,否则我的轴将不会更新的主要问题。
    • 调用主 GCD 队列上的所有 CorePlot 方法 *did 最终解决了我的非更新轴问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    • 2017-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多