Dash App
The Dash interface exposes the entire InstaWell pipeline plus a layout designer, CSV upload, validation, and figure browser. This page walks through each card on the page and the architecture behind it.
Launching
pip install 'instawell[dash]'
instawell-dash --port 8060 --experiments-root experiments
# or python -m instawell.dash_app.app --port 9000--host, --port, --experiments-root, and --debug flags are optional; defaults remain 127.0.0.1, 8050, ./experiments, and disabled debug mode.
Experiment Browser
- Lists every experiment folder inside
experiments_root(defaults to./experiments). - The Refresh button re-scans the directory after you run a pipeline.
- Selecting an experiment locks the “New Experiment” and “Designer” cards to avoid mixing states; click Clear to re-enable them.
- After a pipeline run completes, the new experiment is auto-selected via a dedicated
last-pipeline-experimentstore (no fragile HTML parsing).
Layout Designer
Use the designer to create a layout from scratch or highlight wells present in a raw CSV.
- Supports 96/384-well plates.
- Hold Shift and click to build a multi-well selection; assign concentration, ligand, protein, buffer, and unit in one shot.
- Use Copy from Selected Well (enabled when exactly one filled well is selected) to pull the existing values back into the form – handy for making slight tweaks.
- New controls let you pick the layout separator (default
|) and empty placeholder (default^). Exported CSVs respect those characters, so they match the pipeline config. - Empty wells are filled with the placeholder mask (e.g.,
^|^|^|^) to keep parsing consistent.
New Experiment Card
- Upload Raw/Layout CSVs – Drag/drop or click; both are required for validation.
- Configure Parsing Options
- Condition separator (default
|) - Missing-condition placeholder (default
^) - Temperature column name (default
Temperature) - Condition field order (comma-separated)
- Non-protein control marker (default
NPC)
- Condition separator (default
- Validate Layout – Runs the same parser as the pipeline, ensuring separator/placeholder combos work before writing anything to disk. Errors list the offending well + column identifier.
- Setup & View Raw Data – Calls
setup_experimentandingest_data, populates the well filtering card, and enables the “Run Full Pipeline” button. - Run Full Pipeline – Executes steps 02-08 with the selected well filters. Buttons for figures become available as the corresponding CSVs appear.
Validation and setup messages stay visible under their buttons so it’s easy to spot which phase succeeded. Exceptions are logged server-side and the frontend only shows a user-friendly message.
Well Filtering
After setup completes, a grid of well buttons appears. Click individual wells to toggle them for exclusion, or use the Select All / Deselect All buttons. The selection is stored in selected-wells-grid and passed into filter_wells when running the pipeline.
Figures
Buttons across the top map to data availability:
- Raw – per-well traces (always available after setup).
- Averaged, BG Sub, Normalized, Derivative, Tm – enabled only when their respective CSVs exist.
Navigate between figures using the prev/next buttons, the dropdown selector, or the figure counter. Each figure is rendered inline using the same generator functions documented in Pipeline.
Architecture
The Dash app source lives in src/instawell/dash_app/ (~3,100 lines across 15 files).
Module overview
| Module | Purpose |
|---|---|
app.py |
App factory (create_app), CLI entry point, cache + experiments root setup |
layout.py |
Component tree: navbar, cards, dcc.Store definitions |
constants.py |
Magic strings extracted into one place: FIGURE_BUTTON_MAP, FIGURE_STEP_FILES, STEP_ICONS, defaults |
utils.py |
Pure functions: normalize_well, parse_well_name, get_well_grid_dimensions, validate_separator_placeholder, parse_upload, get_experiment_list/status |
designer.py |
Plate layout designer component (96/384-well grid, condition assignment form) |
designer_callbacks.py |
Callbacks for the designer (grid rendering, condition CRUD, CSV export) |
Callbacks package
The callback logic is split into callbacks/ with eight focused modules, each exporting a register_*_callbacks(app, cache) function:
| Module | Callbacks |
|---|---|
_session.py |
Session ID assignment |
_experiment.py |
Experiment banner, toggle, refresh, info display |
_upload.py |
Raw/layout file upload handlers (via shared _handle_upload helper) |
_well_filter.py |
Well grid population, select/deselect all, toggle individual, filter summary |
_validation.py |
Layout validation against parsing settings |
_pipeline.py |
setup_and_ingest, run_pipeline |
_figures.py |
Figure loading, display, prev/next/dropdown navigation |
_helpers.py |
Shared helpers: _handle_upload, _refresh_keep |
The coordinator (__init__.py) registers all modules in one call, preserving the single import from .callbacks import register_callbacks in app.py.
Client-side state (dcc.Store)
| Store ID | Storage | Purpose |
|---|---|---|
session-id |
session | UUID for cache key namespacing |
raw-data-store |
session | Cache key for uploaded raw DataFrame |
layout-data-store |
session | Cache key for uploaded layout DataFrame |
current-experiment-store |
memory | Currently active experiment name |
figures-store |
memory | Serialised list of Plotly figure dicts |
current-figure-index |
memory | Index into figures-store |
selected-wells-grid |
memory | List of wells selected for filtering |
available-wells-store |
memory | All wells present in the raw data |
filtered-wells-store |
memory | Wells passed to filter_wells |
setup-complete-store |
memory | Boolean gate for pipeline button |
last-pipeline-experiment |
memory | Experiment name from last pipeline run |
Logging
All modules log to instawell.dash_app.* namespaces. Uploads, setup, pipeline runs, figure loading, cache misses, and designer exports are traceable in server logs. Exceptions are logged server-side; the frontend only shows user-friendly error messages.
Testing
The Dash app has 114 tests across two files:
test_dash_app.py(75 unit tests) – pure function tests forutils,constants,designer, and_helpers. No Dash server required.test_dash_integration.py(39 integration tests) – creates a real Dash app with a filesystem cache, then:- Bootstrap smoke tests: verifies the app builds, all
dcc.StoreIDs exist in the layout, and all callback outputs are registered. - Direct callback invocation: extracts registered callback functions via
__wrapped__(bypassing Dash 3’s context wrapper) and calls them with controlled inputs. Covers session assignment, button enable/disable logic, well filter summary, figure display + navigation, layout validation with cached data, and a full upload -> setup -> pipeline -> verify output files end-to-end flow.
- Bootstrap smoke tests: verifies the app builds, all
Run them with:
uv run pytest tests/test_dash_app.py tests/test_dash_integration.py -vTips
- Re-running – If you need to tweak separators or the NPC marker, clear the experiment, update the settings, and re-run setup/pipeline. Each step overwrites its outputs deterministically.
- Exporting Plots – Every figure shown in the Dash app can be downloaded via the Plotly mode bar. Use the notebook widget helpers if you prefer to stay in Jupyter.
- Serving Offline/Remote – Override host/port/experiments root using CLI flags (e.g.,
instawell-dash --host 0.0.0.0 --port 8080 --experiments-root /data/exp). In code, callcreate_app(experiments_root="path").run(...). - Curve Fits – The 4PL fitting step is still maturing. Treat
log10_fitplots as exploratory, and double-check the saved diagnostics before using numbers in reports.