Question

I have code which display me graph with two plots. What I want and didn't find how to do is that: On x-axis where is DateTime I need correct proportional intervals between Dates, not the same. Here is my code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    DateTime = @[@"2013-10-05 08:47:52",@"2013-10-06 08:47:52",@"2013-10-07 08:47:52",@"2013-10-08 08:47:52",@"2013-10-09 08:47:52",@"2013-10-12 08:47:52",@"2013-10-13 08:47:52"];
    temp1 = @[@"17.1",@"20",@"19",@"16",@"15",@"15",@"17"];
    temp2 = @[@"13",@"11",@"13",@"10",@"11",@"12",@"13"];
    [self initPlot];
}
-(void)initPlot
{
    [self configureHost];
    [self configureGraph];
    [self configurePlots];
    [self configureAxes];
}
-(void)configureHost
{
    self.hostView = [(CPTGraphHostingView *) [CPTGraphHostingView alloc] initWithFrame:self.view.bounds];
    self.hostView.allowPinchScaling = YES;
    [self.view addSubview:self.hostView];
}
-(void)configureGraph
{
    // 1 - Create the graph
    CPTGraph *graph = [[CPTXYGraph alloc] initWithFrame:self.hostView.bounds];
    [graph applyTheme:[CPTTheme themeNamed:kCPTSlateTheme]];
    self.hostView.hostedGraph = graph;
    // 2 - Set graph title
    NSString *title = @"Testovací graf";
    graph.title = title;
    // 3 - Create and set text style
    CPTMutableTextStyle *titleStyle = [CPTMutableTextStyle textStyle];
    titleStyle.color = [CPTColor blackColor];
    titleStyle.fontName = @"Helvetica-Bold";
    titleStyle.fontSize = 12.0f;
    graph.titleTextStyle = titleStyle;
    graph.titlePlotAreaFrameAnchor = CPTRectAnchorTop;
    //graph.titleDisplacement = CGPointMake(0.0f, 10.0f);
    // 4 - Set padding for plot area
    [graph.plotAreaFrame setPaddingLeft:30.0f];
    [graph.plotAreaFrame setPaddingBottom:100.0f];
    // 5 - Enable user interactions for plot space
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
    plotSpace.allowsUserInteraction = YES;

}
-(void)configurePlots
{
    // 1 - Get graph and plot space
    CPTGraph *graph = self.hostView.hostedGraph;
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
    // 2 - Create the plots
    CPTScatterPlot *probe1Plot = [[CPTScatterPlot alloc] init];
    probe1Plot.dataSource = self;
    probe1Plot.identifier = @"Temp1";
    CPTColor *probe1Color = [CPTColor redColor];
    [graph addPlot:probe1Plot toPlotSpace:plotSpace];
    CPTScatterPlot *probe2Plot = [[CPTScatterPlot alloc] init];
    probe2Plot.dataSource = self;
    probe2Plot.identifier = @"Temp2";
    CPTColor *probe2Color = [CPTColor blueColor];
    [graph addPlot:probe2Plot toPlotSpace:plotSpace];
    // 3 - Set up plot space
    [plotSpace scaleToFitPlots:[NSArray arrayWithObjects:probe1Plot, probe2Plot, nil]];
    CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
    [xRange expandRangeByFactor:CPTDecimalFromCGFloat(1.48f)];
    plotSpace.xRange = xRange;
    CPTMutablePlotRange *yRange = [plotSpace.yRange mutableCopy];
    [yRange expandRangeByFactor:CPTDecimalFromCGFloat(3.0f)];
    plotSpace.yRange = yRange;
    // 4 - Create styles and symbols
    CPTMutableLineStyle *probe1LineStyle = [probe1Plot.dataLineStyle mutableCopy];
    probe1LineStyle.lineWidth = 1.0  ;
    probe1LineStyle.lineColor = probe1Color;
    probe1Plot.dataLineStyle = probe1LineStyle;
    CPTMutableLineStyle *probe1SymbolLineStyle = [CPTMutableLineStyle lineStyle];
    probe1SymbolLineStyle.lineColor = probe1Color;
    CPTPlotSymbol *probe1Symbol = [CPTPlotSymbol ellipsePlotSymbol];
    probe1Symbol.fill = [CPTFill fillWithColor:probe1Color];
    probe1Symbol.lineStyle = probe1SymbolLineStyle;
    probe1Symbol.size = CGSizeMake(3.0f, 3.0f);
    probe1Plot.plotSymbol = probe1Symbol;

    CPTMutableLineStyle *probe2LineStyle = [probe2Plot.dataLineStyle mutableCopy];
    probe2LineStyle.lineWidth = 1.0;
    probe2LineStyle.lineColor = probe2Color;
    probe2Plot.dataLineStyle = probe2LineStyle;
    CPTMutableLineStyle *probe2SymbolLineStyle = [CPTMutableLineStyle lineStyle];
    probe2SymbolLineStyle.lineColor = probe2Color;
    CPTPlotSymbol *probe2Symbol = [CPTPlotSymbol diamondPlotSymbol];
    probe2Symbol.fill = [CPTFill fillWithColor:probe2Color];
    probe2Symbol.lineStyle = probe2SymbolLineStyle;
    probe2Symbol.size = CGSizeMake(3.0f, 3.0f);
    probe2Plot.plotSymbol = probe2Symbol;
}
-(void)configureAxes
{
    // 1 - Create styles
    CPTMutableTextStyle *axisTitleStyle = [CPTMutableTextStyle textStyle];
    axisTitleStyle.color = [CPTColor blackColor];
    axisTitleStyle.fontName = @"Helvetica-Bold";
    axisTitleStyle.fontSize = 10.0f;
    CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
    axisLineStyle.lineWidth = 1.5f;
    axisLineStyle.lineColor = [CPTColor blackColor];
    CPTMutableTextStyle *axisTextStyle = [[CPTMutableTextStyle alloc] init];
    axisTextStyle.color = [CPTColor blackColor];
    axisTextStyle.fontName = @"Helvetica-Bold";
    axisTextStyle.fontSize = 11.0f;
    CPTMutableLineStyle *tickLineStyle = [CPTMutableLineStyle lineStyle];
    tickLineStyle.lineColor = [CPTColor blackColor];
    tickLineStyle.lineWidth = 2.0f;
    CPTMutableLineStyle *gridLineStyle = [CPTMutableLineStyle lineStyle];
    gridLineStyle.lineColor = [CPTColor grayColor];
    gridLineStyle.lineWidth = 0.5f;
    // 2 - Get axis set
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *) self.hostView.hostedGraph.axisSet;
    // 3 - Configure x-axis
    CPTAxis *x = axisSet.xAxis;
    x.title = @"DateTime";
    x.titleTextStyle = axisTitleStyle;
    x.titleOffset = 85.0f;
    x.axisLineStyle = axisLineStyle;
    x.labelingPolicy = CPTAxisLabelingPolicyNone;
    x.labelTextStyle = axisTextStyle;
    x.majorTickLineStyle = axisLineStyle;
    x.majorTickLength = 4.0f;
    x.tickLabelDirection = CPTSignNegative;

    CGFloat dateCount = [DateTime count];
    NSMutableSet *xLabels = [NSMutableSet setWithCapacity:dateCount];
    NSMutableSet *xLocations = [NSMutableSet setWithCapacity:dateCount];
    NSInteger i = 0;
    for (NSString *date in DateTime)
    {
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateStyle:NSDateFormatterShortStyle];
        NSString *str = [self localTime:date];
        CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:str textStyle:x.labelTextStyle];
        CGFloat location = i++;
        label.tickLocation = CPTDecimalFromCGFloat(location);
        label.offset = x.majorTickLength;

        if (label)
        {
            [xLabels addObject:label];
            [xLocations addObject:[NSNumber numberWithFloat:location]];
        }
    }

    x.axisLabels = xLabels;
    x.majorTickLocations = xLocations;
    x.labelRotation = M_PI / 4;

    // 4 - Configure y-axis
    CPTAxis *y = axisSet.yAxis;
    y.title = @"Temperature";
    y.titleTextStyle = axisTitleStyle;
    y.titleOffset = 30.0f;
    y.axisLineStyle = axisLineStyle;
    y.majorGridLineStyle = gridLineStyle;
    y.labelingPolicy = CPTAxisLabelingPolicyNone;
    y.labelTextStyle = axisTextStyle;
    y.labelOffset = -16.0f;
    y.majorTickLineStyle = axisLineStyle;
    y.majorTickLength = 2.0f;
    y.minorTickLength = 2.0f;

    NSInteger majorIncrement = 10;
    NSInteger minorIncrement = 1;
    CGFloat yMax = 40.0f; // should determine dynamically based on max temp
    NSMutableSet *yLabels = [NSMutableSet set];
    NSMutableSet *yMajorLocations = [NSMutableSet set];
    NSMutableSet *yMinorLocations = [NSMutableSet set];
    for (NSInteger j = minorIncrement; j <= yMax; j+= minorIncrement)
    {
        NSInteger mod = j % majorIncrement;
        if (mod == 0)
        {
            CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:[NSString stringWithFormat:@"%li", (long)j] textStyle:y.labelTextStyle];
            NSDecimal location = CPTDecimalFromInteger(j);
            label.tickLocation = location;
            label.offset = -y.majorTickLength - y.labelOffset;
            if (label)
            {
                [yLabels addObject:label];
            }
            [yMajorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:location]];
        }
        else
        {
            [yMinorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:CPTDecimalFromInteger(j)]];
        }
    }
    y.axisLabels = yLabels;
    y.majorTickLocations = yMajorLocations;
    y.minorTickLocations = yMinorLocations;

    CPTGraph *graph = self.hostView.hostedGraph;
    graph.legend = [CPTLegend legendWithGraph:graph];
    CPTMutableLineStyle *legendBorderlineStyle = [CPTMutableLineStyle lineStyle];
    legendBorderlineStyle.lineColor = [CPTColor blackColor];
    legendBorderlineStyle.lineWidth = 1.0f;
    legendBorderlineStyle.lineColor = [CPTColor blackColor];
    graph.legend.borderLineStyle = legendBorderlineStyle;
    graph.legend.fill = [CPTFill fillWithColor:[CPTColor lightGrayColor]];
    graph.legend.cornerRadius = 5.0;
    graph.legend.swatchSize = CGSizeMake(10, 20);
    graph.legendAnchor = CPTRectAnchorBottom;
    graph.legend.textStyle = axisTextStyle;
    graph.legendDisplacement = CGPointMake(150.40, 250.0);   
}
- (NSString *) localTime:(NSString *)time //this is for recount TimeZone ofset
{
    NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
    //Special Locale for fixed dateStrings
    NSLocale *locale = [[NSLocale alloc]initWithLocaleIdentifier:@"en_US_POSIX"];
    [formatter setLocale:locale];

    //Assuming the dateString is in GMT+00:00
    //formatter by default would be set to local timezone
    NSTimeZone *timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    [formatter setTimeZone:timeZone];
    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];

    NSDate *date =[formatter dateFromString:time];

    //After forming the date set local time zone to formatter
    NSTimeZone *localTimeZone = [NSTimeZone localTimeZone];
    [formatter setTimeZone:localTimeZone];

    NSString *newTimeZoneDateString = [formatter stringFromDate:date];

    return newTimeZoneDateString;
}
#pragma mark - CPTPlotDataSource methods
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
   // return [DateTime count];
    if ([(NSString *)plot.identifier isEqualToString:@"Temp1"])
    {
        return temp1.count;
    }
    else if ([(NSString *)plot.identifier isEqualToString:@"Temp2"])
    {
        return temp2.count;
    }
    return 0;
}
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)idx
{

    NSNumber *num = nil;
    switch (fieldEnum) {
        case CPTScatterPlotFieldX:
            num = [NSNumber numberWithUnsignedInteger:idx];
            break;
        case CPTScatterPlotFieldY:
            if ([(NSString *)plot.identifier isEqualToString:@"Temp1"])
            {
                num = [temp1 objectAtIndex:idx];
            }
            else if ([(NSString *)plot.identifier isEqualToString:@"Temp2"])
            {
                num = [temp2 objectAtIndex:idx];
            }
            break;
    }
    return num;
}

I wantproportional gaps between DateTime items on X-axis. If someone helps me, I'll be very lucky. Thanks. :)

Was it helpful?

Solution 2

There are several example apps included with Core Plot that demonstrate working with dates. See, for example, the "Date Plot" demo in the Plot Gallery app.

You need to convert the date value to numeric values and use those for the x-values instead of the data index. Be sure to set the plot space xRange accordingly.

OTHER TIPS

Eric is an expert, and his answer is good enough. But I want to contribute with more details, which are necessary for beginners like me, having a lot of troubles putting things into proper places.

First, you need to set proper range (I did learn a great deal from Eric on that).

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"HH:mm"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:25200]];

NSTimeInterval xLow   = [[dateFormatter dateFromString:@"8:30"] timeIntervalSince1970];
NSTimeInterval xHigh  = [[dateFormatter dateFromString:@"12:00"] timeIntervalSince1970];
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(xLow)
                                               length:CPTDecimalFromDouble(xHigh-xLow)];

Next, for fixed intervals (e.g. half an hour), use the following:

x.labelingPolicy = CPTAxisLabelingPolicyFixedInterval;
NSTimeInterval x1   = [[dateFormatter dateFromString:@"8:30"] timeIntervalSince1970];
NSTimeInterval x2  = [[dateFormatter dateFromString:@"9:30"] timeIntervalSince1970];
x.majorIntervalLength = CPTDecimalFromDouble(x2-x1);

//Label time Format:
CPTTimeFormatter *timeFormatter = [[CPTTimeFormatter alloc] initWithDateFormatter:dateFormatter];
x.labelFormatter   = timeFormatter;

For custom labelling, replace the above two sections with the following:

x.labelingPolicy = CPTAxisLabelingPolicyNone;
NSMutableSet *xLabels = [NSMutableSet setWithCapacity:[self.arrXValues count]];
NSMutableSet *xLocations = [NSMutableSet setWithCapacity:[self.arrXValues count]];
for (NSString *string in self.arrXValues) {
    CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:string  textStyle:axisTextStyle];
    NSDate *time = [dateFormatter dateFromString:string];
    NSTimeInterval interval = [time timeIntervalSince1970];
    label.tickLocation = CPTDecimalFromDouble(interval);
    label.rotation    = M_PI * 1/4;
    label.offset = 0.0f;
    if (label) {
        [xLabels addObject:label];
        [xLocations addObject:[NSString stringWithFormat:@"%f", interval]];
    }
}
x.axisLabels = xLabels;
x.majorTickLocations = xLocations;

And finally, core plot delegate method,

-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)indexPath
{
if(fieldEnum == CPTScatterPlotFieldX)
{
    //return [NSNumber numberWithFloat:[[self.arrXValues objectAtIndex:indexPath] floatValue]];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"HH:mm"];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:25200]];
    NSDate *time = [dateFormatter dateFromString:[self.arrXValues objectAtIndex:indexPath]];
    NSTimeInterval interval = [time timeIntervalSince1970];

    return [NSNumber numberWithDouble:interval];
}
else if(fieldEnum == CPTScatterPlotFieldY) {
    return [NSNumber numberWithFloat:[[self.arrYValues objectAtIndex:indexPath] floatValue]];
}
return nil;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top