2011-06-30 41 views
0

我試圖繪製使用coreplot圖(CPScatterPlot)聲音的分貝值。但問題是,我得到的圖形中Y軸垂直的一條線,它相對於分貝值的變化在Y軸上上下移動。我需要繪製這樣的圖表。 enter image description here如何使用coreplot實時繪製圖表?

這裏是我的代碼: `

-(void) generateDataSamples 
    { 

    samples = [[NSMutableArray alloc]initWithCapacity:NUM_SAMPLES]; 

    for (int i=0; i < NUM_SAMPLES; i++) 

     { 
      // peakVal is a variable that holds the decibel value 
      NSDictionary *sample = [NSDictionary dictionaryWithObjectsAndKeys:       
      [NSNumber numberWithDouble:peakVal],Y_VAL,nil]; 
      [samples addObject:sample]; 
      } 

    } 

-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot; 
{ 
    return [samples count]; 
} 

-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum 
       recordIndex:(NSUInteger)index{ 

NSDictionary *sample = [samples objectAtIndex:index]; 
NSDecimalNumber *num = [NSDecimalNumber zero]; 
    if (fieldEnum == CPScatterPlotFieldX) 
    { 
     num = (NSDecimalNumber *) [NSDecimalNumber numberWithInt:index + 1]; 
    } 
    else if (fieldEnum == CPScatterPlotFieldY) 
    { 
    return [sample valueForKey:Y_VAL]; 
    } 
    return num; 
} 

所以,我應該怎麼辦得到一個圖表,如上圖中?請幫助我,我是新來的。

還有一,你可以在上面的圖片,Y軸標籤放置在繪圖區域內,怎麼可以做什麼?

這裏是我的全部代碼,請建議修改:

#import "MicBlowViewController.h" 
#import "SecondVC.h" 
#define DBOFFSET -74.0 
#define START_POINT 0.0 
#define END_POINT 100.0 
#define NUM_SAMPLES 200.0 
#define MAX_PEAK 100.0 

#define X_VAL @"X_VAL" 
#define Y_VAL @"Y_VAL" 
#define S_VAL @"S_VAL" 


@implementation MicBlowViewController 
@synthesize avgLabel, peakLabel,absValue,pageControl; 


-(void)reloadData 
{ 
    if(!graph) 
    { 
     //setting graph 
     double xAxisStart = START_POINT; 
     double xAxisLength = END_POINT - START_POINT; 
     double maxY = 100;//[[samples valueForKeyPath:@"@max.Y_VAL"] doubleValue]; 
     double yAxisStart = START_POINT; 
     double yAxisLength = maxY+3; 
     xVal=START_POINT+0.1; 
     hostingView = [[CPGraphHostingView alloc] initWithFrame:CGRectMake(0, 79, 320, 361)]; 
     [self.view addSubview:hostingView]; 
     graph = [[CPXYGraph alloc] initWithFrame:CGRectMake(0, 79, 320, 361)]; 
     hostingView.hostedGraph = graph; 

     CPTheme *theme = [CPTheme themeNamed:kCPDarkGradientTheme]; 
     [graph applyTheme:theme]; 
     graph.paddingTop = 0.0; 
     graph.paddingBottom = 0.0; 
     graph.paddingLeft = 0.0; 
     graph.paddingRight = 0.0; 
     [[graph defaultPlotSpace] setAllowsUserInteraction:TRUE]; 
     CPXYAxisSet *axisSet = (CPXYAxisSet *)graph.axisSet; 
     axisSet.yAxis.labelOffset=0.1; 
     CPXYAxis *x = axisSet.xAxis; 
     x.majorIntervalLength = CPDecimalFromDouble(10.0); 
     x.orthogonalCoordinateDecimal = CPDecimalFromInteger(0); 
     x.minorTicksPerInterval = 1; 

     CPXYAxis *y = axisSet.yAxis; 

     y.majorIntervalLength=CPDecimalFromDouble(10.0); 
     y.orthogonalCoordinateDecimal = CPDecimalFromInteger(0); 
     y.minorTicksPerInterval = 1; 
     y.tickDirection = CPSignPositive; 
     y.labelAlignment = CPAlignmentLeft; 
     y.alternatingBandFills = [NSArray arrayWithObjects:[[CPColor whiteColor] colorWithAlphaComponent:0.1], [NSNull null], nil]; 
     CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace; 
     plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromDouble(xAxisStart) 
                 length:CPDecimalFromDouble(xAxisLength)]; 

     plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromDouble(yAxisStart) 
                 length:CPDecimalFromDouble(yAxisLength)];  

     CPScatterPlot *dataSourceLinePlot = [[CPScatterPlot alloc] init]; 
     dataSourceLinePlot.dataSource = self; 
     //[dataSourceLinePlot insertDataAtIndex:[samplesY count]-1 numberOfRecords:1]; 

     CPMutableLineStyle *lineStyle = [[dataSourceLinePlot.dataLineStyle mutableCopy] autorelease]; 
     lineStyle.lineWidth = 2.f; 
     lineStyle.lineColor = [CPColor cyanColor]; 
     dataSourceLinePlot.dataLineStyle = lineStyle; 

     [graph addPlot:dataSourceLinePlot]; 

     [dataSourceLinePlot release]; 
     [graph release]; 
     [hostingView release]; 
    } 
} 

- (void)generateData 
{ 

     // if (plotData == nil) { 
     NSMutableArray *contentArray = [NSMutableArray array]; 

     for (NSUInteger i = 0; i < 200; i++) { 
      //double test = (double)[peakLabel.text doubleValue]; 
      absValue.text =[NSString stringWithFormat:@"%.2f",peakVal]; 
      id x = [NSDecimalNumber numberWithDouble:1.0 + i ]; 
      id y = [NSDecimalNumber numberWithDouble:peakVal * rand()/(double)RAND_MAX + 0.05]; 
      [contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, @"x", y, @"y", nil]]; 
     } 
     plotData = [contentArray retain]; 
     //} 

} 
-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot ; 
{ 
    return [plotData count]; 
} 

-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum 
       recordIndex:(NSUInteger)index; 
{ 
    NSNumber *num = [[plotData objectAtIndex:index] valueForKey:(fieldEnum == CPScatterPlotFieldX ? @"x" : @"y")]; 

    if (fieldEnum == CPScatterPlotFieldY) { 
     num = [NSNumber numberWithDouble:[num doubleValue]]; 

    } 
    return num; 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    pageControl = [[UIPageControl alloc]init]; 
    [pageControl addTarget:self action:@selector(changePage) forControlEvents:UIControlEventValueChanged]; 
    samplesY = [[NSMutableArray alloc]init]; 
    //checking for sound 
    NSURL *url = [NSURL fileURLWithPath:@"/dev/null"]; 

    NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys: 
           [NSNumber numberWithFloat: 44100.0],     AVSampleRateKey, 
           [NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey, 
           [NSNumber numberWithInt: 1],       AVNumberOfChannelsKey, 
           [NSNumber numberWithInt: AVAudioQualityMax],   AVEncoderAudioQualityKey, 
           nil]; 

    NSError *error; 
    recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error]; 

    if (recorder) { 
     [recorder prepareToRecord]; 
     recorder.meteringEnabled = YES; 
     [recorder record]; 
     levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: @selector(levelTimerCallback:) userInfo: nil repeats: YES]; 
    }// else 
    //NSLog([error description]); 
} 


- (void)levelTimerCallback:(NSTimer *)timer { 
    // getting decibel values.... 
    [recorder updateMeters]; 

    const double ALPHA = 0.05; 
    double peakPowerForChannel = pow(10, (0.05 * [recorder peakPowerForChannel:0])); 

    lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * lowPassResults; 

    NSLog(@"Average input: %f Peak input: %f Low pass results: %f", 
      [recorder averagePowerForChannel:0], [recorder peakPowerForChannel:0], lowPassResults); 
    peakval=fabs([recorder peakPowerForChannel:0]); 
    double avgval=fabs([recorder averagePowerForChannel:0]); 
    peakVal=MAX_PEAK - peakval; 
    avgVal=MAX_PEAK - avgval; 
    NSLog(@"First: %.2f",peakVal); 

    avgLabel.text=[NSString stringWithFormat:@"%.2f",avgVal]; 
    peakLabel.text=[NSString stringWithFormat:@"%.2f",peakVal]; 
    if (lowPassResults < 0.95) 
     NSLog(@"Mic blow detected: %d",lowPassResults); 

    [self generateData]; 

    [self reloadData]; 

} 

- (IBAction) changePage:(id)sender{ 
    SecondVC *vc = [[SecondVC alloc]init]; 
    vc.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; 
    [self presentModalViewController:vc animated:YES]; 
    [vc release]; 
} 

- (void)dealloc { 
    [peakLabel.text release]; 
    [avgLabel.text release]; 
    [samples release]; 
    [levelTimer release]; 
    [recorder release]; 
    [super dealloc]; 
} 

@end 

回答

2

它看起來像你使用相同的peakVal對每一個數據點。檢查-generateDataSamples方法,並確保您將正確的值存儲在samples陣列中。如果您已經擁有數組中的數據,則可以完全跳過該方法,只需按-numberForPlot:field:recordIndex:中的索引進行查找即可。

此外,請檢查繪圖空間上的xRangeyRange以確保它們符合您的數據。請記住,繪圖範圍與NSRange類似 - 它們使用起始位置和長度創建,而不是開始和結束值。

以將標籤移動到y軸的右側,使用yAxis.tickDirection = CPTSignPositive;

編輯迴應的評論

每次你得到新的數據時,不要叫-generateDataSamples。相反,將新值添加到samples陣列。第一次使用前不要忘記初始化陣列。

NSDictionary *sample = [NSDictionary dictionaryWithObjectsAndKeys:       
    [NSNumber numberWithDouble:peakVal],Y_VAL,nil]; 
[samples addObject:sample]; 

一旦數據在數組中,告訴Core Plot只加載新點。這比每次更新時重新加載所有數據都要快。

[myScatterPlot insertDataAtIndex:(samples.count - 1) 
       numberOfRecords:1]; 

可以使用CPTPlot方法-deleteDataInIndexRange:刪除舊的數據點,如果你不需要把所有的歷史,在圖中。不要忘記從samples陣列中刪除相應的點。

+0

yAxis.tickDirection = CPTSignPositive;不在我使用的coreplot版本中工作。需要一個小修改,yAxis.tickDirection = CPSignPositive;謝謝 – Mithun

+0

我不能讓它工作,如果你不介意,請你修改代碼?我是新來的,請幫助我。 – Mithun

+0

有人請幫助我,我一直在這工作最後3天,請。 – Mithun