Pretty-printing a table in Python

Often you'll have a table of data. You want to print it out as text, but aligned for readability. Here is a simple module to do that. I'll discuss the code below.

First, we have format_num. This basically just adds commas to our numbers (we want it to be pretty, right?).

import locale
locale.setlocale(locale.LC_NUMERIC, "")

def format_num(num):
    """Format a number according to given places.
    Adds commas, etc. Will truncate floats into ints!"
""

    try:
        inum = int(num)
        return locale.format("%.*f", (0, inum), True)

    except (ValueError, TypeError):
        return str(num)

Next, get_max_width gives us the maximum width of a given column in the table. We'll use this when we decide how much to pad each column.

def get_max_width(table, index):
    """Get the maximum width of the given column index"""

    return max([len(format_num(row[index])) for row in table])

Finally, the money function. Note that I pass in the output stream — this makes the function more versatile (we could print to a file, StringIO(), stdout, etc.). It also makes it easier to unit test. We could have done this behind the scenes by redirecting sys.stdout, but that would be unpythonic! <G>

def pprint_table(out, table):
    """Prints out a table of data, padded for alignment
    @param out: Output stream (file-like object)
    @param table: The table to print. A list of lists.
    Each row must have the same number of columns. "
""

    col_paddings = []

    for i in range(len(table[0])):
        col_paddings.append(get_max_width(table, i))

    for row in table:
        # left col
        print >> out, row[0].ljust(col_paddings[0] + 1),
        # rest of the cols
        for i in range(1, len(row)):
            col = format_num(row[i]).rjust(col_paddings[i] + 2)
            print >> out, col,
        print >> out

And we top it off with a bit of test code.

if __name__ == "__main__":
    table = [["", "taste", "land speed", "life"],
        ["spam", 300101, 4, 1003],
        ["eggs", 105, 13, 42],
        ["lumberjacks", 13, 105, 10]]

    import sys
    out = sys.stdout
    pprint_table(out, table)

The output:

                 taste   land speed    life
spam           300,101            4   1,003
eggs               105           13      42
lumberjacks         13          105      10

The linked zip file has unit tests that exercise the code a bit more thoroughly.

12 comments to Pretty-printing a table in Python

  • Vinicius Ruoso

    Hello,

    I work in a Federal University, and here we implements a huge system for 1.300.000 students of public schools.

    I see you module, and add it to one of my programs. But theres something that I can’t change. I want to align the text inside the table at left. Actualy its align on the right.

    Can you help me on this?
    Thanks a lot

    Vinicius

  • Vinicius Ruoso

    Sorry,

    Just solve it.

    Thanks a lot
    Very nice module

  • Hi Vinicius — glad to hear you solved your problem. I guess it would make the code more flexible to enable configuration of the justification style.

  • Vinicius Ruoso

    Yeah, its possible. I just change one caracter to get the expected out.
    Thanks again

  • duke

    i used your module and the result looked very nice. Thanks a lot.

    Duke

  • Robert

    Another thing (and maybe Python has a module that does this) is to print pretty tables:

    +—————————————-+
    | | taste | land speed | life |
    +—————————————-+
    | data | | | |
    | data | | | |
    | data | | | |
    +—————————————-+

  • Konrad

    Or try the texttable package from PyPI:
    http://pypi.python.org/pypi?name=texttable&amp;:action=display

  • J_Tom_Moon_79

    Hi, Here’s a minor update for python 3.2.
    + Uses character “|” to delineate the table lines.
    - Removes number formatting.

    def pprintTable(out, table):
    	"""Prints out a table of data, padded for alignment
    	@param out: Output stream (file-like object)
    	@param table: The table to print. A list of lists.
    	Each row must have the same number of columns. """
    	
    	def format(num):
    		"""Format a number according to given places.  Adds commas, etc. Will truncate floats into ints!"""
    		#try:
    		#	inum = int(num)
    		#	return locale.format("%.*f", (0, inum), True)
    		#except (ValueError, TypeError):
    		return str(num)
    	def get_max_width(table1, index1):
    		"""Get the maximum width of the given column index"""
    		return max([len(format(row1[index1])) for row1 in table1])
    	
    	col_paddings = []
    	for i in range(len(table[0])):
    		col_paddings.append(get_max_width(table, i))
    	
    	for row in table:
    		# left col
    		print(row[0].ljust(col_paddings[0] + 1),end="||",file=out)
    		# rest of the cols
    		for i in range(1, len(row)):
    			col = format(row[i]).rjust(col_paddings[i] + 1)
    			print(col,end=" |",file=out)
    		print(file=out)
    	return
    

    Example use:

    $ t = [
    		["Header","A","B","C"],
    		["Default Values","3","65","100"],
    		["Actual Values","432","22222","99"]
    	]
    $ pprintTable(sys.stdout,t)
    Header         ||   A |     B |   C |
    Default Values ||   3 |    65 | 100 |
    Actual Values  || 432 | 22222 |  99 |
    
  • J_Tom_Moon_79

    doh!
    This forum software removed my formatting and indentation!
    my post merely a minor re-write, anyway.

  • @J_Tom_Moon_79

    Thanks for the code! I edited your comment to wrap the code in pre tags rather than code tags. I need to update the css file so that multiline code looks nice.

  • Alex

    Ryan,
    What should I do to use float values on the table? I’ve been working at that for a while and can’t figure it out…

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>