核心绘图在x轴上显示月份(iPhone)

3
我希望使用coreplot在iPhone上绘制一个XY图,其中x轴是日期,y轴是一些值。参考coreplot SDK中提供的DatePlot例子,我已经可以在月度尺度上(即x轴范围从该月的第1天到最后一天)绘制具有日期的图表。现在我想要一个年度尺度,即想要在x轴上显示所有月份名称(Jan,Feb,Mar等),并将我的刻度间隔作为一个月的时间。
我使用以下代码来以月度尺度显示值:
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;

现在,对于年度模式,x轴刻度间隔需要为一个月。我尝试了下面的代码,但没有成功。
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;   

我认为这个逻辑失败了,因为每个月的天数不同。现在月份显示在x轴上,但它显示为

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

您可以看到没有二月,并且五月有两个条目。我的刻度间隔如何与每个月的天数相关联。有什么解决方案吗? 谢谢和问候,

2个回答

1

我曾经遇到过同样的问题。我的快速&简单解决方案是进行自定义标记,循环遍历所有月份并将时间戳添加到数组中。

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

我有一个问题,因为我正在使用CPTAxisLabelingPolicyAutomatic,当我缩放时,x轴被重新绘制为1到10。 - nullmicgo

1

在相关问题中已经回答。使用CPTCalendarFormatter而不是CPTTimeFormatter,当您必须以秒为单位设置时间间隔偏移量时(例如,hour = 60 * 60,day = 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;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接