I am working with the core-plot framework to create a bar graph with a legend. It all works except that the legend is duplicating the the columns in each section of the bar graph (Please see attached screen shot).
I have looked through the core-plot class reference and was not able to find anything to fix this problem. I have tried to set the CPTLegend properties numberOfColumns to 1 and the numberOfRows to 3 and that made the legend display the appropriate amount of items in the legend, but the data it was displaying was not correct.
Below is the code I'm using to build the bar graph. Do you all have any suggestions how I can fix this issue? I am assuming this is not so much a bug with core-plot but a limitation of the legend and am hoping there is a workaround.
// Create barChart from theme
barChart = [[CPTXYGraph alloc] initWithFrame:CGRectZero];
CPTTheme *theme = [CPTTheme themeNamed:kCPTDarkGradientTheme];
[barChart applyTheme:theme];
chartView.hostedGraph = barChart;
barChart.plotAreaFrame.masksToBorder = NO;
barChart.paddingLeft = 60.0;
barChart.paddingTop = 10.0;
barChart.paddingRight = 0.0;
barChart.paddingBottom = 30.0;
//find max y
int maxY = 0;
NSMutableArray *maxDrillDownData = [chartData.drillDownData objectForKey:DRILLDOWN_EQUIPMENT_ALL_TYPE];
for (NSMutableArray *dataArray in maxDrillDownData) {
maxY = dataArray.count>maxY?dataArray.count:maxY;
}
//add buffer
maxY = maxY+100;
// Add plot space for horizontal bar charts
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)barChart.defaultPlotSpace;
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromInt(maxY)];
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(3.25)];
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)barChart.axisSet;
CPTXYAxis *x = axisSet.xAxis;
x.axisLineStyle = nil;
x.majorTickLineStyle = nil;
x.minorTickLineStyle = nil;
x.majorIntervalLength = CPTDecimalFromString(#"1");
x.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0");
x.titleLocation = CPTDecimalFromFloat(7.5f);
x.titleOffset = 55.0f;
x.labelOffset = 2.0;
// Define some custom labels for the data elements
x.labelRotation = M_PI/4;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
NSArray *customTickLocations = [NSArray arrayWithObjects:[NSDecimalNumber numberWithFloat:0.5], [NSDecimalNumber numberWithFloat:1.5], [NSDecimalNumber numberWithFloat:2.5], nil];
NSArray *xAxisLabels = (NSMutableArray *)[chartData.labels objectForKey:LABELS_EQUIPMENT_TYPE];
NSUInteger labelLocation = 0;
NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:[xAxisLabels count]];
for (NSNumber *tickLocation in customTickLocations) {
CPTAxisLabel *newLabel = [[CPTAxisLabel alloc] initWithText: [xAxisLabels objectAtIndex:labelLocation++] textStyle:x.labelTextStyle];
newLabel.tickLocation = [tickLocation decimalValue];
newLabel.offset = x.labelOffset;
[customLabels addObject:newLabel];
//[newLabel release];
}
x.axisLabels = [NSSet setWithArray:customLabels];
CPTXYAxis *y = axisSet.yAxis;
y.axisLineStyle = nil;
y.majorTickLineStyle = nil;
y.minorTickLineStyle = nil;
y.majorIntervalLength = CPTDecimalFromString(#"50");
y.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0");
y.title = (NSString *)[chartData.labels objectForKey:LABELS_Y_AXIS];
y.titleOffset = 45.0f;
y.titleLocation = CPTDecimalFromFloat(150.0f);
//identifiers
NSMutableArray *identifiers = (NSMutableArray *)[chartData.identifiers objectForKey:IDENTIFIER_EQUIPMENT_TYPE];
// First bar plot
CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor darkGrayColor] horizontalBars:NO];
barPlot.baseValue = CPTDecimalFromString(#"0");
barPlot.dataSource = self;
barPlot.barOffset = CPTDecimalFromFloat(-0.6f);
barPlot.barWidth = CPTDecimalFromFloat(.5);
barPlot.delegate = self;
barPlot.identifier = (NSString *)[identifiers objectAtIndex:0];
[barChart addPlot:barPlot toPlotSpace:plotSpace];
NSLog(#"barPlot.identifier: %#", barPlot.identifier);
// Second bar plot
barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor blueColor] horizontalBars:NO];
barPlot.dataSource = self;
barPlot.barOffset = CPTDecimalFromFloat(-0.4f);
barPlot.barWidth = CPTDecimalFromFloat(.5);
barPlot.baseValue = CPTDecimalFromString(#"0");
barPlot.identifier = (NSString *)[identifiers objectAtIndex:1];
barPlot.delegate = self;
[barChart addPlot:barPlot toPlotSpace:plotSpace];
NSLog(#"barPlot.identifier: %#", barPlot.identifier);
//third bar plot
barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor redColor] horizontalBars:NO];
barPlot.dataSource = self;
barPlot.barOffset = CPTDecimalFromFloat(-0.2f);
barPlot.barWidth = CPTDecimalFromFloat(.5);
barPlot.baseValue = CPTDecimalFromString(#"0");
barPlot.identifier = (NSString *)[identifiers objectAtIndex:2];
barPlot.delegate = self;
[barChart addPlot:barPlot toPlotSpace:plotSpace];
NSLog(#"barPlot.identifier: %#", barPlot.identifier);
// Add legend
CPTLegend *theLegend = [CPTLegend legendWithGraph:barChart];
theLegend.numberOfColumns = 3;
theLegend.numberOfRows = 1;
theLegend.fill = [CPTFill fillWithColor:[CPTColor whiteColor]];
theLegend.borderLineStyle = [CPTLineStyle lineStyle];
theLegend.cornerRadius = 5.0;
barChart.legend = theLegend;
barChart.legendAnchor = CPTRectAnchorTopRight;
barChart.legendDisplacement = CGPointMake(-10.0f, -20.0f);
Thanks for the help!
Make sure neither of the following methods are implemented in your plot datasource:
-legendTitleForBarPlot:recordIndex:
-barFillForBarPlot:recordIndex:
If either of these methods exist, the plot creates a legend entry for each bar rather than using a single legend entry for the whole plot.
I know this is a very old question, but the provided answers didn't help me in any way. So i looked into it and tried to figure it out. In my opinion the best solution is to only add one plot to your legend instead of adding the graph. Adding the graph adds all plots associated to your graph to the legend.
CPTLegend *theLegend = [CPTLegend legendWithGraph:barChart];
replace with
NSMutableArray *legendPlots =[[NSMutableArray alloc] init];
[legendPlots addObject:barPlot];
CPTLegend *theLegend = [CPTLegend legendWithPlots:legendPlots];
I had the same problem with multiple Pie charts in one Graph. This resolved the problem for me.
Related
I am developing a project using Core-Plot with Objective-C. The client asks to create a line chart (using Scatter Plot for this) where plots the number of ocurrencies x the time.
Well, after study for almost a week, this isn't working. My dots aren't connected and I don't know why.
This blue line should've been connected, since it is one plot.
Here is my code:
-(void)renderInLayer:(CPTGraphHostingView *)layerHostingView withTheme:(CPTTheme *)theme animated:(BOOL)animated{
CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:bounds];
[self addGraph:graph toHostingView:layerHostingView];
[self applyTheme:theme toGraph:graph withDefault:[CPTTheme themeNamed:kCPTDarkGradientTheme]];
graph.paddingTop = 20.0;
graph.paddingRight = 20.0;
graph.paddingLeft = 20.0;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
plotSpace.delegate = self;
CPTMutableLineStyle *axesLineStyle = [CPTMutableLineStyle lineStyle];
axesLineStyle.lineWidth = 1.0f;
axesLineStyle.miterLimit = 1.0f;
axesLineStyle.lineColor = [CPTColor grayColor];
CPTTextStyle *labelTextStyle = [CPTTextStyle textStyleWithAttributes:#{ NSForegroundColorAttributeName: BoardGraphValueColor, NSFontAttributeName: BoardGraphValueFont}];
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
NSNumberFormatter * axisFormat = [[NSNumberFormatter alloc] init];
[axisFormat setNumberStyle:NSNumberFormatterNoStyle];
CPTXYAxis *x = axisSet.xAxis;{
x.visibleRange = [CPTPlotRange plotRangeWithLocation:#(-1.0) length:#(100)];
x.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
x.majorIntervalLength = #2;
x.minorTicksPerInterval = 1;
x.majorTickLineStyle = axesLineStyle;
x.minorTickLineStyle = axesLineStyle;
x.axisLineStyle = axesLineStyle;
x.plotSpace = plotSpace;
x.labelTextStyle = labelTextStyle;
x.labelFormatter = axisFormat;
x.labelOffset = 5.0;
}
CPTXYAxis *y = axisSet.yAxis;{
y.visibleRange = [CPTPlotRange plotRangeWithLocation:#(-1.0) length:#(200)];
y.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
y.majorIntervalLength = #30;
y.minorTicksPerInterval = 6;
y.majorTickLineStyle = axesLineStyle;
y.minorTickLineStyle = axesLineStyle;
y.axisLineStyle = axesLineStyle;
y.plotSpace = plotSpace;
y.labelTextStyle = labelTextStyle;
y.labelFormatter = axisFormat;
y.labelOffset = 5.0;
}
graph.axisSet.axes = #[x, y];
CPTMutableLineStyle *lineStyle = [[CPTMutableLineStyle alloc] init];
lineStyle.lineWidth = 2.0;
CPTScatterPlot *scatterLinePlot = [[CPTScatterPlot alloc] init];
scatterLinePlot.areaBaseValue = #(0.0);
scatterLinePlot.identifier = #(1);
scatterLinePlot.title = #"Title";
lineStyle.lineColor = [CPTColor blueColor];
scatterLinePlot.dataLineStyle = lineStyle;
scatterLinePlot.histogramOption = self.histogramOption;
scatterLinePlot.areaBaseValue = #(0);
scatterLinePlot.delegate = self;
scatterLinePlot.plotSymbolMarginForHitDetection = 5.0;
scatterLinePlot.dataSource = self;
[graph addPlot:scatterLinePlot];
CPTPlotRange *globalYRange = [CPTPlotRange plotRangeWithLocation:#0.0
length:#12.0];
plotSpace.globalYRange = globalYRange;
[plotSpace scaleToFitEntirePlots:[graph allPlots]];}
This is the code for create just one plot, but I need to create six. I did a loop but it is working that way too.
Here's the datasource:
-(NSUInteger)numberOfRecordsForPlot:(nonnull CPTPlot *)plot{
return [self.plotData objectAtIndex:0].count;}
-(NSNumber *)numberForPlot:(nonnull CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index{
NSNumber *num = nil;
NSString *key;
NSArray *currentDataPoint;
NSString *plotIdentifier = (NSString *)plot.identifier;
if ([plotIdentifier isEqual:#(1)]){
currentDataPoint = [self.plotData objectAtIndex:0];
} else if ([plotIdentifier isEqual:#(2)]){
currentDataPoint = [self.plotData objectAtIndex:1];
} else if ([plotIdentifier isEqual:#(3)]){
currentDataPoint = [self.plotData objectAtIndex:2];
} else if ([plotIdentifier isEqual:#(4)]){
currentDataPoint = [self.plotData objectAtIndex:3];
} else if ([plotIdentifier isEqual:#(5)]){
currentDataPoint = [self.plotData objectAtIndex:4];
} else if ([plotIdentifier isEqual:#(6)]){
currentDataPoint = [self.plotData objectAtIndex:5];
}
if (fieldEnum == CPTScatterPlotFieldX) {
return #(index);
} else if (fieldEnum == CPTScatterPlotFieldY) {
key = #"count";
int number = [[[currentDataPoint objectAtIndex:index] valueForKey:key] intValue];
NSLog(#"Y value for index %lu is %d", index, number);
num = [[currentDataPoint objectAtIndex:index] valueForKey:key];
return num;}
return num;
}
What am I doing wrong?
PS: Well, another bug is the color of the bar chart. Each of this should have a different color, but it doesn't work too. The colors provided is that for the legends.
Thanks in advance.
To change the bar color for each bar, implement the -barFillForBarPlot:recordIndex: method in the datasource and return the correct fill for each index. You can also set the border line style for each bar (e.g., to use a different color) with the -barLineStyleForBarPlot:recordIndex: datasource method.
It looks like the data line is getting clipped outside the visible area. Make sure the plot data is available from the datasource when you call -scaleToFitEntirePlots:.
I have added CPTSCatterPlot and CPTBarPlot for two CPTPlotSpaces in one graph.I have worten a method to reloadData for the graph but not working so correctly.I want two of graph reload the y-axis labels after I have called the ScaleToFit method. Here is my Code:
plotSpace1 = (CPTXYPlotSpace*)graph.defaultPlotSpace;
barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor colorWithCGColor:TJCOLOR1.CGColor] horizontalBars:_isHorizontal];
barPlot.identifier = #"Bar";
barPlot.delegate = self;
barPlot.dataSource = self;
[graph addPlot:barPlot toPlotSpace:plotSpace1];
[plotSpace1 scaleToFitPlots:[NSArray arrayWithObject:barPlot]];
plotSpace2 = [[CPTXYPlotSpace alloc]init];
[graph addPlotSpace:plotSpace2];
scatterPlot = [[CPTScatterPlot alloc]init];
scatterPlot.identifier = #"Scatter";
scatterPlot.delegate = self;
scatterPlot.dataSource = self;
[graph addPlot:scatterPlot toPlotSpace:plotSpace2];
[plotSpace2 scaleToFitPlots:[NSArray arrayWithObject:scatterPlot]];
CPTXYAxis *x = axisSet.xAxis;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
x.tickDirection = CPTSignNegative;
x.labelOffset = -20.0f;
x.labelTextStyle = axisTextStyle;
[self xlabelS:x];
x.hidden = YES;
// x.axisConstraints = [CPTConstraints constraintWithLowerOffset:-3.0];
y = [[CPTXYAxis alloc]initWithFrame:CGRectZero];
y.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
y.plotSpace = plotSpace1;
y.coordinate = CPTCoordinateY;
y.orthogonalCoordinateDecimal = CPTDecimalFromFloat(0);
y.labelExclusionRanges = nil;
y.labelTextStyle = axisTextStyle;
y.orthogonalCoordinateDecimal = CPTDecimalFromCGFloat(-0.5);
y.hidden = YES;
y2 = [[CPTXYAxis alloc]initWithFrame:CGRectZero];
y2.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
y2.plotSpace = plotSpace2;
y2.coordinate = CPTCoordinateY;
y2.orthogonalCoordinateDecimal = CPTDecimalFromFloat([_titleArray count]);
y2.titleLocation = CPTDecimalFromInt(0);
y2.labelExclusionRanges = nil;
y2.titleOffset = -10.0f;
y2.labelOffset = -40.0f;
y2.labelTextStyle = axisTextStyle;
y2.hidden = YES;
y2.majorGridLineStyle = gridLineStyle;
NSArray *axies = [NSArray arrayWithObjects:x,y,y2, nil];
// [axies addObject:y2];
graph.axisSet.axes = axies;
- (void)reloadData
{
[graph.plotAreaFrame.plotArea removeAllAnnotations];
[graph reloadData];
[plotSpace1 scaleToFitPlots:[NSArray arrayWithObject:barPlot]];
[plotSpace2 scaleToFitPlots:[NSArray arrayWithObject:scatterPlot]];
CPTXYAxisSet *axisSet = (CPTXYAxisSet*)hostingView.hostedGraph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
[self xlabelS:x];
}
- (void)xlabelS:(CPTXYAxis *)x
{
NSMutableSet *xLabels = [NSMutableSet set];
NSMutableSet *xLocations = [NSMutableSet set];
NSInteger i = 0;
for (NSString *date in _titleArray) {
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:date textStyle:x.labelTextStyle];
CGFloat location = i++;
label.tickLocation = CPTDecimalAdd(CPTDecimalFromCGFloat(location), barPlot.barWidth);
label.offset = x.majorTickLength;
if (label) {
[xLabels addObject:label];
[xLocations addObject:[NSNumber numberWithFloat:location]];
}
}
// x.labelingOrigin = CPTDecimalFromInt(1);
x.axisLabels = xLabels;
y.plotSpace = plotSpace1;
y.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
y2.orthogonalCoordinateDecimal = CPTDecimalFromFloat([_titleArray count] );
}
Only the right y-axies relabeled correctly.Was anywhere I code wrong?Help me please!
The y-axis is tied to plotSpace1. It is independent of the other plot space. No matter how plotSpace2 changes, it won't affect the y-axis. If you want to see both scales, you'll need to add another y-axis to plotSpace2.
I am using CorePlot to plot average prices over few months.
This is what I am trying to achieve
I have been able to produce this
So clearly graph does not look plotted correctly.
Heres the code I am using in my viewController to set up the graph and plot it.
- (void)viewDidLoad {
[super viewDidLoad];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
NSDictionary *jsonDataDictionary;
// Can be done async with loading timers
NSURL *url = [NSURL URLWithString:
#"http://greyloft.com/analytics/query.php?project=PARC%20VISTA&area=1200&months=5"];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if (urlData) {
NSError *error=nil;
jsonDataDictionary = [NSJSONSerialization JSONObjectWithData:urlData
options:kNilOptions
error:&error];
// We receive the order of the months in reverse order in the json i.e. most recent first.
// e.g. Feb-15, Jan-15, Dec-14 and so on
// We need to show plotting in reverse order on x axis effectively needing to reverse the array.
NSArray *reverseAvgRentals = [[jsonDataDictionary objectForKey:#"results"] objectForKey:#"average"];
_averageRentals = [[reverseAvgRentals reverseObjectEnumerator] allObjects];
_transactions = [[jsonDataDictionary objectForKey:#"results"] objectForKey:#"transactions"];
_months = [[NSMutableArray alloc] init];
_rentals = [[NSMutableArray alloc] init];
for (NSDictionary *rental in _averageRentals) {
[_months addObject:[rental objectForKey:#"month"]];
[_rentals addObject:[rental objectForKey:#"average"]];
}
// KVC to find min/max in an array
_minRental = _maxRental = 0;
_minRental = [[_rentals valueForKeyPath:#"#min.intValue"] intValue];
_maxRental = [[_rentals valueForKeyPath:#"#max.intValue"] intValue];
}}
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot {
return [_months count];
}
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
NSNumber *num = [[NSNumber alloc] init];
if (fieldEnum == CPTScatterPlotFieldX) {
// Simply return index as we want to return number for each month
num = [NSNumber numberWithInt:index+1];
} else {
num = [[_averageRentals objectAtIndex:index] valueForKey:#"average"];
}
return num;
}
-(void)initPlot {
[self configureHost];
[self configureGraph];
[self configurePlots];
[self configureAxes];
}
-(void)configureHost {
self.graphHostView = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:self.graphContainerView.bounds];
self.graphHostView.allowPinchScaling = YES;
[self.graphContainerView addSubview:self.graphHostView];
}
-(void)configureGraph {
// Create the graph
CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:self.graphHostView.bounds];
[graph applyTheme:nil];
self.graphHostView.hostedGraph = graph;
[graph.plotAreaFrame setPaddingLeft:30.0f];
[graph.plotAreaFrame setPaddingBottom:30.0f];
[graph.plotAreaFrame setPaddingTop:10.0f];
}
-(void)configurePlots {
// Get graph and plot space
CPTGraph *graph = self.graphHostView.hostedGraph;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
// 2 - Create the plot
CPTScatterPlot *rentPlot = [[CPTScatterPlot alloc] init];
rentPlot.dataSource = self;
rentPlot.identifier = #"Rent";
[graph addPlot:rentPlot toPlotSpace:plotSpace];
// 3 - Set up plot space
CGFloat xMin = 0.0f;
CGFloat xMax = [_months count];
CGFloat yMin = _minRental;
CGFloat yMax = _maxRental;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(xMin)
length:CPTDecimalFromFloat(xMax)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(yMin)
length:CPTDecimalFromFloat(yMax)];
[plotSpace scaleToFitPlots:[graph allPlotSpaces]];
CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
CPTMutablePlotRange *yRange = [plotSpace.yRange mutableCopy];
[xRange expandRangeByFactor:CPTDecimalFromDouble(1.4)];
[yRange expandRangeByFactor:CPTDecimalFromDouble(3.0)];
plotSpace.xRange = xRange;
plotSpace.yRange = yRange;
// 4 - Create styles and symbols
//CPTColor *orangeColor = [CPTColor colorWithComponentRed:239.0f green:92.0f blue:94.0f alpha:1.0f];
CPTColor *orangeColor = [CPTColor orangeColor];
CPTMutableLineStyle *lineStyle = [rentPlot.dataLineStyle mutableCopy];
lineStyle.lineWidth = 2.5f;
lineStyle.lineColor = orangeColor;
rentPlot.dataLineStyle = lineStyle;
CPTMutableLineStyle *symbolLineStyle = [CPTMutableLineStyle lineStyle];
symbolLineStyle.lineWidth = 2.5f;
symbolLineStyle.lineColor = orangeColor;
CPTPlotSymbol *symbol = [CPTPlotSymbol ellipsePlotSymbol];
symbol.fill = [CPTFill fillWithColor:[CPTColor colorWithComponentRed:248.0f
green:244.0f
blue:251.0f
alpha:1.0f]];
symbol.lineStyle = symbolLineStyle;
symbol.size = CGSizeMake(11.0f, 11.0f);
rentPlot.plotSymbol = symbol;
}
-(void)configureAxes {
// 1 - Create styles
CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
axisLineStyle.lineWidth = 0.0f;
CPTMutableTextStyle *axisTextStyle = [[CPTMutableTextStyle alloc] init];
axisTextStyle.color = [CPTColor grayColor];
axisTextStyle.fontName = #"Ubuntu-Bold";
axisTextStyle.fontSize = 14.0f;
CPTMutableLineStyle *majorGridLineStyle = [CPTMutableLineStyle lineStyle];
majorGridLineStyle.lineWidth = 0.75;
majorGridLineStyle.lineColor = [CPTColor lightGrayColor];
// 2 - Get axis set
CPTXYAxisSet *axisSet = (CPTXYAxisSet *) self.graphHostView.hostedGraph.axisSet;
// 3 - Configure x-axis
CPTXYAxis *x = axisSet.xAxis;
x.axisLineStyle = axisLineStyle;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
x.majorIntervalLength = CPTDecimalFromDouble(1.0);
x.orthogonalCoordinateDecimal = CPTDecimalFromDouble(0.0);
x.preferredNumberOfMajorTicks = 6;
x.labelOffset = 50.0f;
x.labelTextStyle = axisTextStyle;
x.majorTickLineStyle = nil;
x.minorTickLineStyle = nil;
NSMutableSet *xLabelSet = [NSMutableSet setWithCapacity:[_months count]];
NSMutableSet *xLocationSet = [NSMutableSet setWithCapacity:[_months count]];
int location = 0;
for (NSString *month in _months) {
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:month textStyle:x.labelTextStyle];
label.tickLocation = CPTDecimalFromInt(location++);
[xLabelSet addObject:label];
[xLocationSet addObject:[NSNumber numberWithInteger:location]];
}
x.axisLabels = xLabelSet;
x.majorTickLocations = xLocationSet;
// 4 - Configure y-axis
CPTXYAxis *y = axisSet.yAxis;
y.axisLineStyle = axisLineStyle;
y.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
y.orthogonalCoordinateDecimal = CPTDecimalFromDouble(-0.1);
y.preferredNumberOfMajorTicks = 6;
y.majorGridLineStyle = majorGridLineStyle;
y.labelTextStyle = axisTextStyle;
y.majorTickLineStyle = nil;
y.minorTickLineStyle = nil;
}
I am not getting the concept of how CorePlot will take the data provided and turn it into the required set.
Any suggestions?
As noted in my comment above, plot ranges take a location and length like NSRange. You can use the min value for the location and max - min for the length.
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromCGFloat(yMin)
length:CPTDecimalFromCGFloat(yMax - yMin)];
For your example of a range covering 1,500 to 4,000, use 1,500 for the location and 2,500 (4,000 - 1,500) for the length.
I am making a scatter plot app in Core Plot 1.4. I am new to Objective-C and Core Plot, so sorry for asking some basic questions. Here is some code I wrote by imitating the sample program(CPTTestApp-iphone).
- (void)viewDidLoad
{
[super viewDidLoad];
...
// Add some initial data
NSMutableArray *contentArray = [NSMutableArray arrayWithCapacity:100];
int i;
for ( i = 0; i < 60; i++ ) {
id x = [NSNumber numberWithFloat:1 + i * 0.05];
id y = [NSNumber numberWithInt:1]; //[NSNumber numberWithFloat:1.2 * rand() / (float)RAND_MAX + 1.2];
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, #"x", y, #"y", nil]];
}
dataForPlot = contentArray;
// Create graph from theme
graph = [[CPTXYGraph alloc] initWithFrame:CGRectZero];
CPTTheme *theme = [CPTTheme themeNamed:kCPTDarkGradientTheme];
[graph applyTheme:theme];
CPTGraphHostingView *hostingView = [[CPTGraphHostingView alloc] init];
hostingView.collapsesLayers = NO; // Setting to YES reduces GPU memory usage, but can slow drawing/scrolling
hostingView.hostedGraph = graph;
[self setView:hostingView];
graph.paddingLeft = 0.0;
graph.paddingTop = 0.0;
graph.paddingRight = 0.0;
graph.paddingBottom = 30.0;
// Setup plot space
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
[plotSpace setXRange:[CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(0) length:CPTDecimalFromInteger(5)]];
[plotSpace setYRange:[CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(0) length:CPTDecimalFromInteger(7)]];
// Axes
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPTDecimalFromString(#"1");
x.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0");
x.minorTicksPerInterval = 5;
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(#"1");
y.minorTicksPerInterval = 5;
y.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0");
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;
y.delegate = self;
// Create a blue plot area
CPTScatterPlot *boundLinePlot = [[CPTScatterPlot alloc] init];
CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
lineStyle.miterLimit = 1.0f;
lineStyle.lineWidth = 3.0f;
lineStyle.lineColor = [CPTColor blueColor];
boundLinePlot.dataLineStyle = lineStyle;
boundLinePlot.identifier = #"Blue Plot";
boundLinePlot.dataSource = self;
[graph addPlot:boundLinePlot toPlotSpace:plotSpace];
// Do a blue gradient
CPTColor *areaColor1 = [CPTColor colorWithComponentRed:0.3 green:0.3 blue:1.0 alpha:0.8];
CPTGradient *areaGradient1 = [CPTGradient gradientWithBeginningColor:areaColor1 endingColor:[CPTColor clearColor]];
areaGradient1.angle = -90.0f;
CPTFill *areaGradientFill = [CPTFill fillWithGradient:areaGradient1];
boundLinePlot.areaFill = areaGradientFill;
boundLinePlot.areaBaseValue = [[NSDecimalNumber zero] decimalValue];
// interpolation
boundLinePlot.interpolation = CPTScatterPlotInterpolationCurved;
#ifdef PERFORMANCE_TEST
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(changePlotRange) userInfo:nil repeats:YES];
#endif
}
Now I have some questions.
From dataForPlot, a blue line with gradient must be rendered the height y=1, but after running this it was not shown. (I haven't adjust the range of x values in dataForPlot but a partial line should be rendered.)
How can I move the origin (0,0) to the middle of the screen?
Why do 1.0-3.0 in x-axis and 1.0, 2.0, 4.0 in y-axis disappear?
Can anyone help me figure these out? Thank you.
What data is being plotted? Please show the datasource methods.
The visible data ranges in the plot area are controlled by the plot space:
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(-5)
length:CPTDecimalFromInteger(10)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(-7)
length:CPTDecimalFromInteger(14)];
The labelExclusionRanges skips over any labels in the specified ranges. If you want to see all of the ticks and labels, don't set this property.
As mentioned in title, I have succesfully add CorePlot into my project and it works as expected. Except there are still axes label shown which I cannot remove or hide. This is my renderInLayer code,
-(void)renderInLayer:(CPTGraphHostingView *)layerHostingView withTheme:(CPTTheme *)theme animated:(BOOL)animated
{
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
CGRect bounds = layerHostingView.bounds;
#else
CGRect bounds = NSRectToCGRect(layerHostingView.bounds);
#endif
CPTGraph *graph = [[[CPTXYGraph alloc] initWithFrame:bounds] autorelease];
[self addGraph:graph toHostingView:layerHostingView];
graph.plotAreaFrame.paddingTop = 0.0;
graph.plotAreaFrame.paddingRight = 0.0;
graph.plotAreaFrame.paddingBottom = 0.0;
graph.plotAreaFrame.paddingLeft = 0.0;
graph.plotAreaFrame.masksToBorder = NO;
// Create the plot
CPTScatterPlot *dataSourceLinePlot = [[[CPTScatterPlot alloc] init] autorelease];
dataSourceLinePlot.identifier = kPlotIdentifier;
dataSourceLinePlot.cachePrecision = CPTPlotCachePrecisionDouble;
CPTMutableLineStyle *lineStyle = [[dataSourceLinePlot.dataLineStyle mutableCopy] autorelease];
lineStyle.lineWidth = 3.0;
lineStyle.lineColor = [CPTColor whiteColor];
dataSourceLinePlot.dataLineStyle = lineStyle;
dataSourceLinePlot.dataSource = self;
dataSourceLinePlot.interpolation = CPTScatterPlotInterpolationCurved;
[graph addPlot:dataSourceLinePlot];
// Plot space
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromUnsignedInteger(0) length:CPTDecimalFromUnsignedInteger(kMaxDataPoints - 2)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromUnsignedInteger(0) length:CPTDecimalFromUnsignedInteger(1)];
[dataTimer invalidate];
[dataTimer release];
if ( animated ) {
dataTimer = [[NSTimer timerWithTimeInterval:1.0 / kFrameRate
target:self
selector:#selector(newData:)
userInfo:nil
repeats:YES] retain];
[[NSRunLoop mainRunLoop] addTimer:dataTimer forMode:NSRunLoopCommonModes];
}
else {
dataTimer = nil;
}
}
And visual out with bad data,
EDIT
I have tried this but it didnt work,
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis *axis = axisSet.xAxis;
axis.hidden = YES;
for (CPTAxisLabel *axisLabel in axis.axisLabels) {
axisLabel.contentLayer.hidden = YES;
}
Ok so I have managed to find the answer my self. If anyone in future wants to remove just the label. Then please do this,
axis.labelingPolicy = CPTAxisLabelingPolicyNone;
If you want to remove the axis of graph completly, then.
graph.axisSet = nil;
Boom all gone, you have clear and nice looking graph now :)
You can simply hide all labels.
CPTAxis *axis = xAxis;
axis.hidden = YES;
for (CPTAxisLabel *axisLabel in axis.axisLabels) {
axisLabel.contentLayer.hidden = YES;
}
I am posting how I customized my xAxis labels:
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)_graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPTDecimalFromString(#"5");
x.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0");
x.minorTicksPerInterval = 4;
x.title = #"";
x.titleTextStyle = axisTitleStyle;
x.labelingPolicy = CPTAxisLabelingPolicyNone; //No labels provided; user sets labels and tick locations.
//x.majorTickLineStyle = axisLineStyle;
x.majorTickLength = 5.0f;
x.tickDirection = CPTSignNegative;
CPTMutableTextStyle *axisLabelStyle = [CPTMutableTextStyle textStyle];
axisLabelStyle.fontName = #"Helvetica Neue Thin";
axisLabelStyle.fontSize = 8.0f;
NSArray *lastThirtyDates = [self.analyticsDataController lastThirtyDays];
NSUInteger daysCount = 31;
NSMutableSet *xLabels = [NSMutableSet setWithCapacity:daysCount];
NSMutableSet *xLocations = [NSMutableSet setWithCapacity:daysCount];
NSMutableSet *xMinorLocations = [NSMutableSet setWithCapacity:daysCount];
for (//iterate over your data source for x values and create your custom labels) {
CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:#"" textStyle:axisLabelStyle];
CGFloat location = i;
label.tickLocation = CPTDecimalFromCGFloat(location);
label.offset = x.majorTickLength;
if (label) {
[xLabels addObject:label];
[xLocations addObject:[NSNumber numberWithFloat:location]];
}
}
x.axisLabels = xLabels;
x.majorTickLocations = xLocations;
x.minorTickLocations = xMinorLocations;