2

I am trying to format long numbers in form of "k" for my axis labels. For example; if I have 10000, I would like it to be displayed as 10k.

I have already tried to follow this answer. But I could not manage to get formatted numbers. What I need to do additionally? Please guide me. Thanks.

EDIT:

HumanReadableFormatter.h

@interface HumanReadableFormatter : NSNumberFormatter

@end

HumanReadableFormatter.m

I have modified code from the link above to meet my requirements.

#import "HumanReadableFormatter.h"

@implementation HumanReadableFormatter

static const char sUnits[] = { '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
static int sMaxUnits = sizeof sUnits - 1;

    -(NSString *) stringForObjectValue:(id)obj
{
    int multiplier =  1000;
    int exponent = 0;

    double bytes = [(NSNumber *)obj doubleValue];

    while ((bytes >= multiplier) && (exponent < sMaxUnits)) {
        bytes /= multiplier;
        exponent++;
    }
    return [NSString stringWithFormat:@"%@ %c", [super stringFromNumber: [NSNumber numberWithDouble: bytes]], sUnits[exponent]];

}

@end

Graph Code:

if(!rightY)
    rightY = [[CPTXYAxis alloc]init];
rightY.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
rightY.orthogonalCoordinateDecimal = CPTDecimalFromFloat(totIntervalShown);
rightY.axisConstraints = [CPTConstraints constraintWithUpperOffset:-40];
rightY.coordinate = CPTCoordinateY;
rightY.majorTickLength = 0;
rightY.minorTickLength = 0;
rightY.tickDirection = CPTSignNone;
rightY.plotSpace  = barPlotSpace;

NSNumberFormatter *numFormatter;
if(lowerLock < 1000) //if value is < 1000, normally format it
{
numFormatter = [[NSNumberFormatter alloc] init];
[numFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
numFormatter.maximumFractionDigits = 2;
numFormatter.minimumFractionDigits = 2;
}
else   //for > 1000, format in human readable form
{
    numFormatter = [[HumanReadableFormatter alloc] init];
//what i need to do here more?
}
rightY.labelFormatter = numFormatter;

//formatted as shown on right side on graph

enter image description here

Nested Loop:

enter image description here

Community
  • 1
  • 1
NightFury
  • 13,436
  • 6
  • 71
  • 120
  • Hi @NightFury, How u plot the right side Y axis with interval and plot. please help me on that – Marios Jul 21 '17 at 10:56

2 Answers2

5

I am posting solution, in case anyone needs it in future. Thanks to @Eric for helping me out.

HumanReadableFormatter.h

@interface HumanReadableFormatter : NSNumberFormatter
{
    NSNumberFormatter *numberFormatter;
}

@end

HumanReadableFormatter.m

@implementation HumanReadableFormatter

static const char sUnits[] = { '\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
static int sMaxUnits = sizeof sUnits - 1;

-(id)init
{
    if(self = [super init])
    {
        numberFormatter = [[NSNumberFormatter alloc] init];
        [numberFormatter setNumberStyle: NSNumberFormatterDecimalStyle];
        numberFormatter.maximumFractionDigits = 1;
        numberFormatter.minimumFractionDigits = 1;

    }
    return self;
}

-(NSString *) stringForObjectValue:(id)obj
{
    int multiplier =  1000;
    int exponent = 0;

    double bytes = [(NSNumber *)obj doubleValue];

    while ((bytes >= multiplier) && (exponent < sMaxUnits)) {
        bytes /= multiplier;
        exponent++;
    }
     NSString *convertedStr = [NSString stringWithFormat:@"%@ %c", [numberFormatter stringFromNumber: [NSNumber numberWithDouble: bytes]], sUnits[exponent]];

    return convertedStr;

}

@end

To use in graph, you need 2 lines of code:

HumanReadableFormatter *formatter = [[HumanReadableFormatter alloc] init];
YAxis.labelFormatter = formatter;
NightFury
  • 13,436
  • 6
  • 71
  • 120
2

Since the labelFormatter uses an NSFormatter, your custom formatter should override -stringForObjectValue:, not -stringFromNumber: which is specific to NSNumberFormatter. Cast the argument to an NSNumber and you can use the same code for the method body.

Eric Skroch
  • 27,381
  • 3
  • 29
  • 36
  • Thank you Eric for your response. I tried to implement what you said, but my code stuck in some nested function call as I have shown in fig. I have noted that it is stuck at return statement in formatter method `stringForObjectValue`. – NightFury Dec 04 '13 at 05:48
  • You're calling the formatter recursively to format itself. Use a different formatter to format the number after determining the exponent. Store it in an instance variable in your formatter class so you don't need to create a new one each time you have to format a number. Look at `CPTCalendarFormatter` or `CPTTimeFormatter` for example code. – Eric Skroch Dec 04 '13 at 23:47