dataframe-textual 1.9.0__py3-none-any.whl → 2.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataframe-textual
3
- Version: 1.9.0
3
+ Version: 2.2.2
4
4
  Summary: Interactive terminal viewer/editor for tabular data
5
5
  Project-URL: Homepage, https://github.com/need47/dataframe-textual
6
6
  Project-URL: Repository, https://github.com/need47/dataframe-textual.git
@@ -62,10 +62,10 @@ A powerful, interactive terminal-based viewer/editor for CSV/TSV/Excel/Parquet/J
62
62
  ### Advanced Features
63
63
  - 📂 **Multi-File Support** - Open multiple files in separate tabs
64
64
  - 🔄 **Tab Management** - Seamlessly switch between open files with keyboard shortcuts
65
- - **Duplicate Tab** - Create a copy of the current tab with the same data
66
- - �📌 **Freeze Rows/Columns** - Keep important rows and columns visible while scrolling
65
+ - 📑 **Duplicate Tab** - Create a copy of the current tab with the same data
66
+ - 📌 **Freeze Rows/Columns** - Keep important rows and columns visible while scrolling
67
67
  - 🎯 **Cursor Type Cycling** - Switch between cell, row, and column selection modes
68
- - 🔗 **Link Column Creation** - Generate clickable URLs using template expressions with placeholder support
68
+ - 📸 **Take Screenshot** - Capture terminal view as a SVG image
69
69
 
70
70
  ## Installation
71
71
 
@@ -83,7 +83,7 @@ This installs an executable `dv`.
83
83
 
84
84
  Then run:
85
85
  ```bash
86
- dv <csv_file>
86
+ dv <file>
87
87
  ```
88
88
 
89
89
  ### Using [uv](https://docs.astral.sh/uv/)
@@ -97,7 +97,7 @@ cd dataframe-textual
97
97
  uv sync --extra excel # with Excel support
98
98
 
99
99
  # Run directly with uv
100
- uv run dv <csv_file>
100
+ uv run dv <file>
101
101
  ```
102
102
 
103
103
  ### Development installation
@@ -110,7 +110,10 @@ cd dataframe-textual
110
110
  # Install from local source
111
111
  pip install -e .
112
112
 
113
- # Or with development dependencies
113
+ # With Excel support
114
+ pip install -e ".[excel]"
115
+
116
+ # With development dependencies
114
117
  pip install -e ".[excel,dev]"
115
118
  ```
116
119
 
@@ -122,8 +125,8 @@ pip install -e ".[excel,dev]"
122
125
  # After pip install dataframe-textual
123
126
  dv pokemon.csv
124
127
 
125
- # Or if running from source
126
- python main.py pokemon.csv
128
+ # Or run from module
129
+ python -m dataframe-textual pokemon.csv
127
130
 
128
131
  # Or with uv
129
132
  uv run python main.py pokemon.csv
@@ -153,34 +156,35 @@ dv data1.tsv < data2.tsv
153
156
  ```
154
157
 
155
158
  When multiple files are opened:
156
- - Each file appears as a separate tab
157
- - Switch between tabs using `>` (next) or `<` (previous), or use `b` for cycling tabs
158
- - Save current tab or all tabs with `Ctrl+S`
159
+ - Each file appears as a separate tab. An Excel file may contain multiple tabs.
160
+ - Switch between tabs using `>` (next) or `<` (previous), or use `b` for cycling through tabs
161
+ - Save current tab to file with `Ctrl+T`
162
+ - Save all tabs to file with `Ctrl+A`
159
163
  - Duplicate the current tab with `Ctrl+D`
160
164
  - Open additional files with `Ctrl+O`
161
- - Each file maintains its own state (edits, sort order, selections, history, etc.)
165
+ - Each file maintains its own state (edits, sort order, selections, history, etc.) and allow undo/redo.
162
166
 
163
167
  ## Command Line Options
164
168
 
165
169
  ```
166
170
  usage: dv [-h] [-f {csv,excel,tsv,parquet,json,ndjson}] [-H] [-I] [-E] [-c COMMENT_PREFIX] [-q QUOTE_CHAR] [-l SKIP_LINES] [-a SKIP_ROWS_AFTER_HEADER] [-n NULL [NULL ...]] [files ...]
167
171
 
168
- Interactive terminal based viewer/editor for tabular data (e.g., CSV/Excel).
172
+ Interactive terminal based viewer/editor for tabular data (e.g., CSV/TSV/Excel).
169
173
 
170
174
  positional arguments:
171
- files Files to view (or read from stdin)
175
+ files Input files (or read from stdin)
172
176
 
173
177
  options:
174
178
  -h, --help show this help message and exit
175
179
  -f, --format {csv,excel,tsv,parquet,json,ndjson}
176
180
  Specify the format of the input files
177
181
  -H, --no-header Specify that input files have no header row
178
- -I, --no-inferrence Do not infer data types when reading CSV/TSV
182
+ -I, --no-inference Do not infer data types when reading CSV/TSV
179
183
  -E, --ignore-errors Ignore errors when reading CSV/TSV
180
184
  -c, --comment-prefix COMMENT_PREFIX
181
185
  Comment lines are skipped when reading CSV/TSV (default: skip none)
182
186
  -q, --quote-char QUOTE_CHAR
183
- Quote character for reading CSV/TSV (default: "; use None to disable)
187
+ Quote character for reading CSV/TSV (default: "; use -q without argument value to disable)
184
188
  -l, --skip-lines SKIP_LINES
185
189
  Skip lines when reading CSV/TSV (default: 0)
186
190
  -a, --skip-rows-after-header SKIP_ROWS_AFTER_HEADER
@@ -207,7 +211,7 @@ dv -l 3 data_with_meta.csv
207
211
  # Skip 1 row after header (e.g., units row)
208
212
  dv -a 1 data_with_units.csv
209
213
 
210
- # CSV with comment lines
214
+ # Skip comment lines (or just -c)
211
215
  dv -c "#" commented_data.csv
212
216
 
213
217
  # Treat specific values as null/missing (e.g., 'NA', 'N/A', '-')
@@ -241,18 +245,22 @@ zcat compressed_data.csv.gz | dv -f csv
241
245
  | `B` | Toggle tab bar visibility |
242
246
  | `q` | Close current tab (prompts to save unsaved changes) |
243
247
  | `Q` | Close all tabs and app (prompts to save unsaved changes) |
244
- | `Ctrl+Q` | Force to quit app (regardless off unsaved changes) |
245
- | `Ctrl+S` | Save current tab or all tabs to file |
248
+ | `Ctrl+Q` | Force to quit app (regardless of unsaved changes) |
249
+ | `Ctrl+T` | Save current tab to file |
250
+ | `Ctrl+A` | Save all tabs to a Excel file |
251
+ | `w` | Save current tab to file (overwrite without prompt) |
252
+ | `W` | Save all tabs to file (overwrite without prompt) |
246
253
  | `Ctrl+D` | Duplicate current tab |
247
254
  | `Ctrl+O` | Open file in a new tab |
248
- | `Double-click tab` | Rename current tab |
255
+ | `Double-click` | Rename tab |
249
256
 
250
257
  #### View & Settings
251
258
 
252
259
  | Key | Action |
253
260
  |-----|--------|
254
261
  | `F1` | Toggle help panel |
255
- | `k` | Cycle through themes |
262
+ | `k` | Cycle through dark, light and other themes |
263
+ | `Ctrl+P` -> `Screenshot` | Capture terminal view as a SVG image |
256
264
 
257
265
  ---
258
266
 
@@ -263,33 +271,39 @@ zcat compressed_data.csv.gz | dv -f csv
263
271
  | Key | Action |
264
272
  |-----|--------|
265
273
  | `g` | Jump to first row |
266
- | `G` | Jump to last row (loads all remaining rows) |
274
+ | `G` | Jump to last row |
267
275
  | `↑` / `↓` | Move up/down one row |
268
276
  | `←` / `→` | Move left/right one column |
269
277
  | `Home` / `End` | Jump to first/last column |
270
278
  | `Ctrl + Home` / `Ctrl + End` | Jump to page top/bottom |
271
279
  | `PageDown` / `PageUp` | Scroll down/up one page |
272
- | `Ctrl+F` | Page down |
273
- | `Ctrl+B` | Page up |
280
+ | `Ctrl+F` | Page forward |
281
+ | `Ctrl+B` | Page backforward |
274
282
 
275
283
  #### Undo/Redo/Reset
284
+ | Key | Action |
285
+ |-----|--------|
276
286
  | `u` | Undo last action |
277
287
  | `U` | Redo last undone action |
278
288
  | `Ctrl+U` | Reset to initial state |
279
289
 
280
- #### Viewing & Display
290
+ #### Display
281
291
 
282
292
  | Key | Action |
283
293
  |-----|--------|
284
- | `Enter` | Record view of current row |
294
+ | `Enter` | Record view of current row transposed |
285
295
  | `F` | Show frequency distribution for current column |
286
296
  | `s` | Show statistics for current column |
287
297
  | `S` | Show statistics for entire dataframe |
298
+ | `m` | Show metadata for row count and column count |
299
+ | `M` | Show metadata for current column |
288
300
  | `K` | Cycle cursor types: cell → row → column → cell |
289
301
  | `~` | Toggle row labels |
290
- | `_` (underscore) | Expand column to full width |
302
+ | `_` (underscore) | Toggle column full width |
291
303
  | `z` | Freeze rows and columns |
292
304
  | `,` | Toggle thousand separator for numeric display |
305
+ | `h` | Hide current column |
306
+ | `H` | Show all hidden rows/columns |
293
307
 
294
308
  #### Data Editing
295
309
 
@@ -298,55 +312,57 @@ zcat compressed_data.csv.gz | dv -f csv
298
312
  | `Double-click` | Edit cell or rename column header |
299
313
  | `delete` | Clear current cell (set to NULL) |
300
314
  | `e` | Edit current cell (respects data type) |
301
- | `E` | Edit entire column with expression |
315
+ | `E` | Edit entire column with value/expression |
302
316
  | `a` | Add empty column after current |
303
317
  | `A` | Add column with name and value/expression |
304
- | `@` | Add a link column from template |
318
+ | `@` | Add a link column from URL template |
305
319
  | `-` (minus) | Delete current column |
306
320
  | `x` | Delete current row |
307
321
  | `X` | Delete current row and all those below |
308
322
  | `Ctrl+X` | Delete current row and all those above |
309
- | `d` | Duplicate current column (appends '_copy' suffix) |
323
+ | `d` | Duplicate current column |
310
324
  | `D` | Duplicate current row |
311
- | `h` | Hide current column |
312
- | `H` | Show all hidden rows/columns |
313
325
 
314
- #### Searching & Filtering
326
+ #### Row Selection
315
327
 
316
328
  | Key | Action |
317
329
  |-----|--------|
318
- | `\` | Search in current column using cursor value and select rows |
319
- | `\|` (pipe) | Search in current column with expression and select rows |
330
+ | `\` | Select rows wth cell matches or those matching cursor value in current column |
331
+ | `\|` (pipe) | Select rows by expression |
320
332
  | `{` | Go to previous selected row |
321
333
  | `}` | Go to next selected row |
322
- | `/` | Find in current column with cursor value and highlight matches |
323
- | `?` | Find in current column with expression and highlight matches |
324
- | `n` | Go to next match |
325
- | `N` | Go to previous match |
326
334
  | `'` | Select/deselect current row |
327
- | `t` | Toggle selected rows (invßert) |
328
- | `T` | Clear all selected rows and/or matches |
329
- | `"` (quote) | Filter to selected rows and remove others |
330
- | `v` | View only rows (and hide others) by selected rows and/or matches or cursor value |
331
- | `V` | View only rows (and hide others) by expression |
332
-
333
- #### SQL Interface
334
-
335
- | Key | Action |
336
- |-----|--------|
337
- | `l` | Simple SQL interface (select columns & where clause) |
338
- | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
335
+ | `t` | Toggle row selections (invert) |
336
+ | `T` | Clear all row selections and/or cell matches |
339
337
 
340
338
  #### Find & Replace
341
339
 
342
340
  | Key | Action |
343
341
  |-----|--------|
342
+ | `/` | Find in current column with cursor value and highlight matching cells |
343
+ | `?` | Find in current column with expression and highlight matching cells |
344
+ | `n` | Go to next matching cell |
345
+ | `N` | Go to previous matching cell |
344
346
  | `;` | Find across all columns with cursor value |
345
347
  | `:` | Find across all columns with expression |
346
348
  | `r` | Find and replace in current column (interactive or replace all) |
347
349
  | `R` | Find and replace across all columns (interactive or replace all) |
348
350
 
349
- #### Sorting
351
+ #### View & Filter
352
+ | Key | Action |
353
+ |-----|--------|
354
+ | `"` (quote) | Filter selected rows (others removed) |
355
+ | `v` | View selected rows (others hidden) |
356
+ | `V` | View selected by expression (others hidden) |
357
+
358
+ #### SQL Interface
359
+
360
+ | Key | Action |
361
+ |-----|--------|
362
+ | `l` | Simple SQL interface (select columns & where clause) |
363
+ | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
364
+
365
+ #### Sorting (supporting multiple columns)
350
366
 
351
367
  | Key | Action |
352
368
  |-----|--------|
@@ -378,7 +394,7 @@ zcat compressed_data.csv.gz | dv -f csv
378
394
  | `c` | Copy current cell to clipboard |
379
395
  | `Ctrl+C` | Copy column to clipboard |
380
396
  | `Ctrl+R` | Copy row to clipboard (tab-separated) |
381
- | `Ctrl+S` | Save current tab to file |
397
+ | `Ctrl+S` | Save to file |
382
398
 
383
399
  ## Features in Detail
384
400
 
@@ -386,10 +402,10 @@ zcat compressed_data.csv.gz | dv -f csv
386
402
 
387
403
  Columns are automatically styled based on their data type:
388
404
  - **integer**: Cyan text, right-aligned
389
- - **float**: Magenta text, right-aligned
405
+ - **float**: Yellow text, right-aligned
390
406
  - **string**: Green text, left-aligned
391
407
  - **boolean**: Blue text, centered
392
- - **temporal**: Yellow text, centered
408
+ - **temporal**: Magenta text, centered
393
409
 
394
410
  ### 2. Row Detail View
395
411
 
@@ -397,108 +413,97 @@ Press `Enter` on any row to open a modal showing all column values for that row.
397
413
  Useful for examining wide datasets where columns don't fit well on screen.
398
414
 
399
415
  **In the Row Detail Modal**:
400
- - Press `v` to **view** all rows containing the selected column value (and hide others)
401
- - Press `"` to **filter** all rows containing the selected column value (and remove others)
416
+ - Press `v` to **view** all rows containing the selected column value (others hidden but preserved)
417
+ - Press `"` to **filter** all rows containing the selected column value (others removed)
418
+ - Press `{` to move to the previous row
419
+ - Press `}` to move to the next row
402
420
  - Press `q` or `Escape` to close the modal
403
421
 
404
- ### 3. Search & Filtering
422
+ ### 3. Row Selection
405
423
 
406
- The application provides multiple search modes for different use cases:
424
+ The application provides multiple modes for selecting rows (marks it for filtering or viewing):
407
425
 
408
- **Search Operations** - Search by value/expression in current column and select rows:
409
- - **`\` - Column Cursor Search**: Search cursor value
410
- - **`|` - Column Expression Search**: Opens dialog to search with custom expression
426
+ - `\` - Select rows with cell matches or those matching cursor value in current column (respects data type)
427
+ - `|` - Opens dialog to select rows with custom expression
428
+ - `'` - Select/deselect current row
429
+ - `t` - Flip selections of all rows
430
+ - `T` - Clear all row selections and cell matches
431
+ - `{` - Go to previous selected row
432
+ - `}` - Go to next selected row
411
433
 
412
- **Find Operations** - Find by value/expression and highlight matches:
413
- - **`/` - Column Find**: Find cursor value within current column
414
- - **`?` - Column Expression Find**: Open dialog to search current column with expression
415
- - **`;` - Global Find**: Find cursor value across all columns
416
- - **`:` - Global Expression Find**: Open dialog to search all columns with expression
417
-
418
- **Selection & Filtering**:
419
- - **`'` - Toggle Row Selection**: Select/deselect current row (marks it for filtering or viewing)
420
- - **`t` - Invert Selections**: Flip selections of all rows
421
- - **`T` - Clear Selections**: Remove all row selections and matches
422
- - **`"` - Filter Selected**: View only the selected rows (others removed)
423
- - **`v` - View by Value**: View rows by selected rows or cursor value (others hidden but preserved)
424
- - **`V` - View by Expression**: View rows using custom expression (others hidden but preserved)
425
-
426
- **Advanced Matching Options**:
434
+ **Advanced Options**:
427
435
 
428
436
  When searching or finding, you can use checkboxes in the dialog to enable:
429
- - **Match Nocase**: Ignore case differences (e.g., "john", "John", "JOHN" all match)
430
- - **Match Whole**: Match complete value, not partial substrings or words (e.g., "cat" won't match in "catfish")
437
+ - **Match Nocase**: Ignore case differences
438
+ - **Match Whole**: Match complete value, not partial substrings or words
431
439
 
432
- These options work with plain text searches. Use Polars regex patterns in expressions for more control:
433
- - **Case-insensitive matching in expressions**: Use `(?i)` prefix in regex (e.g., `(?i)john`)
434
- - **Word boundaries in expressions**: Use `\b` in regex (e.g., `\bjohn\b` matches whole word)
440
+ These options work with plain text searches. Use Polars regex patterns in expressions for more control. For example, use `(?i)` prefix in regex (e.g., `(?i)john`) for case-insensitive matching.
435
441
 
436
442
  **Quick Tips:**
437
- - Search results highlight matching rows/cells in **red**
443
+ - Search results highlight matching rows in **red**
444
+ - Use expression for advanced selection (e.g., $attack > $defense)
438
445
  - Multiple searches **accumulate** - each new search adds to the selections or matches
439
446
  - Type-aware matching automatically converts values. Resort to string comparison if conversion fails
440
447
  - Use `u` to undo any search or filter
441
448
 
442
- ### 3b. Find & Replace
443
-
444
- The application provides powerful find and replace functionality for both single-column and global replacements.
449
+ ### 4. Find & Replace
450
+ Find by value/expression and highlight matching cells:
451
+ - `/` - Find cursor value within current column (respects data type)
452
+ - `?` - Open dialog to search current column with expression
453
+ - `;` - Find cursor value across all columns
454
+ - `:` - Open dialog to search all columns with expression
455
+ - `n` - Go to next matching cell
456
+ - `N` - Go to previous matching cell
445
457
 
446
- **Replace Operations**:
447
- - **`r` - Column Replace**: Replace values in the current column
448
- - **`R` - Global Replace**: Replace values across all columns
458
+ Replace values in current column (`r`) or across all columns (`R`).
449
459
 
450
460
  **How It Works:**
451
461
 
452
- When you press `r` or `R`, a dialog opens where you can enter:
453
- 1. **Find term**: The value or expression to search for
454
- 2. **Replace term**: What to replace matches with
455
- 3. **Matching options**:
456
- - **Match Nocase**: Ignore case differences when matching (unchecked by default)
457
- - **Match Whole**: Match complete words only, not partial words (unchecked by default)
458
- 4. **Replace option**:
459
- - Choose **"Replace All"** to replace all matches at once (with confirmation)
460
- - Otherwise, review and confirm each match individually
461
-
462
- **Replace All** (`r` or `R` → Choose "Replace All"):
463
- - Shows a confirmation dialog with the number of matches and replacements
464
- - Replaces all matches with a single operation
465
- - Full undo support with `u`
466
- - Useful for bulk replacements when you're confident about the change
467
-
468
- **Replace Interactive** (`r` or `R` → Choose "Replace Interactive"):
469
- - Shows each match one at a time with a preview of the replacement
470
- - For each match, press:
471
- - `Enter` or press the `Yes` button - **Replace this occurrence** and move to next
472
- - Press the `Skip` button - **Skip this occurrence** and move to next
473
- - `Escape` or press the `No` button - **Cancel** remaining replacements (but keep already-made replacements)
474
- - Displays progress: `Occurrence X of Y` (Y = total occurrences, X = current)
475
- - Useful for careful replacements where you want to review each change
476
-
477
- **For Global Replace (`R`)**:
478
- - Searches and replaces across all columns simultaneously
479
- - Each column can have different matching behavior (string matching for text, numeric for numbers)
480
- - Preview shows which columns contain matches before replacement
481
- - Useful for standardizing values across multiple columns
462
+ When you press `r` or `R`, enter:
463
+ 1. **Find term**: Value or expression to search for (done by string value)
464
+ 2. **Replace term**: Replacement value
465
+ 3. **Matching options**: Match Nocase (ignore case), Match Whole (complete match only)
466
+ 4. **Replace mode**: All at once or interactive review
482
467
 
483
- **Features:**
484
- - **Full history support**: Use `u` (undo) to revert any replacement
485
- - **Visual feedback**: Matching cells are highlighted before you choose replacement mode
486
- - **Safe operations**: Requires confirmation before replacing
487
- - **Progress tracking**: Shows how many replacements have been made during interactive mode
488
- - **Type-aware**: Respects column data types when matching and replacing
489
- - **Flexible matching**: Support for case-insensitive and whole-word matching
468
+ **Replace All**:
469
+ - Replaces all matches with one operation
470
+ - Shows confirmation with match count
471
+
472
+ **Replace Interactive**:
473
+ - Review each match one at a time (confirm, skip, or cancel)
474
+ - Shows progress
490
475
 
491
476
  **Tips:**
492
- - **NULL**: Replace null/missing values (type `NULL`)
493
- - Use interactive mode for one-time replacements to be absolutely sure
494
- - Use "Replace All" for routine replacements (e.g., fixing typos, standardizing formats)
495
- - Use **Match Nocase** for matching variations of names or titles
496
- - Use **Match Whole** to avoid unintended partial replacements
497
- - Use `u` immediately if you accidentally replace something wrong
498
- - For complex replacements, use Polars expressions or regex patterns in the find term
499
- - Test with a small dataset first before large replacements
477
+ - Search are done by string value (i.e., ignoring data type)
478
+ - Type `NULL` to replace null/missing values
479
+ - Use `Match Nocase` for case-insensitive matching
480
+ - Use `Match Whole` to avoid partial replacements
481
+ - Support undo (`u`)
482
+
483
+ ### 5. Filter vs. View
484
+
485
+ Both operations show selected rows but with fundamentally different effects:
486
+
487
+ | Operation | Keyboard | Effect | Data Preserved |
488
+ |-----------|----------|--------|-----------------|
489
+ | **View** | `v`, `V` | Hides non-matching rows | Yes (hidden, can be restored by `H`) |
490
+ | **Filter** | `"` | Removes non-matching rows | No (permanently deleted) |
491
+
492
+ **When to use View** (`v` or `V`):
493
+ - Exploring or analyzing data safely
494
+ - Switching between different perspectives
495
+ - Press `H` to restore hidden rows (and hidden columns)
496
+
497
+ **When to use Filter** (`"`):
498
+ - Cleaning data (removing unwanted rows)
499
+ - Creating a trimmed dataset for export
500
+ - Permanent row removal from your dataframe
500
501
 
501
- ### 4. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
502
+ **Note**:
503
+ - If currently there are no selected rows and no matching cells, the `"` (Filter) and `v` (View) will use cursor value for search.
504
+ - Both support full undo with `u`.
505
+
506
+ ### 6. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
502
507
 
503
508
  Complex values or filters can be specified via Polars expressions, with the following adaptions for convenience:
504
509
 
@@ -506,6 +511,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
506
511
  - `$_` - Current column (based on cursor position)
507
512
  - `$1`, `$2`, etc. - Column by 1-based index
508
513
  - `$age`, `$salary` - Column by name (use actual column names)
514
+ - `` $`col name` `` - Column by name with spaces (backtick quoted)
509
515
 
510
516
  **Row References:**
511
517
  - `$#` - Current row index (1-based)
@@ -516,6 +522,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
516
522
  - `$age < 30` - Age less than 30
517
523
  - `$status == 'active'` - Status exactly matches 'active'
518
524
  - `$name != 'Unknown'` - Name is not 'Unknown'
525
+ - `$# <= 10` - Top 10 rows
519
526
 
520
527
  **Logical Operators:**
521
528
  - `&` - AND
@@ -530,6 +537,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
530
537
  - `($score >= 80) & ($score <= 90)` - Score between 80 and 90
531
538
  - `~($status == 'inactive')` - Status is not inactive
532
539
  - `$revenue > $expenses` - Revenue exceeds expenses
540
+ - ``$`product id` > 100`` - Product ID with spaces in column name greater than 100
533
541
 
534
542
  **String Matching:** ([Polars string API reference](https://docs.pola.rs/api/python/stable/reference/series/string.html))
535
543
  - `$name.str.contains("John")` - Name contains "John" (case-sensitive)
@@ -552,14 +560,32 @@ Complex values or filters can be specified via Polars expressions, with the foll
552
560
  - Use column names that match exactly (case-sensitive)
553
561
  - Use parentheses to clarify complex expressions: `($a & $b) | ($c & $d)`
554
562
 
555
- ### 5. Sorting
563
+ ### 7. Sorting
556
564
 
557
565
  - Press `[` to sort current column ascending
558
566
  - Press `]` to sort current column descending
559
567
  - Multi-column sorting supported (press multiple times on different columns)
560
568
  - Press same key twice to remove the column from sorting
561
569
 
562
- ### 6. Frequency Distribution
570
+ ### 8. Dataframe & Column Metadata
571
+
572
+ View quick metadata about your dataframe and columns to understand their structure and content.
573
+
574
+ **Dataframe Metadata** (`m`):
575
+ - Press `m` to open a modal displaying:
576
+ - **Row** - Total number of rows in the dataframe
577
+ - **Column** - Total number of columns in the dataframe
578
+
579
+ **Column Metadata** (`M`):
580
+ - Press `M` to open a modal displaying details for all columns:
581
+ - **ID** - 1-based column index
582
+ - **Name** - Column name
583
+ - **Type** - Data type (e.g., Int64, String, Float64, Boolean)
584
+
585
+ **In Metadata Modals**:
586
+ - Press `q` or `Escape` to close
587
+
588
+ ### 9. Frequency Distribution
563
589
 
564
590
  Press `F` to see value distributions of the current column. The modal shows:
565
591
  - Value, Count, Percentage, Histogram
@@ -567,8 +593,8 @@ Press `F` to see value distributions of the current column. The modal shows:
567
593
 
568
594
  **In the Frequency Table**:
569
595
  - Press `[` and `]` to sort by any column (value, count, or percentage)
570
- - Press `v` to **filter** all rows with the selected value (others hidden but preserved)
571
- - Press `"` to **exclude** all rows containing the selected value (others removed)
596
+ - Press `v` to **view** all rows containing the selected value (others hidden but preserved)
597
+ - Press `"` to **filter** all rows containing the selected value (others removed)
572
598
  - Press `q` or `Escape` to close the frequency table
573
599
 
574
600
  This is useful for:
@@ -577,17 +603,11 @@ This is useful for:
577
603
  - Identifying rare or common values
578
604
  - Finding the most/least frequent entries
579
605
 
580
- ### 7. Column & Dataframe Statistics
606
+ ### 10. Column & Dataframe Statistics
581
607
 
582
- Press `s` to see summary statistics for the current column, or press `S` for statistics across the entire dataframe.
583
-
584
- **Column Statistics** (`s`):
585
- - Shows calculated statistics using Polars' `describe()` method
586
- - Displays: count, null count, mean, median, std, min, max, etc.
587
-
588
- **Dataframe Statistics** (`S`):
589
- - Shows statistics for all numeric and applicable columns simultaneously
590
- - Displays: count, null count, mean, median, std, min, max, etc.
608
+ Show summary statistics (count, null count, mean, median, std, min, max, etc.) using Polars' `describe()` method.
609
+ - `s` for the current column
610
+ - `S` for all columns across the entire dataframe
591
611
 
592
612
  **In the Statistics Modal**:
593
613
  - Press `q` or `Escape` to close the statistics table
@@ -601,7 +621,7 @@ This is useful for:
601
621
  - Quick statistical summaries without external tools
602
622
  - Comparing statistics across columns
603
623
 
604
- ### 8. Data Editing
624
+ ### 11. Data Editing
605
625
 
606
626
  **Edit Cell** (`e` or **Double-click**):
607
627
  - Opens modal for editing current cell
@@ -625,39 +645,29 @@ This is useful for:
625
645
  **Delete Column** (`-`):
626
646
  - Removes the entire column from display and dataframe
627
647
 
628
- ### 9. Hide & Show Columns
629
-
630
- **Hide Column** (`h`):
631
- - Temporarily hides the current column from display
632
- - Column data is preserved in the dataframe
633
- - Hidden columns are included in saves
634
-
635
- **Show Hidden Rows/Columns** (`H`):
636
- - Restores all previously hidden rows/columns to the display
648
+ **Add Empty Column** (`a`):
649
+ - Adds a new empty column after the current column
650
+ - Column is initialized with NULL values for all rows
637
651
 
638
- ### 10. Duplicate Column
652
+ **Add Column with Value/Expression** (`A`):
653
+ - Opens dialog to specify column name and initial value/expression
654
+ - Value can be a constant (e.g., `0`, `"text"`) or a Polars expression (e.g., `$age * 2`)
655
+ - Expression can reference other columns and perform calculations
656
+ - Useful for creating derived columns or adding data with formulas
639
657
 
640
- Press `d` to duplicate the current column:
658
+ **Duplicate Column** (`d`):
641
659
  - Creates a new column immediately after the current column
642
660
  - New column has '_copy' suffix (e.g., 'price' → 'price_copy')
643
- - Duplicate preserves all data from original column
644
- - New column is inserted into the dataframe
645
-
646
- This is useful for:
647
- - Creating backup copies of columns before transformation
648
- - Working with alternative versions of column data
649
- - Comparing original vs. processed column values side-by-side
650
-
651
- ### 11. Duplicate Row
661
+ - Useful for creating backups before transformation
652
662
 
653
- Press `D` to duplicate the current row:
663
+ **Duplicate Row** (`D`):
654
664
  - Creates a new row immediately after the current row
655
665
  - Duplicate preserves all data from original row
656
- - New row is inserted into the dataframe
666
+ - Useful for batch adding similar records
657
667
 
658
- This is useful for:
659
- - Creating variations of existing data records
660
- - Batch adding similar rows with modifications
668
+ **Hide/Show Columns** (`h` / `H`):
669
+ - `h` - Temporarily hide current column (data preserved)
670
+ - `H` - Restore all hidden columns and rows
661
671
 
662
672
  ### 12. Column & Row Reordering
663
673
 
@@ -674,7 +684,7 @@ This is useful for:
674
684
  Press `z` to open the dialog:
675
685
  - Enter number of fixed rows and/or columns to keep top rows/columns visible while scrolling
676
686
 
677
- ### 13.5. Thousand Separator Toggle
687
+ ### 14. Thousand Separator Toggle
678
688
 
679
689
  Press `,` to toggle thousand separator formatting for numeric data:
680
690
  - Applies to **integer** and **float** columns
@@ -684,14 +694,11 @@ Press `,` to toggle thousand separator formatting for numeric data:
684
694
  - Display-only: does not modify underlying data in the dataframe
685
695
  - State persists during the session
686
696
 
687
- ### 14. Save File
697
+ ### 15. Save File
688
698
 
689
- Press `Ctrl+S` to save:
690
- - Save filtered, edited, or sorted data back to file
691
- - Choose filename in modal dialog
692
- - Confirm if file already exists
699
+ Press `Ctrl+S` to save filtered, edited, or sorted data back to file
693
700
 
694
- ### 15. Undo/Redo/Reset
701
+ ### 16. Undo/Redo/Reset
695
702
 
696
703
  **Undo** (`u`):
697
704
  - Reverts last action with full state restoration
@@ -709,7 +716,7 @@ Press `Ctrl+S` to save:
709
716
  - Clears all edits, deletions, selections, filters, and sorts
710
717
  - Useful for starting fresh without reloading the file
711
718
 
712
- ### 16. Column Type Conversion
719
+ ### 17. Column Type Conversion
713
720
 
714
721
  Press the type conversion keys to instantly cast the current column to a different data type:
715
722
 
@@ -726,19 +733,19 @@ Press the type conversion keys to instantly cast the current column to a differe
726
733
 
727
734
  **Note**: Type conversion attempts to preserve data where possible. Conversions may lose data (e.g., float to int rounding).
728
735
 
729
- ### 17. Cursor Type Cycling
736
+ ### 18. Cursor Type Cycling
730
737
 
731
738
  Press `K` to cycle through selection modes:
732
739
  1. **Cell mode**: Highlight individual cell (and its row/column headers)
733
740
  2. **Row mode**: Highlight entire row
734
741
  3. **Column mode**: Highlight entire column
735
742
 
736
- ### 18. SQL Interface
743
+ ### 19. SQL Interface
737
744
 
738
745
  The SQL interface provides two modes for querying your dataframe:
739
746
 
740
747
  #### Simple SQL Interface (`l`)
741
- Select specific columns and apply WHERE conditions without writing full SQL:
748
+ SELECT specific columns and apply WHERE conditions without writing full SQL:
742
749
  - Choose which columns to include in results
743
750
  - Specify WHERE clause for filtering
744
751
  - Ideal for quick filtering and column selection
@@ -746,7 +753,6 @@ Select specific columns and apply WHERE conditions without writing full SQL:
746
753
  #### Advanced SQL Interface (`L`)
747
754
  Execute complete SQL queries for advanced data manipulation:
748
755
  - Write full SQL queries with standard [SQL syntax](https://docs.pola.rs/api/python/stable/reference/sql/index.html)
749
- - Support for JOINs, GROUP BY, aggregations, and more
750
756
  - Access to all SQL capabilities for complex transformations
751
757
  - Always use `self` as the table name
752
758
  - Syntax highlighted
@@ -754,30 +760,28 @@ Execute complete SQL queries for advanced data manipulation:
754
760
  **Examples:**
755
761
  ```sql
756
762
  -- Filter and select specific rows and/or columns
757
- SELECT name, age FROM self WHERE age > 30
758
-
759
- -- Aggregate with GROUP BY
760
- SELECT department, COUNT(*) as count, AVG(salary) as avg_salary
763
+ SELECT name, age
761
764
  FROM self
762
- GROUP BY department
765
+ WHERE age > 30
763
766
 
764
- -- Complex filtering with multiple conditions
767
+ -- Use backticks (`) for column names with spaces
765
768
  SELECT *
766
769
  FROM self
767
- WHERE (age > 25 AND salary > 50000) OR department = 'Management'
770
+ WHERE `product id` = 7
768
771
  ```
769
772
 
770
- ### 19. Clipboard Operations
773
+ ### 20. Clipboard Operations
774
+
775
+ Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux.
771
776
 
772
- Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
773
- **Note** May require a X server to work
777
+ **Note**: may require a X server to work.
774
778
 
775
779
  - Press `c` to copy cursor value
776
780
  - Press `Ctrl+C` to copy column values
777
781
  - Press `Ctrl+R` to copy row values (delimited by tab)
778
782
  - Hold `Shift` to select with mouse
779
783
 
780
- ### 20. Link Column Creation
784
+ ### 21. Link Column Creation
781
785
 
782
786
  Press `@` to create a new column containing dynamically generated URLs using template.
783
787
 
@@ -785,16 +789,11 @@ Press `@` to create a new column containing dynamically generated URLs using tem
785
789
 
786
790
  The link template supports multiple placeholder types for maximum flexibility:
787
791
 
788
- - **`$_`** - Current column (the column where cursor was when `@` was pressed)
789
- - Example: `https://example.com/search/$_` - Uses values from the current column
792
+ - **`$_`** - Current column (the column where cursor was when `@` was pressed), e.g., `https://example.com/search/$_` - Uses values from the current column
790
793
 
791
- - **`$1`, `$2`, `$3`, etc.** - Column by 1-based position index
792
- - Example: `https://example.com/product/$1/details/$2` - Uses 1st and 2nd columns
793
- - Index corresponds to column display order (left-to-right)
794
+ - **`$1`, `$2`, `$3`, etc.** - Column by 1-based position index, e.g., `https://example.com/product/$1/details/$2` - Uses 1st and 2nd columns
794
795
 
795
- - **`$name`** - Column by name (use actual column names)
796
- - Example: `https://pubchem.ncbi.nlm.nih.gov/search?q=$product_id` - Uses `product_id` column
797
- - Example: `https://example.com/$region/$city/data` - Uses `region` and `city` columns
796
+ - **`$name`** - Column by name (use actual column names), e.g., `https://example.com/$region/$city/data` - Uses `region` and `city` columns
798
797
 
799
798
  **Features:**
800
799
  - **Multiple Placeholders**: Mix and match placeholders in a single template
@@ -804,7 +803,7 @@ The link template supports multiple placeholder types for maximum flexibility:
804
803
  - Use full undo (`u`) if template produces unexpected URLs
805
804
  - For complex multi-column URLs, use column names (`$name`) for clarity over positions (`$1`)
806
805
 
807
- ### 21. Tab Management
806
+ ### 22. Tab Management
808
807
 
809
808
  Manage multiple files and dataframes simultaneously with tabs.
810
809
 
@@ -814,19 +813,18 @@ Manage multiple files and dataframes simultaneously with tabs.
814
813
  - **`<`** - Move to previous tab
815
814
  - **`b`** - Cycle through tabs
816
815
  - **`B`** - Toggle tab bar visibility
817
- - **`Double-click tab`** - Rename the tab
816
+ - **`Double-click`** - Rename the tab
818
817
  - **`Ctrl+D`** - Duplicate current tab (creates a copy with same data and state)
819
- - **`Ctrl+S`** - Save current tab to file or all tabs in a single Excel file
818
+ - **`Ctrl+T`** - Save current tab to file
819
+ - **`Ctrl+A`** - Save all tabs in a single Excel file
820
+ - **`w`** - Save current tab to file (overwrite without prompt)
821
+ - **`W`** - Save all tabs to file (overwrite without prompt)
820
822
  - **`q`** - Close current tab (closes tab, prompts to save if unsaved changes)
821
823
  - **`Q`** - Close all tabs and exit app (prompts to save tabs with unsaved changes)
822
824
  - **`Ctrl+Q`** - Force to quit app regardless of unsaved changes
823
825
 
824
- **Tab Operations:**
825
-
826
- **Saving & Quitting:**
827
-
828
826
  **Tips:**
829
- - Tabs with unsaved changes are highlighted with a bright border
827
+ - Tabs with unsaved changes are indicated with a bright background
830
828
  - Closing or quitting a tab with unsaved changes triggers a save prompt
831
829
 
832
830
  ## Dependencies