x 轴上带有月份的核心图 (iphone)

发布于 2024-10-16 12:57:45 字数 1440 浏览 2 评论 0原文

我想在 iphone 上使用 coreplot 绘制 XY 图表,其中 x 轴上有日期,y 轴上有一些值。参考 coreplot SDK 附带的 DatePlot 示例,我能够在 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;

现在对于每年模式,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 月,有 2 个 5 月条目。我的刻度间隔如何与每个月的天数相关。有什么解决办法吗? 谢谢和问候,

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,

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

杯别 2024-10-23 12:57:45

我也有同样的问题。我的快速而肮脏的解决方案是进行自定义标签,循环整个月并将时间戳添加到数组中。

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

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];
海螺姑娘 2024-10-23 12:57:45

刚刚在相关问题中回答过。使用 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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文