¿Cómo puedo generar listas como una tabla en el cuaderno Jupyter?


80

Sé que he visto algún ejemplo en alguna parte antes, pero por mi vida no puedo encontrarlo cuando busco en Google.

Tengo algunas filas de datos:

data = [[1,2,3],
        [4,5,6],
        [7,8,9],
        ]

Y quiero generar estos datos en una tabla, por ejemplo

+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 4 | 5 | 6 |
+---+---+---+
| 7 | 8 | 9 |
+---+---+---+

Obviamente, podría usar una biblioteca como prettytable o descargar pandas o algo así, pero no estoy muy interesado en hacer eso.

Solo quiero generar mis filas como tablas en la celda de mi cuaderno Jupyter. ¿Cómo hago esto?


¿Quieres usar solo printfunciones? Son los números fijos de ancho (1 dígito, tres dígitos?
tglaria

Aquí escribí abstracción pitónica. Codifique sin problemas. :) jupyter_table_class.py
not_python

Respuestas:


85

Acabo de descubrir que tabular tiene una opción HTML y es bastante simple de usar.
Muy similar a la respuesta de Wayne Werner:

from IPython.display import HTML, display
import tabulate
table = [["Sun",696000,1989100000],
         ["Earth",6371,5973.6],
         ["Moon",1737,73.5],
         ["Mars",3390,641.85]]
display(HTML(tabulate.tabulate(table, tablefmt='html')))

Sigo buscando algo simple de usar para crear diseños de tablas más complejos, como la sintaxis de látex y el formato para fusionar celdas y hacer sustitución de variables en un cuaderno:
Permita referencias a variables de Python en celdas de Markdown # 2958


¡Alinear cuerdas no funcionó para mí! ¡No alinea la cuerda a la izquierda!
Mojtaba Khodadadi

@MojtabaKhodadadi no lo ha verificado de cerca, pero parece que puede establecer el argumento de columna predeterminado para srtings vs números aquí .
ruffsl

Hoy en día, incluso tabulate.tabulate(table, tablefmt='html')parece funcionar (probé Jupyter 6.0.3, JupyterLab 2.0.1). ¡Agradable!
zonksoft

82

Hay un buen truco: envuelve los datos con pandas DataFrame.

import pandas as pd
data = [[1, 2], [3, 4]]
pd.DataFrame(data, columns=["Foo", "Bar"])

Muestra datos como:

  | Foo | Bar |
0 | 1   | 2   |
1 | 3   | 4   |

14
Como alguien que ama absolutamente Python para todo, PERO la ciencia de datos, me entristece REALMENTE ver que las respuestas de llamadas de función triple, importación cuádruple y nueve líneas reciben votación positiva cuando la respuesta MEJOR es literalmente "un DataFrame de pandas". Mi heurística es: "Si es largo, probablemente esté mal".
one_observation

1
Incluso puede mostrar el DataFrame como HTML usando to_html(), consulte stackoverflow.com/a/29665452/2866660
wvengen

¡Gracias! Sí, la respuesta aceptada definitivamente debería cambiarse a esta.
Helen

59

Finalmente encontré la documentación de jupyter / IPython que estaba buscando.

Necesitaba esto:

from IPython.display import HTML, display

data = [[1,2,3],
        [4,5,6],
        [7,8,9],
        ]

display(HTML(
   '<table><tr>{}</tr></table>'.format(
       '</tr><tr>'.join(
           '<td>{}</td>'.format('</td><td>'.join(str(_) for _ in row)) for row in data)
       )
))

(Puede que haya estropeado un poco las comprensiones, pero display(HTML('some html here'))es lo que necesitábamos)


13

tabletext encaja bien

import tabletext

data = [[1,2,30],
        [4,23125,6],
        [7,8,999],
        ]

print tabletext.to_text(data)

resultado:

┌───┬───────┬─────┐
│ 1230 │
├───┼───────┼─────┤
│ 4231256 │
├───┼───────┼─────┤
│ 78999 │
└───┴───────┴─────┘

4

Si no le importa usar un poco de html, algo como esto debería funcionar.

from IPython.display import HTML, display

def display_table(data):
    html = "<table>"
    for row in data:
        html += "<tr>"
        for field in row:
            html += "<td><h4>%s</h4><td>"%(field)
        html += "</tr>"
    html += "</table>"
    display(HTML(html))

Y luego úsalo así

data = [[1,2,3],[4,5,6],[7,8,9]]
display_table(data)

ingrese la descripción de la imagen aquí


2

Puedes intentar usar la siguiente función

def tableIt(data):
    for lin in data:
        print("+---"*len(lin)+"+")
        for inlin in lin:
            print("|",str(inlin),"", end="")
        print("|")
    print("+---"*len(lin)+"+")

data = [[1,2,3,2,3],[1,2,3,2,3],[1,2,3,2,3],[1,2,3,2,3]]

tableIt(data)

2

Ok, esto fue un poco más difícil de lo que pensé:

def print_matrix(list_of_list):
    number_width = len(str(max([max(i) for i in list_of_list])))
    cols = max(map(len, list_of_list))
    output = '+'+('-'*(number_width+2)+'+')*cols + '\n'
    for row in list_of_list:
        for column in row:
            output += '|' + ' {:^{width}d} '.format(column, width = number_width)
        output+='|\n+'+('-'*(number_width+2)+'+')*cols + '\n'
    return output

Esto debería funcionar para un número variable de filas, columnas y número de dígitos (para números)

data = [[1,2,30],
        [4,23125,6],
        [7,8,999],
        ]
print print_matrix(data)
>>>>+-------+-------+-------+
    |   1   |   2   |  30   |
    +-------+-------+-------+
    |   4   | 23125 |   6   |
    +-------+-------+-------+
    |   7   |   8   |  999  |
    +-------+-------+-------+

1

Un conjunto de funciones de propósito general para representar cualquier estructura de datos de Python (dictados y listas anidadas juntas) como HTML.

from IPython.display import HTML, display

def _render_list_html(l):
    o = []
    for e in l:
        o.append('<li>%s</li>' % _render_as_html(e))
    return '<ol>%s</ol>' % ''.join(o)

def _render_dict_html(d):
    o = []
    for k, v in d.items():
        o.append('<tr><td>%s</td><td>%s</td></tr>' % (str(k), _render_as_html(v)))
    return '<table>%s</table>' % ''.join(o)

def _render_as_html(e):
    o = []
    if isinstance(e, list):
        o.append(_render_list_html(e))
    elif isinstance(e, dict):
        o.append(_render_dict_html(e))
    else:
        o.append(str(e))
    return '<html><body>%s</body></html>' % ''.join(o)

def render_as_html(e):
    display(HTML(_render_as_html(e)))

1

Yo solia tener el mismo problema. No pude encontrar nada que me ayudara, así que terminé haciendo la clase: PrintTablecódigo a continuación. También hay una salida. El uso es simple:

ptobj = PrintTable(yourdata, column_captions, column_widths, text_aligns)
ptobj.print()

o en una línea:

PrintTable(yourdata, column_captions, column_widths, text_aligns).print()

Salida:

-------------------------------------------------------------------------------------------------------------
  Name                                     | Column 1   | Column 2   | Column 3   | Column 4   | Column 5    
-------------------------------------------------------------------------------------------------------------
  Very long name 0                         |          0 |          0 |          0 |          0 |          0  
  Very long name 1                         |          1 |          2 |          3 |          4 |          5  
  Very long name 2                         |          2 |          4 |          6 |          8 |         10  
  Very long name 3                         |          3 |          6 |          9 |         12 |         15  
  Very long name 4                         |          4 |          8 |         12 |         16 |         20  
  Very long name 5                         |          5 |         10 |         15 |         20 |         25  
  Very long name 6                         |          6 |         12 |         18 |         24 |         30  
  Very long name 7                         |          7 |         14 |         21 |         28 |         35  
  Very long name 8                         |          8 |         16 |         24 |         32 |         40  
  Very long name 9                         |          9 |         18 |         27 |         36 |         45  
  Very long name 10                        |         10 |         20 |         30 |         40 |         50  
  Very long name 11                        |         11 |         22 |         33 |         44 |         55  
  Very long name 12                        |         12 |         24 |         36 |         48 |         60  
  Very long name 13                        |         13 |         26 |         39 |         52 |         65  
  Very long name 14                        |         14 |         28 |         42 |         56 |         70  
  Very long name 15                        |         15 |         30 |         45 |         60 |         75  
  Very long name 16                        |         16 |         32 |         48 |         64 |         80  
  Very long name 17                        |         17 |         34 |         51 |         68 |         85  
  Very long name 18                        |         18 |         36 |         54 |         72 |         90  
  Very long name 19                        |         19 |         38 |         57 |         76 |         95  
-------------------------------------------------------------------------------------------------------------

El código de la clase PrintTable

# -*- coding: utf-8 -*-

# Class
class PrintTable:
    def __init__(self, values, captions, widths, aligns):
    if not all([len(values[0]) == len(x) for x in [captions, widths, aligns]]):
        raise Exception()
    self._tablewidth = sum(widths) + 3*(len(captions)-1) + 4
    self._values = values
    self._captions = captions
    self._widths = widths
    self._aligns = aligns

    def print(self):
    self._printTable()

    def _printTable(self):
    formattext_head = ""
    formattext_cell = ""
    for i,v in enumerate(self._widths):
        formattext_head += "{" + str(i) + ":<" + str(v) + "} | "
        formattext_cell += "{" + str(i) + ":" + self._aligns[i] + str(v) + "} | "
    formattext_head = formattext_head[:-3]
    formattext_head = "  " + formattext_head.strip() + "  "
    formattext_cell = formattext_cell[:-3]
    formattext_cell = "  " + formattext_cell.strip() + "  "

    print("-"*self._tablewidth)
    print(formattext_head.format(*self._captions))
    print("-"*self._tablewidth)
    for w in self._values:
        print(formattext_cell.format(*w))
    print("-"*self._tablewidth)

Demostración

# Demonstration

headername = ["Column {}".format(x) for x in range(6)]
headername[0] = "Name"
data = [["Very long name {}".format(x), x, x*2, x*3, x*4, x*5] for x in range(20)] 

PrintTable(data, \
       headername, \
       [70, 10, 10, 10, 10, 10], \
       ["<",">",">",">",">",">"]).print()

1

Recientemente utilicé prettytablepara renderizar una bonita tabla ASCII. Es similar a la salida CLI de postgres.

import pandas as pd
from prettytable import PrettyTable

data = [[1,2,3],[4,5,6],[7,8,9]]
df = pd.DataFrame(data, columns=['one', 'two', 'three'])

def generate_ascii_table(df):
    x = PrettyTable()
    x.field_names = df.columns.tolist()
    for row in df.values:
        x.add_row(row)
    print(x)
    return x

generate_ascii_table(df)

Salida:

+-----+-----+-------+
| one | two | three |
+-----+-----+-------+
|  1  |  2  |   3   |
|  4  |  5  |   6   |
|  7  |  8  |   9   |
+-----+-----+-------+

0

Quiero generar una tabla donde cada columna tiene el ancho más pequeño posible, donde las columnas se rellenan con espacios en blanco (pero esto se puede cambiar) y las filas están separadas por líneas nuevas (pero esto se puede cambiar) y donde cada elemento se formatea usando str( pero...).


def ftable(tbl, pad='  ', sep='\n', normalize=str):

    # normalize the content to the most useful data type
    strtbl = [[normalize(it) for it in row] for row in tbl] 

    # next, for each column we compute the maximum width needed
    w = [0 for _ in tbl[0]]
    for row in strtbl:
        for ncol, it in enumerate(row):
            w[ncol] = max(w[ncol], len(it))

    # a string is built iterating on the rows and the items of `strtbl`:
    #   items are  prepended white space to an uniform column width
    #   formatted items are `join`ed using `pad` (by default "  ")
    #   eventually we join the rows using newlines and return
    return sep.join(pad.join(' '*(wid-len(it))+it for wid, it in zip(w, row))
                                                      for row in strtbl)

La firma de la función ftable(tbl, pad=' ', sep='\n', normalize=str), con sus argumentos predeterminados está destinada a proporcionar la máxima flexibilidad.

Puedes personalizar

  • la almohadilla de la columna ding,
  • la fila septiembre arator, (por ejemplo, pad='&', sep='\\\\\n'para tener la mayor parte de una mesa de látex)
  • la función que se utilizará para normalizar la entrada a un formato de cadena común --- por defecto, para la máxima generalidad es, strpero si sabe que todos sus datos son de punto flotante lambda item: "%.4f"%itempodría ser una opción razonable, etc.

Pruebas superficiales:

Necesito algunos datos de prueba, posiblemente involucrando columnas de diferente ancho para que el algoritmo deba ser un poco más sofisticado (pero solo un poco;)

In [1]: from random import randrange

In [2]: table = [[randrange(10**randrange(10)) for i in range(5)] for j in range(3)]

In [3]: table
Out[3]: 
[[974413992, 510, 0, 3114, 1],
 [863242961, 0, 94924, 782, 34],
 [1060993, 62, 26076, 75832, 833174]]

In [4]: print(ftable(table))
974413992  510      0   3114       1
863242961    0  94924    782      34
  1060993   62  26076  75832  833174

In [5]: print(ftable(table, pad='|'))
974413992|510|    0| 3114|     1
863242961|  0|94924|  782|    34
  1060993| 62|26076|75832|833174
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.