bookmark - UI P1 Polishing

This commit is contained in:
2026-04-10 15:59:59 -04:00
parent 7efea55ddc
commit 1617ee94b9
7 changed files with 661 additions and 269 deletions

View File

@@ -2,8 +2,8 @@
**Date:** 2026-04-10
**Version:** 0.1.0
**Tests:** 136 passing, 0 warnings
**Source:** ~6,900 lines Python | ~1,600 lines tests | ~190 lines HTML templates
**Tests:** 171 passing
**Source:** ~9,200 lines Python | ~1,900 lines tests | ~3,400 lines web (py+js+css) | ~190 lines HTML templates
**Tooling:** uv (Python 3.12.12), hatchling build backend
---
@@ -13,7 +13,7 @@
```bash
cd /Users/noise/Code/impakt
uv sync --dev # install all dependencies
uv run pytest tests/ # run all 136 tests
uv run pytest tests/ # run all 171 tests
uv run impakt info tests/mme_data/3239 # show test metadata
uv run impakt serve tests/mme_data/3239 # launch web UI on :8050
```
@@ -33,6 +33,7 @@ s.plot("11HEAD0000H3ACXP", "11HEAD0000H3ACYP", "11HEAD0000H3ACZP", cfc=1000)
impakt/
pyproject.toml # PEP 621 + uv dependency-groups
uv.lock # lockfile
.gitignore
README.md # Architecture docs with 16 Mermaid diagrams
BRAINSTORM.md # 80+ feature ideas
docs/
@@ -40,7 +41,7 @@ impakt/
src/impakt/
__init__.py # exports Session, Template
channel/ # Data model layer
code.py # ISO channel code parser (14-char + 16-char)
code.py # ISO channel code parser (14-char + 16-char auto-detect)
model.py # Channel, ChannelGroup, TestData, TestMetadata
group.py # Auto-grouping utilities
lookup.py # ISO naming lookup tables (150+ entries)
@@ -67,7 +68,7 @@ impakt/
euro_ncap.py # Euro NCAP (color/points/stars, versioned)
us_ncap.py # US NCAP (injury probability/stars)
iihs.py # IIHS (G/A/M/P)
plot/ # Visualization
plot/ # Visualization engine
engine.py # PlotEngine (Plotly), cursor_values()
spec.py # PlotSpec, ChannelRef, Corridor, CursorValues
cursor.py # Dual X-cursor logic
@@ -83,9 +84,29 @@ impakt/
injury_summary.html
protocol_report.html
web/ # Dash web application
app.py # create_app(), serve()
layout.py # build_layout() -- UI structure
callbacks.py # register_callbacks() -- interactivity
app.py # App factory: create_app(), serve()
state.py # AppState: server-side multi-test state manager
layout.py # Top-level layout: tabs, flex splitter, component assembly
components/ # Reusable layout components
header.py # Navbar, test info panel, open/overlay modals
channel_grid.py # Flat sortable DataTable with wildcard filter + facets
transforms.py # CFC/align/resultant control panel
plot_grid.py # Multi-pane plot area (1x1, 2x1, 1x2, 2x2, 3x1)
cursors.py # Cursor values grid (live hover + X1/X2 locked)
criteria.py # Auto-compute criteria, protocol scoring, results display
report.py # Export panel (PNG/SVG/PDF, CSV, protocol report)
callbacks/ # Feature-specific callback modules
__init__.py # Registration hub: register_callbacks()
channel_callbacks.py # Channel selection, filtering, badge display
plot_callbacks.py # Plot rendering, transform pipeline
cursor_callbacks.py # Live cursor grid updates via polled JS hover
criteria_callbacks.py # Compute All button, protocol scoring
file_callbacks.py # Open test / add overlay modals
export_callbacks.py # CSV export, report generation
assets/ # Browser-side static files
style.css # Custom CSS (compact layout, splitter, scrollbars)
splitter.js # Draggable panel splitter (pure JS, no deps)
cursor_tracker.js # Live cursor tracking (mousemove -> pixel-to-data-X)
plugin/ # Plugin system
registry.py # PluginRegistry, discovery (entrypoints + dir)
script/ # Scripting API + CLI
@@ -100,6 +121,7 @@ impakt/
test_io/ # MMEReader
test_protocol/ # Euro NCAP scoring
test_transform/ # CFC filter, alignment
test_web/ # AppState, app creation, channel grid, criteria auto-compute
fixtures/
generate_mme.py # Synthetic MME generator (26 channels, half-sine)
sample_mme/ # Generated synthetic test data
@@ -116,21 +138,21 @@ impakt/
## What Works
### Fully implemented and tested:
### All modules fully implemented and tested:
| Module | Status | Notes |
|---|---|---|
| **Channel code parser** | Complete | Auto-detects 14-char (no dummy) vs 16-char (with dummy H3/P3/PC). Handles real-world codes from NHTSA, BASt, VW, UTAC. |
| **Channel model** | Complete | Immutable channels, auto-grouping X/Y/Z, resultant computation, hierarchical tree builder. |
| **MME reader** | Complete | Two-format support: (1) Real ISO 13499 (.mme + .chn index + .NNN data files), (2) simplified INI format. Tested against 5 real datasets. |
| **CFC filtering** | Complete | SAE J211 compliant. 4th-order Butterworth, zero-phase (filtfilt). All 4 CFC classes. |
| **Channel code parser** | Complete | Auto-detects 14-char (no dummy) vs 16-char (with dummy H3/P3/PC). |
| **Channel model** | Complete | Immutable channels, auto-grouping X/Y/Z, resultant computation. |
| **MME reader** | Complete | Real ISO 13499 (.mme + .chn index + .NNN data files) + simplified INI. Tested against 5 real datasets. |
| **CFC filtering** | Complete | SAE J211 compliant. 4th-order Butterworth, zero-phase. All 4 CFC classes. |
| **Alignment transforms** | Complete | X-align (manual/threshold/trigger), Y-align (baseline window). |
| **Resultant** | Complete | From ChannelGroup or arbitrary channels. |
| **Math expressions** | Complete | Safe eval with numpy functions. |
| **HIC** | Complete | HIC15/HIC36, cumulative integration, optimal window search. |
| **3ms clip** | Complete | Cumulative exceedance method. |
| **Nij** | Complete | 4 modes (NTE/NTF/NCE/NCF), per-dummy intercepts (H3 50M/5F/95M, child dummies). |
| **Chest deflection** | Complete | Peak sternal displacement. |
| **Nij** | Complete | 4 modes (NTE/NTF/NCE/NCF), per-dummy intercepts. |
| **Chest deflection** | Complete | Peak sternal displacement with unit/sanity validation. |
| **Viscous criterion** | Complete | V(t)*C(t) with chest depth per dummy type. |
| **Femur load** | Complete | Left/right, unit conversion. |
| **Tibia index** | Complete | M/Mc + F/Fc with intercepts. |
@@ -139,48 +161,70 @@ impakt/
| **IIHS** | Complete | G/A/M/P per body region, worst-case overall. |
| **Plot engine** | Complete | Plotly rendering, corridors, cursor values, export. |
| **Template model** | Complete | YAML serialize/deserialize, library manager, session persistence. |
| **Report engine** | Complete | HTML+WeasyPrint PDF, 3 Jinja2 templates. Falls back to HTML if WeasyPrint unavailable. |
| **Report engine** | Complete | HTML+WeasyPrint PDF, 3 Jinja2 templates. |
| **Plugin registry** | Complete | Entry point + directory + API discovery. |
| **CLI** | Complete | `impakt serve/info/channels/evaluate`. |
| **Web UI** | Minimal | Basic Dash app: flat channel list, single CFC dropdown, cursor inputs. Functional but needs major overhaul. |
| **Web UI** | **Functional** | See details below. |
### Key design decisions already made:
### Web UI -- Current State
The web UI has been through a major overhaul and is now functional for daily use:
**Layout:**
- Two tabs: **Data** (channels + plot + cursor grid) and **Analysis** (criteria + export)
- Draggable splitter between left panel and plot area (pure JS, no deps)
- Left panel resizable from 200px to 600px
**Channel Grid (left panel):**
- Flat sortable DataTable showing: #, ISO Code, Description, Unit, Min, Max
- Wildcard filter bar (`*HEAD*AC*`, `11*FO*Z*`, or partial text auto-wrapped)
- Facet dropdowns: body region, measurement type, direction
- Multi-select checkboxes, selected channels shown as color-coded badges
- Columns sortable and resizable (CSS resize)
**Plot Area (right side):**
- Multi-pane layout presets (1x1, 2x1, 1x2, 2x2, 3x1)
- Transform controls: CFC filter, Y-align, X-align (manual/threshold), resultant toggle
- X1/X2 reference lines drawn on plot (red dashed / blue dashed)
**Cursor Values Grid (below plot):**
- Live updating: vertical crosshair and cursor values track mouse movement anywhere in plot area
- Custom JS cursor tracker (mousemove -> Plotly axis p2d/p2l -> data coordinates)
- Polled via dcc.Interval (80ms) -> clientside callback -> server-side interpolation
- Columns: Channel, Unit, Cursor (live), X1 (locked), X2 (locked)
**Analysis Tab:**
- Auto-detect channels by ISO naming and compute HIC15, 3ms clip, Nij, chest defl, femur, tibia
- Protocol scoring: Euro NCAP / US NCAP / IIHS with color-coded results table and star ratings
- CSV export of plotted channel data (with transforms applied)
- Protocol report generation (HTML)
**File Management:**
- Open Test / Add Overlay buttons with modal dialogs
- Test info panel showing all loaded tests with metadata
- Multi-test support in channel grid and plot labels
### Key design decisions:
1. **Immutable channels** -- transforms return new Channel objects; raw data never modified.
2. **`.impakt/` subfolder** -- session state stored alongside test data, not in a central DB.
3. **Template/session split** -- templates are global recipes; sessions are per-test instances with overrides.
4. **Two MME format variants** -- real ISO 13499 and simplified INI. Reader auto-detects.
5. **16-char channel codes** -- positions 11-12 can be dummy type (H3/P3/PC) or measurement type; parser auto-detects.
6. **uv for package management** -- dev deps in `[dependency-groups]`, lockfile committed.
2. **`.impakt/` subfolder** -- session state stored alongside test data.
3. **Template/session split** -- templates are global recipes; sessions are per-test instances.
4. **AppState is server-side** -- numpy arrays stay in Python memory; Dash stores hold only lightweight keys.
5. **Channel keys use `test_id::channel_name`** -- enables multi-test overlay.
6. **Custom JS cursor tracking** -- bypasses Plotly's hover system (which only fires near data points) with raw mousemove + pixel-to-data conversion using Plotly's internal axis API.
7. **uv for package management** -- dev deps in `[dependency-groups]`.
---
## What Needs Building Next: Web UI Overhaul
## Next Steps (Priority 2)
The web UI is the top priority. Current state is a proof-of-concept; needs to become a daily-use tool. The planned features, in priority order:
These are the next features to build, now that Priority 1 is complete:
### Priority 1 -- Must have for the tool to be usable
1. **File/test management** -- open test from UI (path input), open additional tests for overlay, recent tests list, test metadata panel
2. **Proper channel tree** -- collapsible hierarchy (Object > Region > Measurement), select-all per group, preview (peak, unit, rate), color indicators for plotted channels, multi-test awareness
3. **Multi-pane plot layout** -- configurable grid (1x1 through 3x2), drag channels to panes, independent zoom with optional sync, per-pane axis labels
4. **Working criteria panel** -- auto-detect channels from ISO naming, compute all criteria, results table with pass/fail colors, click to highlight time window on plot
5. **Plot export** -- download PNG/SVG/PDF per pane, copy to clipboard, export CSV of plotted data
### Priority 2 -- Makes the tool genuinely productive
6. **Template management UI** -- template browser, apply/save/edit from UI, session auto-save
7. **Enhanced transform controls** -- per-channel CFC, X-align/Y-align controls, one-click resultant
8. **Corridor management** -- load from CSV, draw on plot, corridor library with templates
9. **Channel inspector** -- tabular data view, statistics (min/max/RMS/peak time), peak detection
10. **Math expression builder** -- formula input with autocomplete, variable binding dropdowns, live preview
### Priority 3 -- Differentiators
11. **Annotations** -- text on plots, measurement lines, highlight regions
12. **Comparison mode** -- side-by-side tests, delta plots, synced cursors
13. **Report builder** -- drag-and-drop report composer, PDF preview
14. **Keyboard shortcuts** -- Ctrl+O, Ctrl+S, 1-9 pane switch, F fullscreen, R reset zoom
1. **Template management UI** -- template browser, apply/save/edit from UI, session auto-save
2. **Enhanced transform controls** -- per-channel CFC, per-channel X/Y-align
3. **Corridor management** -- load from CSV, draw on plot, corridor library
4. **Channel inspector** -- tabular data view, statistics (min/max/RMS/peak time)
5. **Math expression builder** -- formula input with autocomplete, live preview
---
@@ -189,11 +233,11 @@ The web UI is the top priority. Current state is a proof-of-concept; needs to be
| Dataset | Lab | Type | Channels | Good for testing |
|---|---|---|---|---|
| `fixtures/sample_mme/` | Synthetic | Frontal barrier | 26 | Unit tests, known values |
| `mme_data/3239/` | NHTSA/Calspan | Frontal barrier (VW Passat) | 133 | Full pipeline, real data, driver+rear passenger |
| `mme_data/AK3T02FO/` | BASt | Frontal 40% offset | 97 | Multi-occupant (driver, rear, child) |
| `mme_data/3239/` | NHTSA/Calspan | Frontal barrier (VW Passat) | 133 | Full pipeline, real data |
| `mme_data/AK3T02FO/` | BASt | Frontal 40% offset | 97 | Multi-occupant |
| `mme_data/AK3T02SI/` | BASt | Side impact | 97 | Side impact protocols |
| `mme_data/VW1FGS15/` | Volkswagen | Pedestrian headform | 10 | Impactor codes (D0), pre-computed resultant |
| `mme_data/98_7707/` | UTAC | Vehicle-to-vehicle | 0 | Metadata-only, graceful empty handling |
| `mme_data/VW1FGS15/` | Volkswagen | Pedestrian headform | 10 | Impactor codes (D0) |
| `mme_data/98_7707/` | UTAC | Vehicle-to-vehicle | 0 | Metadata-only |
---
@@ -207,8 +251,8 @@ Optional: nptdms (for future TDMS reader plugin)
## Known Issues / Technical Debt
1. **VehicleInfo.year parsed as 0** for real MME data (the .mme format doesn't have a vehicle_year field; it's embedded in the vehicle name string like "VOLKSWAGEN PASSAT 2000").
2. **Speed displayed as raw float** (e.g., 55.900001530350906 km/h) -- should round.
3. **report/pdf.py** referenced in `pyproject.toml` directory structure but doesn't exist as separate file (functionality is in `engine.py`).
4. **web/assets/** directory exists but is empty -- no custom CSS yet.
5. **No .gitignore** -- should exclude .venv/, __pycache__/, .pytest_cache/, .ruff_cache/, .impakt/ session dirs.
1. **VehicleInfo.year parsed as 0** for real MME data (.mme format embeds year in vehicle name string).
2. **Speed displayed as raw float** (55.900001530350906 km/h) -- should round.
3. **DataTable deprecation warning** -- Dash recommends migrating to dash-ag-grid. Functional for now.
4. **Cursor poll interval (80ms)** -- adds slight latency to cursor grid updates. Could use WebSocket for lower latency in future.
5. **Chest deflection auto-detect** skips DS channels with peak > 150mm (avoids steering column displacement). May miss some legitimate high-deflection data.