Impression de listes sous forme de données tabulaires

366

Je suis assez nouveau sur Python et j'ai maintenant du mal à bien formater mes données pour la sortie imprimée.

J'ai une liste qui est utilisée pour deux titres et une matrice qui devrait être le contenu du tableau. Ainsi:

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

Notez que les noms de titres ne sont pas nécessairement de mêmes longueurs. Les entrées de données sont cependant toutes des entiers.

Maintenant, je veux représenter cela sous forme de tableau, quelque chose comme ceci:

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

J'ai le pressentiment qu'il doit y avoir une structure de données pour cela, mais je ne la trouve pas. J'ai essayé d'utiliser un dictionnaire et de formater l'impression, j'ai essayé les boucles for avec indentation et j'ai essayé d'imprimer en tant que chaînes.

Je suis sûr qu'il doit y avoir un moyen très simple de le faire, mais je le manque probablement par manque d'expérience.

hjweide
la source
1
+1, j'essayais juste de faire la même chose la nuit dernière. Essayez-vous simplement d'imprimer sur la ligne de commande ou utilisez-vous un module GUI?
HellaMad
Il suffit d'imprimer sur la ligne de commande. Cependant, il doit passer un cas de test unitaire, donc le formatage est assez important ici.
hjweide
3
doublon possible de l' impression de données tabulaires en Python
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Duplicata possible de Python: jolies tables ascii d'impression?
Martin Thoma
Notez que l'exigence ici est assez spécialisée, car les étiquettes de ligne et de colonne sont les mêmes. Donc, dans ce cas particulier, le code ad hoc est un bel exemple de la facilité avec laquelle cela peut être. Mais les autres solutions ici peuvent être meilleures pour un affichage de table plus générique.
nealmcb

Réponses:

189

Du code ad hoc pour 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))

Cela s'appuie sur str.format()le mini-langage de spécification de format .

Sven Marnach
la source
3
Si vous utilisez python2.6, n'oubliez pas d'ajouter l'index team_list sur row_format: row_format = "{0:> 15} {1:> 15} {2:> 15}"
Luis Muñoz
1
Si les données du corps sont plus grandes que les en-têtes, vous pouvez définir la largeur de colonne en fonction de la première ligne de données. pour t dans les données [0]: row_format + = "{: <" + str (len (t) +5) + "}"
morgantaschuk
588

Il existe des packages python légers et utiles à cet effet:

1. tabuler : 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

tabulate a de nombreuses options pour spécifier les en-têtes et le format du tableau.

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 a des options pour lire les données de la base de données csv, html, sql. Vous pouvez également sélectionner un sous-ensemble de données, trier le tableau et modifier les styles de tableau.

3. table de texte : 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  |
+-------+-----+

avec table de texte, vous pouvez contrôler l'alignement horizontal / vertical, le style de bordure et les types de données.

4. tables terminales : 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  |
+-------+-----+

avec table de texte, vous pouvez contrôler l'alignement horizontal / vertical, le style de bordure et les types de données.

Autres options:

  • terminaltables Dessinez facilement des tableaux dans des applications de terminal / console à partir d'une liste de listes de chaînes. Prend en charge les lignes multi-lignes.
  • asciitable Asciitable peut lire et écrire un large éventail de formats de table ASCII via des classes de lecteur d'extension intégrées.
iman
la source
13
J'ai trouvé que tabuler était un outil très utile pour créer des outils CLI centrés sur les données. Cela, combiné avec le clic (clic d'installation pip), et vous avez un vrai ragoût.
alexbw
4
C'est merveilleux, merci. Personnellement, lequel préféreriez-vous parmi ces trois?
Jim Raynor
Réponse brillante! PrettyTable est tellement bon - l'équilibre parfait entre les deux autres options.
edesz
2
terminaltables est bon pour le chinois, peut-être d'autres langues non anglaises
thinker3
5
Je viens de jouer avec les packages principaux et IMO "beautifultable" - meilleur, maintenu, bon API & doco, support pour coloré. "table de texte" - belle API, maintenue et bonne, mais l'utilisation d'une utilisation colorée désaligne les tableaux. "terminaltables" - bon, doco uniquement via des exemples de code. "PrettyTable" - ok, mais les vieux "titres" de table ne fonctionnent pas pour moi. "Tabuler" - bon, mais le coalignmot clé d' alignement des colonnes n'est pas pris en charge dans la version officielle de pypi. "tableprint" - moyenne, complexe API, pas assez d'exemples d'utilisation courants.
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
la source
6
Cela semble très prometteur, merci, mais j'essaie de le faire sans utiliser plus de bibliothèques importées que nécessaire.
hjweide
26
L'utilisation de pandas uniquement pour le formatage de sortie semble être Overkill (O majuscule prévu).
Niels Bom
66
@NielsBom: venez pour le formatage de sortie, restez pour l'analyse des données et la modélisation :)
jfs
30
@JFSebastian pour moi, c'était plutôt "venez pour le formatage de sortie, fuyez en hurlant à cause de la compilation numpy de 10 minutes qui a fait sonner mon ordinateur comme un sèche-cheveux" ;-)
Niels Bom
4
@NielsBom: pip install numpyutilise désormais les roues binaires sur la plupart des plateformes (pas de compilation) . Évidemment, d'autres options d'installation binaires étaient disponibles avant cela.
jfs
68

Python rend cela assez simple.

Quelque chose comme

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

aura la sortie

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

Le% dans la chaîne est essentiellement un caractère d'échappement et les caractères qui suivent indiquent à python le type de format que les données doivent avoir. Le% à l'extérieur et après la chaîne indique à python que vous avez l'intention d'utiliser la chaîne précédente comme chaîne de format et que les données suivantes doivent être mises au format spécifié.

Dans ce cas, j'ai utilisé "% -12i" deux fois. Pour décomposer chaque partie:

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

Depuis les documents: https://docs.python.org/2/library/stdtypes.html#string-formatting

Austin
la source
Cette réponse m'a mis sur la bonne voie pour trouver ce que je cherchais! Pour python 3, j'ai fini par l'utiliser comme print('%-20.2f' % position['deg'], '%-17.2f' % position['v2'])où la .2précision spécifiée du flotteurf
Ross
25

Mise à jour de la réponse de Sven Marnach pour fonctionner en Python 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 a quitté parce que Monica
la source
9

Lorsque je fais cela, j'aime avoir un certain contrôle sur les détails de la mise en forme du tableau. En particulier, je souhaite que les cellules d'en-tête aient un format différent de celui des cellules de corps, et que les largeurs des colonnes du tableau soient aussi larges que chacune doit l'être. Voici ma solution:

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

Voici la sortie:

                   | 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
la source
8

Je pense que ça que vous recherchez.

C'est un module simple qui calcule simplement la largeur maximale requise pour les entrées de table, puis utilise simplement rjust et ljust pour faire une jolie impression des données.

Si vous voulez que votre cap gauche soit aligné à droite, changez simplement cet appel:

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

De la ligne 53 avec:

 print >> out, row[0].rjust(col_paddings[0] + 1),
Bogdan
la source
8

Je sais que je suis en retard à la fête, mais je viens de créer une bibliothèque pour cela qui, je pense, pourrait vraiment aider. C'est extrêmement simple, c'est pourquoi je pense que vous devriez l'utiliser. Il s'appelle TableIT .

Utilisation basique

Pour l'utiliser, suivez d'abord les instructions de téléchargement sur la page GitHub .

Importez-le ensuite:

import TableIt

Faites ensuite une liste de listes où chaque liste intérieure est une ligne:

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

Il ne vous reste plus qu'à l'imprimer:

TableIt.printTable(table)

Voici la sortie que vous obtenez:

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

Noms des champs

Vous pouvez utiliser des noms de champs si vous le souhaitez ( si vous n'utilisez pas de noms de champs, vous n'avez pas à dire useFieldNames = False car il est défini sur celui par défaut ):


TableIt.printTable(table, useFieldNames=True)

De cela, vous obtiendrez:

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

Il existe d'autres utilisations, par exemple, vous pouvez le faire:

import TableIt

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

TableIt.print(myList, useFieldNames=True)

À partir de ce:

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

Ou vous pourriez faire:

import TableIt

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

TableIt.printTable(myList, useFieldNames=True)

Et à partir de cela, vous obtenez:

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

Couleurs

Vous pouvez également utiliser des couleurs.

Vous utilisez les couleurs en utilisant l'option couleur ( par défaut, elle est définie sur Aucune ) et en spécifiant les valeurs RVB.

En utilisant l'exemple ci-dessus:

import TableIt

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

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

Vous obtiendrez alors:

entrez la description de l'image ici

Veuillez noter que l'impression des couleurs peut ne pas fonctionner pour vous, mais cela fonctionne exactement de la même manière que les autres bibliothèques qui impriment du texte en couleur. J'ai testé et chaque couleur fonctionne. Le bleu n'est pas gâché non plus comme il le ferait si vous utilisez la valeur par défaut34m séquence d'échappement ANSI (si vous ne savez pas ce que c'est, peu importe). Quoi qu'il en soit, tout cela vient du fait que chaque couleur est une valeur RVB plutôt qu'une valeur par défaut du système.

Plus d'informations

Pour plus d'informations, consultez la page GitHub

BeastCoder
la source
C'est vraiment un bel outil. Simple mais puissant. Le seul inconvénient, je pense, est que TableIt n'a pas déclaré de LICENCE
Endle_Zhenbo
@Endle_Zhenbo Hey! Merci beaucoup, j'y travaillerai dès que possible!
BeastCoder
@Endle_Zhenbo, je sais que cela fait un moment, mais j'ai finalement placé une licence sur le projet.
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)

Imprime

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
Le Data Scientician
la source
5

Un moyen simple de le faire consiste à parcourir toutes les colonnes, à mesurer leur largeur, à créer un modèle de ligne pour cette largeur maximale, puis à imprimer les lignes. Ce n'est pas exactement ce que vous recherchez , car dans ce cas, vous devez d'abord mettre vos titres dans le tableau, mais je pense que cela pourrait être utile à quelqu'un d'autre.

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

Vous l'utilisez comme ceci:

>>> 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
la source
3

La fonction suivante créera la table demandée (avec ou sans numpy) avec Python 3 (peut-être aussi Python 2). J'ai choisi de définir la largeur de chaque colonne pour qu'elle corresponde à celle du plus long nom d'équipe. Vous pouvez le modifier si vous souhaitez utiliser la longueur du nom de l'équipe pour chaque colonne, mais ce sera plus compliqué.

Remarque: Pour un équivalent direct dans Python 2, vous pouvez remplacer le zippar izipde itertools.

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)

Cela produira le tableau suivant:

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

Si vous souhaitez avoir des séparateurs de lignes verticales, vous pouvez les remplacer " ".joinpar " | ".join.

Références:

Diomedea
la source
2

J'essaierais de parcourir la liste et d'utiliser un formateur CSV pour représenter les données que vous souhaitez.

Vous pouvez spécifier des tabulations, des virgules ou tout autre caractère comme délimiteur.

Sinon, parcourez simplement la liste et imprimez "\ t" après chaque élément

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

Jeffrey Kevin Pry
la source
C'était ma première tentative, cela peut probablement être fait, mais il semble que beaucoup d'efforts soient nécessaires pour obtenir une mise en forme parfaite.
hjweide
2

J'ai trouvé cela juste à la recherche d'un moyen de produire des colonnes simples. Si vous avez juste besoin de colonnes sans tracas , vous pouvez utiliser ceci:

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

EDIT: J'essayais d'être aussi simple que possible, et j'ai donc fait certaines choses manuellement au lieu d'utiliser la liste des équipes. Pour généraliser à la question réelle du 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()

Sortie:

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

Mais cela ne semble plus plus simple que les autres réponses, avec peut-être l'avantage qu'il ne nécessite plus d'importations. Mais la réponse de @ campkeith l'a déjà rencontré et est plus robuste car elle peut gérer une plus grande variété de longueurs d'étiquettes.

pr3sidentspence
la source
1
ceci est discuté sur meta meta.stackoverflow.com/questions/381571/…
Félix Gagnon-Grenier