Основной сюжет с месяцем по оси X (iphone) - PullRequest
3 голосов
/ 08 февраля 2011

Я хотел бы нарисовать график XY, используя coreplot на iphone с датой на оси x и некоторыми значениями на оси y.Обращаясь к примеру поставки DatePlot с SDK coreplot, я смог нарисовать график с датой на оси x в месячном масштабе (т. Е. X колеблется от 1 числа месяца до последнего числа).Теперь мне нужна годовая шкала, то есть я хочу показать все названия месяцев (январь, февраль, март и т. Д.) По оси x и мой интервал между тиками как один месяц.

Я использовал следующий код для отображения значений в месячной шкале

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;

Сейчас В годовом режиме интервал между тиками должен составлять один месяц.Я попробовал приведенный ниже код, но он не работал

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;   

Я думаю, что эта логика не работает, потому что количество дней для каждого месяца отличается.Сейчас месяцы отображаются на оси х, но отображаются как

Январь, Март, Апрель, Май, Май, Июнь, Июль, Август, Сен, Октябрь, Ноябрь, Дек.

Вы видите, что февраля нет, а в мае 2 записи.Как мой тиковый интервал соотносится с количеством дней с каждым месяцем.Любые решения?Спасибо и всего наилучшего,

Ответы [ 2 ]

1 голос
/ 30 октября 2014

Только что ответил в связанном вопросе. Используйте CPTCalendarFormatter вместо CPTTimeFormatter, это хорошо, когда нужно установить смещение временного интервала в секундах (например, час = 60 * 60, день = 24 * 60 * 60), но месяцы имеют переменное количество дней / секунд (30 * 24 * 60 * 60 или 31 * 24 * 60 * 60, 28, високосные годы и т. Д.). CPTCalendarFormatter позволяет вам выбрать календарную единицу для расчета даты на этикетках. Таким образом, фиксируется контрольная дата и единица измерения календаря, в методе источника данных вам нужно будет возвращать количество этих единиц, начиная с контрольной даты.

Вот полный код, наслаждайтесь.

В вашем viewDidLoad или в другом месте вы инициализируете график:

[...]

// 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_)]];

[...]

Метод источника данных для возврата значений по оси:

 -(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;
}
1 голос
/ 15 апреля 2011

У меня была такая же проблема. Мои быстрые и грязные решения - создавать пользовательские метки, проходя по всему месяцу и добавляя метки времени в массив.

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];
...