The Nightly Build.
Expert Tools

VisiData turns each new question about a table into a keystroke on the current column

The sheet is already loaded and every transform lands on the column under the cursor, so asking a new question costs a keystroke instead of a rewrite.

In pandas, the next question is another cell

You have a CSV of sales rows and a question: what is revenue by region. In a notebook the shape of the work is fixed before you know the answer. You write a cell that reads the file, computes a column, groups, and sums; you run it; you read the result. If the grouping was wrong, or you now want product broken out too, you edit the cell and run it again. Each new question about the same data is another round of write, run, reread. The data sits in memory the whole time. What you keep paying is the round trip from question to typed code to result. VisiData (vd), Saul Pwanson's interactive multitool for tabular data, attacks that round trip rather than the compute, and its current release is v3.4, from 30 June 2026.1

Three keystrokes answer revenue by region

Open the file and the sheet is already there to work on: vd sales.csv draws the rows and hands you a cursor. The first question, revenue per row, is a column that does not exist yet. Press = and VisiData prompts for a Python expression; type total = Units * Unit_Cost and a new total column appears, with the existing column names available as variables.23 In pandas this is df['total'] = df.Units * df.Unit_Cost; here it is one key and the same expression, evaluated against every row.

Summing that column by region takes two more keys, each landing on the column the cursor is on. On total, press + and choose sum from the list of aggregators, which attaches a running sum to the column.45 Move the cursor to Region and press F. VisiData pushes a frequency table grouped on the current column and carrying the aggregations of the other columns, so each region gets a row with its count and the summed total beside it.6

a VisiData session, sales.csvVISIDATA
$ vd sales.csv

 Date       | Region | Product | Units | Unit_Cost
 2026-07-01 | West   | Widget  |     3 |      4.00
 2026-07-01 | East   | Gadget  |     1 |      9.00
 2026-07-02 | West   | Gadget  |     2 |      9.00
 2026-07-02 | East   | Widget  |     5 |      4.00
 2026-07-03 | West   | Widget  |     4 |      4.00
 2026-07-03 | East   | Gadget  |     2 |      9.00

=   new column expression:   total = Units * Unit_Cost

 Region | Product | Units | Unit_Cost | total
 West   | Widget  |     3 |      4.00 |    12
 East   | Gadget  |     1 |      9.00 |     9
 West   | Gadget  |     2 |      9.00 |    18
 East   | Widget  |     5 |      4.00 |    20
 West   | Widget  |     4 |      4.00 |    16
 East   | Gadget  |     2 |      9.00 |    18

+   (on total)   choose aggregator:   sum
F   (on Region)  Frequency Table

 Region | count | total_sum
 West   |     3 |        46
 East   |     3 |        47
Fig. 1 · = computes total = Units * Unit_Cost, + sets a sum on that column, and F on Region groups the rows and carries the sum. Keybindings confirmed in source.53

That is the whole loop: no dataframe named twice, no cell rerun, three keys after the file opened. The keys are not memorized up front. Each acts on wherever the cursor sits, and the full command list is one keypress away at Ctrl+H.7

W pivots the same sheet, and M puts it back

A grid of region against product is a different question, and in a notebook it is a different call, df.pivot_table(...). In VisiData it is the pivot key. A pivot groups by whatever columns you have marked as keys, and marking a column as a key is one more keystroke. With Region marked as the key and the cursor on Product, press W and VisiData opens a pivot table that groups rows by the key column and summarizes the current column: one column per product value, the summed total in each cell.8

The inverse question, a wide table folded back to one row per observation, is the melt key. Press M and VisiData opens a melted sheet: the key columns stay, and every non-key column collapses into Variable and Value rows, the tall shape a database load or a plotting call wants.9 The pivot and its inverse, the two reshapes a pandas session spells out as pivot_table and melt, are one keystroke each on the sheet already in front of you.

the same sheet, reshapedVISIDATA
W   (Region key, cursor on Product)   Pivot Table

 Region | Widget | Gadget
 West   |     28 |     18
 East   |     20 |     27

M   (on the pivot)   Melted Sheet

 Region | Variable | Value
 West   | Widget   |    28
 West   | Gadget   |    18
 East   | Widget   |    20
 East   | Gadget   |    27
Fig. 2 · W spreads Product across the top and fills each cell with the summed total; M folds the same sheet back to one row per region-product pair.89
Four questions about one CSV: the pandas idiom, and the VisiData keystrokes that stand in for it.5
Question In pandas In VisiData
revenue per row df['total'] = df.Units * df.Unit_Cost =  total = Units * Unit_Cost
revenue by region df.groupby('Region').total.sum() + sum, then F on Region
region against product df.pivot_table(index='Region', columns='Product', values='total', aggfunc='sum') W on Product
wide back to tall df.melt(id_vars='Region') M

You can move through the file before it loads, but not total it

The sheet you are working is often not fully loaded. VisiData's base sheet loads asynchronously by default. Its reload is decorated @asyncthread and runs in a separate thread, and a loader is a generator that yields rows one at a time. Rows become available as they are parsed, not after a full read.101112 Pwanson's own account of the design: a sheet stays dormant until it is about to be drawn, then loads in a background thread while the interface stays responsive. Open 100 GB of CSVs with vd *.csv and only the top sheet loads, the rest on demand.13 On a large file you can scroll, jump, and open a column the instant the first rows arrive.

What you cannot do mid-load is trust a whole-column result.

The loader's fine print

Navigation and viewing are correct the moment rows appear, but a frequency count, a sort, or an aggregate sum reflects only the rows loaded so far; those results are final only once loading finishes.10

The loader is also not unbounded. A precious sheet stops at options.max_rows, which defaults to 1,000,000,000 rows, so past a billion rows the sheet is truncated, not merely slow.11

What the keystrokes cost, and where a notebook still wins

The cost is the keys themselves. VisiData is modal and vim-flavored: early on you look most commands up, and users report the tool pays back only after that stretch, once the frequent keys are in the hands.14 The five keys here (=, +, F, W, M), plus grouped variants like gF and gM, are a fraction of the set, and each is a character to learn rather than a phrase to read.

The boundary is not the learning. A notebook or a database still wins wherever the work outlives the exploration. A reproducible, version-controlled, multi-step pipeline belongs in code a colleague can rerun. Custom plotting belongs in a plotting library. A join or aggregation over data too large for one machine belongs in SQL.15 VisiData's command log replays a session and can be saved and rerun, which narrows the reproducibility gap without closing it. The changelog records that the log now stores long command names rather than raw keystrokes. That helps, but it is still a session record, not a program.16 VisiData is for the exploratory pass, the part of the work where you do not yet know which questions are worth writing down.

The loop is won by one person's GPL-3.0 project

The trade is clear once the keys are learned: the exploratory loop a notebook spends in write, run, and reread, VisiData spends in move the cursor and press a key, and on that pass it wins. The same design that makes it coherent is also its risk. VisiData is conceived and developed by Saul Pwanson, with Anja Kefala maintaining the documentation and packages; it is effectively a single-primary-author project, licensed GPL-3.0, with about 9,200 GitHub stars.17 Its releases are regular: v3.4 shipped in June 2026, roughly one minor release every two to three quarters across the 3.x line since late 2023, so the project is active rather than stalled.161 The judgment for a practitioner is not whether VisiData is maintained but whether a tool that lives on one person's attention is one to route a daily workflow through. For the pass before the pipeline, where the alternative is a stack of throwaway cells, the keystrokes earn it.

Sources

  1. visidata.org · VisiData home (version and description)
  2. VisiData docs · Columns (derivative columns)
  3. saulpw/visidata · visidata/expr.py
  4. saulpw/visidata · visidata/aggregators.py
  5. VisiData docs · Grouping data and descriptive statistics
  6. saulpw/visidata · visidata/freqtbl.py
  7. VisiData docs · documentation index
  8. saulpw/visidata · visidata/pivot.py
  9. saulpw/visidata · visidata/features/melt.py
  10. VisiData docs · Loaders (asynchronous by default)
  11. saulpw/visidata · visidata/sheets.py
  12. saulpw/visidata · visidata/loaders/csv.py
  13. visidata.org · "Unloaded Sheets" (Saul Pwanson, 2020)
  14. Hacker News · discussion, item 36502435
  15. Hacker News · discussion, item 28826348
  16. saulpw/visidata · CHANGELOG.md
  17. saulpw/visidata · GitHub repository