Turn a DataFrame, query result, or data file into an interactive HTML table — sort it, filter it, label it row by row, and export just the rows you labeled. One command, no server, no build step.
Printing a DataFrame to a terminal gives you a wall of truncated text. Opening it in a spreadsheet means an export, an app switch, and a file you'll forget to delete. Neither lets you do the thing you usually actually want: go through the rows and mark them up.
datatable renders your data as a real interactive table in the browser, and adds a per-row Notes column so you can triage as you read — then export only the rows you annotated. It turns "let me look at this data" into a labeling pass that produces something you can use.
Anyone who explores tabular data with an AI agent or a Python REPL: data scientists checking a query result, engineers triaging a bug or log dump, analysts doing a first pass over a CSV, or anyone hand-labeling rows to build a small training or evaluation set.
- Sort, search, paginate — click a header to sort; numeric columns sort numerically, not lexicographically
- Per-column filters — a filter box under each column title; they combine with AND
- Per-row Notes column — hidden until you tick "Show Notes", saved to
localStorage, survives a refresh - Two exports — "Download CSV" respects your current filter; "Download Labeled Only" appears once you've annotated anything and exports exactly those rows
- Hide columns / filter by value — right-click a header or a cell
- Layout that persists — column order, widths, sort, and filters survive a reload; "Reset View" clears them
- Row grouping —
--groupby teamgroups rows under headers and sorts to match
Requires Python 3.9+ and pandas. Excel input also needs openpyxl; Parquet needs pyarrow.
Drop this folder into your agent's skills directory — ~/.claude/skills/, ~/.agents/skills/, ~/.codex/skills/, or wherever your agent reads skills from. SKILL.md is plain Markdown; any agent that reads skills can use it. Then just ask:
datatable this show me that CSV as a table render the query result so I can label the bad rows
/plugin marketplace add spunt/datatable-skill
/plugin install datatable@datatable
It's a standalone script:
python3 scripts/df2datatable.py data.csv -t "My Data"
python3 scripts/df2datatable.py report.xlsx -t "Q4 Report" --page-length 25
python3 scripts/df2datatable.py results.parquet --groupby region -o /tmp/Or from Python:
import sys; sys.path.insert(0, "scripts")
from df2datatable import df2datatable
df2datatable(df, outname="/tmp/my_table", title="My Data", groupby="region")Try it on the included examples:
python3 scripts/df2datatable.py examples/bug_triage.csv -t "Bug Triage"
# awkward data on purpose: unicode names, regex metacharacters in cells,
# missing values, a wide numeric range, and long wrapping text
python3 scripts/df2datatable.py examples/edge_cases.csv -t "Edge Cases"The script reads your file (CSV, TSV, Excel, JSON, Parquet) or takes a DataFrame directly, renders it with DataFrame.to_html(), and wraps it in a page wired up to DataTables with the annotation column, per-column filters, right-click menus, and export buttons attached. The output is one HTML file that opens in your browser.
Notes live in localStorage, keyed by the table's title — so give related tables a stable, distinct title and your labels come back every time you reopen them. Nothing is uploaded anywhere; the page never phones home with your data.
Stated plainly, because they matter for some uses:
- The page needs network access. jQuery and DataTables load from a CDN, so the file is portable but not offline-capable. Without a connection you get a plain unstyled HTML table.
- It's a browser, so size matters. Comfortable to ~10k rows (1.6 MB, ~250 ms to open). By ~50k it takes tens of seconds. Aggregate or subset above that.
- Notes are local to one browser.
localStoragedoesn't sync between machines or people. Export the labeled rows to share them. - Auto-open is macOS-only (it shells out to
open). Elsewhere the file is still written — just open the printed path, or pass--no-open.
$ python3 -m pytest tests/ -q
34 passed
The suite covers every input format, output-path handling, HTML/JS escaping, and the DataTables options emitted into the page — including regression tests for three bugs found by using it: a title containing < or </script> breaking the page, -o <directory> silently writing a hidden .html dotfile, and right-clicking "Filter By Value" on a cell like Q3 (partial throwing an uncaught regex error. Interactive behaviour (grouping, annotation round-trip, smart vs regex search) is verified against a real browser.
MIT © Bob Spunt. See LICENSE.
