3

I'm using the tabulate module to print a fixed width file and I have one column that I need formatted in such a way that there are 19 places to the left of the decimal and 2 places to the right of the decimal.

import pandas as pd

from tabulate import tabulate

df = pd.DataFrame.from_dict({'A':['x','y','z'],
'B':[1,1.1,11.21],'C':[34.2334,81.1,11]})

df
Out[4]: 
   A      B        C
0  x   1.00  34.2334
1  y   1.10  81.1000
2  z  11.21  11.0000

df['C'] = df['C'].apply(lambda x: format(x,'0>22.2f'))

df
Out[6]: 
   A      B                       C
0  x   1.00  0000000000000000034.23
1  y   1.10  0000000000000000081.10
2  z  11.21  0000000000000000011.00

print(tabulate(df))
-  -  -----  -----
0  x   1     34.23
1  y   1.1   81.1
2  z  11.21  11
-  -  -----  -----

Is there any way I can preserve the formatting in column C without affecting the formatting in column B? I know I could use floatfmt = '0>22.2f' but I don't need column B to look that way just column C.

According to the tabulate documentation strings that look like decimals will be automatically converted to numeric. If I could suppress this then format my table before printing (as in the example above) that would solve it for me as well.

Pete M
  • 154
  • 3
  • 8

2 Answers2

6

The documentation at GitHub is more up-to-date and it states that with floatfmt "every column may have different number formatting". Here is an example using your data:

import pandas as pd
from tabulate import tabulate

df = pd.DataFrame.from_dict({'A':['x','yy','zzz'],
'B':[1,1.1,11.21],'C':[34.2334,81.1,11]})

print(tabulate(df, floatfmt=(None, None, '.2f', '0>22.2f',)))

The result is:

-  ---  -----  ----------------------
0  x     1.00  0000000000000000034.23
1  yy    1.10  0000000000000000081.10
2  zzz  11.21  0000000000000000011.00
-  ---  -----  ----------------------

Additionally, as you suggested, you also have the option disable_numparse which disables the automatic convert from string to numeric. You can then format each field manually but this requires more coding. The option colalign may come handy in such a case, so that you can specify different column alignment for strings and numbers (which you would have converted to formatted strings, too).

famzah
  • 1,462
  • 18
  • 21
2

Do you absolutely need tabulate for this? You can achieve similar effect (bar dashes) with:

In [18]: print(df.__repr__().split('\n',1)[1])                                                                                                
0  x   1.00  0000000000000000034.23
1  y   1.10  0000000000000000081.10
2  z  11.21  0000000000000000011.00

df.__repr__ is representation of df, i.e. what you see when you just type df in a cell. Then I remove the header line by splitting on the first new line char and taking the other half of the split.

Also, if you write it to a machine readable form, you might want to use tabs:

In [8]: df.to_csv(sys.stdout, sep='\t', header=False)                                                                                         
0   x   1.0 0000000000000000034.23
1   y   1.1 0000000000000000081.10
2   z   11.21   0000000000000000011.00

It will render pretty depending on tab rendering settings, but if you output in a file, then you get tab symbols

Artem Trunov
  • 1,340
  • 9
  • 16