2

My script needs to print a table while it is crunching some numbers. Its total run time is several hours, and I need it to add more and more rows to the printed table while it is running. I am trying to use PrettyTable, but I am open to other suggestions how else it can be accomplished. Here is an example of what I am trying to do:

from prettytable import PrettyTable
t = PrettyTable(['Name', 'Age'])
t.add_row(['Alice', 24])
print t

#do some work

t.add_row(['Bob', 19])
print t

The outcome that I get is this:

+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
+-------+-----+
+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
|  Bob  |  19 |
+-------+-----+

Is there a way not to print the entire table every time I add a row but print just a new row underneath of what has already been printed? I am trying to get somethig like this:

+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
+-------+-----+
| Bob   |  19 |
+-------+-----+

Left alignment for the first column would be a nice bonus.

sprogissd
  • 2,755
  • 5
  • 24
  • 45

4 Answers4

3

The code below covers all what you have asked for IF you specify enough SPACES in the column names definition to cover the maximal width of all incoming items (thanks to all contributors to this question - I have used all of what came up here in the code provided below):

from __future__ import print_function

from prettytable import PrettyTable
t = PrettyTable(['Name               ', '   Age'])
t.align['Name               '] = 'l'
t.align['   Age'] = 'r'
t.hrules = 1
t.add_row(['Alice', 24])
print(t)

#do some work

t.add_row(['Bob', 19])
print( "\n".join(t.get_string().splitlines()[-2:]) )

#do some work

t.add_row(['AliceInWonderland', 1019])
print( "\n".join(t.get_string().splitlines()[-2:]) )

Here the output generated by the code above that works also for "AliceInWonderland" being 1019 years old :D :

+---------------------+--------+
| Name                |    Age |
+---------------------+--------+
| Alice               |     24 |
+---------------------+--------+
| Bob                 |     19 |
+---------------------+--------+
| AliceInWonderland   |   1019 |
+---------------------+--------+
Claudio
  • 7,474
  • 3
  • 18
  • 48
  • Thank you very much for putting it all together. It worked! A special thank you goes to Josh and his idea with `print "\n".join(t.get_string().splitlines()[-2:])`. – sprogissd Apr 12 '17 at 16:57
2

You could do something like this:

print "\n".join(t.get_string().splitlines()[-2:])

Replacing the last line of your script with this results in exactly what you want:

+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
+-------+-----+
|  Bob  |  19 |
+-------+-----+

As grr says, you can also use t.align['Name'] = 'l' to left-align the Name column.

+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
+-------+-----+
| Bob   |  19 |
+-------+-----+
ash
  • 5,139
  • 2
  • 27
  • 39
  • What about ['AliceInWonderland', '1024'] ? – Claudio Apr 12 '17 at 16:27
  • This actually worked. Is there a way to specify the column width so that ['AliceInWonderland', '1024'] doesn't mess up the column width? – sprogissd Apr 12 '17 at 16:30
  • The width will break if you insert any element bigger than those in the first row, for name or age. – Grr Apr 12 '17 at 16:37
  • You can specify `right_padding_width` (either an attribute on `t` or as a kwarg to `get_string`), but you'd have to keep track of how much padding you needed to add when printing each row, as there doesn't appear to be a way to specify a minimum column width. – ash Apr 12 '17 at 16:37
  • So how will it change `print "\n".join(t.get_string().splitlines()[-2:])` if I want column Name to be 20 characters wide? – sprogissd Apr 12 '17 at 16:45
  • Claudio has just pointed out that you can append spaces to the column header to set a minimum width -- I'd go for that rather than trying to set `padding_width`. – ash Apr 12 '17 at 16:47
1

You can print the last two rows with:

print t[-2:]

To set the Name field to be left justified just use the align style option:

t.align['Name'] = 'l'
print t
+-------+-----+
| Name  | Age |
+-------+-----+
| Alice |  24 |
| Bob   |  19 |
+-------+-----+

To print a line of +-----+-----+ between each entry set the hrules style option to 1:

t.hrules = 1
print t
+-------+-----+
| Name  | Age |
+-------+-----+
| Alice |  24 |
+-------+-----+
| Bob   |  19 |
+-------+-----+

If you don't want the header to print each time you can set the header style option to False.

t.header = False
print t
+-------+----+
| Alice | 24 |
+-------+----+
| Bob   | 19 |
+-------+----+

There are a couple of good examples that cover what you are asking and more available in the PrettyTable Tutorials Wiki

Grr
  • 15,553
  • 7
  • 65
  • 85
  • I tried to use it instead of the last line in the example, but got the same outcome. – sprogissd Apr 12 '17 at 16:13
  • If you dont want the header to show up you can set `t.header` to False, but you would have to change this for any downstream work after all of your printing. – Grr Apr 12 '17 at 16:19
  • I mean I used `print t[-2:]` instead of `print t` in my example, but got the same outcome. – sprogissd Apr 12 '17 at 16:20
  • With only two entries you would. If you keep adding entries the result will be to only print the last two entries. For example if you add another entry `['Tina', 22]` and call `print t[-2:]` you will see only the entries for Bob and Tina – Grr Apr 12 '17 at 16:22
  • Are you basically trying to build the table in place, or just visualize the most recent change? – Grr Apr 12 '17 at 16:25
0

What you can do is clean the screen before each print and redraw the entire table each time. I think the result would be pretty close to what you describe, to see what it looks like you can try this:

import time
from prettytable import PrettyTable

t = PrettyTable(['Name', 'Age'])
t.add_row(['Alice', 24])

for _ in range(10):
    t.add_row(['Alice', 24])
    print("\033c")
    print(t)
    time.sleep(1)

The magic is the print("\033c"), I'm not sure how portable this is, if it doesn't work you can look the way to clear the terminal for your particular system.

polku
  • 1,575
  • 2
  • 14
  • 11
  • I suppose that this "solution" is not what is asked for, but you never know, so I am eager to see the response to it of the author of this question and his decision which answer is worth to be accepted ... – Claudio Apr 12 '17 at 16:24