A PyQt6 desktop playground for exploring classic sorting algorithms through deterministic, step-by-step animation. Every frame comes from a concrete Step object emitted by the algorithm, making runs reproducible, exportable, and easy to replay for teaching or research.
Bubble Sort, then Quick Sort in the single visualizer, then Compare Mode racing two algorithms — all on the same 28-element dataset:
(Also available as img/demo.mp4 for full-resolution playback.)
Pick a workspace: one algorithm in depth, or two side by side.
The full workspace — categorised algorithm sidebar, transport bar, dataset/preset row, scrubbable timeline, live metric chips, narration, and a details pane driven by the algorithm registry.
Two algorithms racing the same dataset with synchronised transport, each pane carrying its own HUD of comparisons, swaps, writes, steps, and elapsed time.
View → High Contrast Mode switches the whole app to a light, accessible palette. Same frame as the single-visualizer shot above, retinted end to end:
A representative spread, each captured mid-run from the same seeded dataset so the highlight colours (compare / swap / pivot / merge / key / shift) are actually lit. All 13 registered algorithms are listed in the catalog below.
Bubble Sort — O(n²) adjacent swaps![]() |
Quick Sort — median-of-three pivots![]() |
Merge Sort — bottom-up merges![]() |
Radix Sort (LSD) — non-comparison digit passes![]() |
- Single Visualizer: One tab per algorithm with synced HUD, narration, export tools, theme toggle, and keyboard/mouse controls. Manual input fields automatically apply values 1.5 seconds after you stop typing.
- Compare Mode (Fixed!): Launch a dual-pane workspace from the launcher to evaluate two algorithms side by side. Recent fixes ensure proper synchronization and stepping behavior between both panes.
- Deterministic algorithm engine: Bubble, Insertion, Selection, Heap, Shell, Merge (bottom-up), Quick (median-of-three), Cocktail, Counting, Radix (LSD), Bucket, Comb, and a Timsort trace all register through a plugin system and emit strongly typed
Steprecords. - Reproducible data presets: Generate random, nearly-sorted, reverse, reverse-run, few-unique, or already-sorted datasets with a visible seed so anyone can recreate a run exactly.
- Instrumented playback: Stepping, scrubbing, and timed playback all derive from the same checkpointed replay buffer. You can always step backward or jump to any frame without drift.
- Export & benchmark suite: Export traces to CSV/JSON/PNG/GIF and run a batch benchmark that sweeps algorithms against the active dataset configuration and writes a CSV report.
- Metrics Verification Tool: New
scripts/dev/verify_metrics.pyallows offline verification of algorithm metrics including step counts, comparisons, swaps, and inversion counts. - Accessibility & persistence: Dark and high-contrast themes, tooltip theming, saved window geometry, FPS, presets, and the last custom array all round-trip through
QSettings. - Robust logging: A hardened
sys.excepthookwrites to a rotating log viaplatformdirs(if available) before surfacing runtime errors in the UI. - Comprehensive test suite: Over 30 test files covering UI components, algorithm correctness, keyboard shortcuts, replay determinism, export serialization, and property-based testing with Hypothesis.
- Python 3.10 or newer
- Qt runtime (bundled automatically via
PyQt6) - macOS, Windows, or Linux desktop environment
Clone the repository, then choose one of the following setup paths:
# macOS / Linux
./scripts/setup.sh:: Windows
scripts\setup.batBoth scripts create .venv/, activate it temporarily, and install requirements.txt.
Prefer manual setup? Run the equivalent commands yourself:
python -m venv .venv
source .venv/bin/activate # .venv\Scripts\activate on Windows
pip install -r requirements.txtFrom the project root, choose one of these methods:
Option A: Direct launch (requires manual venv activation)
python main.pyOption B: Automated launch script (handles venv and dependencies automatically)
# macOS / Linux
./scripts/run.sh
# Or use the Python version (cross-platform)
python scripts/run.pyThe automated scripts (run.sh and run.py) will create the virtual environment if needed, install/update dependencies, and launch the app—ideal for quick development.
You will land on the launcher window:
- Single Visualizer loads the production-ready tabbed workspace.
- Compare Mode opens a dual-pane view to compare different algorithms' runtimes against each other.
- Enter comma-separated integers in the input field (numbers are automatically applied 1.5 seconds after you stop typing) or click Generate to use the active preset/seed.
- Use Start, Step ▶, Step ◀, the timeline slider, or keyboard shortcuts to navigate. Every action replays the canonical
Stepsequence—no frame skipping. - Toggle Show values at small
nto annotate each bar. - Click Export to choose CSV, JSON, PNG, or GIF. PNG renders the current canvas. GIF synthesizes the animation from captured frames; you must play through the run first.
- Hit Benchmark to produce
benchmark.csvwith wall-clock timing for the active algorithm (three sequential seeds per preset, including any custom array). - The Details pane surfaces algorithm notes, complexity tables, and metadata pulled from the registry.
- Launch two algorithms side by side for direct comparison
- Synchronized playback controls affect both panes simultaneously
- Independent algorithm selection for each pane
- Shared dataset configuration ensures fair comparison
- Fixed stepping behavior ensures both algorithms advance in sync
- Perfect for teaching algorithm efficiency differences
- View → High Contrast Mode switches to a light theme
- View → Show Debug Panel reveals live internals (player state, timers, recent steps) for the active tab
- Auto-apply input with 1.5-second debouncing prevents accidental changes while typing
- Keyboard shortcuts for all major functions (Space for play/pause, Left/Right arrows for stepping, etc.)
| Algorithm | Category | Stable | In-place | Typical Complexity (best / avg / worst) | Notes |
|---|---|---|---|---|---|
| Bubble Sort | Comparison | ✓ | ✓ | O(n) / O(n²) / O(n²) | Early exit once no swaps occur; ideal baseline for demos. |
| Insertion Sort | Comparison | ✓ | ✓ | O(n) / O(n²) / O(n²) | Highlights key vs. shift operations with distinct colors. |
| Selection Sort | Comparison | ✗ | ✓ | O(n²) / O(n²) / O(n²) | Emits compare/swap pairs to visualize the selection process. |
| Heap Sort | Comparison | ✗ | ✓ | O(n log n) | Instrumented heapify and pop phases with pivot highlights. |
| Shell Sort | Comparison | ✗ | ✓ | O(n log n) average | Uses Pratt-inspired gap sequence; shows gap comparisons distinctly. |
| Merge Sort (BU) | Comparison | ✓ | ✗ | O(n log n) | Bottom-up merges with violet merge markers and auxiliary array snapshots. |
| Quick Sort | Comparison | ✗ | ✓ | O(n log n) / O(n log n) / O(n²) | Median-of-three pivot selection with pivot/bounds instrumentation. |
| Cocktail Shaker | Comparison | ✓ | ✓ | O(n) / O(n²) / O(n²) | Bi-directional pass emphasizes swap direction changes. |
| Comb Sort | Comparison | ✗ | ✓ | O(n log n) average | Gap shrink factor 1.3 with final bubble clean-up. |
| Counting Sort | Non-comparison | ✓ | ✗ | O(n + k) | Tracks histogram, prefix sums, and stable placements. |
| Radix Sort (LSD) | Non-comparison | ✓ | ✗ | O(d (n + k)) | Offsets negatives once then streams digit passes through Counting Sort. |
| Bucket Sort | Non-comparison | ✓ | ✗ | O(n) average / O(n²) worst | Normalizes values into buckets and sorts each with Python's Timsort. |
| Timsort Trace | Hybrid | ✓ | ✗ | O(n) / O(n log n) / O(n log n) | Replays Python's run-detection logic, merges, and galloping breakpoints. |
All algorithms emit immutable Step objects so the UI, export system, and property tests remain in lock-step. Replaying the recorded steps produces the exact sorted output you would get from sorted(data).
- Step model (
src/app/core/step.py): Defines the allowed operations (compare,swap,set,pivot,merge_mark, etc.) and enforces immutability for deterministic replay. - Algorithm registry (
src/app/algos/registry.py): Decorators register algorithms with metadata (stable,in_place, complexity notes, description).load_all_algorithms()eagerly imports every module so the UI and tests can enumerate them. - Visualizer base (
src/app/core/base.py): Contains the shared control bar, canvas rendering, checkpointed replay buffer, export/benchmark logic, preset management, narration, and log viewer hooks. Recent updates improve UI integration and input handling. - Player module (
src/app/core/player.py): Enhanced with proper state management and synchronization features for compare mode. - Presets (
src/app/presets/__init__.py): Central place for dataset generators. Each preset records its key, label, description, and generator callable. - UI layers:
ui_single/holds the production tabbed window (SuiteWindow) and hook-up for the debug dock and theme switching.ui_compare/houses the compare workspace with fixed synchronization and stepping logic.ui_shared/packages reusable widgets (pane HUD, theme helpers, constants, narration cards) with enhanced functionality.
- Core replay helpers (
src/app/core/player.py,replay.py,compare.py): Encapsulate forward/back stepping, GIF frame capture, and dual-pane synchronization. - Native experiments:
native/radix_simd.cppis a standalone NEON prototype for fast digit counting. It is not required for normal operation but documents future optimization ideas.
Install development tooling:
pip install -e .[dev]# Linting and formatting
ruff check src tests
black --check src tests
# Type checking
mypy src
# Run test suite
pytest
# Run specific test categories
pytest tests/test_compare_integration.py # Compare mode tests
pytest tests/test_export_serialization.py # Export functionality tests
pytest tests/test_ui_components.py # UI component testsThe new verify_metrics.py script allows offline verification of algorithm behavior:
# Run metrics verification for specific presets and seeds
python scripts/dev/verify_metrics.py --preset reverse_run --seed 34554345 34554346
# Output to CSV for analysis
python scripts/dev/verify_metrics.py --preset random --csv verify_test.csvThis tool helps validate that algorithms produce expected step counts, comparisons, swaps, and maintain deterministic behavior across runs.
tests/contains comprehensive test coverage:- Property-based checks using Hypothesis
- Deterministic replay validation
- Keyboard shortcut coverage
- Export serialization tests (recently updated)
- UI smoke tests
- Compare mode integration tests with full stepping verification
- Logs live under
~/Library/Logs/org.pysort/sorting-visualizer/on macOS or the platformdirs equivalent on other OSes - The app falls back to
./logs/if platformdirs is unavailable - Comprehensive error handling with rotating log files
- This README and inline code comments are the authoritative references
pysort-visualizer/ # Recently renamed from UI_UPDATE_PYSORT
├── main.py # Entry point that boots the PyQt6 application
├── src/
│ └── app/
│ ├── algos/ # Algorithm implementations + registry
│ │ ├── bubble.py # Recently enhanced with better instrumentation
│ │ ├── insertion.py # Updated with improved step tracking
│ │ └── ... # 14 total algorithm implementations
│ ├── core/ # Visualization engine, replay, exports
│ │ ├── base.py # Recently refactored for better UI integration
│ │ ├── player.py # Enhanced with compare mode fixes
│ │ └── ...
│ ├── presets/ # Dataset generators and metadata
│ ├── ui_single/ # Single visualizer window
│ ├── ui_compare/ # Compare mode (recently fixed!)
│ └── ui_shared/ # Reusable widgets with enhanced functionality
├── scripts/ # User-facing entry points
│ ├── setup.sh # macOS/Linux bootstrap (venv + pip install)
│ ├── setup.bat # Windows bootstrap (venv + pip install)
│ ├── run.sh # macOS/Linux automated launcher
│ ├── run.py # Cross-platform automated launcher
│ └── dev/ # Maintainer tooling (not needed to run the app)
│ ├── gate.py # Per-file pytest gate vs. a recorded baseline
│ ├── gate_baseline.json # The recorded baseline
│ ├── capture_media.py # Regenerates every README screenshot + demo video
│ ├── screenshot_wave2.py # Wave 2 both-themes render gate
│ └── verify_metrics.py # Offline metrics verification tool
├── tests/ # Comprehensive test suite (30+ test files)
├── img/ # README screenshots and demo media (generated)
├── docs/ # Roadmap, audits, supporting notes (not versioned)
├── native/radix_simd.cpp # Optional SIMD prototype
├── requirements.txt # Runtime dependencies
├── pyproject.toml # Build, lint, and type-check configuration
└── README.md # This file
- Fixed synchronization issues between dual panes
- Proper stepping behavior now ensures both algorithms advance correctly
- Enhanced state management for consistent playback
- Auto-apply input with 1.5-second debounce timer
- Prevents animation restart when sorted array is detected
- Better HUD display and input field state management
- Updated
base.pyandplayer.pyfor better UI integration - Enhanced
pane.pyin ui_shared for improved functionality - Removed deprecated
debug_controls.pymodule
- Added
verify_metrics.pyfor offline algorithm metrics verification - Supports CSV output for detailed analysis
- Validates step counts, comparisons, swaps, and inversions
- License: Educator Non-Commercial (see
LICENSE.txt). Contact the maintainer for commercial usage. - Maintainer: Justin Guida — justn.guida@snhu.edu
- Repository: https://github.com/jguida941/pysort-visualizer (formerly UI_UPDATE_PYSORT)
- Bug Reports: Please include exported step traces (
Export → CSV) and the RNG seed when reporting bugs.
Enjoy exploring the algorithms!








