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 table

  • rst, a table in restructured text format

  • github, a table in github’s markdown format

  • grid, is like the grid format in the Tabulate package, which mimics Emacs’ table.el package

  • simple_grid draws a grid using single-line box drawing characters

  • heavy_grid draws a grid using thick single-line box drawing characters

  • double_grid draws a grid using double-line box drawing characters

  • box_grid mixes double-line and single-line dashed drawing characters

  • html, a basic html table, viewable in a browser

  • tabulator, 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:

  1. a 2D numpy array

  2. an iterator of lists

  3. a dictionary where each key specifies a column header and each value contains that column’s values.

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