如何使用 coreplot 实时绘制图表?
我正在尝试使用 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.
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
看起来您对每个数据点都使用相同的
peakVal
。检查-generateDataSamples
方法并确保您在samples
数组中存储了正确的值。如果数组中已有数据,则可以完全跳过该方法,只需按-numberForPlot:field:recordIndex:
中的索引进行查找即可。另外,检查绘图空间上的
xRange
和yRange
以确保它们适合您的数据。请记住,绘图范围类似于 NSRange — 它们是使用起始位置和长度而不是起始值和结束值创建的。要将标签移动到 y 轴右侧,请使用 yAxis.tickDirection = CPTSignPositive;。
根据评论进行编辑
不要每次获取新数据时都调用
-generateDataSamples
。相反,请将新值添加到samples
数组中。不要忘记在第一次使用数组之前初始化它。数据进入数组后,告诉 Core Plot 仅加载新点。这比每次更新时重新加载所有数据要快。
如果您不需要保留图表中的所有历史记录,可以使用 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 thesamples
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
andyRange
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 thesamples
array. Don't forget to initialize the array before using it for the first time.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.
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 thesamples
array also.