1

I'm looking to add a footer to my PrettyTable, totalling the data stored in the rows above. I've created a count in the script, but I'd like to add this into the table.

The code I have to create the table below is as follows (.add_row is in a loop):

outTbl = PrettyTable(["Projects", "Number"])
outTbl.add_row([eachProj, count])

...which generates a table looking like this:

+--------------------------+-----------+
|        Projects          |   Number  |
+--------------------------+-----------+
|        Project A         |     5     |
|        Project B         |     9     |
|        Project C         |     8     |
|        Project D         |     2     |
+--------------------------+-----------+

...but I'm looking for the functionality to create the above table with a summary footer at the bottom:

+--------------------------+-----------+
|        Projects          |   Number  |
+--------------------------+-----------+
|        Project A         |     5     |
|        Project B         |     9     |
|        Project C         |     8     |
|        Project D         |     2     |
+--------------------------+-----------+
|          Total           |     24    |
+--------------------------+-----------+

I've searched the module docs online: PrettyTable tutorial, Google prettytable - Tutorial and can't see any reference to a footer, which I find surprising given header is one. Can this be done in PrettyTable, or is there another Python module with this functionality anyone can recommend?

funie200
  • 3,688
  • 5
  • 21
  • 34
DeltaKilo
  • 113
  • 3
  • 12

6 Answers6

3

You can use texttable with small hack around it:

import texttable

table = texttable.Texttable()
table.add_rows([['Projects', 'Number'],
                ['Project A\nProject B\nProject C\nProject D', '5\n9\n8\n2'],
                ['Total', 24]])
print(table.draw())

Output:

+-----------+--------+
| Projects  | Number |
+===========+========+
| Project A | 5      |
| Project B | 9      |
| Project C | 8      |
| Project D | 2      |
+-----------+--------+
| Total     | 24     |
+-----------+--------+
Alderven
  • 7,569
  • 5
  • 26
  • 38
2

There is no separate function to create footer in pretty table. However you can do little trick to create, in case you are particular to use only pretty table as follows

sum = 0
for row in outTbl:
     sum = sum + int(row.get_string(fields=["Number"]).split('\n')[3].replace('|','').replace(' ',''))
outTbl.add_row(['------------','-----------'])
outTbl.add_row(['Total',sum])
print (outTbl)

Output

or if you are looking for particular function with footers you can look at https://stackoverflow.com/a/26937531/3249782 for different approaches you can use

r_batra
  • 400
  • 3
  • 14
2

I had the same problem today and used the following approach to treat the last n lines of my table as result lines that are seperated by a horizontal line (like one that is separating the header):

from prettytable import PrettyTable

t = PrettyTable(['Project', 'Numbers'])
t.add_row(['Project A', '5'])
t.add_row(['Project B', '9'])
t.add_row(['Project C', '8'])
t.add_row(['Project D', '2'])

# NOTE: t is the prettytable table object
# Get string to be printed and create list of elements separated by \n
list_of_table_lines = t.get_string().split('\n')

# Use the first line (+---+-- ...) as horizontal rule to insert later
horizontal_line = list_of_table_lines[0]

# Print the table
# Treat the last n lines as "result lines" that are seperated from the
# rest of the table by the horizontal line
result_lines = 1
print("\n".join(list_of_table_lines[:-(result_lines + 1)]))
print(horizontal_line)
print("\n".join(list_of_table_lines[-(result_lines + 1):]))

This results in the following output:

+-----------+---------+
|  Project  | Numbers |
+-----------+---------+
| Project A |    5    |
| Project B |    9    |
| Project C |    8    |
+-----------+---------+
| Project D |    2    |
+-----------+---------+
Niels
  • 21
  • 1
2

I know I'm late but I've created a function to automagically append a "Total" row to the table. For now NOT resolving if the column is wider than the table.

Python3.6++

Function:

def table_footer(tbl, text, dc):
    res = f"{tbl._vertical_char} {text}{' ' * (tbl._widths[0] - len(text))} {tbl._vertical_char}"

    for idx, item in enumerate(tbl.field_names):
        if idx == 0:
            continue
        if not item in dc.keys():
            res += f"{' ' * (tbl._widths[idx] + 1)} {tbl._vertical_char}"
        else:
            res += f"{' ' * (tbl._widths[idx] - len(str(dc[item])))} {dc[item]} {tbl._vertical_char}"

    res += f"\n{tbl._hrule}"
    return res

Usage:

tbl = PrettyTable()
tbl.field_names = ["Symbol", "Product", "Size", "Price", "Subtotal", "Allocation"]
tbl.add_row([......])

print(tbl)
print(table_footer(tbl, "Total", {'Subtotal': 50000, 'Allocation': '29 %'}

+--------+-------------------------------+-------+---------+----------+------------+
| Symbol |            Product            |  Size |  Price  | Subtotal | Allocation |
+--------+-------------------------------+-------+---------+----------+------------+
|    AMD |   Advanced Micro Devices Inc  | 999.9 |  75.99  |  20000.0 |      23.00 |
|   NVDA |          NVIDIA Corp          |  88.8 |  570.63 |  30000.0 |       6.00 |
+--------+-------------------------------+-------+---------+----------+------------+
| Total  |                               |       |         |    50000 |       29 % |
+--------+-------------------------------+-------+---------+----------+------------+
Dharman
  • 30,962
  • 25
  • 85
  • 135
1

After inspecting the source code of pretty table you can see that after you print the table you can get each column width. Using this you can create a footer by yourself, because pretty table do not give you that option. Here is my approach:

from prettytable import PrettyTable

t = PrettyTable(['Project', 'Numbers'])
t.add_row(['Project A', '5'])
t.add_row(['Project B', '9'])
t.add_row(['Project C', '8'])
t.add_row(['Project D', '2'])
print(t)
total = '24'
padding_bw = (3 * (len(t.field_names)-1))
tb_width = sum(t._widths)
print('| ' + 'Total' + (' ' * (tb_width - len('Total' + total)) +
                        ' ' * padding_bw) + total + ' |')
print('+-' + '-' * tb_width + '-' * padding_bw + '-+')

And here is the output:

+-----------+---------+
|  Project  | Numbers |
+-----------+---------+
| Project A |    5    |
| Project B |    9    |
| Project C |    8    |
| Project D |    2    |
+-----------+---------+
| Total            24 |
+---------------------+

Just change the total var in the code and everything should be working fine

Hello Hello
  • 100
  • 1
  • 6
1

I stole @Niels solution and did this function to print with a delimiter before the last num_footers lines:

def print_with_footer(ptable, num_footers=1):
    """ Print a prettytable with an extra delimiter before the last `num` rows """
    lines = ptable.get_string().split("\n")
    hrule = lines[0]
    lines.insert(-(num_footers + 1), hrule)
    print("\n".join(lines))
Moberg
  • 5,253
  • 4
  • 38
  • 54