1
votes

I'm trying to display a line using a ScatterPlot on Bar plot, which is horizontal. It does work for vertical bar plots, but not for the horizontal one.

This is the source code:

-(id)init
{
    if ( (self = [super init]) ) {
        self.section = kBarPlots;
        self.isOneBarPlot = TRUE;
    }

    return self;
}

-(void)generateData
{
    [[BPDatabaseController sharedController] dataForTopFiveObservationPeriodIncidents:^(NSArray *resultArray) {

        self.plotData = resultArray;
        FilterManager *fm = [FilterManager sharedInstance];

        self.isOneBarPlot = fm.filterPendingIncidents; //is responsible for showing the legend correctly
        [self renderInLayer:self.defaultLayerHostingView withTheme:self.theme animated:YES];
        [super generateData];

    }];
}

-(void)renderInLayer:(CPTGraphHostingView *)layerHostingView withTheme:(CPTTheme *)theme animated:(BOOL)animated
{
    CGRect bounds = layerHostingView.bounds;

    CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:bounds];
    [self addGraph:graph toHostingView:layerHostingView];
    [self applyTheme:theme toGraph:graph withDefault:nil];

    [self setTitleDefaultsForGraph:graph withBounds:bounds];
    [self setPaddingDefaultsForGraph:graph withBounds:bounds];



    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
        graph.paddingLeft = 0.0f;
    }else{
        graph.paddingLeft = 65.0f;
    }

    graph.paddingRight = 0.0f;

    NSNumberFormatter *format = [[NSNumberFormatter alloc] init];
    [format setNumberStyle:NSNumberFormatterNoStyle];

    // Create bar plot
    CPTBarPlot *barPlot = [[CPTBarPlot alloc] init];
    barPlot.lineStyle         = [[CPTTheme themeNamed:kCPTDarkBlueTheme] axisLineStyle:kBarLineStyle];
    barPlot.barWidth          = CPTDecimalFromFloat(0.60f); // bar is 75% of the available space
    barPlot.barCornerRadius   = 0.0;
    barPlot.barsAreHorizontal = YES;
    barPlot.dataSource        = self;
    barPlot.identifier        = kBarPlotPending;
    barPlot.delegate          = self;
    barPlot.fill                = [[CPTTheme themeNamed:kCPTDarkBlueTheme] barFillForBarPlotOfType:kHorizontalRed];
    barPlot.labelTextStyle      = [[CPTTheme themeNamed:kCPTDarkBlueTheme] barTextStyle];
    barPlot.labelFormatter  = format;
    barPlot.labelOffset =  1.0;
    barPlot.anchorPoint = CGPointMake(0.0, 0.0);
    [barPlot addAnimation:[self plotAnimationWithKeyPath:@"transform.scale.x"] forKey:@"someKey"];

    if(!self.isOneBarPlot){
        [graph addPlot:barPlot];
    }

    // Create bar plot
    CPTBarPlot *barPlot2 = [[CPTBarPlot alloc] init];
    barPlot2.lineStyle         = [[CPTTheme themeNamed:kCPTDarkBlueTheme] axisLineStyle:kBarLineStyle];;
    barPlot2.barWidth          = CPTDecimalFromFloat(0.60f); // bar is 75% of the available space
    barPlot2.barCornerRadius   = 0.0;
    barPlot2.barsAreHorizontal = YES;
    barPlot2.dataSource        = self;
    barPlot2.identifier        = kBarPlotOfficial;
    barPlot2.delegate          = self;
    barPlot2.labelFormatter  = format;
    barPlot2.fill               = [[CPTTheme themeNamed:kCPTDarkBlueTheme] barFillForBarPlotOfType:kHorizontalBlue];
    barPlot2.anchorPoint = CGPointMake(0.0, 0.0);
    barPlot2.labelTextStyle     = [[CPTTheme themeNamed:kCPTDarkBlueTheme] barTextStyle];
    if(!self.isOneBarPlot){
        barPlot2.labelOffset =  -1.0;
    }
    [graph addPlot:barPlot2];



    [barPlot2 addAnimation:[self plotAnimationWithKeyPath:@"transform.scale.x"] forKey:@"someKey"];

    // make the bars thinner if only one data set is available
    if ([self.plotData count] == 1) {
        barPlot.barWidthScale = kBarWithScaleOneItem;
        barPlot2.barWidthScale = kBarWithScaleOneItem;
    }

    if ([self.plotData count] > 0) {

        // Plot space
        CPTMutablePlotRange *barRange = [[barPlot plotRangeEnclosingBars] mutableCopy];
        [barRange expandRangeByFactor:CPTDecimalFromDouble(1.05)];


        CPTXYPlotSpace *barPlotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
        barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0f) length:CPTDecimalFromFloat([self calculateDatasourcePeak])];
        barPlotSpace.yRange = barRange;

        CPTScatterPlot *targetLinePlot = [[CPTScatterPlot alloc] init];
        targetLinePlot.identifier = kBarPlotTarget;
        targetLinePlot.title = NSLocalizedString(kBarPlotTarget, nil);

        CPTMutableLineStyle *barLineStyleTarget = [[CPTMutableLineStyle alloc] init];
        barLineStyleTarget.lineWidth = 2.0;
        barLineStyleTarget.lineColor = [CPTColor grayColor];

        targetLinePlot.dataLineStyle = barLineStyleTarget;
        targetLinePlot.dataSource = self;
        [graph addPlot:targetLinePlot toPlotSpace:barPlotSpace];



        [self configureAxis:graph];

        [self createDarkBackgroundPlot:graph isHorizontal:TRUE];

    }else{

        self.emtyPlot.alpha = 1.0;

        // Create axes
        CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
        CPTXYAxis *y          = axisSet.yAxis;
        {
            y.majorIntervalLength         = CPTDecimalFromInteger(0);
            y.axisLineStyle               = nil;
            y.labelingPolicy              = CPTAxisLabelingPolicyNone;
            y.labelTextStyle              = nil;
            y.majorTickLineStyle    = nil;
            y.minorTickLineStyle = nil;
            y.axisConstraints             = [CPTConstraints constraintWithLowerOffset:7.0];

        }

        CPTXYAxis *x = axisSet.xAxis;
        {
            x.majorIntervalLength         = CPTDecimalFromInteger(0);
            x.axisConstraints             = [CPTConstraints constraintWithLowerOffset:8.0];
            x.axisLineStyle               = nil;
            x.labelingPolicy              = CPTAxisLabelingPolicyAutomatic;
            x.majorTickLineStyle    = nil;
            x.minorTickLineStyle = nil;
            x.labelTextStyle = nil;

        }
    }
}

-(void)configureAxis:(CPTGraph *)graph{

    [super configureAxis:graph];

    NSNumberFormatter *format = [[NSNumberFormatter alloc] init];
    [format setNumberStyle:NSNumberFormatterNoStyle];

    //legend
    CPTLegend *theLegend = [CPTLegend legendWithGraph:graph];
    theLegend.borderLineStyle = [[CPTTheme themeNamed:kCPTDarkBlueTheme] axisLineStyle:kBarLineStyle];
    theLegend.cornerRadius    = 0.0;
    theLegend.swatchSize      = CGSizeMake(16.0, 16.0);
    theLegend.textStyle     = [[CPTTheme themeNamed:kCPTDarkBlueTheme] barTextStyle];
    theLegend.numberOfRows  = 1;
    graph.legend             = theLegend;
    graph.legendAnchor       = CPTRectAnchorBottom;
    graph.legendDisplacement = CGPointMake(0.0, 0.0);

    // Create axes
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *y          = axisSet.yAxis;
    {
        y.majorIntervalLength         = CPTDecimalFromInteger(1);
        y.axisLineStyle               = [[CPTTheme themeNamed:kCPTDarkBlueTheme] axisLineStyle:kYAxisLineStyle];
        y.labelingPolicy              = CPTAxisLabelingPolicyNone;
        y.orthogonalCoordinateDecimal = CPTDecimalFromInteger(1);
        y.labelTextStyle = [[CPTTheme themeNamed:kCPTDarkBlueTheme] barTextStyle];
        y.axisConstraints             = [CPTConstraints constraintWithLowerOffset:5.0];
    }

    NSMutableSet *yAxisLegend = [NSMutableSet set];

    for (int i = 0; i < self.plotData.count; i++) {
        CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:[self addLineBreakToString:(NSString*)[[self.plotData objectAtIndex:i] objectForKey:kResultLabel] ]textStyle:[[CPTTheme themeNamed:kCPTDarkBlueTheme] barTextStyle]];
        label.tickLocation = CPTDecimalFromInteger(i);

        [yAxisLegend addObject:label];
    }
    y.axisLabels = yAxisLegend;


    CPTXYAxis *x = axisSet.xAxis;
    {
        x.majorIntervalLength         = CPTDecimalFromInteger(1);
        x.axisConstraints             = [CPTConstraints constraintWithLowerOffset:8.0];
        x.axisLineStyle               = [[CPTTheme themeNamed:kCPTDarkBlueTheme] axisLineStyle:kXAxisLineStyle];
        x.labelingPolicy              = CPTAxisLabelingPolicyAutomatic;
        x.majorTickLineStyle = nil;
        x.minorTickLineStyle = nil;
        //x.labelFormatter = format;
        x.orthogonalCoordinateDecimal = CPTDecimalFromInteger(-1);
        x.labelTextStyle = [[CPTTheme themeNamed:kCPTDarkBlueTheme] barTextStyle];
        x.labelOffset = 5.0f;

    }
}

#pragma mark -
#pragma mark Plot Data Source Methods

-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{

    return self.plotData.count;
}

-(NSArray *)numbersForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndexRange:(NSRange)indexRange
{
    NSArray *nums = [super numbersForPlot:plot field:fieldEnum recordIndexRange:indexRange];

    if (!nums) {
        switch ( fieldEnum ) {
            case CPTBarPlotFieldBarLocation:
                nums = [NSMutableArray arrayWithCapacity:indexRange.length];
                for ( NSUInteger i = indexRange.location; i < NSMaxRange(indexRange); i++ ) {
                    [(NSMutableArray *)nums addObject : @(i)];
                }
                break;

            case CPTBarPlotFieldBarTip: {

                if ([plot.identifier isEqual:kBarPlotTarget]) {

                    nums = [NSMutableArray arrayWithCapacity:indexRange.length];
                    for ( NSUInteger i = indexRange.location; i < NSMaxRange(indexRange); i++ ) {
                        [(NSMutableArray *)nums addObject:@(100)];
                    }

                }else{

                NSString *dataKey = nil;
                if ([plot.identifier isEqual:kBarPlotOfficial]) {
                    dataKey = kResultOfficial;
                }
                else {
                    dataKey = kResultSum;
                }

                nums = [NSMutableArray arrayWithCapacity:indexRange.length];
                for ( NSUInteger i = indexRange.location; i < NSMaxRange(indexRange); i++ ) {

                    NSNumber *number = [[self.plotData objectAtIndex:i] objectForKey:dataKey];
                    [(NSMutableArray *)nums addObject : number];
                }
                }
                break;
            }

            default:
                break;
        }
    }
    return nums;
}

-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)idx
{
    CPTTextLayer *textLayer = (id)[NSNull null];;
    NSNumber *number = nil;

    if ([plot.identifier isEqual:kBarPlotPending]) {
        number = [[self.plotData objectAtIndex:idx] objectForKey:kResultSum];

    }
    else if ([plot.identifier isEqual:kBarPlotOfficial]) {

        NSNumber *officialNumber = [[self.plotData objectAtIndex:idx] objectForKey:kResultOfficial];
        NSNumber *pendingNumber = [[self.plotData objectAtIndex:idx] objectForKey:kResultSum];

        CGFloat maxNumber = [self calculateDatasourcePeak];

        // 1.) if the max peak it to high and the current value to low the
        //     official is not shown correclty (not enough space) => do not show it
        // 2.) do not show the official if its the same number as pending
        if (!(maxNumber > 100 && [officialNumber intValue] < 50) && ([officialNumber intValue] != [pendingNumber intValue])) {
            number = officialNumber;
        }
    }

    if ([number intValue] > 0) {
        textLayer = [[CPTTextLayer alloc] initWithText:[number stringValue] style:[[CPTTheme themeNamed:kCPTDarkBlueTheme] barTextStyle]];
    }

    return textLayer;
}

#pragma mark - CPTBarPlot delegate methods

-(void)plot:(CPTPlot *)plot dataLabelWasSelectedAtRecordIndex:(NSUInteger)index
{
    NSLog(@"Data label for '%@' was selected at index %d.", plot.identifier, (int)index);
}

The legend on the bottom does show that there should be a target line, but no one is displayed

1
Can you post the rest of your datasource methods? Make sure - numberForPlot:field:recordIndex: or whichever data method you're using checks for the proper fields. Bar plots will ask the datasource for the CPTBarPlotFieldBarLocation and CPTBarPlotFieldBarTip fields. - Eric Skroch
I tried to implement it. It still won't show a line. I've edited the new code above - user2529173

1 Answers

0
votes

Different plot types use different datasource field enumerations. Bar plots will use CPTBarPlotFieldBarLocation and CPTBarPlotFieldBarTip. Scatter plots like the target line plot will use CPTScatterPlotFieldX and CPTScatterPlotFieldY. Make sure the datasource is checking the right field enum values for each plot.