Closed GoogleCodeExporter closed 9 years ago
The correct method signature is:
-(NSString *)legendTitleForBarPlot:(CPTBarPlot *)barPlot
recordIndex:(NSUInteger)index;
The Colored Bar Chart sample in the Plot Gallery app demonstrates how this
works. Compare your code to that example and post some more detail about your
code if you're still having problems.
Original comment by eskr...@mac.com
on 16 Mar 2012 at 9:39
I am using the right method signature and have studied the Colored Bar Chart
sample in the gallery before implementing it. However, it is not working in my
implementation even though all other data source methods and delegates are
called correctly.
Could you please check my code below, I have tried so many alternatives, but
cannot figure out the solution to my bug.
This is how I have implemented it:
1. I have subclassed CPTXYGraph (I do not know if this is generally a good idea
though...):
.h:
==
#import "CorePlot-CocoaTouch.h"
#import "CPTXYGraph.h"
#import "IBCompany+FinstatAccessors.h"
@interface BarLineChart : CPTXYGraph
@property (strong, nonatomic) IBCompany *company;
@property (strong, nonatomic) IBFinPeriod *finPeriod;
@property (strong, nonatomic) NSArray *barColors;
@property (strong, nonatomic) id <CPTPlotDataSource, CPTPlotSpaceDelegate,
CPTBarPlotDataSource, CPTBarPlotDelegate, CPTLegendDelegate,
CPTScatterPlotDelegate, CPTScatterPlotDataSource> delegate;
- (void)setupChart;
- (void)setAbsoluteValues:(NSArray*)absoluteValues
RelativeValues:(NSArray*)relativeValues
forCompany:(IBCompany*)company
forFiscalPeriods:(FiscalPeriodType)fiscalPeriodType;
@end
.m:
===
#import "BarLineChart.h"
@implementation BarLineChart
@synthesize company = _company;
@synthesize finPeriod = _finPeriod;
@synthesize barColors = _barColors;
@synthesize delegate = _delegate;
- (void)setupChart
{
if (!_barColors) _barColors = [[NSArray alloc] initWithObjects:
[CPTColor darkGrayColor], [CPTColor purpleColor], [CPTColor blueColor],[CPTColor cyanColor], nil];
CPTTheme *theme = [CPTTheme themeNamed:kCPTPlainWhiteTheme];
[self applyTheme:theme];
self.plotAreaFrame.masksToBorder = NO;
// Border
self.plotAreaFrame.borderLineStyle = nil;
self.plotAreaFrame.cornerRadius = 5.0f;
// Paddings
self.paddingLeft = 40.0;
self.paddingTop = 10.0;
self.paddingRight = 20.0;
self.paddingBottom = 10.0;
self.plotAreaFrame.paddingLeft = 10.0;
self.plotAreaFrame.paddingTop = 10.0;
self.plotAreaFrame.paddingRight = 20.0;
self.plotAreaFrame.paddingBottom = 40.0;
self.plotAreaFrame.backgroundColor = nil;
}
NSNumberFormatter *numberFormatter;
float numberDivisor = 1;
- (void)setAbsoluteValues:(NSArray*)absoluteValues
RelativeValues:(NSArray*)relativeValues
forCompany:(IBCompany*)company
forFiscalPeriods:(FiscalPeriodType)fiscalPeriodType;
{
// determine min und max dimensions of x and y-axis:
__block int minY = 0;
__block int maxY = 0;
[absoluteValues enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
minY = MIN(minY, [[company aggregateValueForCoa: (NSString*)obj
Aggregate: @"@min.item"
FiscalPeriodType: fiscalPeriodType] intValue]);
maxY = MAX(maxY, [[company aggregateValueForCoa: (NSString*)obj
Aggregate: @"@max.item"
FiscalPeriodType: fiscalPeriodType] intValue]);
}];
NSLog(@" minY: %i and maxY: %i", minY, maxY);
int yTotalLength = maxY + 1 - MIN(0, minY);
int xAxisLength;
if (fiscalPeriodType == kFiscalYear) xAxisLength = company.annualPeriods.count; else xAxisLength = company.interimPeriods.count;
// set absolute plot space to min and max vales:
CPTXYPlotSpace *absolutePlotSpace = (CPTXYPlotSpace *)self.defaultPlotSpace;
absolutePlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(MIN(0, minY)) length:CPTDecimalFromInt(yTotalLength)]; // plus 1 to compensate for rounding
absolutePlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat(xAxisLength + 0.5)];
self.defaultPlotSpace.delegate = self.delegate;
CPTXYPlotSpace *relativePlotSpace = [[CPTXYPlotSpace alloc] init];
//[relativePlotSpace scaleToFitPlots:[self allPlots]];
relativePlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(0)
length:CPTDecimalFromInt(1)]; // from 0% to 100%
relativePlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f)
length:CPTDecimalFromFloat(xAxisLength + 0.5)];
relativePlotSpace.delegate = self.delegate;
[self addPlotSpace:relativePlotSpace];
numberFormatter = [[NSNumberFormatter alloc]init];
NSString *numberUnit;
if (maxY > 10000) { //display as billions
numberDivisor = 0.001;
numberUnit = [[NSString alloc]initWithString:@" bn"];
}
else { // display as millions
numberDivisor = 1;
numberUnit = [[NSString alloc]initWithString:@" mn"];
}
[numberFormatter setMultiplier:[NSNumber numberWithFloat:numberDivisor]];
// Configure axes:
// Text styles
CPTMutableTextStyle *axisTitleTextStyle = [CPTMutableTextStyle textStyle];
axisTitleTextStyle.fontName = @"Helvetica-Bold";
axisTitleTextStyle.fontSize = 14.0;
axisTitleTextStyle.color = [CPTColor grayColor];
// Line styles
CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
axisLineStyle.lineWidth = 2.0;
axisLineStyle.lineCap = kCGLineCapRound;
axisLineStyle.lineColor = [CPTColor darkGrayColor];
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.axisSet;
CPTXYAxis *x = axisSet.xAxis;
x.axisLineStyle = axisLineStyle;
x.majorTickLineStyle = nil;
x.minorTickLineStyle = nil;
x.majorIntervalLength = CPTDecimalFromInt(1);
x.orthogonalCoordinateDecimal = CPTDecimalFromInt(0);
x.title = @"fiscal period ends";
x.titleLocation = CPTDecimalFromFloat(7.5f);
x.titleOffset = 10.0f;
CPTXYAxis *y = axisSet.yAxis;
y.coordinate = CPTCoordinateY;
y.axisLineStyle = axisLineStyle;
y.labelFormatter = numberFormatter;
y.labelingPolicy = CPTAxisLabelingPolicyEqualDivisions;
y.majorIntervalLength = CPTDecimalFromInt(2);
y.majorTickLength = 5;
y.majorTickLineStyle = axisLineStyle;
y.minorTickLength = 0;
y.minorTickLineStyle = axisLineStyle;
// y.minorTicksPerInterval = 1;
y.orthogonalCoordinateDecimal = CPTDecimalFromInt(0);
y.preferredNumberOfMajorTicks = 10 + 1;
y.tickDirection = CPTSignNegative;
y.titleTextStyle = axisTitleTextStyle;
y.title = (NSString*)[[company reportingCurrencyCode] stringByAppendingString:numberUnit];
y.titleOffset = -10.0f;
//y.titleLocation = CPTDecimalFromDouble(yTotalLength - 5.0f);
//y.titleRotation = 2 * M_PI;
//y.majorGridLineStyle = axisLineStyle;
NSNumberFormatter *percentageFormatter = [[NSNumberFormatter alloc] init];
[percentageFormatter setNumberStyle:NSNumberFormatterPercentStyle];
CPTXYAxis *y2 = [[CPTXYAxis alloc] init];
y2.axisLineStyle = axisLineStyle;
y2.coordinate = CPTCoordinateY;
y2.orthogonalCoordinateDecimal = CPTDecimalFromDouble(xAxisLength + 0.5);
y2.plotSpace = relativePlotSpace;
y2.separateLayers = NO;
y2.majorTickLineStyle = axisLineStyle;
y2.minorTicksPerInterval = 1;
y2.preferredNumberOfMajorTicks = 10 + 1;
y2.labelFormatter = percentageFormatter;
y2.labelingPolicy = CPTAxisLabelingPolicyEqualDivisions;
y2.tickDirection = CPTSignPositive;
//y2.title = @"%";
y2.titleTextStyle = axisTitleTextStyle;
y2.titleOffset = 0.0;
//y2.titleLocation = CPTDecimalFromDouble(1 + 0.1);
// Add the y2 axis to the axis set:
self.axisSet.axes = [NSArray arrayWithObjects:x, y, y2, nil];
NSMutableArray *barPlots = [[NSMutableArray alloc]init];
for (int i = 0; i <= [absoluteValues count] -1 ; i++) {
CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[self.barColors objectAtIndex: i] horizontalBars:NO];
barPlot.baseValue = CPTDecimalFromInt(0);
barPlot.barOffset = CPTDecimalFromFloat(0.00f);
barPlot.barWidth = CPTDecimalFromFloat(0.5f);
barPlot.barCornerRadius = 5;
barPlot.identifier = [absoluteValues objectAtIndex: i];
barPlot.dataSource = self.delegate;
barPlot.delegate = self.delegate;
[barPlots addObject:barPlot];
[self addPlot:barPlot toPlotSpace:absolutePlotSpace];
}
CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
for (int i = 0; i <= [relativeValues count] -1 ; i++) {
CPTScatterPlot *linePlot = [[CPTScatterPlot alloc]init];
linePlot.identifier = [relativeValues objectAtIndex: i];
lineStyle.lineWidth = 2.0;
lineStyle.lineColor = [CPTColor darkGrayColor];
linePlot.dataLineStyle = lineStyle;
linePlot.areaBaseValue = CPTDecimalFromInt(0);
linePlot.dataSource = self.delegate;
[self addPlot:linePlot toPlotSpace:relativePlotSpace];
}
// Add legend
CPTLegend *legend = [CPTLegend legendWithGraph:self];
legend.fill = [CPTFill fillWithColor:[CPTColor colorWithGenericGray:0.15]];
legend.borderLineStyle = axisLineStyle;
legend.cornerRadius = 10.0;
legend.swatchSize = CGSizeMake(16.0, 16.0);
CPTMutableTextStyle *legendTextStyle = [CPTMutableTextStyle textStyle];
legendTextStyle.color = [CPTColor whiteColor];
legendTextStyle.fontSize = 10.0;
legend.textStyle = legendTextStyle;
legend.rowMargin = 1.0;
legend.paddingLeft = 10.0;
legend.paddingTop = 10.0;
legend.paddingRight = 10.0;
legend.paddingBottom = 10.0;
legend.delegate = self.delegate;
self.legend = legend;
self.legendAnchor = CPTRectAnchorTop;
self.legendDisplacement = CGPointMake(0.0, 5.0);
}
@end
I am creating the BarLineChart in my view controller, defined below:
.h:
===
#import "CompanyViewController.h"
#import "IBCompany+FinstatAccessors.h"
#import "IBFinPeriod.h"
#import "CorePlot-CocoaTouch.h"
#import "ChartSelectViewController.h"
#import "BarLineChart.h"
@interface FinstatViewController : CompanyViewController <UITableViewDelegate,
UITableViewDataSource, UISplitViewControllerDelegate,
UIPopoverControllerDelegate, CompanyPresenter, ChartSelectionDelegate,
CPTPlotDataSource, CPTBarPlotDataSource, CPTBarPlotDelegate,
CPTPlotSpaceDelegate, CPTLegendDelegate, CPTScatterPlotDataSource,
CPTScatterPlotDelegate>
@property (strong, nonatomic) IBCompany *company;
@end
.m:
===
....
- (void) setChart;
{
NSDictionary *chartToDrawDict = [charts objectAtIndex:0];
BarLineChart *barChart = [[BarLineChart alloc]initWithFrame: self.view.bounds ];
barChart.delegate = self;
self.chart.hostedGraph = barChart;
[barChart setupChart];
[barChart setAbsoluteValues:[chartToDrawDict objectForKey:@"absoluteItems"]
RelativeValues:[chartToDrawDict objectForKey:@"relativeItems"]
forCompany:self.company
forFiscalPeriods:self.periodTypeSegmentedControl.selectedSegmentIndex]; //SegmentedControl: 0 = Annual, 1 = Interim
}
...
-(NSString *)legendTitleForBarPlot:(CPTBarPlot *)barPlot
recordIndex:(NSUInteger)index
{
return [NSString stringWithFormat:@"THIS METHOD WILL NEVER BE CALLED"];
}
-(BOOL)legend:(CPTLegend *)legend shouldDrawSwatchAtIndex:(NSUInteger)index
forPlot:(CPTPlot *)plot inRect:(CGRect)rect inContext:(CGContextRef)context;
{
return NO;
}
- (CPTFill *)barFillForBarPlot:(CPTBarPlot *)barPlot
recordIndex:(NSUInteger)index
{
return [CPTFill fillWithColor:[CPTColor colorWithComponentRed:1.0 green:1.0 blue:1.0 alpha:1.0]];
}
Please note: All delegates and data source methods, excluding -(NSString
*)legendTitleForBarPlot:(CPTBarPlot *)barPlot recordIndex:(NSUInteger)index are
called correctly. I have set any delegate and data source pointer to the view
controller. Could it be that there is an issue from subclassing CPTXYGraph?
Any help would be appreciated!!
Thank you!
Original comment by Alexande...@gmail.com
on 17 Mar 2012 at 8:47
I don't know why it would recognize the other datasource methods but not
-legendTitleForBarPlot:recordIndex:. It should be called once for each data
index. Therefore it should be called as long as the bar plot has more than zero
data points.
One comment about your graph subclass: CPTXYGraph is a subclass of CALayer
which already has a delegate property. You're masking the built-in property. I
would either remove yours and use the one provided by CALayer or change the
name to prevent confusion.
Original comment by eskr...@mac.com
on 17 Mar 2012 at 1:23
I tried both: Using CALayers' delegate and renaming mine, but unfortunately
this does not resolve my error. Is there any other way to provide the legend
labels?
Original comment by Alexande...@gmail.com
on 17 Mar 2012 at 2:56
-legendTitleForBarPlot:recordIndex: is only needed if you want a separate
legend entry for each bar on the bar plot. If you only want a single legend
entry for each plot, don't implement that method. The legend title comes from
the title property (or the identifier if it's a string) in that case.
Original comment by eskr...@mac.com
on 17 Mar 2012 at 3:54
The title property was exactly what I was looking for to set a custom legend
label (instead of the identifier). Thank you very much!
Original comment by Alexande...@gmail.com
on 17 Mar 2012 at 4:07
Original comment by eskr...@mac.com
on 17 Mar 2012 at 4:42
I am running into a similar problem in that legendTitleForBarPlot is not being
called. However unlike the original poster I do want a separate legend entry
for each bar on the bar plot. Was this issue ever resolved for apps that do
need separate legend issues?
Original comment by dkn...@datasciencesolutions.net
on 9 Apr 2013 at 5:38
I am getting this problem as well! Anyone has a solution? Or even a workaround
would do. Yes, I am that desperate.
Original comment by krishna....@gmail.com
on 15 Apr 2013 at 8:33
This issue was closed almost a year ago. If the current version of Core Plot
(1.2) has a problem, please open a new issue and give as much detail as you can
that will help us reproduce and fix the problem.
Original comment by eskr...@mac.com
on 15 Apr 2013 at 11:11
Original issue reported on code.google.com by
Alexande...@gmail.com
on 16 Mar 2012 at 8:13