multiple function curves in core-plot - objective-c

I'm currently trying to add more than one mathematical function curves. Below is part of my code.
// draw all expression curves (in viewDidLoad)
for ( j=0; j<self.expNum; j++ ) {
[self getDataForPlot1:self.plotIndex]; // get DataForPlot of one selected expression
[self addCurve:self.plotIndex];
}
I'm trying to add all curves after drawing the axes, but it is only the last input curve that is drawn. How can I separate the dataForPlot for each function?
-(void)getDataForPlot1:(int)index
{
int i;
NSString *exp;
int bound, plotNum;
double interval;
bound = 3 * scaleX;
plotNum = 3 * 60;
interval = (double)bound / plotNum;
NSMutableArray *contentArray = [NSMutableArray arrayWithCapacity:2*plotNum];
for ( i = -plotNum; i < plotNum; i++ ) {
id x;
x = [NSNumber numberWithFloat: i * interval];
// get one expression
.......
id y = [exp numberByEvaluatingString]; // get y values from the expression
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, #"x", y, #"y", nil]];
}
dataForPlot = contentArray;
}
-(void)addCurve:(int)index {
CPTScatterPlot *boundLinePlot = [[CPTScatterPlot alloc] init];
CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
lineStyle.miterLimit = 1.0f;
lineStyle.lineWidth = 3.0f;
lineStyle.lineColor = [CPTColor blueColor];
boundLinePlot.dataLineStyle = lineStyle;
boundLinePlot.identifier = #"Blue Plot";
boundLinePlot.dataSource = self;
[graph addPlot:boundLinePlot toPlotSpace:plotSpace];
boundLinePlot.interpolation = CPTScatterPlotInterpolationCurved;
}

(Answering the question based on comments above)
Save a copy of each dataset separately. It looks like the calculated plot data gets overwritten each time you call -getDataForPlot1:.
Also, set a unique identifier for each plot so the datasource can know which one is requesting data.

Related

How do you animate different Core Animation layers simultaneously?

I'm currently trying to implement an animation using Core Animation on iOS. Right now I can apply multiple animations to a single layer using CAAnimationGroup, but if I want to repeat that across various different layers --- simultaneously --- things get hazy.
Currently it looks like CAAnimationGroup is a singleton class (or at least, I only seem to get one instance, and I allocate using [CAAnimationGroup animation].
Any ideas?
NSMutableDictionary* elementInstanceData = [self.elementInstanceValues objectForKey:elementInstance];
NSArray* animationValues = [elementInstanceData objectForKey:#"animationValues"];
NSArray* keyTimeValues = [elementInstanceData objectForKey:#"keyTimeValues"];
NSNumber* elementDurationTime = elementInstanceData[#"duration"];
if(animationValues != nil)
{
NSMutableArray* transValues = [[NSMutableArray alloc]init];
NSMutableArray* scaleValues = [[NSMutableArray alloc]init];
NSMutableArray* rotateValues = [[NSMutableArray alloc]init];
for(NSDictionary* transforms in animationValues)
{
NSValue* trans = transforms[#"translate"];
[transValues addObject:trans];
NSValue* scale = transforms[#"scale"];
[scaleValues addObject:scale];
NSValue* rotate = transforms[#"rotate"];
[rotateValues addObject:rotate];
}
NSMutableArray* ratioTimeValues = [[NSMutableArray alloc]init];
for(NSNumber* time in keyTimeValues)
{
float percentage = ([time floatValue] / [elementDurationTime floatValue]);
[ratioTimeValues addObject:[NSNumber numberWithFloat:percentage ]];
}
NSCAssert( [ratioTimeValues count] == [transValues count], #"Keytime/value mismatch (times:%d, values: %d)", [ratioTimeValues count], [transValues count]) ;
CAKeyframeAnimation* transAnim = [CAKeyframeAnimation animationWithKeyPath:#"position"];
[transAnim setValues:transValues];
[transAnim setKeyTimes:ratioTimeValues];
transAnim.beginTime = CACurrentMediaTime() + startTime;
transAnim.duration = durationTime;
[allAnimations addObject:transAnim];
CAKeyframeAnimation* scaleAnim = [CAKeyframeAnimation animationWithKeyPath:#"transform"];
[scaleAnim setValues:scaleValues];
[scaleAnim setKeyTimes:ratioTimeValues];
scaleAnim.beginTime = CACurrentMediaTime() + startTime;
scaleAnim.duration = durationTime;
[allAnimations addObject:scaleAnim];
CAKeyframeAnimation* rotAnim = [CAKeyframeAnimation animationWithKeyPath:#"transform.rotation.z"];
[rotAnim setValues:rotateValues];
[rotAnim setKeyTimes:ratioTimeValues];
rotAnim.beginTime = CACurrentMediaTime() + startTime;
rotAnim.duration = durationTime;
[allAnimations addObject:rotAnim];
}
CAAnimationGroup* elementInstanceAnimationGroup = [CAAnimationGroup animation];
elementInstanceAnimationGroup.animations = allAnimations;
elementInstanceAnimationGroup.beginTime = CACurrentMediaTime();
elementInstanceAnimationGroup.duration = [elementDurationTime floatValue];
elementInstanceAnimationGroup.delegate = self;
[elementInstanceData setObject:elementInstanceAnimationGroup forKey:#"animationGroup"];
UIView* targetView = [elementInstanceData objectForKey:#"target"];
[targetView.layer addAnimation:elementInstanceAnimationGroup forKey:nil];
I can apply multiple animations to a single layer using CAAnimationGroup, but if I want to repeat that across various different layers --- simultaneously --- things get hazy.
A single animation group can animate properties of different named sublayers.
For example, suppose I have a layer with two sublayers. The name of the first sublayer is "manny" and the name of the second sublayer is "moe". And let's say I want to animate the position of the two sublayers individually.
Then I use a keyPath of "sublayers.manny.position" for one animation, and a keyPath of "sublayers.moe.position", group them, and attach the group to the superlayer.
You can create an animation or animation group and add it to multiple layers.
CABasicAnimation* fadeIn = [CABasicAnimation animationWithKeyPath:#"opacity"];
fadeIn.duration = 0.35;
fadeIn.fromValue = [NSNumber numberWithDouble:0];
fadeIn.toValue = [NSNumber numberWithDouble:1];
for (int i = 0; i < self.indicatorBars.count; i++) {
[self.indicatorBars[i] addAnimation:fadeIn forKey:#"opacity"];
}

Creating An Array of CGFloat for Gradient Locations

I'm trying to create a gradient color out of an array of dictionary (colorArray2). This dictionary contains 5 keys: r, g, b, a, p. r, g, b, a are component values (strings), p being the location. I'm trying to create a gradient color with initWithColors:atLocations:colorSpace. For now, I have the following.
NSGradient *aGradient;
NSColorSpace *space = [NSColorSpace genericRGBColorSpace];
NSMutableArray *cArray = [[NSMutableArray alloc] initWithObjects:nil]; // storing colors
NSMutableArray *pArray = [[NSMutableArray alloc] initWithObjects:nil]; // storing locations
for (NSInteger i2 = 0; i2 < colorArray2.count; i2++) {
NSString *r = [[colorArray2 objectAtIndex:i2] objectForKey:key2a];
NSString *g = [[colorArray2 objectAtIndex:i2] objectForKey:key2b];
NSString *b = [[colorArray2 objectAtIndex:i2] objectForKey:key2c];
NSString *a = [[colorArray2 objectAtIndex:i2] objectForKey:key2d];
NSString *p = [[colorArray2 objectAtIndex:i2] objectForKey:key2e];
NSColor *color = [NSColor colorWithSRGBRed:[r integerValue]/255.0f green:[g integerValue]/255.0f blue:[b integerValue]/255.0f alpha:[a integerValue]/100.0f];
[cArray addObject:color];
[pArray addObject:[NSNumber numberWithDouble:[p doubleValue]]];
}
So I have an array (cArray) containing colors. What I don't know is how to create an array of locations. According to the documentation, locations is an array of CGFloat values containing the location for each color in the gradient. How do I enumerate whatever to create a float array?
Thank you for your help.
Update
More specifically, how do I make pArray to get something like
double d[] = {0.1, 0.2, 0.3, 0.5, 1.0};
so that I can have
aGradient = [[NSGradient alloc] initWithColors:cArray atLocations:d colorSpace:space];
NSGradient's documentation states that locations parameter should be of type const CGFloat*, so you can't use NSArray*. The following should work:
// Allocate a C-array with the same length of colorArray2
CGFloat* pArray = (CGFloat*)malloc(colorArray2.count * sizeof(CGFloat));
for (NSInteger i2 = 0; i2 < colorArray2.count; i2++) {
// Extract location
NSString* p = [[colorArray2 objectAtIndex:i2] objectForKey:key2e];
pArray[i2] = [p doubleValue];
}
// Do whaterver with pArray
...
// Remember to free it
free(pArray);
You can use:
NSArray *colors = #[[NSColor colorWithWhite:.3 alpha:1.0],
[NSColor colorWithWhite:.6 alpha:1.0],
[NSColor colorWithWhite:.3 alpha:1.0]];
CGFloat locations[3] = {0.0, 0.5, 1.0};
NSGradient *gradient = [[NSGradient alloc] initWithColors:colors atLocations:locations colorSpace:[NSColorSpace genericRGBColorSpace]];
[gradient drawInRect:CGRectMake(100.0, 7.0, 10.0, 18.0) angle:-90];
To the other answers: no. Just no.
Actual answer:
How do I make an array of CGFloats in objective c?
First of all, this is Objective-C, not C. Technically you can use malloc, but that's a really terrible hack. You should convert to an NSNumber and then you can populate the NSArray. After, you can convert back using NSNumber's floatValue method. This way is proper Objective-C. Mixing and matching C and Obj-C just creates spaghetti code which is hard to read and eventually becomes unmaintainable.
I got it.
NSInteger count,index;
double *dArray;
count = pArray.count;
dArray = (double *) malloc(sizeof(double) * count);
for (index = 0; index < count; index++) {
dArray[index] = [[pArray objectAtIndex:index] floatValue];
}
aGradient = [[NSGradient alloc] initWithColors:cArray atLocations:dArray colorSpace:space];

Dynamically set the width of bar in bar graph

Hi All
Can someone help me with this problem I have encountered
Can I plot a bargraph in coreplote with unequal bar width meaning Say my X-axis interval is 1 unit and I have set the bar graph width as same 1 unit. But there are certain points where x-axis value changes at 0.5units and i want the bar width to be equal to the width where change has occurred. And the data is dynamically changing. Is there any other solution that I can use and still looks like a bar graph. The only reason for using bar is I need to fill the plot space.
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)barChart.defaultPlotSpace;
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromInt(0)
length:CPDecimalFromInt(rangeY)];
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(-0.5f)
length:CPDecimalFromFloat(rangeX)];
CPXYAxisSet *axisSet = (CPXYAxisSet *)barChart.axisSet;
CPXYAxis *x = axisSet.xAxis;
x.axisLineStyle = nil;
x.majorTickLineStyle = nil;
x.minorTickLineStyle = nil;
x.majorIntervalLength = CPDecimalFromString(#"1");
x.orthogonalCoordinateDecimal = CPDecimalFromString(#"0");
x.title = [[[tempCol colName] componentsSeparatedByString:#"*#"] objectAtIndex:0];
x.titleLocation = CPDecimalFromFloat((rangeX-1)/2);
x.titleOffset = 25.0f;
// Define some custom labels for the data elements
x.labelRotation = 0;
x.labelingPolicy = CPAxisLabelingPolicyNone;
NSMutableArray *customTickLocations = [[NSMutableArray alloc] init];
NSMutableArray *xAxisLabels = [[NSMutableArray alloc] init];
for (int i = 0; i < [tempGraph.d2pArray count]; i++) {
tempD2P = [tempGraph.d2pArray objectAtIndex:i];
[customTickLocations addObject:[NSNumber numberWithInt:i]];
[xAxisLabels addObject:[tempD2P d2pName]];
}
NSUInteger labelLocation = 0;
NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:[xAxisLabels count]];
for (NSNumber *tickLocation in customTickLocations) {
CPAxisLabel *newLabel = [[CPAxisLabel alloc]
initWithText:[xAxisLabels objectAtIndex:labelLocation++]
textStyle:x.labelTextStyle];
newLabel.tickLocation = [tickLocation decimalValue];
newLabel.offset = 0;
newLabel.rotation = 0;
newLabel.alignment = CPAlignmentCenter;
[customLabels addObject:newLabel];
[newLabel release];
newLabel = nil;
}
[xAxisLabels release];
xAxisLabels = nil;
[customTickLocations release];
customTickLocations = nil;
x.axisLabels = [NSSet setWithArray:customLabels];
CPXYAxis *y = axisSet.yAxis;
CPLineStyle *majorGridLineStyle = [CPLineStyle lineStyle];
majorGridLineStyle.lineWidth = 0.75;
majorGridLineStyle.lineColor = [CPColor colorWithCGColor:[[UIColor grayColor] CGColor]];
y.axisLineStyle = nil;
y.majorTickLineStyle = nil;
y.majorGridLineStyle = majorGridLineStyle;
y.minorTickLineStyle = nil;
y.majorIntervalLength = CPDecimalFromInt(rangeY/8);
y.orthogonalCoordinateDecimal = CPDecimalFromString(#"-0.5");
y.title = [[[tempCol colName] componentsSeparatedByString:#"*#"] objectAtIndex:1];
y.titleOffset = 30 + 5*log10(mult);
y.titleLocation = CPDecimalFromInt(rangeY/2);
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:0];
y.labelFormatter = formatter;
[formatter release];
formatter = nil;
char firstChar = 'F';
CPBarPlot *barPlot;
// First bar plot
for (int i = 0; i < noOfBarCharts; i++) {
static CPTextStyle *whiteText = nil;
if ( !whiteText ) {
whiteText = [[CPTextStyle alloc] init];
whiteText.color = [CPColor whiteColor];
whiteText.fontSize = 14;
}
barPlot = [CPBarPlot tubularBarPlotWithColor:[CPColor colorWithComponentRed:[[[rgbArray objectAtIndex:0] objectAtIndex:i] floatValue]/255.0
green:[[[rgbArray objectAtIndex:1] objectAtIndex:i] floatValue]/255.0
blue:[[[rgbArray objectAtIndex:2] objectAtIndex:i] floatValue]/255.0
alpha:1.0]
horizontalBars:NO];
barPlot.baseValue = CPDecimalFromString(#"0");
barPlot.dataSource = self;
barPlot.barOffset = ([tempGraph.graType rangeOfString:#"GROUPED"].location != NSNotFound)?(i+0.5)-(noOfBarCharts/2):0;
barPlot.labelOffset = 0;
barPlot.barWidth = 20;
barPlot.identifier = [NSString stringWithFormat:#"%d%c", [tempGraph.graID intValue], (firstChar - noOfBarCharts +1 + i)];
barPlot.delegate = self;
[barChart addPlot:barPlot
toPlotSpace:plotSpace];
I figured it out myself instead of using a bar chart i used a scatter plot with step graph That did the trick :
Plot.interpolation = CPTScatterPlotInterpolationStepped;
and filled the plot with:
Plot.areaFill = [CPTFill fillWithColor:[CPTColor blueColor]];
Plot.areaBaseValue = CPTDecimalFromInteger(0);
If you're not putting a border line on the bars, you could make the bar width half the distance between bars and double-up the wide ones.

Aligning CCMenu to a grid

Does anybody know the best practice approach to getting an array of CCMenuItems to align to a grid? This is a cocos2d question
For example :
int levelCount = 10;
CCMenu *menuArray = [CCMenu menuWithItems:nil];
for (int x = 1; x<=levelCount; x++) {
CCLOG(#"Creating level icon for Level %i", x);
[menuArray addChild:[CCMenuItemImage itemFromNormalImage:#"Button2n.png"
selectedImage:#"Button2s.png"
target:self
selector:#selector(onPlay:)]];
}
[menuArray alignToGridWouldbeGreat????!!!!];
[self addChild:menuArray];
I can align vertically, horizontally, in columns or rows however cannot wrap a column or row configuration.
Thanks in advance!
You just have to call one of the overloaded alignItemsInColumns or alignItemsInRows methods. For example if you have 15 menu items and you want 3 rows of 5 columns, do this:
CCMenu* menu = [CCMenu menuWithItems:...];
NSNumber* itemsPerRow = [NSNumber numberWithInt:5];
[menu alignItemsInColumns:itemsPerRow, itemsPerRow, itemsPerRow, nil];
The only down side is that there doesn't seem to be a way to set padding when aligning to a grid.
Ok, while not as flexible as I would like, I've got a decent enough solution for my purposes. Anyone else can feel free to use this code if they too find it useful.
//////// Put images (or whatever) for all levels in an array /////////
int levelCount = 15;
NSMutableArray* menuArray = [NSMutableArray arrayWithCapacity:levelCount];
for (int x = 1; x<=levelCount; x++) {
CCLOG(#"Creating level icon for Level %i", x);
CCMenuItemImage* item = [CCMenuItemImage itemFromNormalImage:#"Button2n.png"
selectedImage:#"Button2s.png"
target:self
selector:#selector(onPlay:)];
[menuArray addObject:item];
}
//////// arrange in a grid with specific number of columns /////////
CGSize screenSize = [CCDirector sharedDirector].winSize;
int columns = 5;
int spaceBetweenColumns = columns + 1;
int spacing = screenSize.width / spaceBetweenColumns;
CCLOG(#"screenWidth (%f) / columnsWithEdges (%i) = spacing = %i, ", screenSize.width, spaceBetweenColumns, spacing);
CGPoint currentDrawPoint = CGPointMake(0, screenSize.height - spacing); // start at the top
for (CCMenuItem *item in menuArray) {
currentDrawPoint.x = currentDrawPoint.x + spacing;
if (currentDrawPoint.x > (columns * spacing)) {
// start a new line as we have reached the end of the previous one
currentDrawPoint.x = spacing;
currentDrawPoint.y = currentDrawPoint.y - spacing;
}
item.position = currentDrawPoint;
[self addChild:item];
}
Here is my solution, i hope it helps.
First define this struct somewhere:
typedef struct
{
int cols;
}RowInfo;
Then:
-(void)layoutMenu:(CCMenu *)menu rowInfo:(RowInfo[])inf rows:(int)rows padding:(CGPoint)padding
{
CCMenuItem *dummy = (CCMenuItem *)[menu.children objectAtIndex:0];
int itemIndex = 0;
float w = dummy.contentSize.width;
float h = dummy.contentSize.height;
CGSize screenSize = [[CCDirector sharedDirector]winSize];
CCArray *items = [menu children];
float startX;
for (int i = rows - 1; i >=0; i--)
{
int colsNow = info[i].cols;
startX = (screenSize.width - (colsNow * w + padding.x * (colsNow - 1)))/2;
float y = i * (padding.y + h);
for (int j = 0; j < colsNow; j++)
{
CCMenuItem *item = (CCMenuItem *)[items objectAtIndex:itemIndex];
item.anchorPoint = ccp(0,0);
item.position = ccp(startX, y);
startX += padding.x + w;
itemIndex++;
}
}
}
The call goes like this(a custom keyboard):
//create custom keyboard
NSArray *captions = [NSArray arrayWithObjects:
#"Q", #"W", #"E", #"R", #"T", #"Y", #"U", #"I", #"O", #"P",
#"A", #"S", #"D", #"F", #"G",#"H", #"J", #"K", #"L",
#"Z", #"X", #"C", #"V", #"B", #"N", #"M", nil];
CCMenu *menu = [CCMenu menuWithItems:nil];
[self addChild:menu];
for (NSString *caption in captions)
{
CCLabelTTF *label = [CCLabelTTF labelWithString:caption fontName:#"Courier" fontSize:25];
CCMenuItemLabel *item = [CCMenuItemLabel itemWithLabel:label target:self selector:#selector(callDelegate:)];
[menu addChild:item];
}
RowInfo info[3] = {{7}, {9}, {10}}; //inverse order
[self layoutMenu:menu withRowInfo:info rows:3 padding:ccp(15, 15)];
May be you can try this....
[menuArray alignItemsVerticallyWithPadding:20.0];
or
[first_menu alignItemsHorizontallyWithPadding:20.0];
To the best of my knowledge Anish's answer is your best course of action. It would be the same as aligning to a grid and it is what I personally use. Just set your menu position and alignment padding and you should have what you are looking for.

Moving date on x-axis

I have been playing with Core Plot and trying to create a dynamic date x-axis. From the date plot example I have managed to create a static date axis, but would like to create a two-minute window at any time and update the xRange values. I am not sure on how to pass dates as the xRange min and length values and display time on the x-axis.
I have looked at examples, but I haven't been able to utilize NSTimeInterval (if this is how to do it...).
Below is the picture (if it helps)
Below is my attempt so far; can someone please advise me on how to achieve this?
- (void)loadView {
// Alloc & Init Main View and since the display resolution is 1024x768 take 20 off for labels later
UIView *tmpView = [ [ UIView alloc ] initWithFrame:CGRectMake(0, 0, 1024.0,768.0) ];
[ tmpView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ];
[ tmpView setBackgroundColor:[ UIColor redColor ] ];
// Alloc Graph View
graphView = [ [ CPGraphHostingView alloc ] initWithFrame:CGRectMake(0, 0, 1024.0,768.0) ];
[ tmpView addSubview:[ graphView autorelease ] ];
// Set MainView
[ self setView:[ tmpView autorelease ] ];
}
-(void)viewDidLoad{
[super viewDidLoad];
NSDate *refDate = [NSDate date];
// NSTimeInterval oneDay = 24 * 60 * 60;
NSTimeInterval oneHour = 60 * 60;
NSTimeInterval fivemin= 5 * 60;
// Create graph from theme
graph = [(CPXYGraph *) [CPXYGraph alloc] initWithFrame:self.view.bounds];
CPTheme *theme = [CPTheme themeNamed:kCPDarkGradientTheme];
[graph applyTheme:theme];
graphView.hostedGraph = graph;
//padding
graph.paddingLeft = 20.0;
graph.paddingTop = 20.0;
graph.paddingRight = 20.0;
graph.paddingBottom = 20.0;
graph.plotAreaFrame.paddingTop=10.0;
graph.plotAreaFrame.paddingLeft=50.0;
graph.plotAreaFrame.paddingRight=35.0;
graph.plotAreaFrame.paddingBottom=50.0;
// Setup scatter plot space
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
NSTimeInterval xLow = 0.0f;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(xLow) length:CPDecimalFromFloat(oneHour)];
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0.0f) length:CPDecimalFromFloat(100.0f)];
//Line Styles
CPLineStyle *lineStyle = [CPLineStyle lineStyle];
lineStyle.lineColor = [CPColor redColor];
lineStyle.lineWidth = 2.0f;
CPLineStyle *majorGridLineStyle = [CPLineStyle lineStyle];
majorGridLineStyle.lineWidth = 0.75;
majorGridLineStyle.lineColor = [[CPColor colorWithGenericGray:0.2] colorWithAlphaComponent:0.75];
CPLineStyle *minorGridLineStyle = [CPLineStyle lineStyle];
minorGridLineStyle.lineWidth = 0.25;
minorGridLineStyle.lineColor = [[CPColor whiteColor] colorWithAlphaComponent:0.1];
CPXYAxisSet *axisSet = (CPXYAxisSet *)graph.axisSet;
// X-Axes formatting
CPXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPDecimalFromFloat(oneHour);
x.orthogonalCoordinateDecimal = CPDecimalFromString(#"0");
x.minorTicksPerInterval = 0;
x.labelOffset=0;
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
dateFormatter.dateStyle = kCFDateFormatterShortStyle;
CPTimeFormatter *timeFormatter = [[[CPTimeFormatter alloc] initWithDateFormatter:dateFormatter] autorelease];
timeFormatter.referenceDate = refDate;
x.labelFormatter = timeFormatter;
x.majorGridLineStyle = majorGridLineStyle;
x.minorGridLineStyle = minorGridLineStyle;
x.title=#"Time Axis";
//Y-Axes formatting
CPXYAxis *y = axisSet.yAxis;
y.majorIntervalLength = [ [ NSDecimalNumber decimalNumberWithString:#"10.0" ] decimalValue ];
y.orthogonalCoordinateDecimal = CPDecimalFromString(#"0");
y.minorTicksPerInterval = 5;
y.labelOffset = 0.0;
y.majorGridLineStyle = majorGridLineStyle;
y.minorGridLineStyle = minorGridLineStyle;
y.preferredNumberOfMajorTicks = 10;
y.minorTickLineStyle = nil;
y.labelTextStyle = nil;
y.visibleRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0.0f) length:CPDecimalFromFloat(100.0f)];
CPConstraints yConstraints = {CPConstraintFixed, CPConstraintFixed};
y.isFloatingAxis=YES;
y.constraints=yConstraints;
// Create a plot that uses the data source method
CPScatterPlot *dataSourceLinePlot = [[[CPScatterPlot alloc] init] autorelease];
dataSourceLinePlot.identifier = #"Date Plot";
dataSourceLinePlot.dataLineStyle = lineStyle;
dataSourceLinePlot.dataSource = self;
[graph addPlot:dataSourceLinePlot];
mydata = [[NSMutableArray alloc]initWithObjects:
[NSDecimalNumber numberWithInt:0],
nil ];
//a timer to re-load the graph every 2 seconds and re-draw x-axis
Timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(testingTimer:) userInfo:nil repeats:YES];
}
-(NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot
{
return mydata.count;
}
-(NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
switch ( fieldEnum ) {
case CPScatterPlotFieldX:
return (NSDecimalNumber *)[NSDecimalNumber numberWithUnsignedInteger:index];
case CPScatterPlotFieldY:
return [mydata objectAtIndex:index];
}
return nil;
}
-(void) testingTimer: (NSTimer *) Timer{
//generating random number and add to mydata array
testdata=arc4random() % 100;
[mydata addObject:[NSNumber numberWithInt:testdata]];
[graph reloadData];
count++;
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(count) length:CPDecimalFromFloat(5*30.0f)];
}
the location for the xRange is where you want the plot to start, for example if you had 5 minutes(assuming 1 entry per second) of data loaded for the plot and you wanted to start at minute 3 your location would be 3*60. your length would always be 2*60 if you only want to show 2 minutes of data.
you probably want to change x.majorIntervalLength as well, that value controls how often a major tick is placed along the x axis. your major tick usually has a label associated with it, so you'd want to lower that value to something more appropriate for only 2 minutes of data