Getting Started

Tables

Painless creation of nice-looking tables of data for Python.

Starting simple

>>> from ansitable import ANSITable
>>> 
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", 5.5, 6)
>>> table.row("ccccccc", 8.8, 9)
>>> table.print()
          col1   column 2 has a big header   column 3  
     aaaaaaaaa                         2.2          3  
 bbbbbbbbbbbbb                         5.5          6  
       ccccccc                         8.8          9

This produces a table with column widths automatically chosen, headings and column data all right-justified (default).

By default output is printed to the console (stdout), but you can:

  • Provide a file option to .print() to write to a specified output stream

  • Obtain a multi-line string version with str(table)

Borders

You can add borders made up of regular ASCII characters:

>>> from ansitable import ANSITable, Column
>>> table = ANSITable(
... Column("col1"),
... Column("column 2 has a big header"),
... Column("column 3"),
... border="ascii"
... )
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", 5.5, 6)
>>> table.row("ccccccc", 8.8, 9)
>>> table.print()
+---------------+---------------------------+----------+
|          col1 | column 2 has a big header | column 3 |
+---------------+---------------------------+----------+
|     aaaaaaaaa |                       2.2 |        3 |
| bbbbbbbbbbbbb |                       5.5 |        6 |
|       ccccccc |                       8.8 |        9 |
+---------------+---------------------------+----------+

Or use ANSI box-drawing characters (supported by most terminal emulators):

>>> from ansitable import ANSITable, Column
>>> table = ANSITable(
... Column("col1"),
... Column("column 2 has a big header"),
... Column("column 3"),
... border="thick"
... )
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", 5.5, 6)
>>> table.row("ccccccc", 8.8, 9)
>>> table.print()
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃          col1 ┃ column 2 has a big header ┃ column 3 ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━┫
┃     aaaaaaaaa ┃                       2.2 ┃        3 ┃
┃ bbbbbbbbbbbbb ┃                       5.5 ┃        6 ┃
┃       ccccccc ┃                       8.8 ┃        9 ┃
┗━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━┛

Other border options: "thin", "round" (thin with rounded corners), and "double".

Formatting and alignment

Specify Python format strings for columns:

>>> from ansitable import ANSITable, Column
>>> table = ANSITable(
... Column("col1"),
... Column("column 2 has a big header", "{:.3g}"),
... Column("column 3", "{:-10.4f}")
... )
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", 5.5, 6)
>>> table.row("ccccccc", 8.8, 9)
>>> table.print()
          col1   column 2 has a big header     column 3  
     aaaaaaaaa                         2.2       3.0000  
 bbbbbbbbbbbbb                         5.5       6.0000  
       ccccccc                         8.8       9.0000

Control alignment with colalign (data) and headalign (heading): - "<" — left - ">" — right (default) - "^" — center

>>> from ansitable import ANSITable, Column
>>> table = ANSITable(
... Column("col1", headalign="<"),
... Column("column 2 has a big header", colalign="^"),
... Column("column 3", colalign="<"),
... border="thick"
... )
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, 9)
>>> table.print()
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ col1          ┃ column 2 has a big header ┃ column 3 ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━┫
┃     aaaaaaaaa ┃            2.2            ┃ 3        ┃
┃ bbbbbbbbbbbbb ┃           -5.5            ┃ 6        ┃
┃       ccccccc ┃            8.8            ┃ 9        ┃
┗━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━┛

Add dividing lines with .rule():

>>> from ansitable import ANSITable, Column
>>> table = ANSITable(
... Column("col1", headalign="<"),
... Column("column 2 has a big header", colalign="^"),
... Column("column 3", colalign="<"),
... border="thick"
... )
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.rule()
>>> table.row("ccccccc", 8.8, -9)
>>> table.print()
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ col1          ┃ column 2 has a big header ┃ column 3 ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━┫
┃     aaaaaaaaa ┃            2.2            ┃ 3        ┃
┃ bbbbbbbbbbbbb ┃           -5.5            ┃ 6        ┃
┣━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━┫
┃       ccccccc ┃            8.8            ┃ -9       ┃
┗━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━┛

Width constraints

Limit column width with the width argument:

>>> from ansitable import ANSITable, Column
>>> table = ANSITable(
... Column("col1", width=10),
... Column("column 2 has a big header", "{:.3g}"),
... Column("column 3", "{:-10.4f}")
... )
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", 5.5, 6)
>>> table.row("ccccccc", 8.8, 9)
>>> table.print()
       col1   column 2 has a big header     column 3  
  aaaaaaaaa                         2.2       3.0000  
 bbbbbbbbb…                         5.5       6.0000  
    ccccccc                         8.8       9.0000

Excess text is truncated with an ellipsis (U+2026). Disable with ellipsis=False.

Color and styling

If you have the colored package installed, you can set foreground/background colors and text styles (bold, reverse, underlined, dim):

from ansitable import ANSITable, Column, Cell
table = ANSITable(
    Column("col1", headalign="<", colcolor="red", headstyle="underlined"),
    Column("column 2 has a big header", colalign="^", colstyle="bold"),
    Column("column 3", colalign="<", colbgcolor="green"),
    border="thick", bordercolor="blue"
)
table.row("aaaaaaaaa", 2.2, 3)
table.row("bbbbbbbbbbbbb", -5.5, 6)
table.row("ccccccc", 8.8, -9)
print(table)

Rendered output with colors:

col1 column 2 has a big header column 3
aaaaaaaaa 2.2 3
bbbbbbbbbbbbb -5.5 6
ccccccc 8.8 -9

Override styles per-row or per-cell:

from ansitable import ANSITable, Column, Cell
table = ANSITable(
    Column("col1", headalign="<"),
    Column("column 2 has a big header", colalign="^"),
    Column("column 3", colalign="<"),
    border="thick"
)
table.row("aaaaaaaaa", 2.2, 3)
table.row("bbbbbbbbbbbbb", Cell(-5.5, bgcolor="blue"), 6, bgcolor="yellow")
table.row("ccccccc", 8.8, 9)
print(table)

Rendered output with per-cell colors:

col1 column 2 has a big header column 3
aaaaaaaaa 2.2 3
bbbbbbbbbbbbb -5.5 6
ccccccc 8.8 9

Sorting

Sort table rows by a column:

>>> from ansitable import ANSITable
>>> table = ANSITable("name", "score")
>>> table.row("alice", 3)
>>> table.row("bob", 1)
>>> table.row("carol", 2)
>>> table.sort("score", key=int)
ANSITable: 3 x 2:  name; score
>>> table.print()
  name   score  
   bob       1  
 carol       2  
 alice       3

The .sort() method supports:

  • column — column name (str) or index (int)

  • key — optional function to transform values before comparison

  • reverse — sort in descending order (default: False)

Horizontal rules (added with .rule()) are silently dropped from sorted output.

Export formats

Export tables to markup languages for use in documents:

Markdown:

>>> from ansitable import ANSITable
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, -9)
>>> print(table.markdown())
|           col1  |  column 2 has a big header  |  column 3  |
| ------------: | ------------------------: | -------: |
|      aaaaaaaaa  |                        2.2  |         3  |
|  bbbbbbbbbbbbb  |                       -5.5  |         6  |
|        ccccccc  |                        8.8  |        -9  |

HTML:

Supports CSS styling of cells and colors.

>>> from ansitable import ANSITable
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, -9)
>>> print(table.html()[:200] + "...")
<table>
  <tr style=''>
    <th style='text-align:right;'>col1</th>
    <th style='text-align:right;'>column 2 has a big header</th>
    <th style='text-align:right;'>column 3</th>
  </tr>
  <tr style...

reStructuredText (ReST) “simple table”:

>>> from ansitable import ANSITable
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, -9)
>>> print(table.rest())
=============  =========================  ========  
         col1  column 2 has a big header  column 3  
=============  =========================  ========  
    aaaaaaaaa                        2.2         3  
bbbbbbbbbbbbb                       -5.5         6  
      ccccccc                        8.8        -9  
=============  =========================  ========

LaTeX:

Alignment options supported.

>>> from ansitable import ANSITable
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, -9)
>>> print(table.latex()[:150] + "...")
\begin{tabular}{ |r|r|r| }\hline
\multicolumn{1}{|r|}{col1} & \multicolumn{1}{|r|}{column 2 has a big header} & \multicolumn{1}{|r|}{column 3}\\\hline...

Wikitable (Wikipedia):

>>> from ansitable import ANSITable
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, -9)
>>> print(table.wikitable())
{| class="wikitable" col1right col2right col3right
|-
!           col1  !!  column 2 has a big header  !!  column 3  
|-
|      aaaaaaaaa  ||                        2.2  ||         3  
|-
|  bbbbbbbbbbbbb  ||                       -5.5  ||         6  
|-
|        ccccccc  ||                        8.8  ||        -9  
|}

CSV:

>>> from ansitable import ANSITable
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, -9)
>>> print(table.csv())
col1,column 2 has a big header,column 3
aaaaaaaaa,2.2,3
bbbbbbbbbbbbb,-5.5,6
ccccccc,8.8,-9

Matrices

Display NumPy arrays as formatted matrices:

>>> from ansitable import ANSIMatrix
>>> import numpy as np
>>> 
>>> np.random.seed(42)
>>> formatter = ANSIMatrix(style='thick')
>>> m = np.random.rand(4, 4) - 0.5
>>> formatter.print(m)
┏                                           ┓
┃-0.125      0.451      0.232      0.0987   ┃
┃-0.344     -0.344     -0.442      0.366    ┃
┃ 0.101      0.208     -0.479      0.47     ┃
┃ 0.332     -0.288     -0.318     -0.317    ┃
┗                                           ┛

Add superscript and subscript suffixes:

>>> from ansitable import ANSIMatrix
>>> import numpy as np
>>> 
>>> np.random.seed(42)
>>> formatter = ANSIMatrix(style='thick')
>>> m = np.random.rand(4, 4) - 0.5
>>> formatter.print(m, suffix_super='T', suffix_sub='3')
┏                                           ┓T
┃-0.125      0.451      0.232      0.0987   ┃
┃-0.344     -0.344     -0.442      0.366    ┃
┃ 0.101      0.208     -0.479      0.47     ┃
┃ 0.332     -0.288     -0.318     -0.317    ┃
┗                                           ┛3

Pandas integration

Convert Pandas DataFrames to ANSITable:

>>> import pandas as pd
>>> from ansitable import ANSITable
>>> 
>>> df = pd.DataFrame({"calories": [420, 380, 390], "duration": [50, 40, 45]})
>>> table = ANSITable.Pandas(df, border="thin")
>>> table.print()
┌──────────┬──────────┐
│ calories │ duration │
├──────────┼──────────┤
│      420 │       50 │
│      380 │       40 │
│      390 │       45 │
└──────────┴──────────┘

Convert ANSITable back to DataFrame:

>>> from ansitable import ANSITable
>>> import pandas as pd
>>> 
>>> table = ANSITable("col1", "column 2 has a big header", "column 3")
>>> table.row("aaaaaaaaa", 2.2, 3)
>>> table.row("bbbbbbbbbbbbb", -5.5, 6)
>>> table.row("ccccccc", 8.8, -9)
>>> 
>>> df = table.pandas()
>>> print(df)
            col1 column_2_has_a_big_header column_3
0      aaaaaaaaa                       2.2        3
1  bbbbbbbbbbbbb                      -5.5        6
2        ccccccc                       8.8       -9

Column names are converted to valid Python identifiers (spaces → underscores), allowing attribute access like df.column_2_has_a_big_header. Disable this with underscores=False.