How to rapidly create an NSMutableArray with CFDataRef image pixel data in Xcode for iOS - objective-c

My question is simple, I have the following code, it creates an array of Hues got from a function that returns the UIColor of an image (this is not important, just context). So, I need to create this array as fast as possible, this test runs with only a 5x5 pixels image and it takes about 3sec, I want to be able to run a 50x50 pixels image (at least) in about 2 secods (tops), any ideas?
- (void)createArrayOfHues: (UIImage *)imageScaned{
if (imageScaned != nil) {
NSLog(#"Creating Array...");
UIImageView *img = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
img.contentMode = UIViewContentModeScaleToFill;
img.image = imageScaned;
img.contentMode = UIViewContentModeRedraw;
img.hidden = YES;
int i = 0;
CGFloat hue = 0;
CGFloat sat = 0;
CGFloat brit = 0;
CGFloat alph = 0;
CGFloat hue2 = 0;
CGFloat sat2 = 0;
CGFloat brit2 = 0;
CGFloat alph2 = 0;
[_colorsArray removeAllObjects];
[_satForHue removeAllObjects];
[_britForHue removeAllObjects];
[_alphForHue removeAllObjects];
_colorsArray = [[NSMutableArray alloc] initWithCapacity:(25)];
_satForHue = [[NSMutableArray alloc] initWithCapacity:(25)];
_britForHue = [[NSMutableArray alloc] initWithCapacity:(25)];
_alphForHue = [[NSMutableArray alloc] initWithCapacity:(25)];
while (i<25) {
for (int y=1; y <= 5; y++){
for (int x = 1; x <= 2.5; x++){
if (x != (5-x)){
UIColor *color = [self colorMatch:imageScaned :x :y];
UIColor *color2 = [self colorMatch:imageScaned :(5-x) :y];
if([color getHue:&hue saturation:&sat brightness:&brit alpha:&alph] && [color2 getHue:&hue2 saturation:&sat2 brightness:&brit2 alpha:&alph2]){
NSNumber *hueId = [NSNumber numberWithFloat:(float)hue];
NSNumber *satId = [NSNumber numberWithFloat:(float)sat];
NSNumber *britId = [NSNumber numberWithFloat:(float)brit];
NSNumber *alphId = [NSNumber numberWithFloat:(float)alph];
NSNumber *hueId2 = [NSNumber numberWithFloat:(float)hue2];
NSNumber *satId2 = [NSNumber numberWithFloat:(float)sat2];
NSNumber *britId2 = [NSNumber numberWithFloat:(float)brit2];
NSNumber *alphId2 = [NSNumber numberWithFloat:(float)alph2];
[_colorsArray insertObject:hueId atIndex:i];
[_satForHue insertObject:satId atIndex:i];
[_britForHue insertObject:britId atIndex:i];
[_alphForHue insertObject:alphId atIndex:i];
[_colorsArray insertObject:hueId2 atIndex:(i+1)];
[_satForHue insertObject:satId2 atIndex:(i+1)];
[_britForHue insertObject:britId2 atIndex:(i+1)];
[_alphForHue insertObject:alphId2 atIndex:(i+1)];
}
NSLog(#"color inserted at %i with x: %i and y: %i" , i , x, y);
i++;
}else {
UIColor *color = [self colorMatch:imageScaned :x :y];
if([color getHue:&hue saturation:&sat brightness:&brit alpha:&alph]){
NSNumber *hueId = [NSNumber numberWithFloat:(float)hue];
NSNumber *satId = [NSNumber numberWithFloat:(float)sat];
NSNumber *britId = [NSNumber numberWithFloat:(float)brit];
NSNumber *alphId = [NSNumber numberWithFloat:(float)alph];
[_colorsArray insertObject:hueId atIndex:i];
[_satForHue insertObject:satId atIndex:i];
[_britForHue insertObject:britId atIndex:i];
[_alphForHue insertObject:alphId atIndex:i];
}
}
}
}
}
NSLog(#"Returns the array");
}else{
NSLog(#"Returns nothing");
}
}
The code for colorMatch:
- (UIColor *) colorMatch: (UIImage *)image :(int) x :(int) y {
isBlackColored = NO;
if (image == nil){
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL customColor = [defaults boolForKey:#"custom_color"];
if (customColor){
float red = [defaults floatForKey:#"custom_color_slider_red"];
float green = [defaults floatForKey:#"custom_color_slider_green"];
float blue = [defaults floatForKey:#"custom_color_slider_blue"];
return [UIColor colorWithRed:red green:green blue:blue alpha:1];
}else
isDefaultS = YES;
}
else{
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8* data = CFDataGetBytePtr(pixelData);
int pixelInfo = ((image.size.width * y) + x ) * 4;
UInt8 red = data[pixelInfo];
UInt8 green = data[(pixelInfo + 1)];
UInt8 blue = data[pixelInfo + 2];
UInt8 alpha = data[pixelInfo + 3];
CFRelease(pixelData);
float redC = red/255.0f;
float greenC = green/255.0f;
float blueC = blue/255.0f;
UIColor* color = [UIColor colorWithRed:redC green:greenC blue:blueC alpha:alpha/255.0f];
return color;
}
return nil;
}

I think your main performance bottleneck is not the initialization of NSMutableArray instances, but the way you index your image:
UIColor *color = [self colorMatch:imageScaned :x :y];
I guess this method converts the UIImage to a CGImageRef, copies its data, indexes it, then destroys/releases these temporary objects, or something like this - for every single pixel...
You should refactor this code to get hold of the image buffer only once, and then work with it like a regular C pointer/array. If that doesn't solve your performance problem, you should do some profiling.

Related

Can not differentiate between data for plots, CorePlot

I am trying to plot 2 lines on 1 graph using CorePlot. Right now I am plotting the same data twice, I am not sure how to choose the other data source.
Any help would be appreciated.
Code:
graph view code .m:
CPTScatterPlot *limitplot = [[CPTScatterPlot alloc] init];
limitplot.dataSource = self;
limitplot.identifier = #"limplot";
limitplot.dataLineStyle = lineStylelimit;
limitplot.plotSymbol = plotSymbollimit;
[self.graph addPlot:limitplot];
CPTScatterPlot *calplot = [[CPTScatterPlot alloc] init];
calplot.dataSource = self;
calplot.identifier = #"plot";
calplot.dataLineStyle = lineStylecalc;
calplot.plotSymbol = plotSymbolcalc;
[self.graph addPlot:calplot];
}
// Delegate method that returns the number of points on the plot
-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot
{
if ( [plot.identifier isEqual:#"limplot"] )
{
return [self.graphData count];
}
else if ( [plot.identifier isEqual:#"plot"] )
{
return [self.graphData 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:#"limplot"] )
{
NSValue *value = [self.graphData 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];
}
} else if ( [plot.identifier isEqual:#"plot"] )
{
NSValue *value = [self.graphData 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];
}
Data .m:
NSMutableArray *limitdata = [NSMutableArray array];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5477, 5400)]];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5292, 5400)]];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5053, 6425)]];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5029, 7154)]];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5138, 8300)]];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5503, 8300)]];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5570, 7100)]];
[limitdata addObject:[NSValue valueWithCGPoint:CGPointMake(5477, 5400)]];
self.lewis = [[TUTSimpleScatterPlot alloc] initWithHostingView:_graphHostingView andData:limitdata];
[self.lewis initialisePlot];
double cofullMass = [coTOMass doubleValue];
double cofullStation = [coTOstation doubleValue];
double coeeMass = [coEEmass doubleValue];
double coeeStation = [coEEstation doubleValue];
double cossMass = [coSSmass doubleValue];
double cossStation = [coSSstation doubleValue];
double codryMass = [coZmass doubleValue];
double codryStation = [coZstation doubleValue];
NSMutableArray *caldata = [NSMutableArray array];
[caldata addObject:[NSValue valueWithCGPoint:CGPointMake(cofullStation, cofullMass)]];
[caldata addObject:[NSValue valueWithCGPoint:CGPointMake(coeeStation, coeeMass)]];
[caldata addObject:[NSValue valueWithCGPoint:CGPointMake(cossStation, cossMass)]];
[caldata addObject:[NSValue valueWithCGPoint:CGPointMake(codryStation, codryMass)]];
self.lewis = [[TUTSimpleScatterPlot alloc] initWithHostingView:_graphHostingView andData:caldata];
[self.lewis initialisePlot];
You've got everything correct including testing the plot identifier and the fieldEnum. Once you determine which plot is asking for data, use that to choose the right data array instead of getting the count and data points from self.graphData for both plots.

Drawing an Bar graph on cocoa using core plot

I'm new to mac app development. I'm drawing a bar graph using core plot frame work.
What actually i want to is, when i select a month i want to draw graph for last 6 months.when i select '12/2012' I'm able to draw the graph correctly for last 6 months. But when i select '02/2013' the graph is showing only January and February and not the previous months.
- (int)maxVal:(NSMutableArray *)arr {
NSDictionary *dict = [arr objectAtIndex:0];
NSString* dictValue = [dict objectForKey:#"X_VAL"];
int mxm = [dictValue intValue];
for (int i=0; i<[arr count]; i++) {
if ([[[arr objectAtIndex:i] objectForKey:#"X_VAL"] intValue] > mxm) {
mxm = [[[arr objectAtIndex:i] objectForKey:#"X_VAL"] intValue];
}
}
return mxm;
}
- (int)minVal:(NSMutableArray *)arr {
int mn = [[[arr objectAtIndex:0] objectForKey:#"X_VAL"] intValue];
for (int i=0; i<[arr count]; i++) {
if ([[[arr objectAtIndex:i] objectForKey:#"X_VAL"] intValue] < mn) {
mn = [[[arr objectAtIndex:i] objectForKey:#"X_VAL"] intValue];
}
}
return mn;
}
- (void)drawGraph {
if ([graphMutableArray count] > 0) {
NSRect viewRect = [aGraphView bounds];
double xAxisStart = 0, yAxisStart = 0, xAxisLength = [graphMutableArray count], yAxisLength = [[graphMutableArray valueForKeyPath:#"#max.Y_VAL"] doubleValue], tenthPartOfYAxis = (yAxisLength + (yAxisLength / 10));
NSLog(#"Y Axis Length = %f", yAxisLength);
for (int k = 0; k < xAxisLength; k++) {
NSDictionary *dict1 = [graphMutableArray objectAtIndex:k];
NSDictionary *dict2 = [dict1 objectForKey:#"X_VAL"];
NSDictionary *dict3 = [dict1 valueForKey:#"Y_VAL"];
NSLog(#"dict 2 = %# and dict 3 = %#", dict2, dict3);
}
graph = [[CPTXYGraph alloc] initWithFrame:viewRect];
[graph applyTheme:[CPTTheme themeNamed:kCPTSlateTheme]];//kCPTDarkGradientTheme]];//kCPTStocksTheme]];
aGraphView.hostedGraph = graph;
graph.plotAreaFrame.masksToBorder = NO;
graph.paddingLeft = 90.0;
graph.paddingTop = 20.0;
graph.paddingRight = 20.0;
graph.paddingBottom = 70.0;
// Add plot space for horizontal bar charts
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(xAxisStart)
length:CPTDecimalFromDouble(xAxisLength + 1)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(yAxisStart)
length:CPTDecimalFromDouble(tenthPartOfYAxis)];
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
NSString *cptDecimalstr = [NSString stringWithFormat:#"%f", xAxisLength /[x.axisLabels count]];
x.majorIntervalLength = CPTDecimalFromString(cptDecimalstr);
x.minorTicksPerInterval = 1;
x.majorTickLineStyle = nil;
x.minorTickLineStyle = nil;
x.axisLineStyle = nil;
x.titleLocation = CPTDecimalFromFloat(1.0f);
x.titleOffset = 55.0f;
// Define some custom labels for the data elements
x.labelRotation = M_PI/4;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
NSLog(#"Max = %d and Min = %d", [self maxVal:graphMutableArray], [self minVal:graphMutableArray]);
NSMutableArray *tempCustomTickLocations = [NSMutableArray arrayWithObjects:[NSNumber numberWithFloat:0.5],[NSNumber numberWithFloat:1.7],[NSNumber numberWithFloat:3.0],[NSNumber numberWithFloat:4.1],[NSNumber numberWithFloat:5.3],[NSNumber numberWithFloat:6.5],[NSNumber numberWithFloat:6.9],[NSNumber numberWithFloat:7.1],[NSNumber numberWithFloat:7.5],[NSNumber numberWithFloat:8.1],[NSNumber numberWithFloat:8.5],[NSNumber numberWithFloat:8.9],nil];
NSMutableArray *tempMonthsArr = [NSMutableArray arrayWithObjects:#"",#"January", #"February", #"March", #"April", #"May", #"June", #"July", #"August", #"September", #"October", #"November", #"December", nil];
NSMutableArray *tempMonthsMutArr
= [[[NSMutableArray alloc] initWithCapacity:[graphMutableArray count]] autorelease], *tempMutCustomTickLocations
= [[[NSMutableArray alloc] initWithCapacity:[graphMutableArray count]] autorelease];
int k = 0;
for (int l = [self minVal:graphMutableArray]; l <=[self maxVal:graphMutableArray]; l++) {
NSString *tempMonth = [tempMonthsArr objectAtIndex:l];
[tempMonthsMutArr addObject:tempMonth];
[tempMutCustomTickLocations addObject:[tempCustomTickLocations objectAtIndex:k]];
k = k + 1;
NSLog(#"tempMutCustomTickLocations= %#",tempMutCustomTickLocations);
}
if ([self minVal:graphMutableArray] == [self maxVal:graphMutableArray]) {
NSString *tempMonth = [tempMonthsArr objectAtIndex:[self minVal:graphMutableArray]];
[tempMonthsMutArr addObject:tempMonth];
[tempMutCustomTickLocations addObject:[tempCustomTickLocations objectAtIndex:0]];
}
NSMutableArray *customTickLocations = [NSMutableArray arrayWithArray:tempMutCustomTickLocations];
NSArray *xAxisLabels = [NSArray arrayWithArray:tempMonthsMutArr];
NSUInteger labelLocation = 0;
NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:[graphMutableArray count]];
for (NSNumber *tickLocation in customTickLocations) {
//NSLog(#"tickLocation==%d",tickLocation.intValue);
CPTAxisLabel *newLabel = [[CPTAxisLabel alloc] initWithText: [xAxisLabels objectAtIndex:labelLocation++] textStyle:x.labelTextStyle];
newLabel.tickLocation = [tickLocation decimalValue];//[tickLocation decimalValue];
newLabel.offset = x.labelOffset + x.majorTickLength;
// NSLog(#"[tickLocation floatValue] = %f", [tickLocation floatValue]);
newLabel.offset = x.labelOffset + x.majorTickLength;
//NSLog(#"x.labelOffset = %f, x.majorTickLength = %f and newLabel.offset = %f", x.labelOffset, x.majorTickLength, newLabel.offset);
newLabel.rotation = M_PI/4;
//NSLog(#"-=-=-=--=-=-=- %f",x.labelOffset);
//NSLog(#"%f", x.majorTickLength );
[customLabels addObject:newLabel];
//NSLog(#"%#",customLabels);
[newLabel release];
}
x.axisLabels = [NSSet setWithArray:customLabels];
NSLog(#"%#",x.axisLabels);
CPTXYAxis *y = axisSet.yAxis;
y.axisLineStyle = nil;
y.majorTickLineStyle = nil;
y.minorTickLineStyle = nil;
NSString *cptDecimalStr = [NSString stringWithFormat:#"%f", yAxisLength / 10];
y.majorIntervalLength = CPTDecimalFromString(cptDecimalStr);
//y.constantCoordinateValue = CPTDecimalFromString(#"0");
// y.title = #"Y Axis";
y.titleOffset = 45.0f;
y.titleLocation = CPTDecimalFromFloat(150.0f);
//CPTPieChart
CPTBarPlot *plot = [[CPTBarPlot alloc] initWithFrame:CGRectZero];
plot.plotRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0.0)
length:CPTDecimalFromDouble(xAxisLength)];
plot.barOffset = [[NSDecimalNumber decimalNumberWithString:#"0.50"]
decimalValue]; //CPTDecimalFromDouble(0.50f);
plot.fill = [CPTFill fillWithColor:[CPTColor lightGrayColor]];
plot.dataSource = self;
[graph addPlot:plot ];//toPlotSpace:plotSpace];
}
else {
aGraphView.hostedGraph = nil;
[[NSAlert alertWithMessageText:#"No Data Found" defaultButton:#"Ok" alternateButton:nil otherButton:nil informativeTextWithFormat:#""] runModal];
}
}
Can Anyone Help me to solve the problem!!!
You need to update the xRange of the plot space. This will move the axis labels to the correct position and draw data points in the new range. You'll also need to add the new data points to the plot.

How to set the UILabel's UIColor from a Plist

the question is in the title, How to set the UILabel's UIColor from a Plist ?
i tried this :
UIColor *colorLabel;
i add a NSString row in my Plist, and wrote redColor as a value but doesnt work...
How can i handle it ?
Thanks guys.
I would personally store the RGBA values instead of a string and then you can just use
+ (UIColor *)colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha
Do not do the below
Just as an interesting side note the most inflexible way would be to use the UIColor convenience methods like this
[UIColor performSelector:NSSelectorFromString(#"redColor")]
I think you need convert from string to an UIColor. You put colors into your plist by hex-colors (for red - ff0000) and then use something like following function for get UIColor.
+ (UIColor *) colorWithHexString: (NSString *) stringToConvert
{
    NSString *cString = [[stringToConvert stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
    // String should be 6 or 8 characters
    if ([cString length] < 6) return [UIColor blackColor];
    // strip 0X if it appears
    if ([cString hasPrefix:#"0X"]) cString = [cString substringFromIndex:2];
    if ([cString length] != 6) return [UIColor blackColor];
    // Separate into r, g, b substrings
    NSRange range;
    range.location = 0;
    range.length = 2;
    NSString *rString = [cString substringWithRange:range];
    range.location = 2;
    NSString *gString = [cString substringWithRange:range];
    range.location = 4;
    NSString *bString = [cString substringWithRange:range];
    // Scan values
    unsigned int r, g, b;
    [[NSScanner scannerWithString:rString] scanHexInt:&r];
    [[NSScanner scannerWithString:gString] scanHexInt:&g];
    [[NSScanner scannerWithString:bString] scanHexInt:&b];
    
    return [UIColor colorWithRed:((float) r / 255.0f)
                       green:((float) g / 255.0f)
                            blue:((float) b / 255.0f)
                       alpha:1.0f];
}
To preserve human readability, I did a category for this:
#implementation UIColor (EPPZRepresenter)
NSString *NSStringFromUIColor(UIColor *color)
{
const CGFloat *components = CGColorGetComponents(color.CGColor);
return [NSString stringWithFormat:#"[%f, %f, %f, %f]",
components[0],
components[1],
components[2],
components[3]];
}
UIColor *UIColorFromNSString(NSString *string)
{
NSString *componentsString = [[string stringByReplacingOccurrencesOfString:#"[" withString:#""] stringByReplacingOccurrencesOfString:#"]" withString:#""];
NSArray *components = [componentsString componentsSeparatedByString:#", "];
return [UIColor colorWithRed:[(NSString*)components[0] floatValue]
green:[(NSString*)components[1] floatValue]
blue:[(NSString*)components[2] floatValue]
alpha:[(NSString*)components[3] floatValue]];
}
#end
The same formatting that is used by NSStringFromCGAffineTransform. This is actually a part of a bigger scale plist object representer in eppz!kit at GitHub.

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.

unable to show anything on x-axis and y-axis labels in core-plot

I'm using core plot in an application and from past one week I am trying to show labels on x-axis and y-axis. But haven't succeed yet. I'm posting my code here with screen shot. If someone knows any solution to fix the problem let me know urgently.
Code -
-(void)viewDidLoad {
[super viewDidLoad];
// Initialize all graph dependent data.
//self.dataForPlot = [[NSMutableArray alloc] initWithCapacity:0];
minYValues = [[NSMutableArray alloc] initWithCapacity:0];
maxYValues = [[NSMutableArray alloc] initWithCapacity:0];
[self createGraph];
[self customizeGraph];
}
- (void) createGraph{
// Create graph
graph = [[CPXYGraph alloc] initWithFrame:CGRectZero];
CPGraphHostingView *hostingView = (CPGraphHostingView *)self.view;
hostingView.collapsesLayers = YES;
hostingView.hostedGraph = graph;
hostingView.frame = self.view.frame;
//Create a blue plot area
CPScatterPlot *boundLinePlot = [[[CPScatterPlot alloc] init] autorelease];
boundLinePlot.dataLineStyle.miterLimit = 1.0f;
boundLinePlot.dataLineStyle.lineWidth = 1.0f;
UIColor* color = [UIColor orangeColor];
boundLinePlot.dataLineStyle.lineColor = [CPColor colorWithCGColor:[color CGColor]];
boundLinePlot.dataSource = self;
[graph addPlot:boundLinePlot];
}
- (void) customizeGraph{
if(graph)
{
graph.paddingLeft = 20.0;
graph.paddingTop = 20.0;
graph.paddingRight = 20.0;
graph.paddingBottom = 20.0;
CPScatterPlot *goalWeightPlot = [[[CPScatterPlot alloc] init] autorelease];
goalWeightPlot.identifier = kGoalWeightPlot;
//boundLinePlot.dataLineStyle.miterLimit = 5.0f;
goalWeightPlot.dataLineStyle.lineWidth = 1.0f;
goalWeightPlot.dataLineStyle.lineColor = [CPColor redColor];
goalWeightPlot.dataLineStyle.dashPattern = [NSArray arrayWithObjects:[NSNumber numberWithFloat:5.0],[NSNumber numberWithFloat:2.0],nil];
goalWeightPlot.dataSource = self;
[graph addPlot:goalWeightPlot];
// Create a blue plot area
CPScatterPlot *boundLinePlot = [[[CPScatterPlot alloc] init] autorelease];
boundLinePlot.identifier = kActualWeightPlot;
//boundLinePlot.dataLineStyle.miterLimit = 5.0f;
boundLinePlot.dataLineStyle.lineWidth = 1.0f;
boundLinePlot.dataLineStyle.lineColor = [CPColor orangeColor];
boundLinePlot.dataSource = self;
// Add plot symbols
CPLineStyle *symbolLineStyle = [CPLineStyle lineStyle];
symbolLineStyle.lineColor = [CPColor orangeColor];
CPPlotSymbol *plotSymbol = [CPPlotSymbol ellipsePlotSymbol];
plotSymbol.fill = [CPFill fillWithColor:[CPColor orangeColor]];
plotSymbol.lineStyle = symbolLineStyle;
plotSymbol.size = CGSizeMake(5.0, 5.0);
boundLinePlot.plotSymbol = plotSymbol;
[graph addPlot:boundLinePlot];
}
}
- (void) resetData{
dataForPlot = nil;
}
- (void) setGraphData:(NSArray*)graphData andRefrenceValue:(float)goalValue{
self.refereceValue = goalValue;
[self setGraphData:graphData];
}
- (void) setGraphData:(NSArray*)graphData{
//Check if we have any single weight entry in the array
if(graphData && [graphData count] > 0) {
[self prepareGraphData:graphData];
[self setRangeForGraph];
[graph reloadData];
}
}
- (NSArray *)sortedWeightEntriesByWeightDate:(NSArray *)unsortedArray {
NSMutableArray *tempArray = [NSMutableArray array];
for(int i=0;i<[unsortedArray count];i++) {
NSDateFormatter *df = [[NSDateFormatter alloc]init];
WeightEntry *entry = [unsortedArray objectAtIndex:i];
[df setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [df dateFromString:entry.weightDate];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
if(date) {
[dict setObject:entry forKey:#"entity"];
[dict setObject:date forKey:#"date"];
[tempArray addObject:dict];
}
[df release];
}
NSInteger counter = [tempArray count];
NSDate *compareDate;
NSInteger index;
for(int i = 0 ; i < counter; i++) {
index = i;
compareDate = [[tempArray objectAtIndex:i] valueForKey:#"date"];
NSDate *compareDateSecond;
for(int j = i+1 ; j < counter; j++)
{
compareDateSecond=[[tempArray objectAtIndex:j] valueForKey:#"date"];
NSComparisonResult result = [compareDate compare:compareDateSecond];
if(result == NSOrderedDescending)
{
compareDate = compareDateSecond;
index=j;
}
}
if(i!=index)
[tempArray exchangeObjectAtIndex:i withObjectAtIndex:index];
}
NSMutableArray *sortedArray = [NSMutableArray arrayWithCapacity:0];
NSInteger counterIndex = [tempArray count];
for(int i = 0; i < counterIndex ; i++) {
[sortedArray addObject:[[tempArray objectAtIndex:i] valueForKey:#"entity"]];
}
return [NSArray arrayWithArray:sortedArray];
}
- (void) prepareGraphData:(NSArray*)data{
data = [self sortedWeightEntriesByWeightDate:data];
NSNumber* minYValue = nil;
NSNumber* maxYValue = nil;
NSMutableArray *contentArray = [NSMutableArray arrayWithCapacity:[data count]];
NSUInteger i;
for ( i = 0; i < [data count]; i++ ) {
WeightEntry* weightEntry = [data objectAtIndex:i];
if(i == 0){
maxYValue = [NSNumber numberWithFloat:weightEntry.weight];
minYValue = [NSNumber numberWithFloat:weightEntry.weight];
}
//id x = [NSNumber numberWithFloat:weightEntry.weight];
//id y = [NSNumber numberWithFloat:1.2*rand()/(float)RAND_MAX + 1.2];
id x = [NSNumber numberWithFloat:i];
id y = [NSNumber numberWithFloat:weightEntry.weight];
if([y floatValue] > [maxYValue floatValue])
maxYValue = y;
if([y floatValue] < [minYValue floatValue])
minYValue = y;
//[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, #"x", y, #"y",[NSNumber numberWithFloat:goalWeight],#"goalY",nil]];
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, #"x", y, #"y",nil]];
}
self.dataForPlot = [NSArray arrayWithArray:contentArray];
[minYValues addObject:minYValue];
[maxYValues addObject:maxYValue];
lblHighValue.text = [NSString stringWithFormat:#"High = %0.2f", [maxYValue floatValue]];
lblLowValue.text = [NSString stringWithFormat:#"Low = %0.2f", [minYValue floatValue]];
lblRefrenceValue.text = [NSString stringWithFormat:#"Goal = %0.2f", self.refereceValue];
}
// Update the Plot Space Range to cover all graphs
- (void) setRangeForGraph{
NSNumber* minimumYValue;
NSNumber* maxmumYValue;
if([minYValues count] > 0 && [maxYValues count] > 0){
minimumYValue = [minYValues objectAtIndex:0];
maxmumYValue = [maxYValues objectAtIndex:0];
// Calculate minimum y value among all graphs.
for (int i = 0 ; i < [minYValues count] ; i++) {
if([[minYValues objectAtIndex:i] floatValue] < [minimumYValue floatValue])
minimumYValue = [minYValues objectAtIndex:i];
}
// Calculate maximum y value among all graphs.
for (int i = 0 ; i < [maxYValues count] ; i++) {
if([[maxYValues objectAtIndex:i] floatValue] > [maxmumYValue floatValue])
maxmumYValue = [maxYValues objectAtIndex:i];
}
NSDecimalNumber *high = [NSDecimalNumber decimalNumberWithDecimal:[maxmumYValue decimalValue]];
high = [high decimalNumberByAdding:[NSDecimalNumber decimalNumberWithString:#"30"]];
// Modify the y range for plot space to cover all values.
CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0.0) length:[high decimalValue]];
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat(0.0) length:CPDecimalFromInt([self.dataForPlot count])];
CPPlotAreaFrame *area = (CPPlotAreaFrame *)graph.plotAreaFrame;
area.paddingLeft = 20;
area.paddingBottom = 10;
CPXYAxisSet *axisSet = (CPXYAxisSet*)graph.axisSet;
//axis.paddingLeft = 20.0;
axisSet.xAxis.paddingBottom = 50.0;
CPXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPDecimalFromInteger([self.dataForPlot count]);
CPXYAxis *y = axisSet.yAxis;
y.majorIntervalLength = CPDecimalFromFloat([high floatValue]);
axisSet.xAxis.orthogonalCoordinateDecimal = CPDecimalFromFloat([minimumYValue floatValue]);
//axisSet.xAxis.labelOffset = 0.0;
CPLineStyle *lineStyle = [CPLineStyle lineStyle];
lineStyle.lineColor = [CPColor colorWithCGColor:((UIColor*)kProtienColor).CGColor];
lineStyle.lineWidth = 1.0f;
// style the graph with white text and lines
CPTextStyle *whiteText = [CPTextStyle textStyle];
whiteText.color = [CPColor redColor];
//CPXYAxis *x = axisSet.xAxis;
x.majorIntervalLength = CPDecimalFromString(#"1");
x.axisLineStyle = lineStyle;
//x.majorGridLineStyle=lineStyle;
//x.minorTicksPerInterval = 0;
//x.minorTickLineStyle = lineStyle;
x.title = #"Weight";
x.titleOffset = 3.0f;
x.titleLocation = CPDecimalFromFloat(3.0f);
x.titleTextStyle = whiteText;
x.labelTextStyle = whiteText;
//y.majorIntervalLength = CPDecimalFromString(#"150");
//y.minorTicksPerInterval = 10;
y.axisLineStyle = lineStyle;
y.title = #"Date";
y.titleTextStyle = whiteText;
y.titleOffset = 0;
y.minorTickLineStyle = lineStyle;
//y.titleLocation = CPDecimalFromFloat(graph.frame.origin.y+10);
//y.majorGridLineStyle=lineStyle;
//y.labelTextStyle=whiteText;
}
}
- (NSUInteger)numberOfRecordsForPlot:(CPPlot *)plot {
int nofOfRecords = 0;
#try {
nofOfRecords = [self.dataForPlot count];
}
#catch (NSException * e) {
NSLog(#"Exception while calculating graph index : %#", [e description]);
}
#finally {
//NSLog(#"Number of Records : %d For Graph Index : %d", nofOfRecords, graphIndex);
return nofOfRecords;
}
}
- (NSNumber *)numberForPlot:(CPPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index {
NSNumber *num = 0;
//int plotIndex = [(NSString *)plot.identifier intValue];
if([self.dataForPlot count] > 0){
if(![((NSString*)[plot identifier]) isEqualToString:kGoalWeightPlot]){
num = [[dataForPlot objectAtIndex:index] valueForKey:(fieldEnum == CPScatterPlotFieldX ? #"x" : #"y")];
}else {
if(fieldEnum == CPScatterPlotFieldX)
num = [[dataForPlot objectAtIndex:index] valueForKey:#"x"];
else {
num = [NSNumber numberWithFloat:self.refereceValue];
}
}
}
return num;
}
Screenshot -
I want to show custom labels on x-axis and default labels on y-axis.
EDIT:
I've tried adding sample class of barChart+XIB from CPTest-iPhoneApp. The bar chart appears but axis label's don't. Here is the screenshot form CPTest-iPhone app and mine.
CPXYAxis *yy = axisSet.yAxis;
yy.axisLineStyle.lineColor=[CPColor whiteColor];
yy.majorTickLineStyle = nil;
yy.minorTickLineStyle = nil;
yy.title = #"Y Axis";
yy.titleLocation = CPDecimalFromFloat(100.0f);
yy.titleOffset = 245.0f;
// Define some custom labels for the data elements
yy.labelingPolicy = CPAxisLabelingPolicyNone;
NSArray *customTickLocations1 = [NSArray arrayWithObjects:[NSDecimalNumber numberWithInt:0], [NSDecimalNumber numberWithInt:10],[NSDecimalNumber numberWithInt:20], [NSDecimalNumber numberWithInt:30], nil];
NSArray *yAxisLabels = [NSArray arrayWithObjects:#"a",#"b", #"c",nil];
NSUInteger labelLocation1 = 0;
NSMutableArray *customLabels1 = [NSMutableArray arrayWithCapacity:[yAxisLabels count]];
for (NSNumber *tickLocation1 in customTickLocations1)
{
CPAxisLabel *newLabel1 = [[CPAxisLabel alloc]
initWithText: [yAxisLabels objectAtIndex:labelLocation1++]
textStyle:yy.labelTextStyle];
newLabel1.tickLocation = [tickLocation1 decimalValue];
newLabel1.offset = yy.labelOffset + yy.majorTickLength;
[customLabels1 addObject:newLabel1];
[newLabel1 release];
}
yy.axisLabels = [NSSet setWithArray:customLabels1];
I have resolved my problem. All I have to do is start adding core-plot from beginning. I removed core-plot from my project again add voila! it's working