如何输出列表作为一个表在木星笔记本?

我知道我以前在什么地方见过这样的例子,但是我无论如何也找不到。

我有一些数据行:

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

我想把这些数据输出到一个表中,例如。

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

显然,我可以使用一个图书馆,如可爱的或下载熊猫或其他东西,但我非常不感兴趣这样做。

我只是想把我的行作为表输出到我的 Jupiter 笔记本单元中。我该怎么做呢?

178012 次浏览

You could try to use the following function

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)

Ok, so this was a bit harder than I though:

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

This should work for variable number of rows, columns and number of digits (for numbers)

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

I finally re-found the jupyter/IPython documentation that I was looking for.

I needed this:

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

(I may have slightly mucked up the comprehensions, but display(HTML('some html here')) is what we needed)

tabletext fit this well

import tabletext


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


print tabletext.to_text(data)

result:

┌───┬───────┬─────┐
│ 1 │     2 │  30 │
├───┼───────┼─────┤
│ 4 │ 23125 │   6 │
├───┼───────┼─────┤
│ 7 │     8 │ 999 │
└───┴───────┴─────┘

I just discovered that tabulate has a HTML option and is rather simple to use.

Update: As of Jupyter v6 and later, the returned table should just render via the output cell:

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

As for Jupyter v5 or earlier, you may need to be more explicit, similar to Werner's answer:

from IPython.display import HTML, display
display(HTML(table))

Still looking for something simple to use to create more complex table layouts like with latex syntax and formatting to merge cells and do variable substitution in a notebook:
Allow references to Python variables in Markdown cells #2958

A general purpose set of functions to render any python data structure (dicts and lists nested together) as 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)))

I used to have the same problem. I could not find anything that would help me so I ended up making the class PrintTable--code below. There is also an output. The usage is simple:

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

or in one line:

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

Output:

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

The code for the class 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)

Demonstration

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

I want to output a table where each column has the smallest possible width, where columns are padded with white space (but this can be changed) and rows are separated by newlines (but this can be changed) and where each item is formatted using str (but...).


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)

The function signature, ftable(tbl, pad=' ', sep='\n', normalize=str), with its default arguments is intended to provide for maximum flexibility.

You can customize

  • the column padding,
  • the row separator, (e.g., pad='&', sep='\\\\\n' to have the bulk of a LaTeX table)
  • the function to be used to normalize the input to a common string format --- by default, for the maximum generality it is str but if you know that all your data is floating point lambda item: "%.4f"%item could be a reasonable choice, etc.

Superficial testing:

I need some test data, possibly involving columns of different width so that the algorithm needs to be a little more sophisticated (but just a little bit;)

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

There is a nice trick: wrap the data with pandas DataFrame.

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

It displays data like:

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

I recently used prettytable for rendering a nice ASCII table. It's similar to the postgres CLI output.

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)

Output:

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

If you don't mind using a bit of html, something like this should work.

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

And then use it like this

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

enter image description here

You can add your own formatters. Recursion is optional but really nice.

Try this in JupyterLite:

from html import escape


fmtr = get_ipython().display_formatter.formatters['text/html']


def getfmtr(obj, func=None):
if fmtr.for_type(type(obj)):
return fmtr.for_type(type(obj))(obj)
else:
return escape(obj.__str__()).replace("\n", "<br>")


def strfmtr(obj):
return escape(obj.__str__()).replace("\n", "<br>")


fmtr.for_type(str, strfmtr)


def listfmtr(self):
_repr_ = []
_repr_.append("<table>")
for item in self:
_repr_.append("<tr>")
_repr_.append("<td>")
_repr_.append(getfmtr(item))
_repr_.append("<td>")
_repr_.append("</tr>")
_repr_.append("</table>")
return str().join(_repr_)


fmtr.for_type(list, listfmtr)


def dictfmtr(self):
_repr_ = []
_repr_.append("<table>")
for key in self:
_repr_.append("<th>")
_repr_.append(getfmtr(key))
_repr_.append("<th>")
_repr_.append("<tr>")
for key, value in self.items():
_repr_.append("<td>")
_repr_.append(getfmtr(value))
_repr_.append("<td>")
_repr_.append("</tr>")
_repr_.append("</table>")
return str().join(_repr_)


fmtr.for_type(dict, dictfmtr)


[
"Jupyter is really cool!",
[1, 2],
[
{"Name": "Adams", "Age": 32},
{"Name": "Baker", "Age": 32}
]
]