|
12 | 12 | from numpy.lib.format import read_array, write_array
|
13 | 13 | import numpy as np
|
14 | 14 |
|
| 15 | +import decimal |
| 16 | +import math |
| 17 | + |
15 | 18 | import pandas._tseries as lib
|
16 | 19 |
|
17 | 20 | # XXX: HACK for NumPy 1.5.1 to suppress warnings
|
@@ -355,6 +358,109 @@ def set_printoptions(precision=None, column_space=None):
|
355 | 358 | if column_space is not None:
|
356 | 359 | _column_space = column_space
|
357 | 360 |
|
| 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 | + |
358 | 464 | _float_format = lambda x: '%.4g' % x
|
359 | 465 | _column_space = 12
|
360 | 466 |
|
|
0 commit comments