samuelltk / core-plot

Automatically exported from code.google.com/p/core-plot
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

legendTitleForBarPlot: is never called (bug?) #409

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?

1. Implement bar chart
2. Setup legend, delegates and datasource
3. Implement legendTitleForBarPlot:

What is the expected output? What do you see instead?

legendTitleForBarPlot: should be called and return the titles for the legend.
I have set all delegates and datasource pointers correctly. 
All other datasource methods are called correctly, except for 
legendTitleForBarPlot:, which is the only method which is not called. I believe 
there is a bug in CorePlot.

What version of the product are you using? On what operating system?
CorePlot 1.0, iOS 5.1 Simulator

Please provide any additional information below.

Original issue reported on code.google.com by Alexande...@gmail.com on 16 Mar 2012 at 8:13

GoogleCodeExporter commented 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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
-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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago

Original comment by eskr...@mac.com on 17 Mar 2012 at 4:42

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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

GoogleCodeExporter commented 9 years ago
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