Модификация моего кода CorePlot для размещения дат на оси X - PullRequest
0 голосов
/ 21 марта 2012

Я пытаюсь создать простой график с двумя линиями с помощью CorePlot.Начиная с великолепного учебника, найденного на http://www.johnwordsworth.com/2011/10/adding-charts-to-your-iphone-ipad-app-using-core-plot/, я смог сначала создать одну строку (скопировать и вставить из учебника было легко), а затем немного изменить, чтобы добавить вторую строку.

Началов следующем коде (который работает) я хотел бы получить даты на оси X вместо чисел.Значения в этом примере сохраняются в массиве CGPoint с.Я думаю, мне придется что-то изменить в numberForPlot, но как?

TUTSimpleScatterPlot.h

    #import <Foundation/Foundation.h>
    #import "CorePlot-CocoaTouch.h"

@interface TUTSimpleScatterPlot : NSObject <CPTScatterPlotDataSource> {
        CPTGraphHostingView *_hostingView;
        CPTXYGraph *_graph;
        NSMutableDictionary *_graphData;
    }

    @property (nonatomic, retain) CPTGraphHostingView *hostingView;
    @property (nonatomic, retain) CPTXYGraph *graph;
    @property (nonatomic, retain) NSMutableDictionary *graphData;

    -(id)initWithHostingView:(CPTGraphHostingView *)hostingView andData:(NSMutableDictionary *)data;

    // Specific code that creates the scatter plot.
    -(void)initialisePlot;

TUTSimpleScatterPlot.m

#import "TUTSimpleScatterPlot.h"

@implementation TUTSimpleScatterPlot
@synthesize hostingView = _hostingView;
@synthesize graph = _graph;
@synthesize graphData = _graphData;

-(id)initWithHostingView:(CPTGraphHostingView *)hostingView andData:(NSMutableDictionary *)data
{
    self = [super init];

    if ( self != nil ) {
        self.hostingView = hostingView;
        self.graphData = data;
        self.graph = nil;
    }

    return self;
}

// This does the actual work of creating the plot if we don't already have a graph object.
-(void)initialisePlot
{
    // Start with some simple sanity checks before we kick off
    if ( (self.hostingView == nil) || (self.graphData == nil) ) {
        NSLog(@"TUTSimpleScatterPlot: Cannot initialise plot without hosting view or data.");
        return;
    }

    if ( self.graph != nil ) {
        NSLog(@"TUTSimpleScatterPlot: Graph object already exists.");
        return;
    }

    // Create a graph object which we will use to host just one scatter plot.
    CGRect frame = [self.hostingView bounds];
    self.graph = [[CPTXYGraph alloc] initWithFrame:frame];

    // Add some padding to the graph, with more at the bottom for axis labels.
    self.graph.plotAreaFrame.paddingTop = 20.0f;
    self.graph.plotAreaFrame.paddingRight = 20.0f;
    self.graph.plotAreaFrame.paddingBottom = 50.0f;
    self.graph.plotAreaFrame.paddingLeft = 20.0f;

    // Tie the graph we've created with the hosting view.
    self.hostingView.hostedGraph = self.graph;

    // If you want to use one of the default themes - apply that here.
    //[self.graph applyTheme:[CPTTheme themeNamed:kCPTDarkGradientTheme]];

    // Create a line style that we will apply to the axis and data line.
    CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
    lineStyle.lineColor = [CPTColor whiteColor];
    lineStyle.lineWidth = 2.0f;

    CPTMutableLineStyle *lineStyle2 = [CPTMutableLineStyle lineStyle];
    lineStyle2.lineColor = [CPTColor redColor];
    lineStyle2.lineWidth = 2.0f;

    // Create a text style that we will use for the axis labels.
    CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle];
    textStyle.fontName = @"Helvetica";
    textStyle.fontSize = 14;
    textStyle.color = [CPTColor whiteColor];

    // Create the plot symbol we're going to use.
    CPTPlotSymbol *plotSymbol = [CPTPlotSymbol crossPlotSymbol];
    plotSymbol.lineStyle = lineStyle;
    plotSymbol.size = CGSizeMake(8.0, 8.0);

    // Setup some floats that represent the min/max values on our axis.
    float xAxisMin = -10;
    float xAxisMax = 10;
    float yAxisMin = 0;
    float yAxisMax = 100;

    // We modify the graph's plot space to setup the axis' min / max values.
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
    plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(xAxisMin) length:CPTDecimalFromFloat(xAxisMax - xAxisMin)];
    plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(yAxisMin) length:CPTDecimalFromFloat(yAxisMax - yAxisMin)];

    // Modify the graph's axis with a label, line style, etc.
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.graph.axisSet;

    axisSet.xAxis.title = @"Data X";
    axisSet.xAxis.titleTextStyle = textStyle;
    axisSet.xAxis.titleOffset = 30.0f;
    axisSet.xAxis.axisLineStyle = lineStyle;
    axisSet.xAxis.majorTickLineStyle = lineStyle;
    axisSet.xAxis.minorTickLineStyle = lineStyle;
    axisSet.xAxis.labelTextStyle = textStyle;
    axisSet.xAxis.labelOffset = 3.0f;
    axisSet.xAxis.majorIntervalLength = CPTDecimalFromFloat(2.0f);
    axisSet.xAxis.minorTicksPerInterval = 1;
    axisSet.xAxis.minorTickLength = 5.0f;
    axisSet.xAxis.majorTickLength = 7.0f;

    axisSet.yAxis.title = @"Data Y";
    axisSet.yAxis.titleTextStyle = textStyle;
    axisSet.yAxis.titleOffset = 40.0f;
    axisSet.yAxis.axisLineStyle = lineStyle;
    axisSet.yAxis.majorTickLineStyle = lineStyle;
    axisSet.yAxis.minorTickLineStyle = lineStyle;
    axisSet.yAxis.labelTextStyle = textStyle;
    axisSet.yAxis.labelOffset = 3.0f;
    axisSet.yAxis.majorIntervalLength = CPTDecimalFromFloat(10.0f);
    axisSet.yAxis.minorTicksPerInterval = 1;
    axisSet.yAxis.minorTickLength = 5.0f;
    axisSet.yAxis.majorTickLength = 7.0f;

    // Add a plot to our graph and axis. We give it an identifier so that we
    // could add multiple plots (data lines) to the same graph if necessary.
    CPTScatterPlot *plot = [[CPTScatterPlot alloc] init];
    plot.dataSource = self;
    plot.identifier = @"mainplot";
    plot.dataLineStyle = lineStyle;
    plot.plotSymbol = plotSymbol;
    [self.graph addPlot:plot];


    // second plot
    CPTScatterPlot *plot2 = [[CPTScatterPlot alloc] init];
    plot2.dataSource = self;
    plot2.identifier = @"otherplot";
    plot2.dataLineStyle = lineStyle2;
    plot2.plotSymbol = plotSymbol;
    [self.graph addPlot:plot2];

}

// Delegate method that returns the number of points on the plot
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
    if ( [plot.identifier isEqual:@"mainplot"] )
    {
        return [[self.graphData objectForKey:@"1"] count];
    }

    if ( [plot.identifier isEqual:@"otherplot"] )
    {
        return [[self.graphData objectForKey:@"2"] count];

    }

    return 0;
}

// Delegate method that returns a single X or Y value for a given plot.
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
    if ( [plot.identifier isEqual:@"mainplot"] )
    {
        NSValue *value = [[self.graphData objectForKey:@"1"] objectAtIndex:index];
        CGPoint point = [value CGPointValue];

        // FieldEnum determines if we return an X or Y value.
        if ( fieldEnum == CPTScatterPlotFieldX )
        {
            return [NSNumber numberWithFloat:point.x];
        }
        else    // Y-Axis
        {
            return [NSNumber numberWithFloat:point.y];
        }
    }

    if ( [plot.identifier isEqual:@"otherplot"] )
    {
        NSValue *value = [[self.graphData objectForKey:@"2"] objectAtIndex:index];
        CGPoint point = [value CGPointValue];

        // FieldEnum determines if we return an X or Y value.
        if ( fieldEnum == CPTScatterPlotFieldX )
        {
            return [NSNumber numberWithFloat:point.x];
        }
        else    // Y-Axis
        {
            return [NSNumber numberWithFloat:point.y];
        }
    }


    return [NSNumber numberWithFloat:0];
}

@end

И в другом классе я вызываю вышеуказанный метод:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    NSMutableArray *data = [NSMutableArray array];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(-10, 100)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(-8, 50)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(-6, 20)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(-4, 10)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(-2, 5)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(0, 0)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(2, 4)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(4, 16)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(6, 36)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(8, 64)]];
    [data addObject:[NSValue valueWithCGPoint:CGPointMake(10, 100)]];

    // second line values
    NSMutableArray *data2 = [NSMutableArray array];
    [data2 addObject:[NSValue valueWithCGPoint:CGPointMake(0, 0)]];
    [data2 addObject:[NSValue valueWithCGPoint:CGPointMake(3, 5)]];
    [data2 addObject:[NSValue valueWithCGPoint:CGPointMake(5, 17)]];
    [data2 addObject:[NSValue valueWithCGPoint:CGPointMake(7, 37)]];
    [data2 addObject:[NSValue valueWithCGPoint:CGPointMake(9, 65)]];
    [data2 addObject:[NSValue valueWithCGPoint:CGPointMake(11, 99)]];

    NSMutableDictionary *dataDictionary = [NSMutableDictionary dictionary];
    [dataDictionary setObject:data forKey:@"1"];
    [dataDictionary setObject:data2 forKey:@"2"];




    self.scatterPlot = [[TUTSimpleScatterPlot alloc] initWithHostingView:_graphHostingView andData:dataDictionary];
    [self.scatterPlot initialisePlot];

}

Наконециспользуемые данные будут содержать метку времени и значение для каждой строки.Я преобразую метку времени, чтобы создать читаемую дату на оси X.Это будет для одной или нескольких строк.

1 Ответ

1 голос
/ 22 марта 2012

В Core Plot есть несколько примеров приложений, которые показывают, как наносить даты на ось. Классы CPTCalendarFormatter и CPTTimeFormatter полезны для форматирования дат. CPTCalendarFormatter был добавлен после релиза 1.0, поэтому вам нужно будет загрузить последний код с Mercurial, если вы хотите его использовать.

...