dataframe-textual 1.10.1__py3-none-any.whl → 1.16.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.10.1
3
+ Version: 1.16.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
+ | `w` | Save current tab to file (overwrite without prompt) |
251
+ | `Ctrl+A` | Save all tabs to file |
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
 
@@ -269,19 +277,21 @@ zcat compressed_data.csv.gz | dv -f csv
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 |
@@ -290,6 +300,8 @@ zcat compressed_data.csv.gz | dv -f csv
290
300
  | `_` (underscore) | Expand column to full width |
291
301
  | `z` | Freeze rows and columns |
292
302
  | `,` | Toggle thousand separator for numeric display |
303
+ | `h` | Hide current column |
304
+ | `H` | Show all hidden rows/columns |
293
305
 
294
306
  #### Data Editing
295
307
 
@@ -298,55 +310,57 @@ zcat compressed_data.csv.gz | dv -f csv
298
310
  | `Double-click` | Edit cell or rename column header |
299
311
  | `delete` | Clear current cell (set to NULL) |
300
312
  | `e` | Edit current cell (respects data type) |
301
- | `E` | Edit entire column with expression |
313
+ | `E` | Edit entire column with value/expression |
302
314
  | `a` | Add empty column after current |
303
315
  | `A` | Add column with name and value/expression |
304
- | `@` | Add a link column from template |
316
+ | `@` | Add a link column from URL template |
305
317
  | `-` (minus) | Delete current column |
306
318
  | `x` | Delete current row |
307
319
  | `X` | Delete current row and all those below |
308
320
  | `Ctrl+X` | Delete current row and all those above |
309
321
  | `d` | Duplicate current column (appends '_copy' suffix) |
310
322
  | `D` | Duplicate current row |
311
- | `h` | Hide current column |
312
- | `H` | Show all hidden rows/columns |
313
323
 
314
- #### Searching & Filtering
324
+ #### Row Selection
315
325
 
316
326
  | Key | Action |
317
327
  |-----|--------|
318
- | `\` | Search in current column using cursor value and select rows |
319
- | `\|` (pipe) | Search in current column with expression and select rows |
328
+ | `\` | Select rows that matches cursor value in current column |
329
+ | `\|` (pipe) | Select rows by expression |
320
330
  | `{` | Go to previous selected row |
321
331
  | `}` | 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
332
  | `'` | 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) |
333
+ | `t` | Toggle row selections (invert) |
334
+ | `T` | Clear all row selections and/or cell matches |
339
335
 
340
336
  #### Find & Replace
341
337
 
342
338
  | Key | Action |
343
339
  |-----|--------|
340
+ | `/` | Find in current column with cursor value and highlight matching cells |
341
+ | `?` | Find in current column with expression and highlight matching cells |
342
+ | `n` | Go to next matching cell |
343
+ | `N` | Go to previous matching cell |
344
344
  | `;` | Find across all columns with cursor value |
345
345
  | `:` | Find across all columns with expression |
346
346
  | `r` | Find and replace in current column (interactive or replace all) |
347
347
  | `R` | Find and replace across all columns (interactive or replace all) |
348
348
 
349
- #### Sorting
349
+ #### View & Filter
350
+ | Key | Action |
351
+ |-----|--------|
352
+ | `"` (quote) | Filter to rows that are selected or contain matching cells (and remove others) |
353
+ | `v` | View rows (and hide others) by row selections and cell matches or cursor value |
354
+ | `V` | View rows (and hide others) by expression |
355
+
356
+ #### SQL Interface
357
+
358
+ | Key | Action |
359
+ |-----|--------|
360
+ | `l` | Simple SQL interface (select columns & where clause) |
361
+ | `L` | Advanced SQL interface (full SQL query with syntax highlight) |
362
+
363
+ #### Sorting (supporting multiple columns)
350
364
 
351
365
  | Key | Action |
352
366
  |-----|--------|
@@ -386,10 +400,10 @@ zcat compressed_data.csv.gz | dv -f csv
386
400
 
387
401
  Columns are automatically styled based on their data type:
388
402
  - **integer**: Cyan text, right-aligned
389
- - **float**: Magenta text, right-aligned
403
+ - **float**: Yellow text, right-aligned
390
404
  - **string**: Green text, left-aligned
391
405
  - **boolean**: Blue text, centered
392
- - **temporal**: Yellow text, centered
406
+ - **temporal**: Magenta text, centered
393
407
 
394
408
  ### 2. Row Detail View
395
409
 
@@ -399,106 +413,95 @@ Useful for examining wide datasets where columns don't fit well on screen.
399
413
  **In the Row Detail Modal**:
400
414
  - Press `v` to **view** all rows containing the selected column value (and hide others)
401
415
  - Press `"` to **filter** all rows containing the selected column value (and remove others)
416
+ - Press `{` to move to the **previous row** (respects hidden rows)
417
+ - Press `}` to move to the **next row** (respects hidden rows)
402
418
  - Press `q` or `Escape` to close the modal
403
419
 
404
- ### 3. Search & Filtering
420
+ ### 3. Row Selection
405
421
 
406
- The application provides multiple search modes for different use cases:
422
+ The application provides multiple modes for selecting rows (marks it for filtering or viewing):
407
423
 
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
411
-
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)
424
+ - `\` - Select rows that match cursor value in current column (respects data type)
425
+ - `|` - Opens dialog to select rows with custom expression
426
+ - `'` - Select/deselect current row
427
+ - `t` - Flip selections of all rows
428
+ - `T` - Clear all row selections and cell matches
429
+ - `{` - Go to previous selected row
430
+ - `}` - Go to next selected row
425
431
 
426
432
  **Advanced Matching Options**:
427
433
 
428
434
  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")
435
+ - **Match Nocase**: Ignore case differences
436
+ - **Match Whole**: Match complete value, not partial substrings or words
431
437
 
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)
438
+ 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
439
 
436
440
  **Quick Tips:**
437
- - Search results highlight matching rows/cells in **red**
441
+ - Search results highlight matching rows in **red**
442
+ - Use expression for advanced selection (e.g., $attack > $defense)
438
443
  - Multiple searches **accumulate** - each new search adds to the selections or matches
439
444
  - Type-aware matching automatically converts values. Resort to string comparison if conversion fails
440
445
  - Use `u` to undo any search or filter
441
446
 
442
- ### 3b. Find & Replace
443
-
444
- The application provides powerful find and replace functionality for both single-column and global replacements.
447
+ ### 4. Find & Replace
448
+ **Find Operations** - Find by value/expression and highlight matching cells:
449
+ - `/` - Find cursor value within current column (respects data type)
450
+ - `?` - Open dialog to search current column with expression
451
+ - `;` - Find cursor value across all columns
452
+ - `:` - Open dialog to search all columns with expression
453
+ - `n` - Go to next matching cell
454
+ - `N` - Go to previous matching cell
445
455
 
446
- **Replace Operations**:
447
- - **`r` - Column Replace**: Replace values in the current column
448
- - **`R` - Global Replace**: Replace values across all columns
456
+ Replace values in current column (`r`) or across all columns (`R`).
449
457
 
450
458
  **How It Works:**
451
459
 
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
460
+ When you press `r` or `R`, enter:
461
+ 1. **Find term**: Value or expression to search for (done by string value)
462
+ 2. **Replace term**: Replacement value
463
+ 3. **Matching options**: Match Nocase (ignore case), Match Whole (complete match only)
464
+ 4. **Replace mode**: All at once or interactive review
482
465
 
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
466
+ **Replace All**:
467
+ - Replaces all matches with one operation
468
+ - Shows confirmation with match count
469
+
470
+ **Replace Interactive**:
471
+ - Review each match one at a time (confirm, skip, or cancel)
472
+ - Shows progress: `X of Y`
490
473
 
491
474
  **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
475
+ - Search are done by string value (i.e. ignoring data type)
476
+ - Type `NULL` to replace null/missing values
477
+ - Use `Match Nocase` for case-insensitive matching
478
+ - Use `Match Whole` to avoid partial replacements
479
+ - Support undo (`u`)
480
+
481
+ ### 5. Filter vs. View
482
+
483
+ Both operations show rows that are selected or contain matching cells, but with fundamentally different effects:
484
+
485
+ | Operation | Keyboard | Effect | Data Preserved |
486
+ |-----------|----------|--------|-----------------|
487
+ | **View** | `v`, `V` | Hides non-matching rows | Yes (hidden, can be restored by `H`) |
488
+ | **Filter** | `"` | Removes non-matching rows | No (permanently deleted) |
489
+
490
+ **When to use View** (`v` or `V`):
491
+ - Exploring or analyzing data safely
492
+ - Switching between different perspectives
493
+ - Press `H` to restore hidden rows (and hidden columns)
494
+
495
+ **When to use Filter** (`"`):
496
+ - Cleaning data (removing unwanted rows)
497
+ - Creating a trimmed dataset for export
498
+ - Permanent row removal from your dataframe
500
499
 
501
- ### 4. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
500
+ **Note**:
501
+ - If currently there are no selected rows and no matching cells, the `"` (Filter) and `v` (View) will use cursor value for search.
502
+ - Both support full undo with `u`.
503
+
504
+ ### 6. [Polars Expressions](https://docs.pola.rs/api/python/stable/reference/expressions/index.html)
502
505
 
503
506
  Complex values or filters can be specified via Polars expressions, with the following adaptions for convenience:
504
507
 
@@ -506,6 +509,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
506
509
  - `$_` - Current column (based on cursor position)
507
510
  - `$1`, `$2`, etc. - Column by 1-based index
508
511
  - `$age`, `$salary` - Column by name (use actual column names)
512
+ - `` $`col name` `` - Column by name with spaces (backtick quoted)
509
513
 
510
514
  **Row References:**
511
515
  - `$#` - Current row index (1-based)
@@ -516,6 +520,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
516
520
  - `$age < 30` - Age less than 30
517
521
  - `$status == 'active'` - Status exactly matches 'active'
518
522
  - `$name != 'Unknown'` - Name is not 'Unknown'
523
+ - `$# <= 10` - Top 10 rows
519
524
 
520
525
  **Logical Operators:**
521
526
  - `&` - AND
@@ -530,6 +535,7 @@ Complex values or filters can be specified via Polars expressions, with the foll
530
535
  - `($score >= 80) & ($score <= 90)` - Score between 80 and 90
531
536
  - `~($status == 'inactive')` - Status is not inactive
532
537
  - `$revenue > $expenses` - Revenue exceeds expenses
538
+ - ``$`product id` > 100`` - Product ID with spaces in column name greater than 100
533
539
 
534
540
  **String Matching:** ([Polars string API reference](https://docs.pola.rs/api/python/stable/reference/series/string.html))
535
541
  - `$name.str.contains("John")` - Name contains "John" (case-sensitive)
@@ -552,14 +558,32 @@ Complex values or filters can be specified via Polars expressions, with the foll
552
558
  - Use column names that match exactly (case-sensitive)
553
559
  - Use parentheses to clarify complex expressions: `($a & $b) | ($c & $d)`
554
560
 
555
- ### 5. Sorting
561
+ ### 7. Sorting
556
562
 
557
563
  - Press `[` to sort current column ascending
558
564
  - Press `]` to sort current column descending
559
565
  - Multi-column sorting supported (press multiple times on different columns)
560
566
  - Press same key twice to remove the column from sorting
561
567
 
562
- ### 6. Frequency Distribution
568
+ ### 8. Dataframe & Column Metadata
569
+
570
+ View quick metadata about your dataframe and columns to understand their structure and content.
571
+
572
+ **Dataframe Metadata** (`m`):
573
+ - Press `m` to open a modal displaying:
574
+ - **Rows** - Total number of rows in the dataframe
575
+ - **Columns** - Total number of columns in the dataframe
576
+
577
+ **Column Metadata** (`M`):
578
+ - Press `M` to open a modal displaying details for all columns:
579
+ - **ID** - 1-based column index
580
+ - **Name** - Column name
581
+ - **Type** - Data type (e.g., Int64, String, Float64, Boolean)
582
+
583
+ **In Metadata Modals**:
584
+ - Press `q` or `Escape` to close
585
+
586
+ ### 9. Frequency Distribution
563
587
 
564
588
  Press `F` to see value distributions of the current column. The modal shows:
565
589
  - Value, Count, Percentage, Histogram
@@ -577,17 +601,11 @@ This is useful for:
577
601
  - Identifying rare or common values
578
602
  - Finding the most/least frequent entries
579
603
 
580
- ### 7. Column & Dataframe Statistics
604
+ ### 10. Column & Dataframe Statistics
581
605
 
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.
606
+ Show summary statistics (count, null count, mean, median, std, min, max, etc.) using Polars' `describe()` method.
607
+ - `s` for the current column
608
+ - `S` for all columns across the entire dataframe
591
609
 
592
610
  **In the Statistics Modal**:
593
611
  - Press `q` or `Escape` to close the statistics table
@@ -601,7 +619,7 @@ This is useful for:
601
619
  - Quick statistical summaries without external tools
602
620
  - Comparing statistics across columns
603
621
 
604
- ### 8. Data Editing
622
+ ### 11. Data Editing
605
623
 
606
624
  **Edit Cell** (`e` or **Double-click**):
607
625
  - Opens modal for editing current cell
@@ -625,39 +643,29 @@ This is useful for:
625
643
  **Delete Column** (`-`):
626
644
  - Removes the entire column from display and dataframe
627
645
 
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
646
+ **Add Empty Column** (`a`):
647
+ - Adds a new empty column after the current column
648
+ - Column is initialized with NULL values for all rows
637
649
 
638
- ### 10. Duplicate Column
650
+ **Add Column with Value/Expression** (`A`):
651
+ - Opens dialog to specify column name and initial value/expression
652
+ - Value can be a constant (e.g., `0`, `"text"`) or a Polars expression (e.g., `$age * 2`)
653
+ - Expression can reference other columns and perform calculations
654
+ - Useful for creating derived columns or adding data with formulas
639
655
 
640
- Press `d` to duplicate the current column:
656
+ **Duplicate Column** (`d`):
641
657
  - Creates a new column immediately after the current column
642
658
  - 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
659
+ - Useful for creating backups before transformation
652
660
 
653
- Press `D` to duplicate the current row:
661
+ **Duplicate Row** (`D`):
654
662
  - Creates a new row immediately after the current row
655
663
  - Duplicate preserves all data from original row
656
- - New row is inserted into the dataframe
664
+ - Useful for batch adding similar records
657
665
 
658
- This is useful for:
659
- - Creating variations of existing data records
660
- - Batch adding similar rows with modifications
666
+ **Hide/Show Columns** (`h` / `H`):
667
+ - `h` - Temporarily hide current column (data preserved)
668
+ - `H` - Restore all hidden columns and rows
661
669
 
662
670
  ### 12. Column & Row Reordering
663
671
 
@@ -674,7 +682,7 @@ This is useful for:
674
682
  Press `z` to open the dialog:
675
683
  - Enter number of fixed rows and/or columns to keep top rows/columns visible while scrolling
676
684
 
677
- ### 13.5. Thousand Separator Toggle
685
+ ### 14. Thousand Separator Toggle
678
686
 
679
687
  Press `,` to toggle thousand separator formatting for numeric data:
680
688
  - Applies to **integer** and **float** columns
@@ -684,14 +692,11 @@ Press `,` to toggle thousand separator formatting for numeric data:
684
692
  - Display-only: does not modify underlying data in the dataframe
685
693
  - State persists during the session
686
694
 
687
- ### 14. Save File
695
+ ### 15. Save File
688
696
 
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
697
+ Press `Ctrl+S` to save filtered, edited, or sorted data back to file
693
698
 
694
- ### 15. Undo/Redo/Reset
699
+ ### 16. Undo/Redo/Reset
695
700
 
696
701
  **Undo** (`u`):
697
702
  - Reverts last action with full state restoration
@@ -709,7 +714,7 @@ Press `Ctrl+S` to save:
709
714
  - Clears all edits, deletions, selections, filters, and sorts
710
715
  - Useful for starting fresh without reloading the file
711
716
 
712
- ### 16. Column Type Conversion
717
+ ### 17. Column Type Conversion
713
718
 
714
719
  Press the type conversion keys to instantly cast the current column to a different data type:
715
720
 
@@ -726,19 +731,19 @@ Press the type conversion keys to instantly cast the current column to a differe
726
731
 
727
732
  **Note**: Type conversion attempts to preserve data where possible. Conversions may lose data (e.g., float to int rounding).
728
733
 
729
- ### 17. Cursor Type Cycling
734
+ ### 18. Cursor Type Cycling
730
735
 
731
736
  Press `K` to cycle through selection modes:
732
737
  1. **Cell mode**: Highlight individual cell (and its row/column headers)
733
738
  2. **Row mode**: Highlight entire row
734
739
  3. **Column mode**: Highlight entire column
735
740
 
736
- ### 18. SQL Interface
741
+ ### 19. SQL Interface
737
742
 
738
743
  The SQL interface provides two modes for querying your dataframe:
739
744
 
740
745
  #### Simple SQL Interface (`l`)
741
- Select specific columns and apply WHERE conditions without writing full SQL:
746
+ SELECT specific columns and apply WHERE conditions without writing full SQL:
742
747
  - Choose which columns to include in results
743
748
  - Specify WHERE clause for filtering
744
749
  - Ideal for quick filtering and column selection
@@ -754,30 +759,28 @@ Execute complete SQL queries for advanced data manipulation:
754
759
  **Examples:**
755
760
  ```sql
756
761
  -- 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
762
+ SELECT name, age
761
763
  FROM self
762
- GROUP BY department
764
+ WHERE age > 30
763
765
 
764
- -- Complex filtering with multiple conditions
766
+ -- Use backticks (`) for column names with spaces
765
767
  SELECT *
766
768
  FROM self
767
- WHERE (age > 25 AND salary > 50000) OR department = 'Management'
769
+ WHERE `product id` = 7
768
770
  ```
769
771
 
770
- ### 19. Clipboard Operations
772
+ ### 20. Clipboard Operations
773
+
774
+ Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux.
771
775
 
772
- Copies value to system clipboard with `pbcopy` on macOS and `xclip` on Linux
773
- **Note** May require a X server to work
776
+ **Note** May require a X server to work.
774
777
 
775
778
  - Press `c` to copy cursor value
776
779
  - Press `Ctrl+C` to copy column values
777
780
  - Press `Ctrl+R` to copy row values (delimited by tab)
778
781
  - Hold `Shift` to select with mouse
779
782
 
780
- ### 20. Link Column Creation
783
+ ### 21. Link Column Creation
781
784
 
782
785
  Press `@` to create a new column containing dynamically generated URLs using template.
783
786
 
@@ -785,16 +788,11 @@ Press `@` to create a new column containing dynamically generated URLs using tem
785
788
 
786
789
  The link template supports multiple placeholder types for maximum flexibility:
787
790
 
788
- - **`$_`** - Current column (the column where cursor was when `@` was pressed)
789
- - Example: `https://example.com/search/$_` - Uses values from the current column
791
+ - **`$_`** - Current column (the column where cursor was when `@` was pressed), e.g., `https://example.com/search/$_` - Uses values from the current column
790
792
 
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)
793
+ - **`$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
794
 
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
795
+ - **`$name`** - Column by name (use actual column names), e.g., `https://example.com/$region/$city/data` - Uses `region` and `city` columns
798
796
 
799
797
  **Features:**
800
798
  - **Multiple Placeholders**: Mix and match placeholders in a single template
@@ -804,7 +802,7 @@ The link template supports multiple placeholder types for maximum flexibility:
804
802
  - Use full undo (`u`) if template produces unexpected URLs
805
803
  - For complex multi-column URLs, use column names (`$name`) for clarity over positions (`$1`)
806
804
 
807
- ### 21. Tab Management
805
+ ### 22. Tab Management
808
806
 
809
807
  Manage multiple files and dataframes simultaneously with tabs.
810
808
 
@@ -814,19 +812,18 @@ Manage multiple files and dataframes simultaneously with tabs.
814
812
  - **`<`** - Move to previous tab
815
813
  - **`b`** - Cycle through tabs
816
814
  - **`B`** - Toggle tab bar visibility
817
- - **`Double-click tab`** - Rename the tab
815
+ - **`Double-click`** - Rename the tab
818
816
  - **`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
817
+ - **`Ctrl+T`** - Save current tab to file
818
+ - **`w`** - Save current tab to file (overwrite without prompt)
819
+ - **`Ctrl+A`** - Save all tabs in a single Excel file
820
+ - **`W`** - Save all tabs to file (overwrite without prompt)
820
821
  - **`q`** - Close current tab (closes tab, prompts to save if unsaved changes)
821
822
  - **`Q`** - Close all tabs and exit app (prompts to save tabs with unsaved changes)
822
823
  - **`Ctrl+Q`** - Force to quit app regardless of unsaved changes
823
824
 
824
- **Tab Operations:**
825
-
826
- **Saving & Quitting:**
827
-
828
825
  **Tips:**
829
- - Tabs with unsaved changes are highlighted with a bright border
826
+ - Tabs with unsaved changes are indicated with a bright background
830
827
  - Closing or quitting a tab with unsaved changes triggers a save prompt
831
828
 
832
829
  ## Dependencies