12

TL;DR -> Is there a table writing module on PyPi (I've failed to find any) that takes in lists as parameters and makes a table out of those lists. I am asking this because I've looked on PyPI, but I have not found anything similar to actually printing strings or writing strings to files.

Imagine having a lot of statistics, and having to write them down neatly in a table, like this, (I've been trying to teach a class about the differences between the different sorting algorithms out there) (Also, please note that the example given here does not match the output of the code given below. I've simple done this in order to explain what I want and not make huge chunks of code that one has to scroll through):

#########################
#   LENGTH ||| TIME(s)  #
#########################
#       0  ||| 0.00000  #
#     250  ||| 0.00600  #
#     500  ||| 0.02100  #
#     750  ||| 0.04999  #
#    1000  ||| 0.08699  #
#    1250  ||| 0.13499  #
#    1500  ||| 0.19599  #
#    1750  ||| 0.26900  #
#    2000  ||| 0.35099  #
#########################

Ideally, I would write something like this to save to a file, like the one below. set of lists, one list containing the one set of values, the other containing another set of corresponding values.

if __name__ == '__main__':
    with open(os.path.join(os.path.dirname(__file__), 'Sort Stats', 'stats_exp.txt'), 'w') as stats:
        stats.write(
            "O-######################==#######################==#######################==######################-O\n")
        stats.writelines(
            "|{0:^23}||{1:^23}||{2:^23}||{3:^23}|\n".format("Bubble Sort", "Insertion Sort", "Merge Sort (R)",
                                                            "Merge Sort (I)"))
        stats.write(
            "|#######################||#######################||#######################||#######################|\n")
        stats.write(
            "|   LENGTH  |  TIME(s)  ||   LENGTH  |  TIME(s)  ||   LENGTH  |  TIME(s)  ||   LENGTH  |  TIME(s)  |\n")
        stats.write(
            "|#######################||#######################||#######################||#######################|\n")
        for times_taken, t1, t2, t3, t4 in zip(total_lengths, sort_times_bubble, sort_times_ins, sort_times_merge_r,
                                               sort_times_merge_i):
            stats.write(
                "|{0:^11}|{1:^11}||{2:^11}|{3:^11}||{4:^11}|{5:^11}||{6:^11}|{7:^11}|\n"
                .format(
                    times_taken, str(t1)[:6],
                    times_taken, str(t2)[:6],
                    times_taken, str(t3)[:6],
                    times_taken, str(t4)[:6],
                )
            )
        stats.write(
            "O-######################==#######################==#######################==######################-O\n")

    print "Data writing complete"

As you can see, its not exactly pretty, and most importantly its not something that is easy to extend, since it pretty much prints something out.

What I want to do is create a module for this and upload it to PyPI. However, if someone's already made something akin to this, then it would be wasted effort, and I could simple fork their repositories instead of actually having to write the code from scratch.

Games Brainiac
  • 80,178
  • 33
  • 141
  • 199
  • Using pprint on a dict might be nice? – Noctua Oct 01 '13 at 20:26
  • When convenient, just place your data into a Pandas DataFrame. You can print it tabularly with `to_string` but it also gives other options like printing as an HTML table. I've separately written code for myself that also lets me dump the contents of a DataFrame to a LaTeX tabular table too. – ely Oct 01 '13 at 20:41

2 Answers2

28

PrettyTable module is what you need:

PrettyTable is a simple Python library designed to make it quick and easy to represent tabular data in visually appealing ASCII tables.

>>> import prettytable
>>> x = prettytable.PrettyTable(["Length", "Time"])
>>> x.add_row([0, 0.00000])
>>> x.add_row([250, 0.00600]) 
>>> x.add_row([500, 0.02100]) 
>>> x.add_row([750, 0.04999])    
>>> print x
+--------+---------+
| Length |   Time  |
+--------+---------+
|   0    |   0.0   |
|  250   |  0.006  |
|  500   |  0.021  |
|  750   | 0.04999 |
+--------+---------+

Or, texttable:

texttable is a module to generate a formatted text table, using ASCII characters.

>>> import texttable
>>> x = texttable.Texttable()
>>> x.add_rows([["Length", "Time"], [0, 0.00000], [250, 0.00600], [500, 0.02100], [750, 0.04999]])
>>> print x.draw()
+--------+-------+
| Length | Time  |
+========+=======+
| 0      | 0     |
+--------+-------+
| 250    | 0.006 |
+--------+-------+
| 500    | 0.021 |
+--------+-------+
| 750    | 0.050 |
+--------+-------+

Also see relevant thread: How can I pretty-print ASCII tables with Python?

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • Thank you so much for this Alex! :D I deeply appreciate it. I was kind of hoping that I could make my own module and contribute to PyPi through this little project, but there are such good libraries out there, I think I'll just modify one of them. :) Again, thanks for your help. – Games Brainiac Oct 01 '13 at 20:56
  • @GamesBrainiac Sure, you are welcome. Yeah, it's difficult to invent smth unique nowadays.. – alecxe Oct 01 '13 at 21:05
  • Thank you, prettytable Works well. Combined with ClipboardJS to create a "Copy as Text" button next to an HTML table. – Nick Woodhams Mar 25 '19 at 00:49
  • PrettyTable is broken for me. There is a newer fork of it called PTable on https://pypi.org/project/PTable which works fine for me on Python 3.7.2. – NZD Mar 28 '19 at 01:21
7

I’m just going to throw a solution from me in which I’ve actually written last week just to test something out. It currently right-aligns everything but it would be simple enough to add some alignment parameters or something.

def printTable (tbl, borderHorizontal = '-', borderVertical = '|', borderCross = '+'):
    cols = [list(x) for x in zip(*tbl)]
    lengths = [max(map(len, map(str, col))) for col in cols]
    f = borderVertical + borderVertical.join(' {:>%d} ' % l for l in lengths) + borderVertical
    s = borderCross + borderCross.join(borderHorizontal * (l+2) for l in lengths) + borderCross

    print(s)
    for row in tbl:
        print(f.format(*row))
        print(s)

Example:

>>> x = [['Length', 'Time(ms)'], [0, 0], [250, 6], [500, 21], [750, 50], [1000, 87], [1250, 135], [1500, 196], [1750, 269], [2000, 351]]
>>> printTable(x)
+--------+----------+
| Length | Time(ms) |
+--------+----------+
|      0 |        0 |
+--------+----------+
|    250 |        6 |
+--------+----------+
|    500 |       21 |
+--------+----------+
|    750 |       50 |
+--------+----------+
|   1000 |       87 |
+--------+----------+
|   1250 |      135 |
+--------+----------+
|   1500 |      196 |
+--------+----------+
|   1750 |      269 |
+--------+----------+
|   2000 |      351 |
+--------+----------+
poke
  • 369,085
  • 72
  • 557
  • 602