Sorting, Filtering, Searching and Statistics

← Contents

This page describes how TableSkim compares values. The rules are the same in the GUI and the terminal UI, and for every file format.

Values and types

Each cell holds one of: empty (NULL), text, an integer, a decimal number, a boolean (TRUE / FALSE), a date or a date-time. Excel, Parquet, JSON and database files store these types. In CSV / TSV files every cell is text, but TableSkim still recognizes:

Sorting

For CSV / TSV and Excel files, sorting reads the whole sheet into memory first. For Parquet, JSON and databases, the sort runs inside the database, so it works for tables of any size.

Filtering

A filter is a list of conditions, combined with All (AND: every condition must match) or Any (OR: at least one must match). Each condition tests one column.

Operators

OperatorMatches cells that...
containscontain the text, ignoring upper and lower case
not containsdo not contain the text, ignoring case
=are equal to the value (see below)
≠are not equal to the value
< ≤ > ≥are less than / at most / greater than / at least the value
is emptyare empty (NULL or empty text)
is not emptyare not empty
matchescontain a match of the regular expression, ignoring case
not matchescontain no match of the regular expression
is a numberare numbers or numeric text (not booleans, dates, NaN or infinity)
is a dateare dates, date-times or ISO date text that is not a number

How =, ≠, <, ≤, > and ≥ compare

The comparison depends on the cell and on the value you type:

Regular expressions

matches and not matches use RE2 syntax, ignoring upper and lower case. The pattern may match anywhere in the cell; anchor it with ^ and $ to match the whole cell, for example ^(Tokyo|Osaka)$. An invalid pattern is reported and the filter is not applied.

Examples

GoalCondition(s)
People in Tokyo aged 45 or olderCity = Tokyo and Age ≥ 45 (Match: All)
Rows from January 2024Date ≥ 2024-01-01 and Date < 2024-02-01
Rows on a given day, whatever the timeTimestamp = 2024-01-31
E-mail addresses at example.com or .orgEmail matches @example\.(com|org)$
Rows with a missing valueSalary is empty
Tokyo or OsakaCity = Tokyo, City = Osaka (Match: Any)

Quick filters

The quick filters (Filter: = "value" in the GUI cell menu, = / ! in the TUI) add an = / ≠ condition with the value of the cell as it is shown, which is then compared by type as described above. On an empty cell they add is empty / is not empty. A condition that is already in the filter is not added twice.

Searching

Column statistics

Statistics are computed for one column over the rows of the current view (after the filter):

ItemMeaning
RowsNumber of rows
EmptyNumber of empty cells (NULL or empty text), with percentage
DistinctNumber of different non-empty values
NumbersNumber of cells that are numbers (numeric text included)
Min / MaxSmallest and largest value, in sort order
Sum / MeanSum and mean of the numbers
Std devStandard deviation of the numbers
Most frequentThe most common values, with counts and percentages

Changing the filter recomputes the statistics. For Parquet, JSON and DuckDB files the values are counted inside the database.

Histograms

A histogram counts one column over the rows of the current view (after the filter), like the column statistics. It is opened with Edit → Histogram... in the GUI (see Using the GUI) and B in the terminal UI (see Using the Terminal UI).

What is counted

The values of the column are read as the filters read them:

If the column holds both, the histogram counts the kind it holds more of; the values of the other kind are reported as "other values" in the summary, and empty cells as "empty". A column with neither numbers nor dates shows its most frequent values instead.

How bins are chosen

The aim is about 30 bins with widths that are easy to read:

Each bin includes its lower edge and excludes its upper edge, written [lower, upper). The last bin of numbers also includes its upper edge, written [lower, upper], so the maximum value is counted.

Filtering from a bar

Choosing a bar (double-click in the GUI, Enter in the TUI) adds three conditions to the filter, is a number (is a date for times), ≥ lower and < upper (≤ upper for the last bin of numbers), which keep exactly the rows counted in that bar. The first one leaves out the "other values": without it, text such as 15 kg would still pass ≥ 10 and < 20 as text. For a bin of years, months or days the edges are dates, such as ≥ 1994-01-01 and < 1996-01-01. For a text column, the bar's value is added as an = condition. You can see and edit these conditions in the Filter pane (f in the TUI).

For Parquet, JSON and DuckDB files the values are counted inside the database.

Scatter plots and 2D density

A scatter plot draws one column (X) against another (Y) over the rows of the current view; its 2D density counts those rows on a grid. They are opened with Edit → Scatter Plot... in the GUI (see Using the GUI) and, as a density only, M in the terminal UI (see Using the Terminal UI).

When X holds text, its 30 most frequent values (in the order of the histogram's most frequent values) are categories, and the other values together are (other). Each category gets a box plot of its Y values:

Choosing a box (double-click in the GUI, Enter in the TUI) adds = the category's value on X and is a number (or is a date) on Y. "(other)" cannot be chosen, as it is not one value.

Choosing a cell (double-click in the GUI, Enter in the TUI) adds the conditions of both columns' bins to the filter, which keep exactly the rows counted in the cell. Dragging a rectangle in the GUI adds is a number (or is a date), ≥ and ≤ conditions on both columns, with the bounds rounded a little finer than the bins.

Group By

Edit → Group By... in the GUI (see Using the GUI) and A in the terminal UI (see Using the Terminal UI) count the rows of the current view by the values of some columns.