如何使用 coreplot 实时绘制图表?

发布于 2024-11-17 15:32:40 字数 8151 浏览 2 评论 0原文

我正在尝试使用 coreplot 在图表(CPScatterPlot)上绘制声音的分贝值。但问题是我得到的图表有一条垂直于 Y 轴的线,并且它相对于分贝值的变化在 Y 轴上上下移动。我需要绘制这样的图表。 在此处输入图像描述

这是我的代码: `

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

I'm trying to plot the decibel values of sound on a graph(CPScatterPlot) using coreplot. But the problem is I'm getting the graph with a line that is perpendicular for Y axis, and it's moving up and down on the Y axis with respect to the changes in the decibel values. I need to plot a graph like this. enter image description here

here is my code:
`

    -(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; 
}

So, what should I do to get a graph as in the figure above? Please help me, I'm new on here.

And one more, as you can in the above picture, the Y axis labels are placed inside the plot area, how it can be done?

Here is my entire code, please suggest the modifications:

#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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

堇年纸鸢 2024-11-24 15:32:40

看起来您对每个数据点都使用相同的 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 数组中删除相应的点。

It looks like you're using the same peakVal for every data point. Check the -generateDataSamples method and make sure you're storing the correct values in the samples array. If you already have the data in an array, you can skip that method completely and just do the lookup by index in -numberForPlot:field:recordIndex:.

Also, check the xRange and yRange on the plot space to make sure they fit your data. Remember that plot ranges are like NSRange—they are created using a starting location and length, not start and end values.

To move the labels to the right side of the y-axis, use yAxis.tickDirection = CPTSignPositive;.

Edit in response to the comments

Don't call -generateDataSamples every time you get new data. Instead, add the new value to the samples array. Don't forget to initialize the array before using it for the first time.

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

Once the data is in the array, tell Core Plot to load only the new point. This will be faster than reloading all of the data every time you update.

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

You can use the CPTPlot method -deleteDataInIndexRange: to remove old data points if you don't need to keep all of the history in the graph. Don't forget to remove the corresponding point from the samples array also.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文