Generate Tables from Data#
The generate_table
function can be used to generate tables in various formats for viewing tabular data. The formats currently available are:
text
, a simple text based tablerst
, a table in restructured text formatgithub
, a table in github’s markdown formatgrid
, is like thegrid
format in the Tabulate package, which mimics Emacs’ table.el packagesimple_grid
draws a grid using single-line box drawing charactersheavy_grid
draws a grid using thick single-line box drawing charactersdouble_grid
draws a grid using double-line box drawing charactersbox_grid
mixes double-line and single-line dashed drawing charactershtml
, a basic html table, viewable in a browsertabulator
, a table with sortable, filterable columns that’s viewable in a browser, built using the tabulator.js library.
All of the *grid
formats have a corresponding *outline
format that is identical but
doesn’t draw lines between data rows.
- openmdao.visualization.tables.table_builder.generate_table(rows, tablefmt='text', **options)[source]
Return the specified table builder class.
- Parameters:
- rowsiter of iters
This specifies the cells in each table row.
- tablefmtstr
This determines which table builder object will be returned.
- **optionsdict
Named arguments specific to a given table builder class.
- Returns:
- TableBuilder
A table builder object.
Table Row Data#
Different keyword arguments can be passed to generate_table
depending on the table format specified via the tablefmt
argument. The first argument must always be the data object containing all of the row cell data. That data object has several allowable formats:
a 2D numpy array
an iterator of lists
a dictionary where each key specifies a column header and each value contains that column’s values.
a list of dictionaries where each dict represents the values of a single row and whose keys are the column headers.
Note that for numbers 3 and 4, you must specify headers='keys'
if you want to use the dictionary keys
as the column headers.
Creating Tables#
There are a core set of arguments accepted for all table formats and some that are table format specific.
The arguments that are accepted are those accepted by the TableBuilder
class that corresponds to each
table format.
The base class for all tables is TableBuilder
, and it has the following interface. Its
parameters are accepted by generate_table
for all table formats.
- openmdao.visualization.tables.table_builder.TableBuilder(rows, headers=None, column_meta=None, precision=4, missing_val='', max_width=None)[source]
Base class for all table builders.
- Parameters:
- rowsiter of iters
Data used to fill table cells.
- headersiter of str, ‘keys’, or None
If not None, header strings for all columns. Size must match number of columns in each row of data in rows. A value of ‘keys’ means that rows is either a dict or a list of dicts and the keys of that/those dict(s) should be used as headers.
- column_metaiter of dict or None
If not None, contains a dict for each table column and the dict contains values of metadata for that column.
- precisionint or str
Precision applied to all columns of real numbers. May be overridden by column metadata for a specific column. Defaults to 4.
- missing_valstr
A value that will replace any cell data having a value of None. Defaults to ‘’.
- max_widthint or None
If not None, specifies the maximum width, in characters, allowed for the table. If the table cannot meet the max width requirement by resizing columns, the max_width is ignored.
- Attributes:
- missing_valstr
String to replace any data values of None.
- max_widthint or None
If not None, specifies the maximum allowable width, in characters, of the table.
- _ncolsint
Number of columns.
- _raw_rowsiter of iters
Table row data from the caller, possibly converted to list of lists if caller passed in dict or iter of dicts.
- _rowslist of lists
Table row data after initial formatting.
- _column_metadict
Metadata for each column, keyed by column index, starting at 0.
- _data_widthslist of int
Width of widest data cell in each column.
- _header_widthslist of int
Width of each column header.
- _default_formatsdict
Dict mapping each column type to its default format string.
The headers
argument exists for cases where you just want to specify the header strings without
adding any additional metadata for each column. If you want to do things like set the alignment of
a column, you’ll need to set the column metadata yourself, either by passing a list of column
metadata dicts via the column_meta
argument, or by calling update_column_meta
on the table
builder object returned from generate_table
.
The headers
argument also has two special values, keys
for specifying that the keys
of a dictionary should be used as headers, and firstrow
for specifying that the first row
of the given row data will be used as the headers.
- openmdao.visualization.tables.table_builder.TableBuilder.update_column_meta(self, col_idx, **options)
Update metadata for the column at the specified index (starting at index 0).
- Parameters:
- col_idxint
The index of the column, starting at 0.
- **optionsdict
The metadata dict will be updated with these options.
Text Tables#
The text
, rst
, and github
table formats use table builder classes that all inherit from TextTableBuilder
. Its parameters are shown below.
- openmdao.visualization.tables.table_builder.TextTableBuilder(rows, top_border=Line(left='| ', sep='---', right=' |', hline='-'), header_bottom_border=Line(left='| ', sep=' | ', right=' |', hline='-'), bottom_border=Line(left='| ', sep='---', right=' |', hline='-'), header_line=Line(left='| ', sep=' | ', right=' |', hline=''), data_row_line=Line(left='| ', sep=' | ', right=' |', hline=''), row_separator=None, **kwargs)[source]
Base class for all text-based table builders.
- Parameters:
- rowsiter of iters
Data used to fill table cells.
- top_borderLine
Top border info.
- header_bottom_borderLine
Header bottom border info.
- bottom_borderLine
Bottom border info.
- header_lineLine
Header line info.
- data_row_lineLine
Data row line info.
- row_separatorLine or None
If not None, info for lines between data rows.
- **kwargsdict
Keyword args for the base class.
- Attributes:
- top_borderLine
Top border info.
- header_bottom_borderLine
Header bottom border info.
- bottom_borderLine
Bottom border info.
- header_lineLine
Header line info.
- data_row_lineLine
Data row line info.
- row_separatorLine or None
If not None, info for lines between data rows.
You can easily create a text based table with custom border strings and column separators by
creating a TextTableBuilder
directly and setting the values of column_sep
, top_border
, bottom_border
, etc.
HTML Tables#
The html
table format generates tables in plain HTML table format using HTMLTableBuilder
. It’s parameters are shown below.
- openmdao.visualization.tables.table_builder.HTMLTableBuilder(rows, html_id=None, title='', center=False, style=None, safe=True, **kwargs)[source]
Class that generates a table in plain HTML format.
- Parameters:
- rowsiter of iters
Data used to fill table cells.
- html_idstr or None
If not None, the HTML id for the <table> block.
- titlestr or None
If not None, the title appearing above the table on the web page.
- centerbool
If True, center the table on the page.
- styledict or None
If not None, a dict mapping table style parameters to their values.
- safebool
If True (the default), html escape text in the cells.
- **kwargsdict
Keyword args for the base class.
- Attributes:
- _html_idstr or None
If not None, this is the html id of the table block.
- _titlestr or None
If not None, this is the title that will appear on the web page above the table.
- _safebool
If True (the default), html escape text in the cells.
- _data_styledict
Contains style metadata for <td> blocks.
- _header_styledict
Contains style metadata for <th> blocks.
- _styledict or None
Contains style metadata for the table.
The tabulator
table format generates interactive tables using the Tabulator.js
library. These
tables can have sortable and/or filterable columns. They are built by the TabulatorJSBuilder
class. It’s parameters are shown below.
- openmdao.visualization.tables.table_builder.TabulatorJSBuilder(rows, html_id='tabul-table', title='', filter=True, sort=True, center=False, table_meta=None, **kwargs)[source]
Class that generates an interactive table using Tabulator.js.
- Parameters:
- rowsiter of iters
Data used to fill table cells.
- html_idstr or None
If not None, the HTML id for the <table> block.
- titlestr or None
If not None, the title appearing above the table on the web page.
- filterbool
If True, include filter fields in the column headers where it makes sense.
- sortbool
If True, add sorting to column headers.
- centerbool
If True, center the table on the page.
- table_metadict or None
If not None, a dict of Tabulator.js metadata names mapped to their values.
- **kwargsdict
Keyword args for the base class.
- Attributes:
- _html_idstr or None
If not None, this is the html id of the table block.
- _titlestr or None
If not None, this is the title that will appear on the web page above the table.
- _filterbool
If True, include filter fields in the column headers where it makes sense.
- _sortbool
If True, add sorting to column headers.
- _centerbool
If True, center the table on the page.
- _table_metadict
Metadata for the table.
- font_sizeint
The font size used by the table.
Below are some examples of various table formats and how to create and modify them.
import openmdao.api as om
# Let's create some simple table data
rows = [
['Any bear can dance.', 3.1415926, 42, False],
['Every frog gets hungry.', -1.33e9, -2, True],
['Individual jesters keep logs.', 999.99, 1234, False],
['Many noodles on plates.', 4398.3219, 62835, False],
['Quaint rosy snakes travel under vases.', .0008654, -7842, False],
['When Xerxes yawps zestfully.', -1.831e-9, -200, True]
]
# Now some header strings
headers = ['Some Nonsense', 'Some floats', 'Ints', 'Some Bools']
First, make a simple text table and display it.
table = om.generate_table(rows, tablefmt='text', headers=headers)
table.display()
| ------------------------------------------------------------------------- |
| Some Nonsense | Some floats | Ints | Some Bools |
| -------------------------------------- | ----------- | ----- | ---------- |
| Any bear can dance. | 3.142 | 42 | False |
| Every frog gets hungry. | -1.33e+09 | -2 | True |
| Individual jesters keep logs. | 1e+03 | 1234 | False |
| Many noodles on plates. | 4.398e+03 | 62835 | False |
| Quaint rosy snakes travel under vases. | 0.0008654 | -7842 | False |
| When Xerxes yawps zestfully. | -1.831e-09 | -200 | True |
| ------------------------------------------------------------------------- |
If we want to limit the width of our table, we can set the max_width
argument when we create it.
table = om.generate_table(rows, tablefmt='text', headers=headers, max_width=70)
table.display()
| ------------------------------------------------------------------ |
| Some Nonsense | Some floats | Ints | Some Bools |
| ------------------------------- | ----------- | ----- | ---------- |
| Any bear can dance. | 3.142 | 42 | False |
| Every frog gets hungry. | -1.33e+09 | -2 | True |
| Individual jesters keep logs. | 1e+03 | 1234 | False |
| Many noodles on plates. | 4.398e+03 | 62835 | False |
| Quaint rosy snakes travel under | 0.0008654 | -7842 | False |
| vases. | | | |
| When Xerxes yawps zestfully. | -1.831e-09 | -200 | True |
| ------------------------------------------------------------------ |
Now let’s fix the header alignment of the first column. Note that column indices start at 0, so we specify 0 for the index of the first column.
table.update_column_meta(0, header_align='center')
table.display()
| ------------------------------------------------------------------ |
| Some Nonsense | Some floats | Ints | Some Bools |
| ------------------------------- | ----------- | ----- | ---------- |
| Any bear can dance. | 3.142 | 42 | False |
| Every frog gets hungry. | -1.33e+09 | -2 | True |
| Individual jesters keep logs. | 1e+03 | 1234 | False |
| Many noodles on plates. | 4.398e+03 | 62835 | False |
| Quaint rosy snakes travel under | 0.0008654 | -7842 | False |
| vases. | | | |
| When Xerxes yawps zestfully. | -1.831e-09 | -200 | True |
| ------------------------------------------------------------------ |
Now let’s try the other table formats. First, the text based formats.
formats = ['rst', 'grid', 'simple_grid', 'heavy_grid', 'double_grid', 'box_grid',
'outline', 'simple_outline', 'heavy_outline', 'double_outline', 'box_outline']
for fmt in formats:
print(f"\n{fmt} table format:\n")
table = om.generate_table(rows, tablefmt=fmt, headers=headers)
table.display()
rst table format:
====================================== =========== ===== ==========
Some Nonsense Some floats Ints Some Bools
====================================== =========== ===== ==========
Any bear can dance. 3.142 42 False
Every frog gets hungry. -1.33e+09 -2 True
Individual jesters keep logs. 1e+03 1234 False
Many noodles on plates. 4.398e+03 62835 False
Quaint rosy snakes travel under vases. 0.0008654 -7842 False
When Xerxes yawps zestfully. -1.831e-09 -200 True
====================================== =========== ===== ==========
grid table format:
+----------------------------------------+-------------+-------+------------+
| Some Nonsense | Some floats | Ints | Some Bools |
+========================================+=============+=======+============+
| Any bear can dance. | 3.142 | 42 | False |
+----------------------------------------+-------------+-------+------------+
| Every frog gets hungry. | -1.33e+09 | -2 | True |
+----------------------------------------+-------------+-------+------------+
| Individual jesters keep logs. | 1e+03 | 1234 | False |
+----------------------------------------+-------------+-------+------------+
| Many noodles on plates. | 4.398e+03 | 62835 | False |
+----------------------------------------+-------------+-------+------------+
| Quaint rosy snakes travel under vases. | 0.0008654 | -7842 | False |
+----------------------------------------+-------------+-------+------------+
| When Xerxes yawps zestfully. | -1.831e-09 | -200 | True |
+----------------------------------------+-------------+-------+------------+
simple_grid table format:
┌────────────────────────────────────────┬─────────────┬───────┬────────────┐
│ Some Nonsense │ Some floats │ Ints │ Some Bools │
├────────────────────────────────────────┼─────────────┼───────┼────────────┤
│ Any bear can dance. │ 3.142 │ 42 │ False │
├────────────────────────────────────────┼─────────────┼───────┼────────────┤
│ Every frog gets hungry. │ -1.33e+09 │ -2 │ True │
├────────────────────────────────────────┼─────────────┼───────┼────────────┤
│ Individual jesters keep logs. │ 1e+03 │ 1234 │ False │
├────────────────────────────────────────┼─────────────┼───────┼────────────┤
│ Many noodles on plates. │ 4.398e+03 │ 62835 │ False │
├────────────────────────────────────────┼─────────────┼───────┼────────────┤
│ Quaint rosy snakes travel under vases. │ 0.0008654 │ -7842 │ False │
├────────────────────────────────────────┼─────────────┼───────┼────────────┤
│ When Xerxes yawps zestfully. │ -1.831e-09 │ -200 │ True │
└────────────────────────────────────────┴─────────────┴───────┴────────────┘
heavy_grid table format:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┓
┃ Some Nonsense ┃ Some floats ┃ Ints ┃ Some Bools ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━┫
┃ Any bear can dance. ┃ 3.142 ┃ 42 ┃ False ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━┫
┃ Every frog gets hungry. ┃ -1.33e+09 ┃ -2 ┃ True ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━┫
┃ Individual jesters keep logs. ┃ 1e+03 ┃ 1234 ┃ False ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━┫
┃ Many noodles on plates. ┃ 4.398e+03 ┃ 62835 ┃ False ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━┫
┃ Quaint rosy snakes travel under vases. ┃ 0.0008654 ┃ -7842 ┃ False ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━┫
┃ When Xerxes yawps zestfully. ┃ -1.831e-09 ┃ -200 ┃ True ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━━┛
double_grid table format:
╔════════════════════════════════════════╦═════════════╦═══════╦════════════╗
║ Some Nonsense ║ Some floats ║ Ints ║ Some Bools ║
╠════════════════════════════════════════╬═════════════╬═══════╬════════════╣
║ Any bear can dance. ║ 3.142 ║ 42 ║ False ║
╠════════════════════════════════════════╬═════════════╬═══════╬════════════╣
║ Every frog gets hungry. ║ -1.33e+09 ║ -2 ║ True ║
╠════════════════════════════════════════╬═════════════╬═══════╬════════════╣
║ Individual jesters keep logs. ║ 1e+03 ║ 1234 ║ False ║
╠════════════════════════════════════════╬═════════════╬═══════╬════════════╣
║ Many noodles on plates. ║ 4.398e+03 ║ 62835 ║ False ║
╠════════════════════════════════════════╬═════════════╬═══════╬════════════╣
║ Quaint rosy snakes travel under vases. ║ 0.0008654 ║ -7842 ║ False ║
╠════════════════════════════════════════╬═════════════╬═══════╬════════════╣
║ When Xerxes yawps zestfully. ║ -1.831e-09 ║ -200 ║ True ║
╚════════════════════════════════════════╩═════════════╩═══════╩════════════╝
box_grid table format:
╔════════════════════════════════════════╤═════════════╤═══════╤════════════╗
║ Some Nonsense ┊ Some floats ┊ Ints ┊ Some Bools ║
╠════════════════════════════════════════╪═════════════╪═══════╪════════════╣
║ Any bear can dance. ┊ 3.142 ┊ 42 ┊ False ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈╢
║ Every frog gets hungry. ┊ -1.33e+09 ┊ -2 ┊ True ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈╢
║ Individual jesters keep logs. ┊ 1e+03 ┊ 1234 ┊ False ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈╢
║ Many noodles on plates. ┊ 4.398e+03 ┊ 62835 ┊ False ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈╢
║ Quaint rosy snakes travel under vases. ┊ 0.0008654 ┊ -7842 ┊ False ║
╟┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┿┈┈┈┈┈┈┈┈┈┈┈┈╢
║ When Xerxes yawps zestfully. ┊ -1.831e-09 ┊ -200 ┊ True ║
╚════════════════════════════════════════╧═════════════╧═══════╧════════════╝
outline table format:
+----------------------------------------+-------------+-------+------------+
| Some Nonsense | Some floats | Ints | Some Bools |
+========================================+=============+=======+============+
| Any bear can dance. | 3.142 | 42 | False |
| Every frog gets hungry. | -1.33e+09 | -2 | True |
| Individual jesters keep logs. | 1e+03 | 1234 | False |
| Many noodles on plates. | 4.398e+03 | 62835 | False |
| Quaint rosy snakes travel under vases. | 0.0008654 | -7842 | False |
| When Xerxes yawps zestfully. | -1.831e-09 | -200 | True |
+----------------------------------------+-------------+-------+------------+
simple_outline table format:
┌────────────────────────────────────────┬─────────────┬───────┬────────────┐
│ Some Nonsense │ Some floats │ Ints │ Some Bools │
├────────────────────────────────────────┼─────────────┼───────┼────────────┤
│ Any bear can dance. │ 3.142 │ 42 │ False │
│ Every frog gets hungry. │ -1.33e+09 │ -2 │ True │
│ Individual jesters keep logs. │ 1e+03 │ 1234 │ False │
│ Many noodles on plates. │ 4.398e+03 │ 62835 │ False │
│ Quaint rosy snakes travel under vases. │ 0.0008654 │ -7842 │ False │
│ When Xerxes yawps zestfully. │ -1.831e-09 │ -200 │ True │
└────────────────────────────────────────┴─────────────┴───────┴────────────┘
heavy_outline table format:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━┓
┃ Some Nonsense ┃ Some floats ┃ Ints ┃ Some Bools ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━╋━━━━━━━━━━━━┫
┃ Any bear can dance. ┃ 3.142 ┃ 42 ┃ False ┃
┃ Every frog gets hungry. ┃ -1.33e+09 ┃ -2 ┃ True ┃
┃ Individual jesters keep logs. ┃ 1e+03 ┃ 1234 ┃ False ┃
┃ Many noodles on plates. ┃ 4.398e+03 ┃ 62835 ┃ False ┃
┃ Quaint rosy snakes travel under vases. ┃ 0.0008654 ┃ -7842 ┃ False ┃
┃ When Xerxes yawps zestfully. ┃ -1.831e-09 ┃ -200 ┃ True ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━┻━━━━━━━━━━━━┛
double_outline table format:
╔════════════════════════════════════════╦═════════════╦═══════╦════════════╗
║ Some Nonsense ║ Some floats ║ Ints ║ Some Bools ║
╠════════════════════════════════════════╬═════════════╬═══════╬════════════╣
║ Any bear can dance. ║ 3.142 ║ 42 ║ False ║
║ Every frog gets hungry. ║ -1.33e+09 ║ -2 ║ True ║
║ Individual jesters keep logs. ║ 1e+03 ║ 1234 ║ False ║
║ Many noodles on plates. ║ 4.398e+03 ║ 62835 ║ False ║
║ Quaint rosy snakes travel under vases. ║ 0.0008654 ║ -7842 ║ False ║
║ When Xerxes yawps zestfully. ║ -1.831e-09 ║ -200 ║ True ║
╚════════════════════════════════════════╩═════════════╩═══════╩════════════╝
box_outline table format:
╔════════════════════════════════════════╤═════════════╤═══════╤════════════╗
║ Some Nonsense ┊ Some floats ┊ Ints ┊ Some Bools ║
╠════════════════════════════════════════╪═════════════╪═══════╪════════════╣
║ Any bear can dance. ┊ 3.142 ┊ 42 ┊ False ║
║ Every frog gets hungry. ┊ -1.33e+09 ┊ -2 ┊ True ║
║ Individual jesters keep logs. ┊ 1e+03 ┊ 1234 ┊ False ║
║ Many noodles on plates. ┊ 4.398e+03 ┊ 62835 ┊ False ║
║ Quaint rosy snakes travel under vases. ┊ 0.0008654 ┊ -7842 ┊ False ║
║ When Xerxes yawps zestfully. ┊ -1.831e-09 ┊ -200 ┊ True ║
╚════════════════════════════════════════╧═════════════╧═══════╧════════════╝
And now for the web based table formats.
table = om.generate_table(rows, tablefmt='html', headers=headers)
table.display()
'table.html'
table = om.generate_table(rows, tablefmt='tabulator', headers=headers)
table.display()
'tabulator_table.html'
Note that the tabulator table above has sortable columns and that the first and last columns are filterable. Numerical columns are not filterable.