Skip to main content

Filtering

Once you've selected rows (see Row Selection), press " to open a new filtered sheet containing only those rows. This two-step model — select, then filter — is non-destructive: your source data never changes.

Learning Focus

Selection and filtering are two steps: (1) select rows with |, z|, or , — (2) open filtered sheet with ". This is safer than Excel's AutoFilter because the source sheet is never modified.

Open a Filtered Sheet (")

# 1. Select rows
| # move to column, press |, enter regex
# or
z| # select by Python expression
# or
, # select by current cell value

# 2. Open filtered sheet
"
KeyContentsLinked to source?
"Selected rows onlyYes — reflects source changes
g"All rows (no filter)Yes — useful for working copy
gz"Selected rows, deep copiedNo — fully independent

Save the Filtered View

# After opening filtered sheet with "
Ctrl+S
# Save to file — only filtered rows are written

Filter by Regex (|)

Select rows where the current column matches a pattern.

| regex # select rows matching regex in current column
g| regex # select rows matching regex in ANY visible column
\ regex # unselect matching rows

Common patterns:

GoalRegexCommand
Contains 'error'error| error
Starts with 'SG'^SG| ^SG
Ends with '.com'\.com$| \.com$
Exact match^active$| ^active$
Contains digits\d+| \d+
Either X or Y^X$|^Y$| ^X$|^Y$
vd ~/github/practice-folder/visidata/01-loading/01-employees.csv

# Filter employees in Engineering
# Move to 'department' column
|
# Enter: Engineering
# → Engineering rows highlighted yellow

# Open filtered sheet
"
# → new sheet with only Engineering employees

# Save to CSV
Ctrl+S
# Enter: /tmp/engineering.csv

Filter by Python Expression (z|)

Select rows matching a Python condition. Column names are variables.

z| expr # select rows matching Python expression
z\ expr # unselect matching rows
# Filter: salary above 80000
z|
# Enter: salary > 80000
"

# Filter: engineering employees with high salary
z|
# Enter: department == "Engineering" and salary > 85000
"

# Filter: empty/null values
z|
# Enter: region is None
"

# Filter: text contains
z|
# Enter: "web" in hostname

Filter by Value Match (,)

Quick-select all rows sharing the current cell's value — no typing.

, # select all rows with same display value as current cell
z, # select by stored (not display) value
g, # select rows matching current row across ALL columns
# Move cursor to a cell containing 'sg'
,
# → all rows where current column = 'sg' are selected
"
# → filtered sheet with only sg rows

Multi-Condition Filtering

Equivalent to Excel's =FILTER(range, (cond1)*(cond2)*(cond3)):

# Excel: =FILTER(orders, (region="APAC")*(amount>1000)*(status="shipped"))
# VisiData:
z|
# Enter: region == 'APAC' and amount > 1000 and status == 'shipped'
"

Filter-Friendly (Custom — ff)

Natural-language column filter with is, is not, contains, starts with, ends with conditions and multi-value and/or/comma support.

Space ff Enter # prompt: filter friendly: <column> <op> <value> [and/or ...]
ConditionExample
isstatus is pending,completed
is notstatus is not shipped
containsemail contains gmail
starts withname starts with A
ends withemail ends with .com
vd shortcuts_template.csv

Space
# Type: ff
# Enter: status is idea
# → only rows where status column = "idea"

Uses the same _all_rows master list system as fk/fx/fclear — filter in-place, add rows, clear to restore.


Keyword Filter (Custom — fk)

This is a custom command defined in 35-filter.py under the common-config repository. Unlike the default filter methods that require selection first, fk directly prompts for keywords and filters in-place.

Space fk Enter # prompt: filter keywords (comma-separated): done,pending
Space fclear Enter # restore the previous row view

Type comma-separated keywords. Rows where any visible column contains any keyword are kept; all others are hidden. The filter is an OR across keywords and columns.

vd ~/github/practice-folder/visidata/04-cleaning/sales.csv

Space
# Type: fk
# Enter: pending,urgent
# → rows where any column contains "pending" OR "urgent"

Space
# Type: fclear
# Enter
# → previous row view restored

Expression Filter (Custom — fx)

Filter rows in-place using a Python expression. Column names are available as variables.

Space fx Enter # prompt: filter expression: amount > 500
Space fclear Enter # restore the previous row view

Only rows where the expression evaluates to True are kept. Same Python syntax as z| but hides non-matching rows directly instead of marking them.

vd ~/github/practice-folder/visidata/01-loading/01-employees.csv

Space
# Type: fx
# Enter: salary > 70000
# → only rows where salary > 70000 remain visible

Space
# Type: fclear
# Enter
# → previous row view restored

These patterns directly map to Notion's column filter operators — no special syntax needed, just Python.

Using this sample table:

idcustomerstatuspriorityamountemail
1Alicependinghigh150.00alice@foo.com
2Bobshippedlow32.50bob@bar.com
3Charliependinglow89.00charlie@gmail.com
4Alicecompletedhigh200.00alice@foo.com
5Dianapendingmedium512.00diana@gmail.com
6Bobcancelledlow15.00bob@bar.com
Notion operatorfx expressionKeeps rowsExplanation
isstatus == "pending"1, 3, 5Exact match on column value
is-notstatus != "shipped"1, 3, 4, 5, 6Not equal to value
contains"gmail" in email3, 5Substring anywhere in column
not-contains"gmail" not in email1, 2, 4, 6Substring absent from column
starts withstatus.startswith("p")1, 3, 5Column value begins with text
ends withemail.endswith(".com")1, 2, 3, 4, 5, 6Column value ends with text

Combining Conditions

Use and, or, and parentheses to build multi-column filters — all in a single fx expression. Using the same sample table:

fx expressionKeeps rowsMeaning
status == "pending" and priority == "high"1pending AND high priority
amount > 100 or priority == "high"1, 3, 4, 5amount > 100 OR high priority
(status == "shipped" or status == "completed") and amount > 402shipped/completed AND amount > 40
"gmail" in email or customer == "Alice"1, 3, 4, 5gmail email OR customer is Alice
# Quick reference — paste directly after `fx`:
amount > 500
status == 'done'
department != 'Engineering' and salary > 70000
"web" in hostname
region == 'sg' or region == 'kl'

Deduplication

# Step 1: Find duplicates on a key column
# Move to 'employee_id' column
Shift+F

# Step 2: Cast count column to int
#

# Step 3: Filter frequency table for duplicates
z|
# Enter: count > 1

# Step 4: Drill into source rows for a duplicate value
Enter

# Step 5: Select duplicate row to delete
s

# Step 6: Return to source and delete
q
gd

Top-N Filter

# Top 10 highest values (Excel Top 10 AutoFilter equivalent)

# Step 1: Cast to numeric type
# Move to 'amount' → %

# Step 2: Sort descending
]

# Step 3: Select top N rows
# Navigate to row N, then:
# Or use expression:
z|
# Enter: amount >= threshold

# Step 4: Open filtered sheet
"

Clear Selections

gu # unselect all rows
\ regex # unselect rows matching regex
z\ expr # unselect rows matching expression

Excel Filter Translation

Excel / Google SheetsVisiDataDescription
=FILTER(A:B, C:C="active")| active"Filter by text match
=FILTER(A:B, (C="X")*(D="Y"))z| c == 'X' and d == 'Y'"Multi-condition
=IF(A2>100, A2, "")z| amount > 100"Filter by condition
AutoFilter dropdown| or ,Select by value
Advanced Filter (unique)Shift+FUnique value list
Remove duplicatesShift+F → filter count>1 → gdDeduplicate
Top 10 filter] sort → select → "Sort descending first
=UNIQUE(A:A)Shift+FUnique values
Slicers| regex"Visual filter equivalent
Blank filterz| value is NoneFilter nulls
Number filter (> 100)z| amount > 100Numeric condition
=FILTER(A:B, ISNUMBER(SEARCH("keyword", A:A)))Space fkkeywordKeyword across all columns (OR)
=FILTER(A:B, condition)Space fxexprPython expression filter

Quick Reference

KeyAction
"Open filtered sheet (selected rows only)
g"Open sheet copy (all rows, linked)
gz"Open deep copy (selected rows, independent)
| regexSelect rows matching regex in current column
g| regexSelect rows matching regex in any column
z| exprSelect rows matching Python expression
\ regexUnselect rows matching regex
z\ exprUnselect rows matching expression
,Select rows matching current cell value
g,Select rows matching current row (all columns)
guUnselect all rows
SpaceffEnterFilter-friendly: <col> <op> <value> (natural language)
SpacefkEnterFilter rows by keyword (comma-separated, OR across columns)
SpacefxEnterFilter rows by Python expression
SpacefclearEnterRestore all rows (preserves added rows)

Hands-On Practice

vd ~/github/practice-folder/visidata/01-loading/01-employees.csv

# 1. Filter by department: move to 'department' → | → Engineering → "
# 2. Save filtered: Ctrl+S → /tmp/engineering.csv
# 3. Press q → back to source
# 4. Filter by salary > 80000: z| → salary > 80000 → "
# 5. Press q → gu → clear all
# 6. Filter by value: move to 'Marketing' cell → , → "

What's Next