Skip to content

Commit 6141961

Browse files
lodagrowesm
authored andcommitted
Adding set_eng_float_format(), which controls default float format for DataFrame.
1 parent f6aa7ca commit 6141961

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

pandas/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from pandas.core.api import *
2323
from pandas.core.common import set_printoptions
24+
from pandas.core.common import set_eng_float_format
2425
from pandas.io.parsers import read_csv, read_table, ExcelFile
2526
from pandas.io.pytables import HDFStore
2627
from pandas.stats.api import *

pandas/core/common.py

+106
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
from numpy.lib.format import read_array, write_array
1313
import numpy as np
1414

15+
import decimal
16+
import math
17+
1518
import pandas._tseries as lib
1619

1720
# XXX: HACK for NumPy 1.5.1 to suppress warnings
@@ -355,6 +358,109 @@ def set_printoptions(precision=None, column_space=None):
355358
if column_space is not None:
356359
_column_space = column_space
357360

361+
class EngFormatter(object):
362+
"""
363+
Formats float values according to engineering format.
364+
365+
Based on matplotlib.ticker.EngFormatter
366+
"""
367+
368+
# The SI engineering prefixes
369+
ENG_PREFIXES = {
370+
-24: "y",
371+
-21: "z",
372+
-18: "a",
373+
-15: "f",
374+
-12: "p",
375+
-9: "n",
376+
-6: "u",
377+
-3: "m",
378+
0: "",
379+
3: "k",
380+
6: "M",
381+
9: "G",
382+
12: "T",
383+
15: "P",
384+
18: "E",
385+
21: "Z",
386+
24: "Y"
387+
}
388+
389+
def __init__(self, precision=None, use_eng_prefix=False):
390+
self.precision = precision
391+
self.use_eng_prefix = use_eng_prefix
392+
393+
def __call__(self, num):
394+
""" Formats a number in engineering notation, appending a letter
395+
representing the power of 1000 of the original number. Some examples:
396+
397+
>>> format_eng(0) for self.precision = 0
398+
'0'
399+
400+
>>> format_eng(1000000) for self.precision = 1,
401+
self.use_eng_prefix = True
402+
'1.0M'
403+
404+
>>> format_eng("-1e-6") for self.precision = 2
405+
self.use_eng_prefix = False
406+
'-1.00E-06'
407+
408+
@param num: the value to represent
409+
@type num: either a numeric value or a string that can be converted to
410+
a numeric value (as per decimal.Decimal constructor)
411+
412+
@return: engineering formatted string
413+
"""
414+
415+
dnum = decimal.Decimal(str(num))
416+
417+
sign = 1
418+
419+
if dnum < 0:
420+
sign = -1
421+
dnum = -dnum
422+
423+
if dnum != 0:
424+
pow10 = decimal.Decimal(int(math.floor(dnum.log10()/3)*3))
425+
else:
426+
pow10 = decimal.Decimal(0)
427+
428+
pow10 = pow10.min(max(self.ENG_PREFIXES.keys()))
429+
pow10 = pow10.max(min(self.ENG_PREFIXES.keys()))
430+
int_pow10 = int(pow10)
431+
432+
if self.use_eng_prefix:
433+
prefix = self.ENG_PREFIXES[int_pow10]
434+
else:
435+
if int_pow10 < 0:
436+
prefix = 'E-%02d' % (-int_pow10)
437+
else:
438+
prefix = 'E+%02d' % int_pow10
439+
440+
mant = sign*dnum/(10**pow10)
441+
442+
if self.precision is None:
443+
format_str = u"%g%s"
444+
elif self.precision == 0:
445+
format_str = u"%i%s"
446+
elif self.precision > 0:
447+
format_str = (u"%%.%if%%s" % self.precision)
448+
449+
formatted = format_str % (mant, prefix)
450+
451+
return formatted.strip()
452+
453+
def set_eng_float_format(precision=3, use_eng_prefix=False):
454+
"""
455+
Alter default behavior on how float is formatted in DataFrame.
456+
Format float in engineering format.
457+
458+
See also EngFormatter.
459+
"""
460+
global _float_format, _column_space
461+
_float_format = EngFormatter(precision, use_eng_prefix)
462+
_column_space = max(12, precision + 9)
463+
358464
_float_format = lambda x: '%.4g' % x
359465
_column_space = 12
360466

0 commit comments

Comments
 (0)