TikzTable: basics

TikzTable shares its entire builder API with TexTable: every call on that page (index columns, rules, header groups, highlights, formatters) works here, unchanged, because both classes are emitters over one shared implementation. What changes is the TeX dialect: TikzTable renders through nicematrix, which lays the table out on a TikZ cell-position lattice.

That lattice is the reason to choose it: per-cell borders, free-form \draw commands, and cell-geometry control that a plain tabular cannot express (see TikzTable styling). The cost is a heavier preamble (nicematrix and tikz) and two compiler passes, because nicematrix records cell positions on the first pass and draws on the second. preview(), save_pdf(), and save_png() handle the double pass; if the table does not need those drawing features, prefer TexTable.

import numpy as np
import pandas as pd

districts = pd.DataFrame(
    {
        "District": [f"CD {i}" for i in range(1, 9)],
        "BVAP share": [0.12, 0.18, 0.22, 0.31, 0.38, 0.44, 0.52, 0.58],
        "Dem share": [0.35, 0.41, 0.44, 0.47, 0.50, 0.55, 0.61, 0.66],
        "Polsby-Popper": [0.18, 0.22, 0.27, 0.31, 0.33, 0.35, 0.41, 0.44],
        "Pop. deviation": [0.004, 0.002, np.nan, 0.006, 0.001, 0.008, 0.003, 0.005],
    }
)
districts
District BVAP share Dem share Polsby-Popper Pop. deviation
0 CD 1 0.12 0.35 0.18 0.004
1 CD 2 0.18 0.41 0.22 0.002
2 CD 3 0.22 0.44 0.27 NaN
3 CD 4 0.31 0.47 0.31 0.006
4 CD 5 0.38 0.50 0.33 0.001
5 CD 6 0.44 0.55 0.35 0.008
6 CD 7 0.52 0.61 0.41 0.003
7 CD 8 0.58 0.66 0.44 0.005

The default table

from gerrytools.latex import TikzTable

table = TikzTable(districts)
table.set_decimal_count(3)
print(table)
\documentclass[border=2pt]{standalone}
\usepackage{tikz, nicematrix}
\usetikzlibrary{calc}
\begin{document}
\begin{NiceTabular}{ccccc}[name=table, cell-space-limits=1pt]
\textbf{District} & \textbf{BVAP share} & \textbf{Dem share} & \textbf{Polsby-Popper} & \textbf{Pop. deviation}{\rule[-\dimexpr1\doublerulesep+\arrayrulewidth\relax]{0pt}{0pt}} \\
\hline
CD 1 & 0.120 & 0.350 & 0.180 & 0.004 \\
CD 2 & 0.180 & 0.410 & 0.220 & 0.002 \\
CD 3 & 0.220 & 0.440 & 0.270 & NaN \\
CD 4 & 0.310 & 0.470 & 0.310 & 0.006 \\
CD 5 & 0.380 & 0.500 & 0.330 & 0.001 \\
CD 6 & 0.440 & 0.550 & 0.350 & 0.008 \\
CD 7 & 0.520 & 0.610 & 0.410 & 0.003 \\
CD 8 & 0.580 & 0.660 & 0.440 & 0.005 \\
\CodeAfter
\begin{tikzpicture}
  \draw[line width=\arrayrulewidth] ([yshift=1\doublerulesep]row-2-|col-1) -- ([yshift=1\doublerulesep]row-2-|col-6);
\end{tikzpicture}
\end{NiceTabular}
\end{document}

Default TikzTable

The printed source is again a complete standalone document; note the nicematrix preamble and the NiceTabular environment. print_table() prints the environment alone.

Index columns and header groups

table = TikzTable(districts)
table.set_decimal_count(2)
table.include_index(name="Row")
table.set_header_groups(
    {
        "Identity": ["District"],
        "Demographics and votes": ["BVAP share", "Dem share"],
        "Diagnostics": ["Polsby-Popper", "Pop. deviation"],
    }
)
print(table)
\documentclass[border=2pt]{standalone}
\usepackage{tikz, nicematrix}
\usetikzlibrary{calc}
\begin{document}
\begin{NiceTabular}{cccccc}[name=table, cell-space-limits=1pt]
\multicolumn{1}{c}{} & \multicolumn{1}{c}{\textbf{Identity}} & \multicolumn{2}{c}{\textbf{Demographics and votes}} & \multicolumn{2}{c}{\textbf{Diagnostics}} \\
\textbf{Row} & \textbf{District} & \textbf{BVAP share} & \textbf{Dem share} & \textbf{Polsby-Popper} & \textbf{Pop. deviation}{\rule[-\dimexpr1\doublerulesep+\arrayrulewidth\relax]{0pt}{0pt}} \\
\hline
0 & CD 1 & 0.12 & 0.35 & 0.18 & 0.00 \\
1 & CD 2 & 0.18 & 0.41 & 0.22 & 0.00 \\
2 & CD 3 & 0.22 & 0.44 & 0.27 & NaN \\
3 & CD 4 & 0.31 & 0.47 & 0.31 & 0.01 \\
4 & CD 5 & 0.38 & 0.50 & 0.33 & 0.00 \\
5 & CD 6 & 0.44 & 0.55 & 0.35 & 0.01 \\
6 & CD 7 & 0.52 & 0.61 & 0.41 & 0.00 \\
7 & CD 8 & 0.58 & 0.66 & 0.44 & 0.01 \\
\CodeAfter
\begin{tikzpicture}
  \draw[line width=\arrayrulewidth] ([yshift=1\doublerulesep]row-3-|col-1) -- ([yshift=1\doublerulesep]row-3-|col-7);
\end{tikzpicture}
\end{NiceTabular}
\end{document}

TikzTable with index and grouped headers

Row highlights

table = TikzTable(districts)
table.set_decimal_count(2)
table.highlight_rows([1], color="cherryblossompink")
table.highlight_rows([4], color="lightblue!35!white")
table.highlight_rows([7], color="amber!40!white")
print(table)
\documentclass[border=2pt]{standalone}
\usepackage{latexcolors, colortbl, tikz, nicematrix}
\usetikzlibrary{calc}
\begin{document}
\begin{NiceTabular}{ccccc}[name=table, cell-space-limits=1pt]
\CodeBefore
  \rowcolor{cherryblossompink}{3}
  \rowcolor{lightblue!35!white}{6}
  \rowcolor{amber!40!white}{9}
\Body
\textbf{District} & \textbf{BVAP share} & \textbf{Dem share} & \textbf{Polsby-Popper} & \textbf{Pop. deviation}{\rule[-\dimexpr1\doublerulesep+\arrayrulewidth\relax]{0pt}{0pt}} \\
\hline
CD 1 & 0.12 & 0.35 & 0.18 & 0.00 \\
CD 2 & 0.18 & 0.41 & 0.22 & 0.00 \\
CD 3 & 0.22 & 0.44 & 0.27 & NaN \\
CD 4 & 0.31 & 0.47 & 0.31 & 0.01 \\
CD 5 & 0.38 & 0.50 & 0.33 & 0.00 \\
CD 6 & 0.44 & 0.55 & 0.35 & 0.01 \\
CD 7 & 0.52 & 0.61 & 0.41 & 0.00 \\
CD 8 & 0.58 & 0.66 & 0.44 & 0.01 \\
\CodeAfter
\begin{tikzpicture}
  \draw[line width=\arrayrulewidth] ([yshift=1\doublerulesep]row-2-|col-1) -- ([yshift=1\doublerulesep]row-2-|col-6);
\end{tikzpicture}
\end{NiceTabular}
\end{document}

Highlighted rows in a TikzTable

Rules

The rule controls match TexTable, plus add_toprule() / add_bottomrule() for booktabs-style framing.

table = TikzTable(districts)
table.set_decimal_count(2)
table.add_vrule_right_of(0)
table.add_hrule_above([4])
table.add_toprule()
table.add_bottomrule()
print(table)
\documentclass[border=2pt]{standalone}
\usepackage{tikz, nicematrix}
\usetikzlibrary{calc}
\begin{document}
\begin{NiceTabular}{c|cccc}[name=table, cell-space-limits=1pt]
\hline
\textbf{District} & \textbf{BVAP share} & \textbf{Dem share} & \textbf{Polsby-Popper} & \textbf{Pop. deviation}{\rule[-\dimexpr1\doublerulesep+\arrayrulewidth\relax]{0pt}{0pt}} \\
\hline
CD 1 & 0.12 & 0.35 & 0.18 & 0.00 \\
CD 2 & 0.18 & 0.41 & 0.22 & 0.00 \\
CD 3 & 0.22 & 0.44 & 0.27 & NaN \\
CD 4 & 0.31 & 0.47 & 0.31 & 0.01 \\
\hline
CD 5 & 0.38 & 0.50 & 0.33 & 0.00 \\
CD 6 & 0.44 & 0.55 & 0.35 & 0.01 \\
CD 7 & 0.52 & 0.61 & 0.41 & 0.00 \\
CD 8 & 0.58 & 0.66 & 0.44 & 0.01 \\
\hline
\CodeAfter
\begin{tikzpicture}
  \draw[line width=\arrayrulewidth] ([yshift=1\doublerulesep]row-2-|col-1) -- ([yshift=1\doublerulesep]row-2-|col-6);
\end{tikzpicture}
\end{NiceTabular}
\end{document}

TikzTable with top and bottom rules