我希望能够在运行时在iOS设备上更新/重新加载ScatterPlot。具体来说,我记录音频输入,做一些有趣的东西,并将结果作为一个简单的NSNumber值放入一个数组。每当发生这种情况时,在我想要更新的Plot上调用reloadData,但遗憾的是,没有任何反应。基本上,我的做法与答案中描述的相同:real time plotting on iPhone using core plot?。它只是不起作用,所以我认为我犯了一些愚蠢的错误。
这是相关的方法:
-(NSNumber *) numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
double val = (index/5.0) -10;
if (fieldEnum == CPTScatterPlotFieldX) {
return [NSNumber numberWithDouble:val];
} else {
if ([plot.identifier isEqual: @"X Squared Plot"]) {
return [NSNumber numberWithDouble:10-(0.25*val*val)];
} else if( [plot.identifier isEqual:@"LivePlot"]) {
if (!_isMeasuring) {
return [NSNumber numberWithFloat:0.0f];
} else {
printf("%f", [[_plotIndizesAndVolume objectAtIndex:index] floatValue]);
return [NSNumber numberWithFloat:[[_plotIndizesAndVolume objectAtIndex:index] floatValue]];
}
} else {
return 0;
}
}
}
X Squared Plot与我现在的需求无关,它只是一个参考。 LivePlot是我需要并想要更新的。 _plotIndizesAndVolume是我存储我的值的NSMutableArray。它有500个元素,所有这些元素在执行开始时都用[NSNumber numberWithFloat:0.0f]初始化。 Plot也有500个indizes,因此我们不会出界或其他什么。
代码执行正常,调用方法,printf语句正常工作并正确显示浮点数,Plot只是不更新。
我也试过
if (index < [_plotIndizesAndVolume count]) {
return [NSNumber numberWithFloat:[_plotIndizesAndVolume objectAtIndex:index]];
} else {
return [NSNumber numberWithFloat:0.0f];
}
没有数组中的500个0.0fs,因此我只能以0.0f的方式访问值。这当然更好,它也不起作用。
有什么想法吗?
更新1:
如果我在应用程序开头只用随机数填充_plotIndizesAndVolume,那么该图就完全遵循这些数字。
如果我在方法中使用printf,我可以在绘图上调用重新加载后完美地读取更新的值。
但是,这些更新的值未显示在图中。无论_plotIndizesAndVolume-Array中哪些值发生变化,该图仍然是在调用-reloadData之后的方式。
所以,从我所看到的:我可以正确访问数组,我可以正确地更新和读取新值,图仍然保持不变并且不会改变。我糊涂了。可能我仍然犯了一些随机的愚蠢错误,我只是没有看到它。
UPDATE2:
好吧,似乎我的问题不是reloadData本身,而是我称之为的地方。更多背景:我正在使用诺瓦卡因通过设备麦克风测量分贝。这很好用。然后,我想通过corePlot(我在上面描述)中在图形中可视化部分测量的dB。我有一个名为startMeasuring
的方法,我称之为然后 - 显然 - 开始测量分贝。每当发生这种情况时,我将测量值设为_plotIndicesAndVolume
并在图上调用reloadData
。
该方法看起来像这样(并且主要直接从novocain示例中复制):
-(void) startMeasuring {
if (_isMeasuring) {
return;
}
__weak ViewController * wself = self;
self.ringBuffer = new RingBuffer(32768, 2);
self.audioManager = [Novocaine audioManager];
// MEASURE SOME DECIBELS!
// ==================================================
__block float dbVal = 0.0;
__block int count = 0;
__block int limiter = 0;
[self.audioManager setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) {
vDSP_vsq(data, 1, data, 1, numFrames*numChannels);
float meanVal = 0.0;
vDSP_meanv(data, 1, &meanVal, numFrames*numChannels);
float one = 1.0;
vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0);
dbVal = dbVal + 0.2*(meanVal - dbVal);
float reducedVal = (dbVal + 66.0f)/3;
if (!wself.measuringPaused && limiter > 10) {
[wself.plotIndizesAndVolume replaceObjectAtIndex:count withObject:[NSNumber numberWithFloat:reducedVal]];
[[wself.graph plotWithIdentifier:@"LivePlot"] reloadData];
limiter = -1;
++count;
}
++limiter;
}];
[self.audioManager play];
_isMeasuring = true;
}
我从测量块中调用reloadData
。我不太清楚使用积木,我只是假设我能做到这一点。但是,如果我尝试更改数组中的数据,然后从其他地方手动重新加载绘图,则它会起作用,并且绘图会相应地更新。这个问题是否与我在块内调用该方法有关?
即便如此,我仍然不确定为什么它不起作用,因为printf语句完美地工作 - 所以我假设正确调用updateData方法并正确更新值。
更新3:
如果我在测量过程中从其他地方拨打reloadData
,图表会根据_plotIndizesAndVolume
中的内容进行更新。如果我从块内部调用它,它就不会更新(即使我从块中调用另一个方法,然后调用reloadData
)。但是,我需要实时更新。我假设我每隔x毫秒也可以重新加载一次(下一次尝试),我仍然很好奇为什么它首先不起作用。
更新4:如更新3中所假设的,如果我通过NSTimer从其他地方调用reloadData
,它确实是我想要它做的事情。为什么我不能在块内调用呢?
答案 0 :(得分:3)
从主线程中调用-reloadData
(以及任何其他Core Plot方法)。
答案 1 :(得分:2)
您可能需要在计时器中更新绘图空间x-range / y-range
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
[plotSpace scaleToFitPlots:[self.graph allPlots]];
CPTPlot *thePlot = [self.graph plotWithIdentifier:kIdentifier];
[thePlot reloadData];