1

I've been using CorePlot to draw a pie chart before which works fine. I would now like to visualise data in a scatter plot beneath my already existing pie chart. To that end I have added a new view with InterfaceBuilder, identical to the one already hosting my pie chart. I've set the data source and the delegate to self and the corresponding delegate methods are called correctly. The seemingly only thing that is not working is the actual display of the graph in the hosting view.

Here's what it looks like. Top: the working pie chart; bottom: what should be my scatter plot:

Top: the working pie chart; bottom: what should be my scatter plot.

The only visible thing of the scatter plot is the small rectangle.

Here's the corresponding code:

- (id)init
{
    // ...

    sp1 = [[MyPlotClass alloc] initWithTheme:[CPTTheme themeNamed:kCPTPlainWhiteTheme]];

    // the following returns an NSArray. Everything working as expected here.
    pieChartData = [self getEMDTurnoverSums];
    [pieChartData retain];

    sp2 = [[MyPlotClass alloc] initWithTheme:[CPTTheme themeNamed:kCPTPlainWhiteTheme]];

    // dito getEMDTurnoverSums
    scatterPlotData = [self getEMDTurnoverData];
    [scatterPlotData retain];

    return self;
}

- (void)viewDidLoad
{
    /*
     * ------------------------
     *      Pie Chart
     * ------------------------
     */

    graph1 = [sp1 getPieChartGraphForView:graphView1];

    CPTPieChart *pieChart = [sp1 initPieChartWithIdentifier:@"emd" andLineWidth:1.0f];
    pieChart.dataSource = self;
    pieChart.delegate   = self;

    CPTLegend *legend = [CPTLegend legendWithGraph:graph1];
    legend.numberOfColumns = 1;
    legend.numberOfRows    = 3;
    legend.cornerRadius    = 5.0;

    CPTMutableTextStyle *textStyle = [[[CPTMutableTextStyle alloc] init] autorelease];
    textStyle.fontSize             = 15.0;
    legend.textStyle               = textStyle;

    graph1.legend             = legend;
    graph1.legendAnchor       = CPTRectAnchorLeft;
    graph1.legendDisplacement = CGPointMake(30.0, 30.0);

    if (self.interfaceOrientation == UIDeviceOrientationLandscapeLeft ||
        self.interfaceOrientation == UIDeviceOrientationLandscapeRight)
    {
        graphView1.frame = CGRectMake(5.0f, 500.0f, 750.0f, 510.0f);
    }

    [graph1 addPlot:pieChart];
    [pieChart release];

    /*
     * ------------------------
     *      Scatter Plot
     * ------------------------
     */

    graph2 = [sp2 getScatterPlotGraphForView:graphView2];

    CPTScatterPlot *scatterPlot = [sp2 initScatterPlotWithIdentifier:@"scatterPlot" andLineWidth:5.0f andColor:[CPTColor blackColor]];
    scatterPlot.dataSource = self;
    scatterPlot.delegate   = self;

    CPTLegend *scatterPlotLegend = [CPTLegend legendWithGraph:graph2];
    scatterPlotLegend.numberOfColumns = 2;
    scatterPlotLegend.numberOfRows    = 3;
    scatterPlotLegend.cornerRadius    = 5.0;

    // see PieChart
    scatterPlotLegend.textStyle = textStyle;

    graph2.legend = scatterPlotLegend;
    graph2.legendAnchor = CPTRectAnchorLeft;
    graph2.legendDisplacement = CGPointMake(30.0, 30.0);

    if (self.interfaceOrientation == UIDeviceOrientationLandscapeLeft ||
        self.interfaceOrientation == UIDeviceOrientationLandscapeRight)
    {
        graphView2.frame = CGRectMake(5.0f, 240.0f, 750.0f, 270.0f);
    }

    [graph2 addPlot:scatterPlot];
    [scatterPlot release];

    /*
     * ------------------------
     *       END PLOTS
     * ------------------------
     */

    [super viewDidLoad];
}

The delegate methods:

- (NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
    if ([(NSString *)plot.identifier isEqualToString:@"emd"]) {
        NSLog(@"numberOfRecordsForPlot: emd: %i", [pieChartData count]);

        return [pieChartData count];
    } else if ([(NSString *)plot.identifier isEqualToString:@"scatterPlot"]) {
        NSLog(@"numberOfRecordsForPlot: scatterPlot: %i", [scatterPlotData count]);
        NSLog(@"numberOfRecordsForPlot: scatterPlot: %@", scatterPlotData);

        return [scatterPlotData count];
    }

    return 0;
}

- (NSNumber *)numberForPlot:(CPTPlot *)plot
                      field:(NSUInteger)fieldEnum
                recordIndex:(NSUInteger)index
{
    if ([(NSString *)plot.identifier isEqualToString:@"emd"]) {
        return [pieChartData objectAtIndex:index];
    } else if ([(NSString *)plot.identifier isEqualToString:@"scatterPlot"]) {
        NSDictionary *fieldMapping = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:
                                                                          @"e_turnover",
                                                                          @"m_turnover",
                                                                          @"d_turnover",
                                                                          @"na_turnover",
                                                                          @"sum_turnover",
                                                                          nil]
                                                                 forKeys:[NSArray arrayWithObjects:
                                                                          @"0",
                                                                          @"1",
                                                                          @"2",
                                                                          @"3",
                                                                          @"4",
                                                                          nil]];

        NSLog(@"scatterPlotData: %@", scatterPlotData);
        NSLog(@"fieldMapping   : %@", fieldMapping);

        NSNumber *returnValue = [(NSDictionary *)[scatterPlotData objectAtIndex:index] objectForKey:
                                 [fieldMapping objectForKey:
                                  [NSString stringWithFormat:@"%i", fieldEnum]]];
        NSLog(@"returnValue: %@", returnValue);

        return returnValue;
    }

    return 0;
}

- (NSString *)legendTitleForPieChart:(CPTPieChart *)pieChart
                         recordIndex:(NSUInteger)index
{
    switch (index) {
        case 0:
            return [NSString stringWithFormat:@"Easy Lines - %@ €", [self standardFormatNumber:(NSNumber *)[pieChartData objectAtIndex:0] asDecimal:NO]];

        case 1:
            return [NSString stringWithFormat:@"Medium Lines - %@ €", [self standardFormatNumber:(NSNumber *)[pieChartData objectAtIndex:1] asDecimal:NO]];

        case 2:
            return [NSString stringWithFormat:@"Difficult Lines - %@ €", [self standardFormatNumber:(NSNumber *)[pieChartData objectAtIndex:2] asDecimal:NO]];

        default:
            break;
    }

    return @"";
}



- (CPTFill *)sliceFillForPieChart:(CPTPieChart *)pieChart
                      recordIndex:(NSUInteger)index
{
    switch (index) {
        case 0:
            return [CPTFill fillWithColor:[CPTColor greenColor]];

        case 1:
            return [CPTFill fillWithColor:[CPTColor yellowColor]];

        case 2:
            return [CPTFill fillWithColor:[CPTColor redColor]];

        default:
            break;
    }

    return [CPTFill fillWithColor:[CPTColor blackColor]];
}

Here's the code from MyPlotClass.m:

#import "MyPlotClass.h"

@implementation MyPlotClass

@synthesize paddingLeft;
@synthesize paddingTop;
@synthesize paddingRight;
@synthesize paddingBottom;

@synthesize plotRangeXFrom;
@synthesize plotRangeXLength;
@synthesize plotRangeYFrom;
@synthesize plotRangeYLength;

@synthesize plotSpace;

@synthesize axisLineWidth;
@synthesize axisLineColor;

@synthesize minorTickLengthX;
@synthesize majorTickLengthX;
@synthesize minorTickLengthY;
@synthesize majorTickLengthY;
@synthesize majorIntervalLengthX;
@synthesize majorIntervalLengthY;
@synthesize labelOffsetX;
@synthesize labelOffsetY;
@synthesize minorTicksPerIntervalX;
@synthesize minorTicksPerIntervalY;

@synthesize pieChartRadius;
@synthesize pieChartStartAngle;
@synthesize pieChartSliceDirection;


- (id)init
{
    return [self initWithTheme:[CPTTheme themeNamed:kCPTPlainWhiteTheme]];
}

- (MyPlotClass *)initWithTheme:(CPTTheme *)theme
{
    graph = [[[CPTXYGraph alloc] initWithFrame:CGRectZero] retain];
    [graph applyTheme:theme];

    paddingLeft   = 20.0;
    paddingTop    = 20.0;
    paddingRight  = 20.0;
    paddingBottom = 20.0;

    plotRangeXFrom   = 0.0;
    plotRangeXLength = 0.0;
    plotRangeYFrom   = 0.0;
    plotRangeYLength = 0.0;

    axisLineWidth = 0.0f;
    axisLineColor = [CPTColor blackColor];

    minorTickLengthX       = 0.0f;
    majorTickLengthX       = 0.0f;
    minorTickLengthY       = 0.0f;
    majorTickLengthY       = 0.0f;
    majorIntervalLengthX   = 5.0f;
    majorIntervalLengthY   = 5.0f;
    labelOffsetX           = 3.0f;
    labelOffsetY           = 3.0f;
    minorTicksPerIntervalX = 0;
    minorTicksPerIntervalY = 0;

    pieChartRadius         = 100.0;
    pieChartStartAngle     = M_PI;
    pieChartSliceDirection = CPTPieDirectionClockwise;

    return self;
}


- (CPTXYGraph *)getScatterPlotGraphForView:(UIView *)view
{
    CPTGraphHostingView *hostingView = (CPTGraphHostingView *)view;
    hostingView.hostedGraph = graph;

    graph.paddingLeft   = paddingLeft;
    graph.paddingTop    = paddingTop;
    graph.paddingRight  = paddingRight;
    graph.paddingBottom = paddingBottom;

    plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(plotRangeXFrom)
                                                    length:CPTDecimalFromFloat(plotRangeXLength)];
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(plotRangeYFrom)
                                                    length:CPTDecimalFromFloat(plotRangeYLength)];

    CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
    axisLineStyle.lineColor = axisLineColor;
    axisLineStyle.lineWidth = axisLineWidth;

    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;

    axisSet.xAxis.majorIntervalLength   = [[NSNumber numberWithFloat:majorIntervalLengthX] decimalValue];
    axisSet.xAxis.minorTicksPerInterval = minorTicksPerIntervalX;
    axisSet.xAxis.majorTickLineStyle    = axisLineStyle;
    axisSet.xAxis.minorTickLineStyle    = axisLineStyle;
    axisSet.xAxis.axisLineStyle         = axisLineStyle;
    axisSet.xAxis.minorTickLength       = minorTickLengthX;
    axisSet.xAxis.majorTickLength       = majorTickLengthX;
    axisSet.xAxis.labelOffset           = labelOffsetX;

    axisSet.yAxis.majorIntervalLength   = [[NSNumber numberWithInt:majorIntervalLengthY] decimalValue];
    axisSet.yAxis.minorTicksPerInterval = minorTicksPerIntervalY;
    axisSet.yAxis.majorTickLineStyle    = axisLineStyle;
    axisSet.yAxis.minorTickLineStyle    = axisLineStyle;
    axisSet.yAxis.axisLineStyle         = axisLineStyle;
    axisSet.yAxis.minorTickLength       = minorTickLengthY;
    axisSet.yAxis.majorTickLength       = majorTickLengthY;
    axisSet.yAxis.labelOffset           = labelOffsetY;

    return graph;
}

- (CPTXYGraph *)getPieChartGraphForView:(UIView *)view
{
    CPTGraphHostingView *hostingView = (CPTGraphHostingView *)view;
    hostingView.hostedGraph = graph;

    graph.paddingLeft   = paddingLeft;
    graph.paddingTop    = paddingTop;
    graph.paddingRight  = paddingRight;
    graph.paddingBottom = paddingBottom;

    CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
    axisLineStyle.lineColor = axisLineColor;
    axisLineStyle.lineWidth = axisLineWidth;

    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;

    axisSet.xAxis.majorIntervalLength   = [[NSNumber numberWithFloat:majorIntervalLengthX] decimalValue];
    axisSet.xAxis.minorTicksPerInterval = minorTicksPerIntervalX;
    axisSet.xAxis.majorTickLineStyle    = axisLineStyle;
    axisSet.xAxis.minorTickLineStyle    = axisLineStyle;
    axisSet.xAxis.axisLineStyle         = axisLineStyle;
    axisSet.xAxis.minorTickLength       = minorTickLengthX;
    axisSet.xAxis.majorTickLength       = majorTickLengthX;
    axisSet.xAxis.labelOffset           = labelOffsetX;

    axisSet.yAxis.majorIntervalLength   = [[NSNumber numberWithInt:majorIntervalLengthY] decimalValue];
    axisSet.yAxis.minorTicksPerInterval = minorTicksPerIntervalY;
    axisSet.yAxis.majorTickLineStyle    = axisLineStyle;
    axisSet.yAxis.minorTickLineStyle    = axisLineStyle;
    axisSet.yAxis.axisLineStyle         = axisLineStyle;
    axisSet.yAxis.minorTickLength       = minorTickLengthY;
    axisSet.yAxis.majorTickLength       = majorTickLengthY;
    axisSet.yAxis.labelOffset           = labelOffsetY;

    return graph;
}


- (CPTScatterPlot *)initScatterPlotWithIdentifier:(NSString *)identifier
{
    return [self initScatterPlotWithIdentifier:identifier andLineWidth:3.0f andColor:[CPTColor blackColor]];
}

- (CPTScatterPlot *)initScatterPlotWithIdentifier:(NSString *)identifier
                                     andLineWidth:(CGFloat)lineWidth
                                         andColor:(CPTColor *)lineColor
{
    CPTScatterPlot *scatterPlot = [[[CPTScatterPlot alloc]
                                    initWithFrame:graph.defaultPlotSpace.accessibilityFrame]
                                   autorelease];

    scatterPlot.identifier = identifier;
    CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
    lineStyle.lineWidth = lineWidth;
    lineStyle.lineColor = lineColor;
    scatterPlot.dataLineStyle = lineStyle;
    [graph addPlot:scatterPlot];

    CPTPlotSymbol *greenCirclePlotSymbol = [CPTPlotSymbol ellipsePlotSymbol];
    greenCirclePlotSymbol.fill = [CPTFill fillWithColor:[CPTColor greenColor]];
    greenCirclePlotSymbol.size = CGSizeMake(2.0, 2.0);
    scatterPlot.plotSymbol     = greenCirclePlotSymbol;

    return scatterPlot;
}

- (CPTPieChart *)initPieChartWithIdentifier:(NSString *)identifier
                               andLineWidth:(CGFloat)lineWidth
{
    CPTPieChart *pieChart = [[[CPTPieChart alloc]
                              initWithFrame:graph.defaultPlotSpace.accessibilityFrame]
                             autorelease];

    pieChart.identifier     = identifier;
    pieChart.pieRadius      = pieChartRadius;
    pieChart.startAngle     = pieChartStartAngle;
    pieChart.sliceDirection = pieChartSliceDirection;

    // Prepare a radial overlay gradient for shading/gloss
    CPTGradient *overlayGradient = [[[CPTGradient alloc] init] autorelease];
    overlayGradient.gradientType = CPTGradientTypeRadial;
    overlayGradient = [overlayGradient addColorStop:[[CPTColor blackColor] colorWithAlphaComponent:0.0] atPosition:0.0];
    overlayGradient = [overlayGradient addColorStop:[[CPTColor blackColor] colorWithAlphaComponent:0.3] atPosition:0.9];
    overlayGradient = [overlayGradient addColorStop:[[CPTColor blackColor] colorWithAlphaComponent:0.7] atPosition:1.0];
    pieChart.overlayFill = [CPTFill fillWithGradient:overlayGradient];

    CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
    lineStyle.lineWidth = lineWidth;
    pieChart.borderLineStyle = lineStyle;

    [graph addPlot:pieChart];

    return pieChart;
}


- (void)dealloc
{
    [super dealloc];

    [graph release];
    [plotSpace release];
}


@end

I've spent hours on this and haven't yet been able to pin down the problem. The data is fine, the delegate methods get called and return correct values.

TIA!

2 Answers 2

1

A few observations:

  1. In -initScatterPlotWithIdentifier:andLineWidth:andColor:, the scatter plot is added to graph. Shouldn't that be graph2?

  2. In -numberForPlot:field:recordIndex:, you have to check the field parameter—a switch statement works well. This method will be called twice for each index, once with field == CPTScatterPlotFieldX and once with field == CPTScatterPlotFieldY. You're returning the same value for both fields, so even if you could see the plot, it would be a diagonal line.

  3. axisLineWidth = 0.0f; You'll need to increase this for the scatter plot so the axis lines show up.

0
0

@Eric Skroch:

Thanks for your comment!

  1. No, -initScatterPlotWithIdentifier:andLineWidth:andColor: is a method in MyPlotClass. The member graph there has nothing to do with the variable in the implementing class.

  2. I actually do that in the return statement. I think however that I sacrificed readability here for wanting to be elegant. The following code is more obvious now:

    NSDictionary *curDict = (NSDictionary *)[scatterPlotData objectAtIndex:index];

    switch (fieldEnum) {

    case 0:
        return [curDict objectForKey:@"e_turnover"];
    
    case 1:
        return [curDict objectForKey:@"m_turnover"];
    
    case 2:
        return [curDict objectForKey:@"d_turnover"];
    
    case 3:
        return [curDict objectForKey:@"na_turnover"];
    
    case 4:
        return [curDict objectForKey:@"sum_turnover"];
    
    default:
        break;
    

    }

BTW: Sorry that I put this comment in a separate answer but the comment field won't let me enter multi line code blocks or comments that exceed a certain amount of characters.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.