Generate interactive, self-contained SVG charts from CSV data. All chart rendering happens in the browser using embedded JavaScript.
- Self-contained: No external dependencies, charts work offline
- Pure Browser Rendering: All chart generation happens client-side via embedded JavaScript
- Multiple Chart Types: Scatter plots and histograms with more types coming
- Dynamic & Interactive: Live chart type switching, axis selection, hover highlighting
- Data Filtering: Interactive filtering with multiple operators and real-time updates
- Programmable: Embedded JavaScript API for real-time chart manipulation
- Professional: Clean tick marks, grid lines, and human-readable axis labels
- Extensible: Modular architecture makes adding new chart types simple
- Command-line: Simple CLI interface with sensible defaults
- Minimal Server Footprint: Node.js only creates the SVG container (71 lines)
# Install dependencies
npm install
# Generate a scatter plot
node src/cli.js -x n_depth -y avg_ts -g model data/qwen30b3a_q3.csv > scatter.svg
# Generate a histogram
node src/cli.js -t histogram -f model data/qwen30b3a_q3.csv > histogram.svg
# Generate a numeric histogram with custom bins
node src/cli.js -t histogram -f avg_ts -b 15 data/qwen30b3a_q3.csv > numeric_histogram.svg
svgc [options] <csv-file>
Options:
-w, --width <pixels> Chart width (default: 800)
-h, --height <pixels> Chart height (default: 600)
-o, --output <file> Output SVG file (default: stdout)
-t, --type <type> Chart type: scatter, histogram (default: scatter)
Scatter chart options:
-x, --x-field <field> Field to use for X axis
-y, --y-field <field> Field to use for Y axis
-s, --size-field <field> Field to use for point sizes (optional)
-g, --group-field <field> Field to use for grouping/colors (optional)
Histogram options:
-f, --field <field> Field to use for histogram
-b, --bins <count> Number of bins for numeric data (default: auto)
Other options:
--debug Enable debug logging in generated SVG
--help Show help message
The included sample data shows LLM performance benchmarks. Here are different ways to visualize this data:
node src/cli.js -x n_depth -y avg_ts -g model data/qwen30b3a_q3.csv > examples/performance.svg
Creates an interactive scatter plot showing how different model quantizations (Q2_K, Q3_K, Q4_K, etc.) perform across various context depths.
node src/cli.js -t histogram -f model data/qwen30b3a_q3.csv > examples/model_distribution.svg
Creates a bar chart showing the count of each model type in the dataset.
node src/cli.js -t histogram -f avg_ts -b 20 data/qwen30b3a_q3.csv > examples/performance_dist.svg
Creates a histogram showing the distribution of throughput values with 20 bins.
- Chart Type Selector: Switch between scatter plots and histograms in real-time
- Axis Selection Dropdowns: Interactive dropdowns to change X and Y axis fields (scatter plots)
- Field Selection: Choose which field to visualize in histograms
- Bin Count Control: Adjust the number of bins for numeric histograms
- Group Selection: Choose grouping field from available columns, including "None" option
- Data Filtering: Add multiple filters to show/hide data points based on field values
- HTML Integration: Native HTML controls embedded via
foreignObject
for optimal usability
- Legend Interaction: Hover to highlight, click to hide/show data groups
- Real-time Filtering: Add filters like
model != 'Q8_K_ZL'
orn_depth > 1000
- Multiple Filter Support: Combine multiple conditions with AND logic
- Smart Operators:
=
,!=
,>
,<
,>=
,<=
,contains
,starts with
,ends with
- Type-aware Filtering: Automatically handles numeric vs string comparisons
- Visual feedback with checkboxes and smooth transitions
Once generated, charts can be modified programmatically:
// Change X axis to a different field
changeAxis('x', 'model_size');
// Change Y axis
changeAxis('y', 'stddev_ts');
// Update multiple options at once
updateChart({
xField: 'n_gen',
yField: 'avg_ts',
groupField: 'model_type'
});
- Smart axis ticks: Clean intervals (1, 2, 2.5, 5 × 10^k)
- Grid lines: Subtle dotted guides for easy value reading
- Tick marks: Visual indicators on axes
- Range filtering: Only shows ticks within data bounds
# Install dependencies (runtime only)
npm install --production
# Install all dependencies (including testing tools)
npm install
# Run unit tests
npm test
# Run integration tests (requires puppeteer)
npm run test:integration
# Run all tests
npm run test:all
# Generate example charts
node src/cli.js -x n_depth -y avg_ts -g model data/qwen30b3a_q3.csv > chart.svg
The project includes comprehensive testing:
- Unit Tests: Test CSV parsing and embedded chart functions using a mock browser environment
- Integration Tests: Test generated SVG files in a real browser using Puppeteer
- Embedded Testing: Direct testing of browser-side JavaScript via
embedded-test-helper.js
For users (runtime only):
npm install --production # Only installs csv-parse
For developers (with testing):
npm install # Installs puppeteer for browser testing
npm run test:all # Run complete test suite
Integration tests:
- Load generated SVG files in headless Chrome
- Detect JavaScript errors and runtime issues
- Verify core functionality and DOM structure
- Validate that charts render properly in browsers
This project uses a pure embedded rendering approach:
- Node.js Role: Only creates the SVG container and embeds data/JavaScript
- Browser Role: All chart rendering happens client-side
- Zero Server-side Chart Logic: No chart generation on the server
- Self-contained Output: Generated SVGs work offline without any dependencies
src/
├── cli.js # Command-line interface (HOST)
├── csv.js # CSV parsing with type inference (HOST)
├── svg.js # SVG generation coordinator (HOST)
├── embedded-loader.js # Manages embedding process (HOST)
├── embedded/ # Code that gets embedded into SVGs (EMBEDDED)
│ ├── chart-utils.js # Chart utility functions
│ ├── filter-utils.js # Data filtering utilities
│ ├── filters.js # Filter management functions
│ ├── interactivity.js # Event handling, public API, initialization
│ ├── render-ui.js # UI rendering functions
│ ├── ui-components.js # UI component creation functions
│ └── charts/ # Chart-specific implementations
│ ├── histogram-chart.js # Histogram chart implementation
│ └── scatter-chart.js # Scatter plot implementation
└── generators/ # Server-side SVG utilities (HOST)
└── svg-elements.js # CSS and SVG markup generation
test/ # Testing environment (TEST)
├── embedded-test-helper.js # Mock browser environment
└── *.test.js # Unit and integration tests
The codebase has three distinct execution environments:
- HOST Context (Node.js): Files marked
(HOST)
run during SVG generation - EMBEDDED Context (Browser): Files in
src/embedded/
run inside generated SVGs - TEST Context (Node.js): Test files run with mock browser environment
Key Benefits:
- Clear Separation: Distinct boundaries between build-time and runtime code
- Pure Client-side Rendering: All charts generated in the browser
- Testable Embedded Code: Chart logic in separate files, not strings
- Minimal Build Process: Simple file loading and syntax stripping
- Easy Extension: Add new charts by creating embedded modules only
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass:
npm run test:all
- Submit a pull request
The CI pipeline will automatically:
- Unit Tests: Run on Node.js 18.x, 20.x, and 22.x
- Integration Tests: Validate generated SVGs in headless browsers
- Code Quality: Check syntax, file structure, and package validity
- Chart Generation: Create multiple test charts and validate browser compatibility
- Artifacts: Upload generated charts and logs for inspection (30-day retention)