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
fileoption to.print()to write to a specified output streamObtain 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 comparisonreverse— 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.