Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

set thousands separators in iPython without string formatting

I'm looking for an answer to the following question for over 4 hours already. Most pages indicate string formatting methods. This is not what I want.

I want to set a parameter in IPython for thousands separators for integers and floats. The option should only affect how numbers are displayed in my interactive session. I want to set a parameter once. All solutions where I need to do some formatting for every new output do not cover my need at all. I do some exploratory data analysis and don't want to bother with number formatting for every line of code.

The format should be used with all integers and floats, including those stored in numpy arrays or pandas dataframes.

For those familiar with Mathematica I indicate how one would do this in Mathematica: go to preferences => appearance => numbers => formatting. There you can "enable automatic number formatting" and chose a "digit block separator".

Example: if I type "600 + 600" into my ipython session, I want the following output: 1'200 (where ' would be my thousands separator).

I use IPython consoles in Spyder and IPython notebooks. Thank you.

like image 738
Steve Avatar asked Dec 25 '22 08:12

Steve


1 Answers

If you used str.format and numpy.set_printoptions you could set it globally once:

import numpy as np
import IPython

frm = get_ipython().display_formatter.formatters['text/plain']


def thousands(arg, p, cycle):
    p.text("{:,}".format(arg).replace(",","'"))

frm.for_type(int, thousands)
frm.for_type(float, thousands)

np.set_printoptions(formatter={'int_kind': lambda x: '{:,}'.format(x).replace(",","'")})

 np.set_printoptions(formatter={'float_kind': lambda x: '{:,}'.format(x).replace(",","'")})

frm = get_ipython().display_formatter.formatters['text/plain']
frm.for_type(int, thousands)
frm.for_type(float, thousands)

It does not cover all bases but you can add more logic:

In [2]: arr = np.array([12345,12345])

In [3]: arr
Out[3]: array([12'345, 12'345])

In [4]: 123456
Out[4]: 123'456

In [5]: 123456.343
Out[5]: 123'456.343

You can add it to a startup.py script maing sure you set PYTHONSTARTUP to point to the file so it loads when you start ipython:

~$ ipython2
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
Type "copyright", "credits" or "license" for more information.

IPython 4.0.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.
(.startup.py)
(imported datetime, os, pprint, re, sys, time,np,pd)

In [1]: arr = np.array([12345,12345])

In [2]: arr
Out[2]: array([12'345, 12'345])

In [3]: 12345
Out[3]: "12'345"

For pandas it seems you can set display.float_format with set_option

In [22]: pd.set_option("display.float_format",lambda x: "{:,}".format(x).replace(",","'"))

In [23]: pd.DataFrame([[12345.3,12345.4]])
Out[23]: 
         0        1
0 12'345.3 12'345.4

Based on this answer it seems for later versions of pandas we need to change pandas.core.format.IntArrayFormatter:

So the full startup script would be something like:

import IPython

import numpy as np
import pandas as pd

# numpy
np.set_printoptions(formatter={'float_kind': lambda x: '{:,}'.format(x).replace(",", "'"),
                          'int_kind': lambda x: '{:,}'.format(x).replace(",", "'")})


# pandas
class IntFormatter(pd.core.format.GenericArrayFormatter):
    pd.set_option("display.float_format", lambda x: "{:,}".format(x).replace(",", "'"))

    def _format_strings(self):
        formatter = self.formatter or (lambda x: ' {:,}'.format(x).replace(",", "'"))
        fmt_values = [formatter(x) for x in self.values]
        return fmt_values


pd.core.format.IntArrayFormatter = IntFormatter


# general
def thousands(arg, p, cycle):
    p.text("{:,}".format(arg).replace(",","'"))


frm = get_ipython().display_formatter.formatters['text/plain']
frm.for_type(int, thousands)
frm.for_type(float, thousands)

Which seems to cover most of what you want:

IPython 4.0.1 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.
(.startup.py)
(imported datetime, os, pprint, re, sys, time,np,pd)

In [1]: pd.DataFrame([[12345,12345]])
Out[1]: 
        0       1
0  12'345  12'345

In [2]: pd.DataFrame([[12345,12345.345]])
Out[2]: 
        0          1
0  12'345 12'345.345

In [3]: np.array([12345,678910])
Out[3]: array([12'345, 678'910])

In [4]: np.array([12345.321,678910.123])
Out[4]:  array([12'345.321, 678'910.123])


In [5]: 100000
Out[5]: 100'000

In [6]: 100000.123
Out[6]: 100'000.123

In [7]: 10000000
Out[7]: 10'000'000
like image 88
Padraic Cunningham Avatar answered Jan 17 '23 11:01

Padraic Cunningham