views:

594

answers:

3

I want to get the maximum and minimum values of a NSMutableArray so I can create a core-plot plotspace and graph based around those max and min values.

My code is as follows:

NSMutableArray *contentArray = [NSMutableArray arrayWithCapacity:100];
NSUInteger i;
for (i=0; i<60; i++){
id x = [NSNumber numberWithFloat:i*0.05];
id y = [NSNumber numberWithFloat:1.2*rand()/(float)RAND_Max + 0.6];
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, @"x", y, @"y", nil]];
}

self.dataForPlot = contentArray;

CPXYPlotSpace *plotSpace = (CPXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.xRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat() length:CPDecimalFromFloat()];
plotSpace.yRange = [CPPlotRange plotRangeWithLocation:CPDecimalFromFloat() length:CPDecimalFromFloat()];

What do I fill in the blanks for xRange and yRange assignment if I want the graph to span only the space of what's specified in contentArray?

A: 

You can find max and min values when you fill it, but it would work just when used in your snippet. If you want something more generic you should simply go through the list and searching for it.

// contentArray already defined
int maxX = 0, minX = 1000, maxY = 0, minY = 1000;

for (int i = 0; i < [contentArray count]; ++1)
{
   int curX = [[[contentArray objectForKey:@"x"] objectAtIndex:i] integerValue];
   int curY = [[[contentArray objectForKey:@"y"] objectAtIndex:i] integerValue];

   if (curX < minX)
     minX = curX;
   else if (curX > maxX)
     maxX = curX;

   if (curY < minY)
     minY = curY;
   else if (curY > maxY)
     maxY = curY;
}
Jack
A: 

You could use fast enumeration through the array. .

NSUInteger  maxX = 0;
NSUInteger  minX = 0xFFFFFFFF; //(for 32 bit)
NSUInteger  maxY = 0;
NSUInteger  minY = 0xFFFFFFFF; //(for 32 bit)
for ( NSDictionary *dict in contentArray ) 
{
    NSUInteger   newX = [[dict objectForKey:@"x"] integerValue];
    NSUInteger   newY = [[dict objectForKey:@"y"] integerValue];


    if (maxX > newX) maxX = newX;
    if (minX > newX) minX = newX;
    if (maxY > newY) maxY = newY;
    if (minY > newY) minX = newY;
}
Steven Noyes
+3  A: 

In this case, you should use -[CPPlotSpace scaleToFitPlots:]. For more general calculations on array values, read on...

This is an ideal use for Key-Value coding and associated array operators. In your example,

float maxX = [[contentArray valueForKeyPath:@"@max.x"] floatValue];
float minY = [[contentArray valueForKeyPath:@"@min.x"] floatValue];

float maxY = [[contentArray valueForKeyPath:@"@max.y"] floatValue];
float minY = [[contentArray valueForKeyPath:@"@min.y"] floatValue];

The array operators call valueForKeyPath: on the contentArray which gives an array built by calling the same valueForKeyPath: on each member of the array with the key path to the right of the array operator (i.e. @min and @max). The orignal call then applies the given operator to the resulting array. You could easily define a category on NSArray to give you back a struct of min/max values:

typedef struct {
  float minX; 
  float minY;
  float maxX;
  float maxY;
} ArrayValueSpace;

@implementation NSArray (PlotSpaceAdditions)
- (ArrayValueSpace)psa_arrayValueSpace {
  ArrayValueSpace result;

  result.maxX = [[contentArray valueForKeyPath:@"@max.x"] floatValue];
  result.minX = [[contentArray valueForKeyPath:@"@min.x"] floatValue];

  result.maxY = [[contentArray valueForKeyPath:@"@max.y"] floatValue];
  result.minY = [[contentArray valueForKeyPath:@"@min.y"] floatValue];

  return result;
}
Barry Wark
Thanks Barry, your response was very helpful. Do you know if there is an auto-adjustment feature for axises as well?
Kevin
The `CPAxis` class does support an automatic labeling policy (`CPAxisLabelingPolicyAutomatic`). The axis will, I think, automatically span the plot space so you just need to set the labeling policy to automatic and then tell it to relabel when the plot space changes size.
Barry Wark