问题
I'm currently trying to use the core-plot library to graph some data I get via JSON. I'm trying to plot two graphs on the same chart but am unable to achieve this. When I simply plot just one chart, it works correctly.
Below is my scatter plot code using the core-plot library.
#pragma mark -
#pragma mark Plot construction methods
- (void)constructScatterPlot
{
NSMutableArray *appleContentArray = [NSMutableArray arrayWithCapacity:270];
NSMutableArray *googleContentArray = [NSMutableArray arrayWithCapacity:270];
NSData *stocks = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://d1sz0kydzogekx.cloudfront.net/stocks.txt"]];
NSInputStream *stockStream = [[NSInputStream alloc] initWithData:stocks];
[stockStream open];
NSUInteger i;
i = 1;
if (stockStream) {
NSError *parseError = nil;
id jsonObject = [NSJSONSerialization JSONObjectWithStream:stockStream options:NSJSONReadingAllowFragments error:&parseError];
if ([jsonObject respondsToSelector:@selector(objectForKey:)]) {
for (NSDictionary *stock in [jsonObject objectForKey:@"stocks"]) {
if ([[stock objectForKey:@"stock"] isEqualToString:@"AAPL"]){
id x = [NSNumber numberWithInt:i];
id y = [stock objectForKey:@"close"];
[appleContentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, @"x", y, @"y", nil]];
}
if ([[stock objectForKey:@"stock"] isEqualToString:@"GOOG"]){
id x = [NSNumber numberWithInt:i];
id y = [stock objectForKey:@"close"];
[googleContentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, @"x", y, @"y", nil]];
}
i++;
}
}
} else {
NSLog(@"Failed to open stream.");
}
// Create graph from theme
graph = [[CPTXYGraph alloc] initWithFrame:CGRectZero];
CPTTheme *theme = [CPTTheme themeNamed:kCPTPlainBlackTheme];
[graph applyTheme:theme];
scatterPlotView.hostedGraph = graph;
graph.paddingLeft = 0;
graph.paddingTop = 0.0;
graph.paddingRight = 0;
graph.paddingBottom = 0;
// Setup plot space
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(-20.0) length:CPTDecimalFromFloat(260.0)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(150.0) length:CPTDecimalFromFloat(400.0)];
// Axes
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPTDecimalFromString(@"1000");
x.orthogonalCoordinateDecimal = CPTDecimalFromString(@"2");
x.minorTicksPerInterval = 2;
NSArray *exclusionRanges = [NSArray arrayWithObjects:
[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(1.99) length:CPTDecimalFromFloat(0.02)],
[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.99) length:CPTDecimalFromFloat(0.02)],
[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(2.99) length:CPTDecimalFromFloat(0.02)],
nil];
x.labelExclusionRanges = exclusionRanges;
CPTXYAxis *y = axisSet.yAxis;
y.majorIntervalLength = CPTDecimalFromString(@"50");
y.orthogonalCoordinateDecimal = CPTDecimalFromString(@"2");
y.minorTicksPerInterval = 2;
exclusionRanges = [NSArray arrayWithObjects:
[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(1.99) length:CPTDecimalFromFloat(0.02)],
[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.99) length:CPTDecimalFromFloat(0.02)],
[CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(3.99) length:CPTDecimalFromFloat(0.02)],
nil];
y.labelExclusionRanges = exclusionRanges;
// Create a green Apple plot area
CPTScatterPlot *appleLinePlot = [[[CPTScatterPlot alloc] init] autorelease];
appleLinePlot.identifier = @"Green Plot";
CPTMutableLineStyle *appleLineStyle = [[appleLinePlot.dataLineStyle mutableCopy] autorelease];
appleLineStyle.lineWidth = 2.0;
appleLineStyle.lineColor = [CPTColor greenColor];
appleLinePlot.dataLineStyle = appleLineStyle;
appleLinePlot.opacity = 0.0f;
appleLinePlot.cachePrecision = CPTPlotCachePrecisionDecimal;
// Create a red Google plot area
CPTScatterPlot *googleLinePlot = [[[CPTScatterPlot alloc] init] autorelease];
googleLinePlot.identifier = @"Red Plot";
CPTMutableLineStyle *googleLineStyle = [[googleLinePlot.dataLineStyle mutableCopy] autorelease];
googleLineStyle.lineWidth = 2.0;
googleLineStyle.lineColor = [CPTColor redColor];
googleLinePlot.dataLineStyle = googleLineStyle;
// Animate in the new plot
CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeInAnimation.duration = 0.0f;
fadeInAnimation.removedOnCompletion = NO;
fadeInAnimation.fillMode = kCAFillModeForwards;
fadeInAnimation.toValue = [NSNumber numberWithFloat:1.0];
[appleLinePlot addAnimation:fadeInAnimation forKey:@"animateOpacity"];
[googleLinePlot addAnimation:fadeInAnimation forKey:@"animateOpacity"];
appleLinePlot.cachePrecision = CPTPlotCachePrecisionDecimal;
googleLinePlot.cachePrecision = CPTPlotCachePrecisionDecimal;
appleLinePlot.dataSource = self;
self.dataForPlot = appleContentArray;
[graph addPlot:appleLinePlot];
googleLinePlot.dataSource = self;
self.dataForPlot = googleContentArray;
[graph addPlot:googleLinePlot];
}
#pragma mark -
#pragma mark CPTBarPlot delegate method
-(void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index
{
NSLog(@"barWasSelectedAtRecordIndex %d", index);
}
#pragma mark -
#pragma mark Plot Data Source Methods
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
return [dataForPlot count];
}
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
NSDecimalNumber *num = nil;
num = [[dataForPlot objectAtIndex:index] valueForKey:(fieldEnum == CPTScatterPlotFieldX ? @"x" : @"y")];
if ( [(NSString *)plot.identifier isEqualToString:@"Green Plot"] ) {
if ( fieldEnum == CPTScatterPlotFieldX ) {
num = (NSDecimalNumber *)[NSDecimalNumber numberWithDouble:[num doubleValue]];
}
if ( fieldEnum == CPTScatterPlotFieldY ) {
num = (NSDecimalNumber *)[NSDecimalNumber numberWithDouble:[num doubleValue]];
}
}
if ( [(NSString *)plot.identifier isEqualToString:@"Red Plot"] ) {
if ( fieldEnum == CPTScatterPlotFieldX ) {
num = (NSDecimalNumber *)[NSDecimalNumber numberWithDouble:[num doubleValue]];
}
}
return num;
}
回答1:
Here are a few things that jumped out at me in your code:
The plot data needs to be available for the datasource. The easiest way would be to store the two content arrays in instance variables so they are visible throughout the class rather than in local variables that go away when the
-constructScatterPlot
method is finished.Do both plots always have the same number of plot points? If not, check the plot's identifier in
-numberOfRecordsForPlot:
and return the correct count for each one.-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot { if ( [(NSString *)plot.identifier isEqualToString:@"Green Plot"] ) { return appleContentArray.count; } else if ( [(NSString *)plot.identifier isEqualToString:@"Red Plot"] ) { return googleContentArray.count; } return 0; }
Your datasource could be greatly simplified (my example uses your original data structure):
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index { NSArray *contentArray = nil; if ( [(NSString *)plot.identifier isEqualToString:@"Green Plot"] ) { contentArray = appleContentArray; } else if ( [(NSString *)plot.identifier isEqualToString:@"Red Plot"] ) { contentArray = googleContentArray; } return [[contentArray objectAtIndex:index] valueForKey:(fieldEnum == CPTScatterPlotFieldX ? @"x" : @"y")]; }
Do your content arrays contain the expected values? Do you really need to store the index? Unless you need that for something else, I would simply store the close value in the content array and forget about the dictionary structure. In this case the datasource method becomes:
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index { NSNumber *num = nil; switch ( fieldEnum ) { case CPTScatterPlotFieldX: num = [NSNumber numberWithUnsignedInteger:index]; break; case CPTScatterPlotFieldY: if ( [(NSString *)plot.identifier isEqualToString:@"Green Plot"] ) { num = [appleContentArray objectAtIndex:index]; } else if ( [(NSString *)plot.identifier isEqualToString:@"Red Plot"] ) { num = [googleContentArray objectAtIndex:index]; } break; } return num; }
来源:https://stackoverflow.com/questions/9013197/core-plot-unable-to-plot-two-graphs