Drukowanie list jako danych tabelarycznych

366

Jestem całkiem nowy w Pythonie i teraz mam problem z ładnym sformatowaniem moich danych do wydruku.

Mam jedną listę, która jest używana dla dwóch nagłówków i macierz, która powinna być zawartością tabeli. Tak jak:

teams_list = ["Man Utd", "Man City", "T Hotspur"]
data = np.array([[1, 2, 1],
                 [0, 1, 0],
                 [2, 4, 2]])

Zauważ, że nazwy nagłówków niekoniecznie mają taką samą długość. Wszystkie dane są jednak liczbami całkowitymi.

Teraz chcę to przedstawić w formie tabeli, coś takiego:

            Man Utd   Man City   T Hotspur
  Man Utd         1          0           0
 Man City         1          1           0
T Hotspur         0          1           2

Mam przeczucie, że do tego musi istnieć struktura danych, ale nie mogę jej znaleźć. Próbowałem używać słownika i formatować drukowanie, próbowałem pętli for z wcięciem i próbowałem drukować jako ciągi znaków.

Jestem pewien, że musi istnieć bardzo prosty sposób, ale prawdopodobnie brakuje mi tego z powodu braku doświadczenia.

hjweide
źródło
1
+1, po prostu próbowałem zrobić to samo zeszłej nocy. Próbujesz po prostu drukować w wierszu poleceń, czy używasz modułu GUI?
HellaMad
Po prostu drukuję do wiersza poleceń. Jednak musi przejść test jednostkowy, więc formatowanie jest tutaj bardzo ważne.
hjweide
3
możliwy duplikat Drukowanie danych tabelarycznych w Pythonie
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功
1
Możliwy duplikat Pythona: ładne tabele ascii?
Martin Thoma,
Zauważ, że wymaganie tutaj jest dość wyspecjalizowane, ponieważ etykiety wierszy i kolumn są takie same. W tym konkretnym przypadku kod ad-hoc jest dobrym przykładem tego, jak łatwo może być. Ale inne rozwiązania tutaj mogą być lepsze dla bardziej ogólnego wyświetlania tabeli.
nealmcb

Odpowiedzi:

189

Niektóre ad-hoc kodu dla Python 2.7:

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))

To zależy str.format(), a Format Specyfikacja Mini-Language .

Sven Marnach
źródło
3
Jeśli używasz Python2.6, pamiętaj o dodaniu indeksu team_list do row_format: row_format = "{0:> 15} {1:> 15} {2:> 15}"
Luis Muñoz
1
Jeśli dane w treści są większe niż nagłówki, możesz ustawić szerokość kolumny na podstawie pierwszego wiersza danych. dla t w danych [0]: row_format + = "{: <" + str (len (t) +5) + "}"
morgantaschuk
587

Istnieje kilka lekkich i przydatnych pakietów Pythona do tego celu:

1. tabulatura : https://pypi.python.org/pypi/tabulate

from tabulate import tabulate
print(tabulate([['Alice', 24], ['Bob', 19]], headers=['Name', 'Age']))
Name      Age
------  -----
Alice      24
Bob        19

W tabeli znajduje się wiele opcji określających nagłówki i format tabeli.

print(tabulate([['Alice', 24], ['Bob', 19]], headers=['Name', 'Age'], tablefmt='orgtbl'))
| Name   |   Age |
|--------+-------|
| Alice  |    24 |
| Bob    |    19 |

2. PrettyTable : https://pypi.python.org/pypi/PrettyTable

from prettytable import PrettyTable
t = PrettyTable(['Name', 'Age'])
t.add_row(['Alice', 24])
t.add_row(['Bob', 19])
print(t)
+-------+-----+
|  Name | Age |
+-------+-----+
| Alice |  24 |
|  Bob  |  19 |
+-------+-----+

PrettyTable ma opcje odczytu danych z bazy danych csv, html, sql. Możesz także wybrać podzbiór danych, sortować tabelę i zmieniać style tabel.

3. texttable : https://pypi.python.org/pypi/texttable

from texttable import Texttable
t = Texttable()
t.add_rows([['Name', 'Age'], ['Alice', 24], ['Bob', 19]])
print(t.draw())
+-------+-----+
| Name  | Age |
+=======+=====+
| Alice | 24  |
+-------+-----+
| Bob   | 19  |
+-------+-----+

za pomocą tabeli tekstowej możesz kontrolować wyrównanie w poziomie / pionie, styl obramowania i typy danych.

4. termtables : https://github.com/nschloe/termtables

import termtables as tt

string = tt.to_string(
    [["Alice", 24], ["Bob", 19]],
    header=["Name", "Age"],
    style=tt.styles.ascii_thin_double,
    # alignment="ll",
    # padding=(0, 1),
)
print(string)
+-------+-----+
| Name  | Age |
+=======+=====+
| Alice | 24  |
+-------+-----+
| Bob   | 19  |
+-------+-----+

za pomocą tabeli tekstowej możesz kontrolować wyrównanie w poziomie / pionie, styl obramowania i typy danych.

Inne opcje:

  • terminaltables Łatwo rysuj tabele w aplikacjach terminalowych / konsolowych z listy list ciągów. Obsługuje wiersze wieloliniowe.
  • asciitable Asciitable może odczytywać i zapisywać szeroką gamę formatów tabel ASCII poprzez wbudowane klasy czytników rozszerzeń.
iman
źródło
13
Uważam, że tabulatura jest bardzo przydatnym narzędziem do budowania narzędzi CLI zorientowanych na dane. To, w połączeniu z kliknięciem (kliknięcie instalacji pip), i masz prawdziwą potrawkę.
alexbw
4
To wspaniale, dziękuję. Osobiście, który wolisz spośród tych trzech?
Jim Raynor
Genialna odpowiedź! PrettyTable jest tak dobry - idealna równowaga między pozostałymi dwiema opcjami.
edesz
2
terminaltables jest dobry dla chińskich, może innych języków innych niż angielski
thinker3
5
Właśnie grałem z głównymi pakietami i IMO „beautifultable” - najlepsze, utrzymane, dobre API i doco, obsługa kolorowych. „texttable” - ładny, utrzymany, dobry API, ale użycie kolorowego użycia powoduje wyrównywanie tabel. „terminaltables” - dobre, doco tylko za pomocą przykładów kodu. „PrettyTable” - ok, ale stare „tytuły” tabeli nie działają dla mnie. „Tabulate” - dobre, ale coalignsłowo kluczowe wyrównania kolumn nie jest obsługiwane w oficjalnej wersji pypi. „tableprint” - średni, złożony interfejs API, niewystarczająca liczba typowych przykładów użycia.
abulka
79
>>> import pandas
>>> pandas.DataFrame(data, teams_list, teams_list)
           Man Utd  Man City  T Hotspur
Man Utd    1        2         1        
Man City   0        1         0        
T Hotspur  2        4         2        
jfs
źródło
6
To wygląda bardzo obiecująco, dziękuję, ale staram się to zrobić bez użycia więcej importowanych bibliotek, niż to absolutnie konieczne.
hjweide
26
Używanie pand tylko do formatowania danych wyjściowych wygląda jak Overkill (zamierzone duże O).
Niels Bom,
66
@NielsBom: chodź po formatowanie danych wyjściowych, zostań przy analizie danych i modelowaniu :)
jfs
30
@JFSebastian dla mnie było to bardziej jak „chodź po formatowanie wyjściowe, uciekaj krzycząc z powodu 10-minutowej kompilacji numpy, która sprawiła, że ​​mój komputer brzmiał jak suszarka do włosów” ;-)
Niels Bom
4
@NielsBom: pip install numpyużywa teraz kół binarnych na większości platform (bez kompilacji) . Oczywiście inne opcje instalacji binarnej były dostępne nawet wcześniej.
jfs
68

Python sprawia, że ​​jest to dość łatwe.

Coś jak

for i in range(10):
    print '%-12i%-12i' % (10 ** i, 20 ** i)

będzie miał wynik

1           1           
10          20          
100         400         
1000        8000        
10000       160000      
100000      3200000     
1000000     64000000    
10000000    1280000000  
100000000   25600000000
1000000000  512000000000

% W ciągu jest zasadniczo znakiem ucieczki, a następujące po nim znaki mówią Pythonowi, jaki format powinny mieć dane. % Na zewnątrz i po ciągu mówi pythonowi, że zamierzasz użyć poprzedniego ciągu jako ciągu formatu i że następujące dane powinny zostać wprowadzone w określonym formacie.

W tym przypadku użyłem dwukrotnie „% -12i”. Aby rozbić każdą część:

'-' (left align)
'12' (how much space to be given to this part of the output)
'i' (we are printing an integer)

Z dokumentacji: https://docs.python.org/2/library/stdtypes.html#string-formatting

Austin
źródło
Ta odpowiedź skłoniła mnie do znalezienia tego, czego szukałem! Dla Pythona 3, skończyło się używając go jak print('%-20.2f' % position['deg'], '%-17.2f' % position['v2'])gdzie .2precyzja określa pływakaf
Ross
25

Aktualizowanie odpowiedzi Svena Marnacha do pracy w Pythonie 3.4:

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))
SmrtGrunt zrezygnował, ponieważ Monica
źródło
9

Kiedy to robię, lubię mieć kontrolę nad szczegółami formatowania tabeli. W szczególności chcę, aby komórki nagłówka miały inny format niż komórki ciała, a szerokości kolumn tabeli powinny być tak szerokie, jak to konieczne. Oto moje rozwiązanie:

def format_matrix(header, matrix,
                  top_format, left_format, cell_format, row_delim, col_delim):
    table = [[''] + header] + [[name] + row for name, row in zip(header, matrix)]
    table_format = [['{:^{}}'] + len(header) * [top_format]] \
                 + len(matrix) * [[left_format] + len(header) * [cell_format]]
    col_widths = [max(
                      len(format.format(cell, 0))
                      for format, cell in zip(col_format, col))
                  for col_format, col in zip(zip(*table_format), zip(*table))]
    return row_delim.join(
               col_delim.join(
                   format.format(cell, width)
                   for format, cell, width in zip(row_format, row, col_widths))
               for row_format, row in zip(table_format, table))

print format_matrix(['Man Utd', 'Man City', 'T Hotspur', 'Really Long Column'],
                    [[1, 2, 1, -1], [0, 1, 0, 5], [2, 4, 2, 2], [0, 1, 0, 6]],
                    '{:^{}}', '{:<{}}', '{:>{}.3f}', '\n', ' | ')

Oto wynik:

                   | Man Utd | Man City | T Hotspur | Really Long Column
Man Utd            |   1.000 |    2.000 |     1.000 |             -1.000
Man City           |   0.000 |    1.000 |     0.000 |              5.000
T Hotspur          |   2.000 |    4.000 |     2.000 |              2.000
Really Long Column |   0.000 |    1.000 |     0.000 |              6.000
Campkeith
źródło
8

Myślę, że tego właśnie szukasz.

Jest to prosty moduł, który po prostu oblicza maksymalną wymaganą szerokość wpisów w tabeli, a następnie po prostu używa rjust i ljust do wykonania ładnego wydruku danych.

Jeśli chcesz, aby lewy nagłówek był wyrównany, zmień to połączenie:

 print >> out, row[0].ljust(col_paddings[0] + 1),

Z linii 53 z:

 print >> out, row[0].rjust(col_paddings[0] + 1),
Bogdan
źródło
8

Wiem, że spóźniłem się na przyjęcie, ale właśnie stworzyłem bibliotekę, która moim zdaniem mogłaby naprawdę pomóc. Jest to niezwykle proste, dlatego uważam, że powinieneś go użyć. Nazywa się TableIT .

Podstawowe użycie

Aby z niego skorzystać, najpierw postępuj zgodnie z instrukcjami pobierania na stronie GitHub .

Następnie zaimportuj:

import TableIt

Następnie utwórz listę, w której każda lista wewnętrzna jest rzędem:

table = [
    [4, 3, "Hi"],
    [2, 1, 808890312093],
    [5, "Hi", "Bye"]
]

Następnie wszystko, co musisz zrobić, to wydrukować:

TableIt.printTable(table)

To jest wynik, który otrzymujesz:

+--------------------------------------------+
| 4            | 3            | Hi           |
| 2            | 1            | 808890312093 |
| 5            | Hi           | Bye          |
+--------------------------------------------+

Nazwy pól

Możesz użyć nazw pól, jeśli chcesz ( jeśli nie używasz nazw pól, nie musisz mówić useFieldNames = False, ponieważ jest to ustawione domyślnie ):


TableIt.printTable(table, useFieldNames=True)

Z tego otrzymasz:

+--------------------------------------------+
| 4            | 3            | Hi           |
+--------------+--------------+--------------+
| 2            | 1            | 808890312093 |
| 5            | Hi           | Bye          |
+--------------------------------------------+

Istnieją inne zastosowania, na przykład możesz to zrobić:

import TableIt

myList = [
    ["Name", "Email"],
    ["Richard", "[email protected]"],
    ["Tasha", "[email protected]"]
]

TableIt.print(myList, useFieldNames=True)

Z tego:

+-----------------------------------------------+
| Name                  | Email                 |
+-----------------------+-----------------------+
| Richard               | richard@fakeemail.com |
| Tasha                 | tash@fakeemail.com    |
+-----------------------------------------------+

Lub możesz zrobić:

import TableIt

myList = [
    ["", "a", "b"],
    ["x", "a + x", "a + b"],
    ["z", "a + z", "z + b"]
]

TableIt.printTable(myList, useFieldNames=True)

I z tego otrzymujesz:

+-----------------------+
|       | a     | b     |
+-------+-------+-------+
| x     | a + x | a + b |
| z     | a + z | z + b |
+-----------------------+

Zabarwienie

Możesz także użyć kolorów.

Kolorów używa się za pomocą opcji koloru ( domyślnie jest ustawiona na Brak ) i określania wartości RGB.

Korzystając z powyższego przykładu:

import TableIt

myList = [
    ["", "a", "b"],
    ["x", "a + x", "a + b"],
    ["z", "a + z", "z + b"]
]

TableIt.printTable(myList, useFieldNames=True, color=(26, 156, 171))

Otrzymasz wtedy:

wprowadź opis zdjęcia tutaj

Pamiętaj, że drukowanie kolorów może nie działać, ale działa dokładnie tak samo, jak inne biblioteki drukujące kolorowy tekst. Przetestowałem i każdy kolor działa. Niebieski też nie jest pomieszany, tak jak w przypadku domyślnej 34msekwencji ucieczki ANSI (jeśli nie wiesz, co to jest, nie ma to znaczenia). W każdym razie wszystko wynika z faktu, że każdy kolor ma wartość RGB, a nie domyślną wartość systemową.

Więcej informacji

Aby uzyskać więcej informacji, sprawdź stronę GitHub

BeastCoder
źródło
Tabela To naprawdę miłe narzędzie. Prosty, ale potężny. Myślę, że jedyną wadą jest TableIt nie ogłosił LICENCJI
Endle_Zhenbo
@Endle_Zhenbo Hej! Wielkie dzięki, popracuję nad tym jak najszybciej!
BeastCoder
@Endle_Zhenbo, wiem, że minęło trochę czasu, ale w końcu umieściłem licencję na projekt.
BeastCoder
7

Pure Python 3

def print_table(data, cols, wide):
    '''Prints formatted data on columns of given width.'''
    n, r = divmod(len(data), cols)
    pat = '{{:{}}}'.format(wide)
    line = '\n'.join(pat * cols for _ in range(n))
    last_line = pat * r
    print(line.format(*data))
    print(last_line.format(*data[n*cols:]))

data = [str(i) for i in range(27)]
print_table(data, 6, 12)

Wydrukuje

0           1           2           3           4           5           
6           7           8           9           10          11          
12          13          14          15          16          17          
18          19          20          21          22          23          
24          25          26
Naukowiec danych
źródło
5

Prostym sposobem na to jest zapętlenie wszystkich kolumn, zmierzenie ich szerokości, utworzenie szablonu wiersza dla tej maksymalnej szerokości, a następnie wydrukowanie wierszy. Nie jest to dokładnie to, czego szukasz , ponieważ w tym przypadku musisz najpierw umieścić nagłówki w tabeli, ale myślę, że może być przydatny dla kogoś innego.

table = [
    ["", "Man Utd", "Man City", "T Hotspur"],
    ["Man Utd", 1, 0, 0],
    ["Man City", 1, 1, 0],
    ["T Hotspur", 0, 1, 2],
]
def print_table(table):
    longest_cols = [
        (max([len(str(row[i])) for row in table]) + 3)
        for i in range(len(table[0]))
    ]
    row_format = "".join(["{:>" + str(longest_col) + "}" for longest_col in longest_cols])
    for row in table:
        print(row_format.format(*row))

Używasz go w ten sposób:

>>> print_table(table)

            Man Utd   Man City   T Hotspur
  Man Utd         1          0           0
 Man City         1          1           0
T Hotspur         0          1           2
Emil Stenström
źródło
3

Poniższa funkcja utworzy żądaną tabelę (z numpy lub bez) z Python 3 (być może również Python 2). Wybrałem ustawienie szerokości każdej kolumny, aby pasowała do najdłuższej nazwy drużyny. Możesz go zmodyfikować, jeśli chcesz użyć długości nazwy zespołu dla każdej kolumny, ale będzie to bardziej skomplikowane.

Uwaga: W przypadku bezpośredniego odpowiednika w Pythonie 2 możesz zastąpić go zipz izipitertools.

def print_results_table(data, teams_list):
    str_l = max(len(t) for t in teams_list)
    print(" ".join(['{:>{length}s}'.format(t, length = str_l) for t in [" "] + teams_list]))
    for t, row in zip(teams_list, data):
        print(" ".join(['{:>{length}s}'.format(str(x), length = str_l) for x in [t] + row]))

teams_list = ["Man Utd", "Man City", "T Hotspur"]
data = [[1, 2, 1],
        [0, 1, 0],
        [2, 4, 2]]

print_results_table(data, teams_list)

Spowoduje to utworzenie następującej tabeli:

            Man Utd  Man City T Hotspur
  Man Utd         1         2         1
 Man City         0         1         0
T Hotspur         2         4         2

Jeśli chcesz mieć pionowych separatorów, można zastąpić " ".joinz " | ".join.

Bibliografia:

Diomedea
źródło
2

Spróbowałbym przejrzeć listę i użyć formatera CSV do przedstawienia danych, które chcesz.

Jako separator możesz określić tabulatory, przecinki lub dowolny inny znak.

W przeciwnym razie po prostu przewiń listę i wypisz „\ t” po każdym elemencie

http://docs.python.org/library/csv.html

Jeffrey Kevin Pry
źródło
To była moja pierwsza próba, prawdopodobnie można to zrobić, ale wydaje się, że spore wysiłki doprowadziły do ​​idealnego formatowania.
hjweide
2

Znalazłem to, szukając sposobu na wyprowadzenie prostych kolumn. Jeśli potrzebujesz tylko bezproblemowych kolumn , możesz użyć tego:

print("Titlex\tTitley\tTitlez")
for x, y, z in data:
    print(x, "\t", y, "\t", z)

EDYCJA: Starałem się być tak prosty, jak to możliwe, i tym samym zrobiłem kilka rzeczy ręcznie zamiast korzystać z listy drużyn. Aby uogólnić na aktualne pytanie PO:

#Column headers
print("", end="\t")
for team in teams_list:
    print(" ", team, end="")
print()
# rows
for team, row in enumerate(data):
    teamlabel = teams_list[team]
    while len(teamlabel) < 9:
        teamlabel = " " + teamlabel
    print(teamlabel, end="\t")
    for entry in row:
        print(entry, end="\t")
    print()

Ouputs:

          Man Utd  Man City  T Hotspur
  Man Utd       1       2       1   
 Man City       0       1       0   
T Hotspur       2       4       2   

Ale nie wydaje się to już prostsze niż inne odpowiedzi, z tą korzyścią, że nie wymaga już żadnego importu. Ale odpowiedź @ campkeith już to spełniła i jest bardziej niezawodna, ponieważ może obsługiwać szerszy zakres długości etykiet.

pr3sidentspence
źródło
1
zostało to omówione na stronie meta.stackoverflow.com/questions/381571/...
Félix Gagnon-Grenier