Core plot with month on x Axis (iphone)

I would like to draw an XY graph using coreplot on iphone with date on x axis and some values on y axis. Referring to the DatePlot example shipping with the coreplot SDK, I was able to draw graph with date on x axis on a monthly scale (ie x ranges from 1 date of the month to last date). Now I want an yearly scale , ie I want to show All month names (Jan,Feb,Mar etc) on x axis and my tick inteval as one month time.

I used following code for showing values in a monthly scale

oneXUnit        =   60 * 60 * 24;
x.majorIntervalLength    =  CPDecimalFromFloat((float) oneXUnit);
NSDateFormatter *dateFormatter   =   [[[NSDateFormatter alloc] init]autorelease];
NSString *dateString        =   @"0";
[dateFormatter setDateFormat:@"MM"];
CPTimeFormatter *timeFormatter  =   [[CPTimeFormatter alloc]initWithDateFormatter:dateFormatter];
timeFormatter.referenceDate =   [dateFormatter dateFromString:dateString];
x.labelFormatter    =   timeFormatter;

Now For yearly mode x tick inteval needs to be one month. I tried the below code , but didnt work

oneXUnit        =   60 * 60 * 24 * 30;
x.majorIntervalLength    =  CPDecimalFromFloat((float) oneXUnit);
NSDateFormatter *dateFormatter   =   [[[NSDateFormatter alloc] init]autorelease];
NSString *dateString        =   @"Jan";
[dateFormatter setDateFormat:@"MMM"];
CPTimeFormatter *timeFormatter  =   [[CPTimeFormatter alloc]initWithDateFormatter:dateFormatter];
timeFormatter.referenceDate =   [dateFormatter dateFromString:dateString];
x.labelFormatter    =   timeFormatter;   

I think this logic fails because number of days for each months are different. Now months are showing on x axis, but it is showing as

Jan,Mar,April,May,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec.

You can see that there is no Feb and there are 2 entries for May. How can my tick interval relates with the number of days with each month. Any solutions? Thanks and Regards,


I had the same problem. My quick&dirty solutions is to do custom labeling, looping through all month and add the timestamps to an array.

x.labelingPolicy = CPAxisLabelingPolicyNone;

NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:12];
NSMutableArray *customMajorTickLocations = [NSMutableArray arrayWithCapacity:12];
NSMutableArray *customMinorTickLocations = [NSMutableArray arrayWithCapacity:12];
NSDate* dateCurrentMonth = [[NSDate date] dateAtStartOfYear];

for (NSUInteger iMonth = 0; iMonth < 12; iMonth++)
{
    NSNumber* numMajorTickLocation = [NSNumber numberWithDouble:[dateCurrentMonth timestampAtMidnight]];
    NSNumber* numMinorTickLocation = [NSNumber numberWithDouble:[dateCurrentMonth timestampAtMidnight]+14*oneDay];

CPAxisLabel *newLabel = [[CPAxisLabel alloc] initWithText:[dateFormatter stringFromDate:dateCurrentMonth] textStyle:x.labelTextStyle];
newLabel.tickLocation = [numMinorTickLocation decimalValue];
newLabel.offset = x.labelOffset + x.majorTickLength;

dateCurrentMonth = [[dateCurrentMonth dateByAddingDays:32] dateAtStartOfMonth];

[customLabels addObject:newLabel];
[customMajorTickLocations addObject:numMajorTickLocation];
[customMinorTickLocations addObject:numMinorTickLocation];
[newLabel release];

}

// add a last major tick to close the range
[customMajorTickLocations addObject:[NSNumber numberWithDouble:[dateCurrentMonth timestampAtMidnight]]];

x.axisLabels = [NSSet setWithArray:customLabels];
x.majorTickLocations = [NSSet setWithArray:customMajorTickLocations];
x.minorTickLocations = [NSSet setWithArray:customMinorTickLocations];

Just answered in a related question. Use CPTCalendarFormatter instead of CPTTimeFormatter, that is good when you have to set time interval offset in seconds (ex. hour= 60*60, day=24*60*60), but months have a variable number of days/seconds (30*24*60*60 or 31*24*60*60, 28, leap years ecc.). CPTCalendarFormatter let you decide the calendar unit for date calculations on labels. In this way, fixed a reference date and a reference calendar unit, in the datasource method you will have to return the number of those units starting from the reference date.

Here's full code, enjoy.

In your viewDidLoad or elsewhere you initialize the graph:

[...]

// Graph host view
CPTGraphHostingView* hostView = [[CPTGraphHostingView alloc] initWithFrame:self.view.frame];
[self.view addSubview: hostView];

// Your graph
CPTGraph* graph = [[CPTXYGraph alloc] initWithFrame:hostView.bounds];
hostView.hostedGraph = graph;
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)[graph axisSet];    

// xAxis configuration
CPTXYAxis *xAxis = [axisSet xAxis];
[xAxis setLabelingPolicy:CPTAxisLabelingPolicyFixedInterval];
// Prepare dateFormat for current Locale, we want "JAN 2014" "FEB 2014" and so on
NSString *dateComponents = @"MMMYY";
NSString *localDateFormat = [NSDateFormatter dateFormatFromTemplate:dateComponents options:0 locale:[NSLocale currentLocale]];
NSDateFormatter *labelDateFormatter=[[NSDateFormatter alloc] init];
labelDateFormatter.dateFormat=localDateFormat;    
// Set xAxis date Formatter
CPTCalendarFormatter *xDateYearFormatter = [[CPTCalendarFormatter alloc] initWithDateFormatter:labelDateFormatter];
//Keep in mind this reference date, it will be used to calculate NSNumber in dataSource method
xDateYearFormatter.referenceDate = [NSDate dateWithTimeIntervalSince1970:0];
xDateYearFormatter.referenceCalendarUnit=NSMonthCalendarUnit;    
[xAxis setLabelFormatter:xDateYearFormatter];

// yAxis configuration
CPTXYAxis *yAxis = [axisSet yAxis];
[yAxis setMajorIntervalLength:CPTDecimalFromFloat(_YOURYINTERVAL_)];
[yAxis setLabelingPolicy:CPTAxisLabelingPolicyFixedInterval];
[yAxis setLabelFormatter:_YOURYFORMATTER_];
[yAxis setAxisConstraints:[CPTConstraints constraintWithLowerOffset:0.0]]

// Get the (default) plotspace from the graph so we can set its x/y ranges
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
NSDate *startDate=_YOURSTARTINGDATE_
//Number of months since the reference date
NSInteger xStart=[[[NSCalendar currentCalendar] components: NSCalendarUnitMonth
                                 fromDate: xDateYearFormatter.referenceDate
                                   toDate: _YOURSTARTINGDATE_
                                  options: 0] month];    
[plotSpace setXRange: [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInteger(xStart)     length:CPTDecimalFromInteger(_YOURDATESARRAY_.count-1)]];
[plotSpace setYRange: [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0.0) length:CPTDecimalFromFloat(_YOURMAXYVALUE_)]];

[...]

Datasource method to return values on axis:

 -(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    switch (fieldEnum) {

        case CPTScatterPlotFieldX: {

            NSInteger monthsOffset=[[[NSCalendar currentCalendar] components: NSCalendarUnitMonth  fromDate: [NSDate dateWithTimeIntervalSince1970:0] toDate: [_YOURDATESARRAY_ objectAtIndex:index] options: 0] month];                
            NSNumber *val = [NSNumber numberWithInteger:monthsOffset];    
            return val;
            break;
        }
        case CPTScatterPlotFieldY: {
            NSNumber *val=_YOURVALUEFORYAXIS_;
            return val;
            break;
        }
        default:
            break;
    }

    return nil;
}
链接地址: http://www.djcxy.com/p/61032.html

上一篇: 计算日期时间轴最小值,最大值和主要次要时间间隔

下一篇: 核心情节月x轴(iphone)