Search code examples
core-plot

Despite setting xRange, data is plotted in the wrong place


I'm trying to plot a histogram. The x-axis range should be about 881 to 1281 (I've verified that I'm using a location of 881 and range of 400 when constructing the CPTPlotRange for xRange). The axis draws with the correct range, but my bars end up near 2000 (data space), even though my data source method is sending location values between 881 and 1281.

Here's the code:

- (void)
viewDidLoad
{
    [super viewDidLoad];

    InputVariable           temp(1081.0, 50.0);
    self.hist = new Histogram(temp.mean(), temp.stdDev(), 5.0);
    for (Histogram::SizeT i = 0; i < 1000; ++i)
    {
        double v = temp.randomValue();
        self.hist->add(v);
    }

    const Histogram& hist = *self.hist;

    CPTXYGraph* graph = [[CPTXYGraph alloc] initWithFrame: self.chart1.bounds];
    graph.fill                = [CPTFill fillWithColor: [CPTColor lightGrayColor]];
    graph.cornerRadius        = 4.0;
    self.chart1.hostedGraph = graph;

    self.graph = graph;

    // Plot area

    graph.plotAreaFrame.fill          = [CPTFill fillWithColor:[CPTColor lightGrayColor]];
    graph.plotAreaFrame.paddingTop    = 4.0;
    graph.plotAreaFrame.paddingBottom = 50.0;
    graph.plotAreaFrame.paddingLeft   = 50.0;
    graph.plotAreaFrame.paddingRight  = 4.0;
    graph.plotAreaFrame.cornerRadius  = 4.0;
    graph.plotAreaFrame.masksToBorder = NO;

    graph.plotAreaFrame.axisSet.borderLineStyle = [CPTLineStyle lineStyle];

    graph.plotAreaFrame.plotArea.fill = [CPTFill fillWithColor:[CPTColor whiteColor]];

    // Setup plot space
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
    plotSpace.xRange     = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(hist.lowValue()) length:CPTDecimalFromDouble(hist.range())];
    plotSpace.yRange     = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0.0) length:CPTDecimalFromDouble(hist.maxBinCount() * 1.2)];
    //plotSpace.yScaleType = CPTScaleTypeLog;

    // Line styles
    CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
    axisLineStyle.lineWidth = 2.0;
    //axisLineStyle.lineCap   = kCGLineCapRound;

    CPTMutableLineStyle *majorGridLineStyle = [CPTMutableLineStyle lineStyle];
    majorGridLineStyle.lineWidth = 0.75;
    majorGridLineStyle.lineColor = [CPTColor redColor];

    CPTMutableLineStyle *minorGridLineStyle = [CPTMutableLineStyle lineStyle];
    minorGridLineStyle.lineWidth = 0.25;
    minorGridLineStyle.lineColor = [CPTColor blueColor];

    // Text styles
    CPTMutableTextStyle *axisTitleTextStyle = [CPTMutableTextStyle textStyle];
    axisTitleTextStyle.fontName = @"Helvetica Neue Bold";
    axisTitleTextStyle.fontSize = 14.0;

    // Axes
    // Label x axis with a fixed interval policy
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
    CPTXYAxis *x          = axisSet.xAxis;
    x.separateLayers              = NO;
    x.orthogonalCoordinateDecimal = CPTDecimalFromDouble(0.0);
    x.majorIntervalLength         = CPTDecimalFromDouble(0.5);
    x.minorTicksPerInterval       = 4;
    x.tickDirection               = CPTSignNone;
    x.axisLineStyle               = axisLineStyle;
    x.majorTickLength             = 12.0;
    x.majorTickLineStyle          = axisLineStyle;
    //x.majorGridLineStyle          = majorGridLineStyle;
    x.minorTickLength             = 8.0;
    //x.minorGridLineStyle          = minorGridLineStyle;
    x.title                       = @"Temperature";
    x.titleTextStyle              = axisTitleTextStyle;
    x.titleOffset                 = 25.0;
    //x.alternatingBandFills        = @[[[CPTColor redColor] colorWithAlphaComponent:0.1], [[CPTColor greenColor] colorWithAlphaComponent:0.1]];
    x.labelingPolicy              = CPTAxisLabelingPolicyAutomatic;

    // Label y with an automatic label policy.
    //axisLineStyle.lineColor = [CPTColor greenColor];

    CPTXYAxis *y = axisSet.yAxis;
    y.separateLayers        = YES;
    y.orthogonalCoordinateDecimal = plotSpace.xRange.location;//CPTDecimalFromDouble(hist.lowValue());
    y.minorTicksPerInterval = 9;
    y.tickDirection         = CPTSignNone;
    y.axisLineStyle         = axisLineStyle;
    y.majorTickLength       = 12.0;
    y.majorTickLineStyle    = axisLineStyle;
    //y.majorGridLineStyle    = majorGridLineStyle;
    //y.minorTickLength       = 8.0;
    //y.minorGridLineStyle    = minorGridLineStyle;
    y.title                 = @"Number of Samples";
    y.titleTextStyle        = axisTitleTextStyle;
    y.titleOffset           = 40.0;
    //y.alternatingBandFills  = @[[[CPTColor blueColor] colorWithAlphaComponent:0.1], [NSNull null]];
    y.labelingPolicy        = CPTAxisLabelingPolicyAutomatic;

    //CPTFill *bandFill = [CPTFill fillWithColor:[[CPTColor darkGrayColor] colorWithAlphaComponent:0.5]];
    //[y addBackgroundLimitBand:[CPTLimitBand limitBandWithRange:[CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(7.0) length:CPTDecimalFromDouble(1.5)] fill:bandFill]];
    //[y addBackgroundLimitBand:[CPTLimitBand limitBandWithRange:[CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(1.5) length:CPTDecimalFromDouble(3.0)] fill:bandFill]];


    //  Set up the bar plot…

    //CPTXYPlotSpace *barPlotSpace = [[CPTXYPlotSpace alloc] init];
    CPTXYPlotSpace *barPlotSpace = (CPTXYPlotSpace *) self.graph.defaultPlotSpace;

    //barPlotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0.0) length:CPTDecimalFromDouble(200.0)];
    //barPlotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0.0) length:CPTDecimalFromDouble(15.00)];
    //[self.graph addPlotSpace:barPlotSpace];

    CPTBarPlot *barPlot = [CPTBarPlot tubularBarPlotWithColor:[CPTColor darkGrayColor] horizontalBars: false];
    barPlot.dataSource      =   self;

    barPlot.barsAreHorizontal = false;
    barPlot.barWidth        =   CPTDecimalFromDouble(1.0);
    barPlot.barBasesVary    =   false;
    barPlot.baseValue       =   CPTDecimalFromDouble(0.0);
    barPlot.barOffset       =   CPTDecimalFromDouble(hist.lowValue());
    barPlot.identifier      =   @"Bar Plot";
    //barPlot.plotRange     =   [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0.0) length:CPTDecimalFromDouble(7.0)];

    CPTMutableTextStyle *whiteTextStyle = [CPTMutableTextStyle textStyle];
    whiteTextStyle.color = [CPTColor whiteColor];
    //barPlot.labelTextStyle    = whiteTextStyle;

    [self.graph addPlot:barPlot toPlotSpace:barPlotSpace];
}


- (NSUInteger)
numberOfRecordsForPlot: (CPTPlot*) inPlot
{
    return self.hist->numBins();
}

- (double)
doubleForPlot: (CPTPlot*) inPlot
    field: (NSUInteger) inField
    recordIndex: (NSUInteger) inIdx
{
    const Histogram& h = *self.hist;

    if (inField == CPTBarPlotFieldBarLocation)
    {
        double v = h.binMid(inIdx);
        NSLog(@"v: %f", v);
        return v;
    }
    else if (inField == CPTBarPlotFieldBarTip)
    {
        return h[inIdx];
    }

    return 0.0;
}

And the resulting graph:

Example plot

Any idea what I'm doing wrong? Thanks!


Solution

  • For this application, the barOffset should be zero (0). The offset is used to displace the bars from the location given by the datasource. The most common use is to separate the bars at the same location when plotting multiple bar plots on the same graph that might have overlapping bars at common locations.