I want to be able to update / reload a ScatterPlot on iOS Devices during runtime. To be specific, I record Audio input, do some funny stuff and put the result as a simple NSNumber value into an array. Whenever that happens, reloadData is called on the Plot I want to update but sadly, exactely nothing happens. Basically, I do the same as described in the answer here: real time plotting on iPhone using core plot? . It just doesn't work, so I assume I made some stupid mistake.
我希望能够在运行时更新/重新加载iOS设备上的散列表。具体来说,我记录音频输入,做一些有趣的事情,并将结果作为一个简单的NSNumber值放入数组中。每当发生这种情况时,reloadData就会被调用到我想要更新的情节中,但遗憾的是,完全不会发生任何事情。基本上,我做的和这里描述的一样:用core plot实时绘制iPhone ?。它就是不管用,所以我认为我犯了一些愚蠢的错误。
This the relevant method:
这相关的方法:
-(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;
}
}
}
The X Squared Plot is irrelevant to my needs for now, it's just a reference. The LivePlot is the one I need and want to update. The _plotIndizesAndVolume is the NSMutableArray I store my values in. It has 500 Elements, all of which are initialized with [NSNumber numberWithFloat:0.0f] at the beginning of my execution. The Plot has 500 indizes as well, therefor we don't get out of bounds or whatever.
X²图现在和我的需求无关,它只是一个参考。LivePlot是我需要更新的。_plotIndizesAndVolume是我存储值的NSMutableArray。它有500个元素,所有这些元素在我执行的开始时都是用[NSNumber with float:0.0f]初始化的。情节也有500个独立部分,因此我们不会越界。
The code executes fine, the method is being called, the printf statement works and correctly displays the floats, the Plot just doesn't update.
代码执行得很好,方法被调用,printf语句工作并正确地显示浮动,图只是没有更新。
I also tried
我也试过
if (index < [_plotIndizesAndVolume count]) {
return [NSNumber numberWithFloat:[_plotIndizesAndVolume objectAtIndex:index]];
} else {
return [NSNumber numberWithFloat:0.0f];
}
without having the 500 0.0fs in the array, so that I just access values differently from 0.0f. This of course is better, it just doesn't work either.
数组中没有500 0。0fs,所以我访问的值与0。0f不同。这当然更好,它也不奏效。
Any ideas?
什么好主意吗?
Update 1:
更新1:
-
If I fill the _plotIndizesAndVolume with just random numbers at the beginning of my application, the plot perfectly follows these numbers.
如果我在应用程序的开头用随机数填充_plotIndizesAndVolume,那么这个图就完全符合这些数字。
-
If I printf in the method I can perfectly read the updated values once reload has been called on the plot.
如果我在方法中printf,那么一旦重新加载被调用,我就可以完美地读取更新后的值。
-
However, these updated values aren't shown in the plot. The plot remains the way it is after calling -reloadData on it, no matter which values changed in the _plotIndizesAndVolume-Array.
然而,这些更新后的值并没有显示在图中。在调用-reloadData之后,无论在_plotindizesandvolume -数组中哪个值发生了变化,这个情节都保持原样。
So, from what I can see: I can access the array properly, I can update and read the new values properly, the plot still stays the same and doesn't change. I'm confused. Probably I still made some random stupid mistake, I just don't see it.
因此,从我所看到的:我可以正确地访问数组,我可以正确地更新和读取新值,图仍然保持不变并且不会改变。我困惑。可能我还是犯了一些愚蠢的错误,只是我没看到而已。
Update2:
更新2:
Well, it seems as if my problem isn't the reloadData itself, but from where I call it. Some more context: I'm using novocaine to measure decibel via the device microphone. This works fine. I then want to visualize part of the measured dB in a graph through corePlot (which I described above). I got a method called startMeasuring
which I call somewhen and then - obviously - start measuring decibel. Whenever that happens I put the measured value int _plotIndicesAndVolume
and call reloadData
on the plot.
似乎我的问题不在于reloadData本身,而在于我怎么称呼它。更多的背景:我正在使用novocaine通过设备麦克风来测量分贝。这是很好。然后,我想通过corePlot(我在上面描述过)将测量到的dB的一部分可视化到图中。我有一种叫做“开始测量”的方法,我叫它什么时候开始测量分贝。无论何时发生这种情况,我都将测量值int _plotIndicesAndVolume放在绘图上并调用reloadData。
The method looks like this (and is largely copied directly from the novocain examples):
这个方法看起来是这样的(很大程度上是直接从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;
}
I call reloadData
from within the measuring block. I don't know exactely much about using blocks, I just assumed I could do that. If I, however, try to change the data in the array and afterwards reload the plot manually from somewhere else, it works and the plot updates accordingly. Is the problem related to my call of the method from within the block?
我从测量块中调用reloadData。我不太了解如何使用block,我只是假设我可以这么做。但是,如果我尝试更改数组中的数据,然后从其他地方手动重新加载这个图,那么它就会工作,并相应地更新这个图。问题是否与我从块中调用方法有关?
Even then I'm still unsure why it doesn't work, as the printf statement works perfectly - so I'm under the assumption that the updateData method is correctly invoked and the values are correctly updated.
即使这样,我仍然不确定为什么它不能工作,因为printf语句工作得很好——所以我假定updateData方法被正确调用,值被正确更新。
Update 3:
更新3:
If I call reloadData
from somewhere else during the measurement, the graph updates just fine and according to whatever is in _plotIndizesAndVolume
. It simply doesn't update if I call it from inside the block (even if I call another method from within the block which in turn calles reloadData
). However, I need the live update. I assume I could reload the plot once every x miliseconds as well (going to try that next), I'm still curious as to why it doesn't work in the first place.
如果我在测量期间从其他地方调用reloadData,那么这个图就可以根据_plotIndizesAndVolume中的任何内容进行更新。如果我从块内部调用它,它不会更新(即使我从这个块中调用另一个方法,它也会调用reloadData)。但是,我需要实时更新。我假设我也可以每隔x毫秒重新加载一次情节(接下来再试一次),我仍然很好奇为什么它一开始就不起作用。
Update 4: As assumed in Update 3, if I call reloadData
from somewhere else through a NSTimer, it does exactely what I want it to do. Why can't I call it from within the block then?
更新4:如更新3所假设的,如果我通过一个NSTimer从其他地方调用reloadData,它会精确地执行我想要它做的事情。那为什么我不能在block中调用它呢?
2 个解决方案
#1
3
Call -reloadData
(and any other Core Plot methods) from the main thread.
从主线程调用-reloadData(以及任何其他核心情节方法)。
#2
2
Probably you need to update your plot space x-range/y-range in your timer
也许你需要在你的计时器中更新你的地图空间x-range/y-range
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
[plotSpace scaleToFitPlots:[self.graph allPlots]];
CPTPlot *thePlot = [self.graph plotWithIdentifier:kIdentifier];
[thePlot reloadData];
#1
3
Call -reloadData
(and any other Core Plot methods) from the main thread.
从主线程调用-reloadData(以及任何其他核心情节方法)。
#2
2
Probably you need to update your plot space x-range/y-range in your timer
也许你需要在你的计时器中更新你的地图空间x-range/y-range
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
[plotSpace scaleToFitPlots:[self.graph allPlots]];
CPTPlot *thePlot = [self.graph plotWithIdentifier:kIdentifier];
[thePlot reloadData];