# DataFrame Viewer/Editor
A powerful, interactive terminal-based CSV/Excel viewer/editor built with Python, Polars, and Textual. Inspired by VisiData, this tool provides smooth keyboard navigation, data manipulation, and a clean interface for exploring tabular data directly in your terminal. Now with **multi-file support for simultaneous data comparison**!

## Features
### Core Data Viewing
- 🚀 **Fast CSV Loading** - Powered by Polars for efficient data handling with lazy pagination
- 🎨 **Rich Terminal UI** - Beautiful, color-coded columns with automatic type detection
- ⌨️ **Comprehensive Keyboard Navigation** - Intuitive controls for browsing, editing, and manipulating data
- 📊 **Flexible Input** - Read from files or stdin (pipes/redirects)
- 🔄 **Smart Pagination** - Lazy load rows on demand for handling large datasets
### Data Manipulation
- 📝 **Data Editing** - Edit cells, delete rows, and remove columns
- 🔍 **Search & Filter** - Find values, highlight matches, and filter selected rows
- ↔️ **Column/Row Reordering** - Move columns and rows with simple keyboard shortcuts
- 📈 **Sorting & Statistics** - Multi-column sorting and frequency distribution analysis
- 💾 **Save & Undo** - Save filtered data back to CSV with full undo/redo support
### Advanced Features
- 📌 **Pin Rows/Columns** - Keep important rows and columns visible while scrolling
- 🎯 **Cursor Type Cycling** - Switch between cell, row, and column selection modes
- 📂 **Multi-File Support** - Open multiple CSV files in tabs for side-by-side comparison
- 🔄 **Tab Management** - Seamlessly switch between open files with keyboard shortcuts
## Installation
### Using pip
```bash
# Install from PyPI
pip install dataframe-textual
# With Excel support (fastexcel, xlsxwriter)
pip install dataframe-textual[excel]
```
Then run:
```bash
dataframe-textual <csv_file>
```
### Using uv
```bash
# Quick run using uvx without installation
uvx https://github.com/need47/dataframe-textual.git <csvfile>
# Clone or download the project
cd dataframe-textual
# Run directly with uv
uv run python main.py <csv_file>
#
```
### Development installation
```bash
# Clone the repository
git clone https://github.com/need47/dataframe-textual.git
cd dataframe-textual
# Install from local source
pip install -e .
# Or with development dependencies
pip install -e ".[excel,dev]"
```
## Usage
### Basic Usage - Single File
```bash
# After pip install dataframe-textual
dataframe-textual pokemon.csv
# Or if running from source
python main.py pokemon.csv
# Or with uv
uv run python main.py pokemon.csv
# Read from stdin
cat data.csv | dataframe-textual
dataframe-textual < data.csv
```
### Multi-File Usage - Multiple Tabs
```bash
# Open multiple files in tabs
dataframe-textual file1.csv file2.csv file3.csv
# Open multiple sheets in tabs in an Excel file
dataframe-textual file.xlsx
# Mix files and stdin (file opens first, then read from stdin)
dataframe-textual data1.csv < data2.csv
```
When multiple files are opened:
- Each file appears as a separate tab at the top
- Switch between tabs using `>` (next) or `<` (previous)
- Open additional files with `Ctrl+O`
- Close the current tab with `Ctrl+W`
- Each file maintains its own state (sort order, selections, history, etc.)
- Edits and filters are independent per file
## Keyboard Shortcuts
### App-Level Controls
#### File & Tab Management
| Key | Action |
|-----|--------|
| `Ctrl+O` | Open new CSV file in a new tab |
| `Ctrl+W` | Close current tab |
| `Ctrl+Shift+S` | Save all open tabs to Excel file |
| `>` or `b` | Move to next tab |
| `<` | Move to previous tab |
| `B` | Toggle tab bar visibility |
| `q` | Quit the application |
#### View & Settings
| Key | Action |
|-----|--------|
| `?` or `h` | Toggle help panel (context-sensitive) |
| `k` | Cycle through themes |
---
### Table-Level Controls
#### Navigation
| Key | Action |
|-----|--------|
| `g` | Jump to first row |
| `G` | Jump to last row (loads all remaining rows) |
| `↑` / `↓` | Move up/down one row |
| `←` / `→` | Move left/right one column |
| `PageDown` / `PageUp` | Scroll down/up |
| Arrow keys | Navigate the table |
#### Viewing & Display
| Key | Action |
|-----|--------|
| `Enter` | View full details of current row in modal |
| `F` | Show frequency distribution for column |
| `C` | Cycle cursor type: cell → row → column → cell |
| `#` | Toggle row labels visibility |
#### Data Editing
| Key | Action |
|-----|--------|
| `e` | Edit current cell (respects data type) |
| `d` | Delete current row |
| `-` | Delete current column |
#### Searching & Filtering
| Key | Action |
|-----|--------|
| `\|` (pipe) | Search in current column (case-insensitive) |
| `/` (slash) | Global search across all columns |
| `\` | Search current column using cell value |
| `s` | Select/deselect current row |
| `t` | Toggle highlighting of all selected rows (invert) |
| `T` | Clear all selected rows |
| `"` (quote) | Filter to show only selected rows |
| `v` | Filter by selected rows (if any) or current cell value |
| `V` | Filter by expression (Polars expression syntax) |
#### Sorting
| Key | Action |
|-----|--------|
| `[` | Sort current column ascending |
| `]` | Sort current column descending |
#### Reordering
| Key | Action |
|-----|--------|
| `Shift+↑` | Move current row up |
| `Shift+↓` | Move current row down |
| `Shift+←` | Move current column left |
| `Shift+→` | Move current column right |
#### Data Management
| Key | Action |
|-----|--------|
| `f` | Freeze rows and columns |
| `c` | Copy current cell to clipboard |
| `Ctrl+S` | Save current tab to CSV/TSV file |
| `u` | Undo last action |
| `U` | Reset to original data |
#### Modal Interactions
**In Frequency Distribution Modal** (opened with `F`):
- `[` / `]` - Sort frequency table
- `v` - Filter main table to selected value
- `"` - Highlight rows with selected value
- `q` / `Escape` - Close modal
**In Row Detail Modal** (opened with `Enter`):
- `v` - Filter main table to selected column value
- `"` - Highlight rows with selected column value
- `q` / `Escape` - Close modal
**Tip**: Press `?` or `h` to open the context-sensitive help panel which displays all available shortcuts based on your current focus.
## Features in Detail
### 1. Color-Coded Data Types
Columns are automatically styled based on their data type:
- **Int64** (Integers): Cyan text, right-aligned
- **Float64** (Decimals): Magenta text, right-aligned
- **String**: Green text, left-aligned
- **Boolean**: Blue text, centered
- **Date/Datetime**: Blue text, centered
### 2. Row Detail View
Press `Enter` on any row to open a modal showing all column values for that row. Useful for examining wide datasets where columns don't fit on screen.
**In the Row Detail Modal**:
- Press `v` to **filter** the main table to show only rows with the selected column value
- Press `"` to **highlight** all rows containing the selected column value
- Press `q` or `Escape` to close the modal
### 3. Search & Filtering
**Column Search** (`|`):
- Search for values in the current column
- Case-insensitive substring matching
- All matching rows are highlighted in red
- Multiple searches accumulate selections
**Global Search** (`/`):
- Search for a term across all columns simultaneously
- Cell-level highlighting in red for each matching cell
- Useful for finding a value anywhere in the dataset
- Automatically loads rows if matches extend beyond visible area
- Type-aware matching: converts values to strings before comparing
**Cell-Value Search** (`\`):
- Automatically search using the current cell's value
- Quick way to find all occurrences of a value
**Row Filtering** (`"`):
- Display only the selected (highlighted) rows
- Other rows are hidden but preserved
- Use undo (`u`) to restore
### 4. Filter by Expression
Press `f` to open a powerful filter expression dialog. This allows you to write complex filter conditions using a special syntax:
**Column References:**
- `$_` - Current column (based on cursor position)
- `$1`, `$2`, etc. - Column by 1-based index
- `$age`, `$salary` - Column by name
**Operators:**
- Comparison: `==`, `!=`, `<`, `>`, `<=`, `>=`
- Logical: `&&` (AND), `||` (OR)
- Arithmetic: `+`, `-`, `*`, `/`, `%`
**Examples:**
- `$_ > 50` - Current column greater than 50
- `$salary >= 100000` - Salary at least 100,000
- `$age < 30 && $status == 'active'` - Age less than 30 AND status is active
- `$name == 'Alice' || $name == 'Bob'` - Name is Alice or Bob
- `$salary / 1000 >= 50` - Salary divided by 1,000 is at least 50
See [FILTER_EXPRESSION_GUIDE.md](FILTER_EXPRESSION_GUIDE.md) for comprehensive syntax documentation.
### 5. Sorting
- Press `[` to sort current column ascending
- Press `]` to sort current column descending
- Multi-column sorting supported (press multiple times on different columns)
- Press same key twice to toggle direction
- Frequency view (`F`) shows value distribution with optional sorting
### 6. Frequency Distribution
Press `F` to see how many times each value appears in the current column. The modal shows:
- Value
- Count
- Percentage of total
- **Total row** at the bottom
**In the Frequency Table**:
- Press `[` and `]` to sort by any column (value, count, or percentage)
- Press `v` to **filter** the main table to show only rows with the selected value
- Press `"` to **highlight** all rows containing the selected value
- Press `q` or `Escape` to close the frequency table
This is useful for:
- Understanding value distributions
- Quickly filtering to specific values
- Identifying rare or common values
- Finding the most/least frequent entries
### 7. Data Editing
**Edit Cell** (`e`):
- Opens modal for editing current cell
- Validates input based on column data type
- Shows column name and type
- Integer, number, and text inputs available
**Delete Row** (`d`):
- Delete single row at cursor
- Or delete all selected rows at once
- Deleted rows are marked internally but kept for undo
**Delete Column** (`-`):
- Removes the entire column from view and dataframe
- Cannot be undone directly (use undo feature)
### 8. Column & Row Reordering
**Move Columns**: `Shift+←` and `Shift+→`
- Swaps adjacent columns
- Reorder is preserved when saving
**Move Rows**: `Shift+↑` and `Shift+↓`
- Swaps adjacent rows
- Visual reordering without affecting data
### 9. Pin Rows and Columns
Press `f` to open the pin dialog:
- Enter number of fixed rows: keeps top rows visible while scrolling
- Enter two numbers: `<rows> <columns>` (space-separated)
- Example: `2 3` pins top 2 rows and left 3 columns
### 10. Save to CSV
Press `Ctrl+S` to save:
- Save filtered, edited, or sorted data back to CSV
- Choose filename in modal dialog
- Confirm if file already exists
- Automatic .tsv or .csv detection
### 11. Undo/Redo
Press `u` to undo:
- Reverts last action with full state restoration
- Works for edits, deletions, sorts, searches, etc.
- Shows description of reverted action
### 12. Cursor Type Cycling
Press `C` to cycle through selection modes:
1. **Cell mode**: Highlight individual cell (and its row/column headers)
2. **Row mode**: Highlight entire row
3. **Column mode**: Highlight entire column
Visual feedback shows which mode is active.
### 13. Clipboard Operations
Press `c` to copy:
- Copies current cell value to system clipboard
- Works on macOS (`pbcopy`) and Linux (`xclip`)
- Shows confirmation notification
## Data Type Support
- **Int64, Int32, UInt32**: Integer values
- **Float64, Float32**: Decimal numbers (shown with 4 significant figures)
- **String**: Text data
- **Boolean**: True/False values
- **Date**: ISO date format (YYYY-MM-DD)
- **Datetime**: ISO datetime format
- **Null values**: Displayed as `-`
## Examples
### Single File Examples
```bash
# View Pokemon dataset
dataframe-textual pokemon.csv
# View Titanic dataset with analysis
dataframe-textual titanic.csv
# Filter and view specific columns
cut -d',' -f1,2,3 pokemon.csv | dataframe-textual
# View with grep filter (then use | search in viewer)
grep "Fire" pokemon.csv | dataframe-textual
# Chain with other commands
cat data.csv | sort -t',' -k2 | dataframe-textual
```
### Multi-File Examples
```bash
# Compare two versions of a dataset
dataframe-textual pokemon_v1.csv pokemon_v2.csv
# Side-by-side analysis of related files
dataframe-textual sales_2022.csv sales_2023.csv forecast_2024.csv
# Cross-reference datasets
dataframe-textual customers.csv orders.csv products.csv
# Start with one file, open others using Ctrl+O
dataframe-textual initial_data.csv
# Then press Ctrl+O to open more files interactively
```
### Advanced Workflows
```bash
# Start with a filtered file, compare with original
grep "status=active" data.csv > filtered.csv
dataframe-textual data.csv filtered.csv
# Now compare the full dataset with the filtered version in separate tabs
# Multi-step analysis
# 1. Open multiple related CSVs
# 2. Use Ctrl+O to open additional files as you discover relationships
# 3. Each tab maintains independent sort/filter/search state
# 4. Use Ctrl+W to close tabs when done analyzing
```
## Performance
- **Lazy loading**: Only loads visible rows + 10 rows ahead
- **Efficient sorting**: Uses Polars' optimized sort algorithms
- **Smooth scrolling**: No lag when paging through large files
- **Memory efficient**: Handles datasets larger than RAM
Tested with:
- 10,000+ row CSV files
- Wide datasets (100+ columns)
- Various data types and sizes
## Dependencies
- **polars**: Fast DataFrame library for CSV processing
- **textual**: Terminal UI framework
- **rich**: Rich text and formatting in the terminal
## Architecture Overview
### Single-Table Design
The core of the application is built around the `DataFrameTable` widget:
- **Self-contained**: Each table instance maintains its own complete state (13 independent variables)
- **Fully autonomous**: All operations (editing, sorting, filtering, searching) are handled within the table
- **Event-driven**: Each table owns and handles its keyboard events
- **Backward compatible**: Works identically in single-file mode
### Multi-Table Design
The `DataFrameApp` coordinates multiple independent `DataFrameTable` instances:
- **Tab-based interface**: Uses Textual's `TabbedContent` for tab management
- **Independent state**: Each tab has completely separate state (sort order, selections, history)
- **Seamless switching**: Switch between files without losing context or state
- **File management**: Open/close files dynamically without restarting the application
### State Isolation
Each `DataFrameTable` instance owns:
- DataFrame (`self.df`)
- Sorted columns (`self.sorted_columns`)
- Selected rows (`self.selected_rows`)
- Edit history (`self.histories`)
- Cursor state (position, type)
- Search/filter state
- And 8 more internal state variables
This ensures perfect isolation between tabs with zero cross-contamination.
## Requirements
- Python 3.11+
- POSIX-compatible terminal (macOS, Linux, WSL)
- Terminal supporting ANSI escape sequences and mouse events
## Acknowledgments
- Inspired by [VisiData](https://visidata.org/)
- Built with [Textual](https://textual.textualize.io/), [Polars](https://www.pola.rs/), and [Rich](https://rich.readthedocs.io/)
- All code created through iterative development
Raw data
{
"_id": null,
"home_page": null,
"name": "dataframe-textual",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "csv, data-analysis, excel, interactive, polars, terminal, textual, tui, viewer",
"author": null,
"author_email": "Tiejun Cheng <need47@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/c3/d6/cd9324f259efefb668a3d52240cdb736e20780ac231b11cedca22e3977b8/dataframe_textual-0.3.2.tar.gz",
"platform": null,
"description": "# DataFrame Viewer/Editor\n\nA powerful, interactive terminal-based CSV/Excel viewer/editor built with Python, Polars, and Textual. Inspired by VisiData, this tool provides smooth keyboard navigation, data manipulation, and a clean interface for exploring tabular data directly in your terminal. Now with **multi-file support for simultaneous data comparison**!\n\n\n\n## Features\n\n### Core Data Viewing\n- \ud83d\ude80 **Fast CSV Loading** - Powered by Polars for efficient data handling with lazy pagination\n- \ud83c\udfa8 **Rich Terminal UI** - Beautiful, color-coded columns with automatic type detection\n- \u2328\ufe0f **Comprehensive Keyboard Navigation** - Intuitive controls for browsing, editing, and manipulating data\n- \ud83d\udcca **Flexible Input** - Read from files or stdin (pipes/redirects)\n- \ud83d\udd04 **Smart Pagination** - Lazy load rows on demand for handling large datasets\n\n### Data Manipulation\n- \ud83d\udcdd **Data Editing** - Edit cells, delete rows, and remove columns\n- \ud83d\udd0d **Search & Filter** - Find values, highlight matches, and filter selected rows\n- \u2194\ufe0f **Column/Row Reordering** - Move columns and rows with simple keyboard shortcuts\n- \ud83d\udcc8 **Sorting & Statistics** - Multi-column sorting and frequency distribution analysis\n- \ud83d\udcbe **Save & Undo** - Save filtered data back to CSV with full undo/redo support\n\n### Advanced Features\n- \ud83d\udccc **Pin Rows/Columns** - Keep important rows and columns visible while scrolling\n- \ud83c\udfaf **Cursor Type Cycling** - Switch between cell, row, and column selection modes\n- \ud83d\udcc2 **Multi-File Support** - Open multiple CSV files in tabs for side-by-side comparison\n- \ud83d\udd04 **Tab Management** - Seamlessly switch between open files with keyboard shortcuts\n\n## Installation\n\n### Using pip\n\n```bash\n# Install from PyPI\npip install dataframe-textual\n\n# With Excel support (fastexcel, xlsxwriter)\npip install dataframe-textual[excel]\n```\n\nThen run:\n```bash\ndataframe-textual <csv_file>\n```\n\n### Using uv\n\n```bash\n# Quick run using uvx without installation\nuvx https://github.com/need47/dataframe-textual.git <csvfile>\n\n# Clone or download the project\ncd dataframe-textual\n\n# Run directly with uv\nuv run python main.py <csv_file>\n\n#\n```\n\n### Development installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/need47/dataframe-textual.git\ncd dataframe-textual\n\n# Install from local source\npip install -e .\n\n# Or with development dependencies\npip install -e \".[excel,dev]\"\n```\n\n## Usage\n\n### Basic Usage - Single File\n\n```bash\n# After pip install dataframe-textual\ndataframe-textual pokemon.csv\n\n# Or if running from source\npython main.py pokemon.csv\n\n# Or with uv\nuv run python main.py pokemon.csv\n\n# Read from stdin\ncat data.csv | dataframe-textual\ndataframe-textual < data.csv\n```\n\n### Multi-File Usage - Multiple Tabs\n\n```bash\n# Open multiple files in tabs\ndataframe-textual file1.csv file2.csv file3.csv\n\n# Open multiple sheets in tabs in an Excel file\ndataframe-textual file.xlsx\n\n# Mix files and stdin (file opens first, then read from stdin)\ndataframe-textual data1.csv < data2.csv\n```\n\nWhen multiple files are opened:\n- Each file appears as a separate tab at the top\n- Switch between tabs using `>` (next) or `<` (previous)\n- Open additional files with `Ctrl+O`\n- Close the current tab with `Ctrl+W`\n- Each file maintains its own state (sort order, selections, history, etc.)\n- Edits and filters are independent per file\n\n## Keyboard Shortcuts\n\n### App-Level Controls\n\n#### File & Tab Management\n\n| Key | Action |\n|-----|--------|\n| `Ctrl+O` | Open new CSV file in a new tab |\n| `Ctrl+W` | Close current tab |\n| `Ctrl+Shift+S` | Save all open tabs to Excel file |\n| `>` or `b` | Move to next tab |\n| `<` | Move to previous tab |\n| `B` | Toggle tab bar visibility |\n| `q` | Quit the application |\n\n#### View & Settings\n\n| Key | Action |\n|-----|--------|\n| `?` or `h` | Toggle help panel (context-sensitive) |\n| `k` | Cycle through themes |\n\n---\n\n### Table-Level Controls\n\n#### Navigation\n\n| Key | Action |\n|-----|--------|\n| `g` | Jump to first row |\n| `G` | Jump to last row (loads all remaining rows) |\n| `\u2191` / `\u2193` | Move up/down one row |\n| `\u2190` / `\u2192` | Move left/right one column |\n| `PageDown` / `PageUp` | Scroll down/up |\n| Arrow keys | Navigate the table |\n\n#### Viewing & Display\n\n| Key | Action |\n|-----|--------|\n| `Enter` | View full details of current row in modal |\n| `F` | Show frequency distribution for column |\n| `C` | Cycle cursor type: cell \u2192 row \u2192 column \u2192 cell |\n| `#` | Toggle row labels visibility |\n\n#### Data Editing\n\n| Key | Action |\n|-----|--------|\n| `e` | Edit current cell (respects data type) |\n| `d` | Delete current row |\n| `-` | Delete current column |\n\n#### Searching & Filtering\n\n| Key | Action |\n|-----|--------|\n| `\\|` (pipe) | Search in current column (case-insensitive) |\n| `/` (slash) | Global search across all columns |\n| `\\` | Search current column using cell value |\n| `s` | Select/deselect current row |\n| `t` | Toggle highlighting of all selected rows (invert) |\n| `T` | Clear all selected rows |\n| `\"` (quote) | Filter to show only selected rows |\n| `v` | Filter by selected rows (if any) or current cell value |\n| `V` | Filter by expression (Polars expression syntax) |\n\n#### Sorting\n\n| Key | Action |\n|-----|--------|\n| `[` | Sort current column ascending |\n| `]` | Sort current column descending |\n\n#### Reordering\n\n| Key | Action |\n|-----|--------|\n| `Shift+\u2191` | Move current row up |\n| `Shift+\u2193` | Move current row down |\n| `Shift+\u2190` | Move current column left |\n| `Shift+\u2192` | Move current column right |\n\n#### Data Management\n\n| Key | Action |\n|-----|--------|\n| `f` | Freeze rows and columns |\n| `c` | Copy current cell to clipboard |\n| `Ctrl+S` | Save current tab to CSV/TSV file |\n| `u` | Undo last action |\n| `U` | Reset to original data |\n\n#### Modal Interactions\n\n**In Frequency Distribution Modal** (opened with `F`):\n- `[` / `]` - Sort frequency table\n- `v` - Filter main table to selected value\n- `\"` - Highlight rows with selected value\n- `q` / `Escape` - Close modal\n\n**In Row Detail Modal** (opened with `Enter`):\n- `v` - Filter main table to selected column value\n- `\"` - Highlight rows with selected column value\n- `q` / `Escape` - Close modal\n\n**Tip**: Press `?` or `h` to open the context-sensitive help panel which displays all available shortcuts based on your current focus.\n\n## Features in Detail\n\n### 1. Color-Coded Data Types\n\nColumns are automatically styled based on their data type:\n- **Int64** (Integers): Cyan text, right-aligned\n- **Float64** (Decimals): Magenta text, right-aligned\n- **String**: Green text, left-aligned\n- **Boolean**: Blue text, centered\n- **Date/Datetime**: Blue text, centered\n\n### 2. Row Detail View\n\nPress `Enter` on any row to open a modal showing all column values for that row. Useful for examining wide datasets where columns don't fit on screen.\n\n**In the Row Detail Modal**:\n- Press `v` to **filter** the main table to show only rows with the selected column value\n- Press `\"` to **highlight** all rows containing the selected column value\n- Press `q` or `Escape` to close the modal\n\n### 3. Search & Filtering\n\n**Column Search** (`|`):\n- Search for values in the current column\n- Case-insensitive substring matching\n- All matching rows are highlighted in red\n- Multiple searches accumulate selections\n\n**Global Search** (`/`):\n- Search for a term across all columns simultaneously\n- Cell-level highlighting in red for each matching cell\n- Useful for finding a value anywhere in the dataset\n- Automatically loads rows if matches extend beyond visible area\n- Type-aware matching: converts values to strings before comparing\n\n**Cell-Value Search** (`\\`):\n- Automatically search using the current cell's value\n- Quick way to find all occurrences of a value\n\n**Row Filtering** (`\"`):\n- Display only the selected (highlighted) rows\n- Other rows are hidden but preserved\n- Use undo (`u`) to restore\n\n### 4. Filter by Expression\n\nPress `f` to open a powerful filter expression dialog. This allows you to write complex filter conditions using a special syntax:\n\n**Column References:**\n- `$_` - Current column (based on cursor position)\n- `$1`, `$2`, etc. - Column by 1-based index\n- `$age`, `$salary` - Column by name\n\n**Operators:**\n- Comparison: `==`, `!=`, `<`, `>`, `<=`, `>=`\n- Logical: `&&` (AND), `||` (OR)\n- Arithmetic: `+`, `-`, `*`, `/`, `%`\n\n**Examples:**\n- `$_ > 50` - Current column greater than 50\n- `$salary >= 100000` - Salary at least 100,000\n- `$age < 30 && $status == 'active'` - Age less than 30 AND status is active\n- `$name == 'Alice' || $name == 'Bob'` - Name is Alice or Bob\n- `$salary / 1000 >= 50` - Salary divided by 1,000 is at least 50\n\nSee [FILTER_EXPRESSION_GUIDE.md](FILTER_EXPRESSION_GUIDE.md) for comprehensive syntax documentation.\n\n### 5. Sorting\n\n- Press `[` to sort current column ascending\n- Press `]` to sort current column descending\n- Multi-column sorting supported (press multiple times on different columns)\n- Press same key twice to toggle direction\n- Frequency view (`F`) shows value distribution with optional sorting\n\n### 6. Frequency Distribution\n\nPress `F` to see how many times each value appears in the current column. The modal shows:\n- Value\n- Count\n- Percentage of total\n- **Total row** at the bottom\n\n**In the Frequency Table**:\n- Press `[` and `]` to sort by any column (value, count, or percentage)\n- Press `v` to **filter** the main table to show only rows with the selected value\n- Press `\"` to **highlight** all rows containing the selected value\n- Press `q` or `Escape` to close the frequency table\n\nThis is useful for:\n- Understanding value distributions\n- Quickly filtering to specific values\n- Identifying rare or common values\n- Finding the most/least frequent entries\n\n### 7. Data Editing\n\n**Edit Cell** (`e`):\n- Opens modal for editing current cell\n- Validates input based on column data type\n- Shows column name and type\n- Integer, number, and text inputs available\n\n**Delete Row** (`d`):\n- Delete single row at cursor\n- Or delete all selected rows at once\n- Deleted rows are marked internally but kept for undo\n\n**Delete Column** (`-`):\n- Removes the entire column from view and dataframe\n- Cannot be undone directly (use undo feature)\n\n### 8. Column & Row Reordering\n\n**Move Columns**: `Shift+\u2190` and `Shift+\u2192`\n- Swaps adjacent columns\n- Reorder is preserved when saving\n\n**Move Rows**: `Shift+\u2191` and `Shift+\u2193`\n- Swaps adjacent rows\n- Visual reordering without affecting data\n\n### 9. Pin Rows and Columns\n\nPress `f` to open the pin dialog:\n- Enter number of fixed rows: keeps top rows visible while scrolling\n- Enter two numbers: `<rows> <columns>` (space-separated)\n- Example: `2 3` pins top 2 rows and left 3 columns\n\n### 10. Save to CSV\n\nPress `Ctrl+S` to save:\n- Save filtered, edited, or sorted data back to CSV\n- Choose filename in modal dialog\n- Confirm if file already exists\n- Automatic .tsv or .csv detection\n\n### 11. Undo/Redo\n\nPress `u` to undo:\n- Reverts last action with full state restoration\n- Works for edits, deletions, sorts, searches, etc.\n- Shows description of reverted action\n\n### 12. Cursor Type Cycling\n\nPress `C` to cycle through selection modes:\n1. **Cell mode**: Highlight individual cell (and its row/column headers)\n2. **Row mode**: Highlight entire row\n3. **Column mode**: Highlight entire column\n\nVisual feedback shows which mode is active.\n\n### 13. Clipboard Operations\n\nPress `c` to copy:\n- Copies current cell value to system clipboard\n- Works on macOS (`pbcopy`) and Linux (`xclip`)\n- Shows confirmation notification\n\n## Data Type Support\n\n- **Int64, Int32, UInt32**: Integer values\n- **Float64, Float32**: Decimal numbers (shown with 4 significant figures)\n- **String**: Text data\n- **Boolean**: True/False values\n- **Date**: ISO date format (YYYY-MM-DD)\n- **Datetime**: ISO datetime format\n- **Null values**: Displayed as `-`\n\n## Examples\n\n### Single File Examples\n\n```bash\n# View Pokemon dataset\ndataframe-textual pokemon.csv\n\n# View Titanic dataset with analysis\ndataframe-textual titanic.csv\n\n# Filter and view specific columns\ncut -d',' -f1,2,3 pokemon.csv | dataframe-textual\n\n# View with grep filter (then use | search in viewer)\ngrep \"Fire\" pokemon.csv | dataframe-textual\n\n# Chain with other commands\ncat data.csv | sort -t',' -k2 | dataframe-textual\n```\n\n### Multi-File Examples\n\n```bash\n# Compare two versions of a dataset\ndataframe-textual pokemon_v1.csv pokemon_v2.csv\n\n# Side-by-side analysis of related files\ndataframe-textual sales_2022.csv sales_2023.csv forecast_2024.csv\n\n# Cross-reference datasets\ndataframe-textual customers.csv orders.csv products.csv\n\n# Start with one file, open others using Ctrl+O\ndataframe-textual initial_data.csv\n# Then press Ctrl+O to open more files interactively\n```\n\n### Advanced Workflows\n\n```bash\n# Start with a filtered file, compare with original\ngrep \"status=active\" data.csv > filtered.csv\ndataframe-textual data.csv filtered.csv\n# Now compare the full dataset with the filtered version in separate tabs\n\n# Multi-step analysis\n# 1. Open multiple related CSVs\n# 2. Use Ctrl+O to open additional files as you discover relationships\n# 3. Each tab maintains independent sort/filter/search state\n# 4. Use Ctrl+W to close tabs when done analyzing\n```\n\n## Performance\n\n- **Lazy loading**: Only loads visible rows + 10 rows ahead\n- **Efficient sorting**: Uses Polars' optimized sort algorithms\n- **Smooth scrolling**: No lag when paging through large files\n- **Memory efficient**: Handles datasets larger than RAM\n\nTested with:\n- 10,000+ row CSV files\n- Wide datasets (100+ columns)\n- Various data types and sizes\n\n## Dependencies\n\n- **polars**: Fast DataFrame library for CSV processing\n- **textual**: Terminal UI framework\n- **rich**: Rich text and formatting in the terminal\n\n## Architecture Overview\n\n### Single-Table Design\n\nThe core of the application is built around the `DataFrameTable` widget:\n\n- **Self-contained**: Each table instance maintains its own complete state (13 independent variables)\n- **Fully autonomous**: All operations (editing, sorting, filtering, searching) are handled within the table\n- **Event-driven**: Each table owns and handles its keyboard events\n- **Backward compatible**: Works identically in single-file mode\n\n### Multi-Table Design\n\nThe `DataFrameApp` coordinates multiple independent `DataFrameTable` instances:\n\n- **Tab-based interface**: Uses Textual's `TabbedContent` for tab management\n- **Independent state**: Each tab has completely separate state (sort order, selections, history)\n- **Seamless switching**: Switch between files without losing context or state\n- **File management**: Open/close files dynamically without restarting the application\n\n### State Isolation\n\nEach `DataFrameTable` instance owns:\n- DataFrame (`self.df`)\n- Sorted columns (`self.sorted_columns`)\n- Selected rows (`self.selected_rows`)\n- Edit history (`self.histories`)\n- Cursor state (position, type)\n- Search/filter state\n- And 8 more internal state variables\n\nThis ensures perfect isolation between tabs with zero cross-contamination.\n\n## Requirements\n\n- Python 3.11+\n- POSIX-compatible terminal (macOS, Linux, WSL)\n- Terminal supporting ANSI escape sequences and mouse events\n\n## Acknowledgments\n\n- Inspired by [VisiData](https://visidata.org/)\n- Built with [Textual](https://textual.textualize.io/), [Polars](https://www.pola.rs/), and [Rich](https://rich.readthedocs.io/)\n- All code created through iterative development\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Interactive CSV/Excel viewer for the terminal (Textual TUI)",
"version": "0.3.2",
"project_urls": {
"Bug Tracker": "https://github.com/need47/dataframe-textual/issues",
"Documentation": "https://github.com/need47/dataframe-textual#readme",
"Homepage": "https://github.com/need47/dataframe-textual",
"Repository": "https://github.com/need47/dataframe-textual.git"
},
"split_keywords": [
"csv",
" data-analysis",
" excel",
" interactive",
" polars",
" terminal",
" textual",
" tui",
" viewer"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "3742614f7d7722bc207d69c3d8f9a7ed6fa359ec0c1eb4822c4a65119aaaa520",
"md5": "0f346025d1a0f13f148be996ea39ef1f",
"sha256": "e368576f63627f1e91101fd93b08786c7981d54174c9423308362b54473394c3"
},
"downloads": -1,
"filename": "dataframe_textual-0.3.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0f346025d1a0f13f148be996ea39ef1f",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 34853,
"upload_time": "2025-11-03T01:42:49",
"upload_time_iso_8601": "2025-11-03T01:42:49.958155Z",
"url": "https://files.pythonhosted.org/packages/37/42/614f7d7722bc207d69c3d8f9a7ed6fa359ec0c1eb4822c4a65119aaaa520/dataframe_textual-0.3.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "c3d6cd9324f259efefb668a3d52240cdb736e20780ac231b11cedca22e3977b8",
"md5": "52d3d7ac2828516d708f0efcca86cc7d",
"sha256": "d9ada17715c5e07da0767dcd42315ea77f75810de2cfcf2cc420c6dc7c71c3dc"
},
"downloads": -1,
"filename": "dataframe_textual-0.3.2.tar.gz",
"has_sig": false,
"md5_digest": "52d3d7ac2828516d708f0efcca86cc7d",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 1075493,
"upload_time": "2025-11-03T01:42:51",
"upload_time_iso_8601": "2025-11-03T01:42:51.304912Z",
"url": "https://files.pythonhosted.org/packages/c3/d6/cd9324f259efefb668a3d52240cdb736e20780ac231b11cedca22e3977b8/dataframe_textual-0.3.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-11-03 01:42:51",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "need47",
"github_project": "dataframe-textual",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "dataframe-textual"
}