How to Pretty-Print Ascii Tables with Python

How can I pretty-print ASCII tables with Python?

For some reason when I included 'docutils' in my google searches I stumbled across texttable, which seems to be what I'm looking for.

Printing Lists as Tabular Data

Some ad-hoc code:

row_format ="{:>15}" * (len(teams_list) + 1)
print(row_format.format("", *teams_list))
for team, row in zip(teams_list, data):
print(row_format.format(team, *row))

This relies on str.format() and the Format Specification Mini-Language.

Parsing (reading) prettytable text tables

I think you could do this using python, with a few passes you can convert this into something that suits your needs.

table_str = """
+--------+--------+-------------------+
| Planets |
+--------+--------+-------------------+
| Planet | R (km) | mass (x 10^29 kg) |
+--------+--------+-------------------+
| Sun | 696000 | 1989100000 |
|(Solar) | | |
+--------+--------+-------------------+
| Earth | 6371 | 5973.6 |
+--------+--------+-------------------+
| Moon | 1737 | 73.5 |
+--------+--------+-------------------+
| Mars | 3390 | 641.85 |
+--------+--------+-------------------+
"""

table_list = [
[item.strip() for item in line.split('|') if item] # maintain the number of columns in rows.
for line in table_str.strip().split('\n')
if '+-' not in line # discard +-
]

column_count = len(table_list[1])
row_idx_to_remove = list()
for row_idx, row in enumerate(table_list[2:], start=2):
if any(not c for c in row): # A multiline column entry
row_idx_to_remove.append(row_idx)
for col_idx, col in enumerate(table_list[row_idx - 1]):
table_list[row_idx - 1][col_idx] += row[col_idx]

# Remove the rows that have already been merged into previous ones.
for idx in row_idx_to_remove:
del table_list[idx]

table_dict = {'Name': table_list[0][0], 'Column Names': table_list[1], 'Rows': table_list[2:]}

print(table_dict)
print(table_list)

Output:

{'Name': 'Planets', 'Column Names': ['Planet', 'R (km)', 'mass (x 10^29 kg)'], 'Rows': [['Sun(Solar)', '696000', '1989100000'], ['Earth', '6371', '5973.6'], ['Moon', '1737', '73.5'], ['Mars', '3390', '641.85']]}
[['Planets'], ['Planet', 'R (km)', 'mass (x 10^29 kg)'], ['Sun(Solar)', '696000', '1989100000'], ['Earth', '6371', '5973.6'], ['Moon', '1737', '73.5'], ['Mars', '3390', '641.85']]

This implementation does not handle empty columns in rows nor does it handle the case where every column in a row has more than one line.

You could also make it use re.split, and split on lines containing +-, then you could handle any rows that would contain the edge cases of this implementation.

Edit:
Here is an implementation that uses re.split:

import re

def parse_ascii_table(ascii_table):
table_re_list = re.split(r'\+[+-]+', ascii_table)
table_list = [l.strip().replace('\n', '') for l in table_re_list if l.strip()]
table = {'Title': table_list[0].replace('|', '').strip(),
'Column Names': [ch.strip() for ch in table_list[1].split('|') if ch.strip()],
'Rows': list()}
for row in table_list[2:]:
joined_row = ['' for _ in range(len(row))]
for lines in [line for line in row.split('||')]:
line_part = [i.strip() for i in lines.split('|') if i]
joined_row = [i + j for i, j in zip(joined_row, line_part)]
table['Rows'].append(joined_row)
return table

table_str = """
+--------+--------+-------------------+
| Planets |
+--------+--------+-------------------+
| Planet | R (km) | mass (x 10^29 kg) |
+--------+--------+-------------------+
| Sun | 696000 | 1989100000 |
|(Solar) | | |
+--------+--------+-------------------+
| Earth | 6371 | 5973.6 |
+--------+--------+-------------------+
| Moon | 1737 | 73.5 |
+--------+--------+-------------------+
| Mars | 3390 | 641.85 |
+--------+--------+-------------------+
"""
print(parse_ascii_table(table_str))

Output:

{'Title': 'Planets', 'Column Names': ['Planet', 'R (km)', 'mass (x 10^29 kg)'], 'Rows': [['Sun(Solar)', '696000', '1989100000'], ['Earth', '6371', '5973.6'], ['Moon', '1737', '73.5'], ['Mars', '3390', '641.85']]}

Create ASCII table from given list - Python

Some people pointed out your question may be a duplicate, but the answers in question look somewhat old... Since the introduction of the new string format mini-language, you can do this kind of thing using str.format alone.

Supposing your list looks like:

data = [
["John" , 15.00, 1.20, 10.00, 8.00],
["Robert", 45.00, 6.70, 24.00, 14.00],
["Duncan", 10.00, 5.40, 5.00, 10.00],
["Steven", 30.00, 6.50, 30.00, 16.00],
]

You can use the format method:

# Headers, centered
print("{: ^15s} {: ^15s} {: ^15s} {: ^15s} {: ^15s}".format(
"Name", "Age", "Height", "Pay Rate", "Grade")
)

# Dashes (not very readable, but I'm lazy)
print(" ".join([("-" * 15)] * 5))

# Lines
for line in data:
print("{:15s} {: 15.2f} {: 15.2f} {: 15.2f} {: 15.2f}".format(*line))

The format specification is (see the format specification mini-language):

format_spec ::=  [[fill]align][sign][#][0][width][,][.precision][type]
fill ::= <any character>
align ::= "<" | ">" | "=" | "^"
sign ::= "+" | "-" | " "
width ::= integer
precision ::= integer
type ::= (pretty much like printf)

^ means centered.

Result should be like:

     Name             Age           Height         Pay Rate          Grade     
--------------- --------------- --------------- --------------- ---------------
John 15.00 1.20 10.00 8.00
Robert 45.00 6.70 24.00 14.00
Duncan 10.00 5.40 5.00 10.00
Steven 30.00 6.50 30.00 16.00

Making this shorter and more reusable is left as an exercise for you.

Printing tabular data in Python

Do you know about PyPi?

DataGrid and PrettyTable seem like two good alternatives I found with a brief search. You may have to assemble the data in the format you want it (with "x" for when your condition is true) before sending it to the routines provided.

NumPy: Pretty print tabular data

I seem to be having good output with prettytable:

from prettytable import PrettyTable
x = PrettyTable(dat.dtype.names)
for row in dat:
x.add_row(row)
# Change some column alignments; default was 'c'
x.align['column_one'] = 'r'
x.align['col_two'] = 'r'
x.align['column_3'] = 'l'

And the output is not bad. There is even a border switch, among a few other options:

>>> print(x)
+------------+---------+-------------+
| column_one | col_two | column_3 |
+------------+---------+-------------+
| 0 | 0.0001 | ABCD |
| 1 | 1e-05 | ABCD |
| 2 | 1e-06 | long string |
| 3 | 1e-07 | ABCD |
+------------+---------+-------------+
>>> print(x.get_string(border=False))
column_one col_two column_3
0 0.0001 ABCD
1 1e-05 ABCD
2 1e-06 long string
3 1e-07 ABCD

How to extend pretty print module to tables?

My answer to this kind of regular cases would be to use this module:
prettytable
A simple Python library for easily displaying tabular data in a visually appealing ASCII table format



Related Topics



Leave a reply



Submit