Below is the code for formatting an x value that I have been using.
Examples of what does it do:
It form
There's probably a shorter way to generate the format strings; but they're easy enough to just map to each magnitude. I don't fully understand the behavior you want w/r/t decimal point length, but the logic for that should be easy.
Since what you had was a method, I incorporated this into a class. (This also avoids defining formats
every time the function is called.)
from math import log10
class Formatter(object):
def __init__(self):
self.formats = (('%1.1f', 0),
('%2.1f', 0),
('%1.2f K', 3),
('%1.2f K', 3),
('%2.1f K', 3),
('%1.2f M', 6),
('%1.2f M', 6),
('%2.1f M', 6),
('%1.2f B', 9),
('%1.2f B', 9),
('%2.1f B', 9),
('%1.2f T', 12),
('%1.2f T', 12),
('%2.1f T', 12))
def human_readable(self, x):
if x == 0: return '0'
magnitude = int(log10(abs(x)))
if magnitude > 13: format_str, denominator_mag = '%i T', 12
else: format_str, denominator_mag = self.formats[magnitude]
return (format_str % (x * 1.0 / (10 ** denominator_mag))).lstrip('0')
Edit: Here's one that doesn't use a lookup table:
def human_readable(self, x):
if x == 0: return '0'
magnitude = int(log10(abs(x)))
if magnitude > 13:
format_str = '%i T'
denominator_mag = 12
else:
float_fmt = '%2.1f ' if magnitude % 3 == 1 else '%1.2f '
illion = (magnitude + 1) // 3
format_str = float_fmt + ['', 'K', 'M', 'B', 'T'][illion]
denominator_mag = illion * 3
return (format_str % (x * 1.0 / (10 ** denominator_mag))).lstrip('0')
Try all the different possible ways to format it and pick the shortest one length-wise, with preference given to larger units (e.g., prefer .55 B to 550 M, since they are the same length).
As for stripping leading zeros, one possible solution is checking if s[:2] == '0.'
and replacing it with '.'