|
| 1 | +# High-Performance CSV Plotter |
| 2 | + |
| 3 | +This project contains a React and TypeScript app for plotting large CSV datasets in the browser. |
| 4 | + |
| 5 | +Live app: [plotting.abdusabri.com](https://plotting.abdusabri.com/) |
| 6 | + |
| 7 | +## Overview |
| 8 | + |
| 9 | +- React 18 + TypeScript app built with Vite |
| 10 | +- Browser-based CSV upload and parsing |
| 11 | +- Web Worker-based parsing to keep the UI responsive during file loading |
| 12 | +- Sliding window playback with configurable start position, window size, update interval, and increment size |
| 13 | +- `uPlot`-based chart rendering with downsampling for large windows |
| 14 | +- Window-level `min`, `max`, `average`, and `variance` calculations |
| 15 | + |
| 16 | +## Prerequisites |
| 17 | + |
| 18 | +- Node.js: `22.14.0` or newer |
| 19 | +- npm: `10.9.2` or newer |
| 20 | + |
| 21 | +## Quick Start |
| 22 | + |
| 23 | +### 1. Install dependencies |
| 24 | + |
| 25 | +```bash |
| 26 | +npm install |
| 27 | +``` |
| 28 | + |
| 29 | +### 2. Start the development server |
| 30 | + |
| 31 | +```bash |
| 32 | +npm run dev |
| 33 | +``` |
| 34 | + |
| 35 | +The app runs at [http://localhost:5173](http://localhost:5173). |
| 36 | + |
| 37 | +### 3. Load a dataset |
| 38 | + |
| 39 | +Use the file picker in the app to load a local CSV file, or use the linked 2M-row sample file exposed in the UI. |
| 40 | + |
| 41 | +## Data Format |
| 42 | + |
| 43 | +The current parser expects a simple two-column numeric CSV: |
| 44 | + |
| 45 | +```csv |
| 46 | +0,12.4 |
| 47 | +1,12.9 |
| 48 | +2,11.7 |
| 49 | +``` |
| 50 | + |
| 51 | +- Each row should contain `x,y` |
| 52 | +- Rows that do not parse into numeric pairs are skipped |
| 53 | +- The parser does not currently support headers or column selection |
| 54 | + |
| 55 | +## Scripts |
| 56 | + |
| 57 | +| Script | Description | |
| 58 | +| :--------------------- | :--------------------------------------------------------------- | |
| 59 | +| `npm run dev` | Starts the Vite development server. | |
| 60 | +| `npm run build` | Runs TypeScript build checks and bundles the app for production. | |
| 61 | +| `npm run lint` | Runs ESLint. | |
| 62 | +| `npm run preview` | Serves the production build locally. | |
| 63 | +| `npm run format` | Formats the repository with Prettier. | |
| 64 | +| `npm run format:check` | Checks repository formatting without writing changes. | |
| 65 | + |
| 66 | +## Project Structure |
| 67 | + |
| 68 | +```text |
| 69 | +src/ |
| 70 | + App.tsx # Main page layout and top-level composition |
| 71 | + main.tsx # App entrypoint |
| 72 | + index.css # Global styles |
| 73 | + constants/ # Default plotting and playback settings |
| 74 | + types/ # Shared TypeScript types |
| 75 | + hooks/ |
| 76 | + useDataStream.ts # File loading, worker lifecycle, and progress state |
| 77 | + usePlotWindow.ts # Sliding window state and playback loop |
| 78 | + utils/ |
| 79 | + dataProcessor.ts # Window aggregates and downsampling logic |
| 80 | + workers/ |
| 81 | + csvParser.worker.ts # Chunked CSV parsing in a Web Worker |
| 82 | + components/ |
| 83 | + FileSelector.tsx # File upload and sample data entry point |
| 84 | + PlotControls.tsx # Window and playback controls |
| 85 | + DataPlot.tsx # uPlot chart wrapper |
| 86 | + Aggregates.tsx # Aggregate metrics display |
| 87 | + ui/ # Shared UI primitives |
| 88 | +``` |
| 89 | + |
| 90 | +## Implementation Notes |
| 91 | + |
| 92 | +- Vite, React, and TypeScript keep the app small and straightforward while still making the data flow easy to reason about. |
| 93 | +- `uPlot` and `uplot-react` are used for chart rendering because the app is centered on plotting large datasets efficiently. |
| 94 | +- Tailwind CSS and `shadcn/ui` are used for the controls and layout so the implementation can stay focused on the plotting behavior. |
| 95 | +- CSV parsing runs in [`src/workers/csvParser.worker.ts`](/home/abdu/dev/abdu-fe-data-plot/src/workers/csvParser.worker.ts), where the file is read in chunks and posted back to the main thread in batches. |
| 96 | +- The playback loop in [`src/hooks/usePlotWindow.ts`](/home/abdu/dev/abdu-fe-data-plot/src/hooks/usePlotWindow.ts) uses `requestAnimationFrame` while still respecting the configured update interval. |
| 97 | +- [`src/utils/dataProcessor.ts`](/home/abdu/dev/abdu-fe-data-plot/src/utils/dataProcessor.ts) calculates aggregates and downsampled chart data together for the active window. |
| 98 | + |
| 99 | +## Performance Notes |
| 100 | + |
| 101 | +- File parsing happens off the main thread, so loading large files does not block React rendering. |
| 102 | +- The worker reads the file in chunks instead of decoding the whole file in one synchronous pass. |
| 103 | +- The chart renders a downsampled view of the active window rather than every point in that window. |
| 104 | +- Aggregate metrics are calculated from the full active window, not from the downsampled subset. |
| 105 | +- In practice, the active window size is the main performance lever once the file has been loaded. |
| 106 | + |
| 107 | +## Limitations |
| 108 | + |
| 109 | +- The parser currently expects a narrow two-column numeric CSV format. |
| 110 | +- The full parsed dataset is kept in browser memory after loading. |
| 111 | +- Aggregate calculations are recomputed for each active window. |
0 commit comments