Aerius
Aerius

Reputation: 608

Core-Plot: calling reloadData on Plot or Graph from within block doesn't work

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.

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.

The code executes fine, the method is being called, the printf statement works and correctly displays the floats, the Plot just doesn't update.

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.

Any ideas?

Update 1:

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:

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.

The method looks like this (and is largely copied directly from the novocain examples):

-(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?

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.

Update 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.

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?

Upvotes: 3

Views: 1689

Answers (2)

Philip K. Adetiloye
Philip K. Adetiloye

Reputation: 3270

Probably you need to update your plot space x-range/y-range in your timer

CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
[plotSpace scaleToFitPlots:[self.graph allPlots]];

CPTPlot *thePlot   = [self.graph plotWithIdentifier:kIdentifier];
[thePlot reloadData];

Upvotes: 2

Eric Skroch
Eric Skroch

Reputation: 27381

Call -reloadData (and any other Core Plot methods) from the main thread.

Upvotes: 3

Related Questions