Plain text tables with Python's % operator

on

So, say you had a console Python application where you are trying to print a table of numbers as your output. Printing the numbers without any formatting is messy. By using formatting options for the % operator, you can make tables that are much easier to read.

The first time you print a table, you might try the following:

print label, number_1, number_2, number_3

Your "table" would end up looking like:

The first row 1.001 2.0983 10.12
Another row 11.4 3.144 35.973
Look! Yet another row 12.6 99.72 1.892

Yikes, that table is ugly! I can't tell which number belongs to which column. There must be a way to get Python to create a better looking table of numbers. Good for us, there is. Batteries are included, after all. A quick search yields a reference on C-style string formatting in Python, but it is a bit light in the examples department.

From the docs, it's pretty obvious that our code will be a string followed by the % operator and then a tuple or dictionary. It even gives an example of this where a string is printed with values from a dictionary. What it does not tell us, is how we can use this to create our table.

The first thing we can do is make sure each column gets a specified amount of characters. The longest string in our first column is 21 characters long, so we'll want to make sure that when we make the table, all the rows end up with a label taking up 21 characters. Likewise, the second column has a max of 5 characters; the third has 6, and the last column also has a max of 6 characters. Also, to make the string formatting work, we have to realize that the first column is a string, and the others are floating-point values.

A simple example, just using the minimum width string formatting option would look something like this:

row_dictionary = {
    "label": label,
    "1": number_1,
    "2": number_2,
    "3": number_3
}
print "%(label)21s %(1)5f %(2)6f %(3)6f" % row_dictionary

        The first row 1.001000 2.098300 10.120000
          Another row 11.400000 3.144000 35.973000
Look! Yet another row 12.600000 99.720000 1.892000

Already, that's looking a lot better! But wait, what happened to our numbers? Why did they just get so much longer? The reason our floating-point numbers got so much longer is because when formatting as %f there is a default precision of 6. That means, all floating point numbers we give it will end up having 6 digits after the decimal point--even if they wouldn't be shown after running through str().

So, we have to decide how much precision we want our users to see. Since the numbers I picked are rather arbitrary, the precisions I pick can be arbitrary as well. I think a precision of 0 for the first, 1 for the second, and 2 for the third will work well. If you are writing an actual program, you can choose your precisions based on the user requirements. :-)

Our new example table using the precisions we decided will look something like this:

print "%(label)21s %(1)3.0f %(2)6.1f %(3)6.2f" % row_dictionary

        The first row   1    2.1  10.12
          Another row  11    3.1  35.97
Look! Yet another row  13   99.7   1.89

I think we're almost done. Notice that by defining a precision less than the amount of digits in the number, the final output is rounded accordingly. Since most people expect string labels to be left aligned and because I want to show how to use the "conversion flags", we'll make our label column left-aligned instead of the default right alignment. That'll be pretty easy to do, just put a - sign in front of the minimum width of 21.

print "%(label)-21s %(1)3.0f %(2)6.1f %(3)6.2f" % row_dictionary
The first row           1    2.1  10.12
Another row            11    3.1  35.97
Look! Yet another row  13   99.7   1.89

There you have it. A beautiful table created using Python's string formatting operator. That's all there is to it. Now your data tables are that much easier to read.