docs: update all documentation for Dash migration (Phase 6)

Rewrote README.md, USER_GUIDE.md, and DEPLOYMENT.md to reflect
the Dash application. Updated RALPH_PROMPT.md, guardrails.md, and
DESIGN_SYSTEM.md to remove Reflex references. All non-archive
documentation now reflects the current Dash + DMC architecture.
This commit is contained in:
Andrew Charlwood
2026-02-06 14:54:12 +00:00
parent 4cb5641c2d
commit 54b4a0f743
8 changed files with 635 additions and 956 deletions
+89 -289
View File
@@ -1,10 +1,10 @@
# Reflex Deployment Guide
# Deployment Guide
This guide covers deployment options for the Patient Pathway Analysis web application built with Reflex.
This guide covers deployment options for the Patient Pathway Analysis web application built with Dash.
## Overview
Reflex applications compile to a FastAPI backend and Next.js frontend. This creates two deployment artifacts that can be deployed together or separately depending on your infrastructure requirements.
The application is a single-process Python Dash app that serves both the frontend and API from one server. It reads pre-computed data from a local SQLite database.
## Development Mode
@@ -12,9 +12,9 @@ For local development:
```bash
# Start development server with hot reload
reflex run
python run_dash.py
# Access the application at http://localhost:3000
# Access the application at http://localhost:8050
```
## Production Deployment Options
@@ -24,84 +24,55 @@ reflex run
The simplest approach for internal deployments:
```bash
# Run in production mode (optimized build)
reflex run --env prod
```
# Run with Gunicorn (Linux/macOS)
gunicorn dash_app.app:server -b 0.0.0.0:8050 --workers 4
This starts:
- FastAPI backend on port 8000
- Next.js frontend on port 3000
# Or directly with Python
python run_dash.py
```
For background execution:
```bash
# Using nohup (Linux/macOS)
nohup reflex run --env prod > reflex.log 2>&1 &
nohup gunicorn dash_app.app:server -b 0.0.0.0:8050 --workers 4 > dash.log 2>&1 &
# Using PowerShell (Windows)
Start-Process -NoNewWindow -FilePath "reflex" -ArgumentList "run --env prod"
Start-Process -NoNewWindow -FilePath "python" -ArgumentList "run_dash.py"
```
### Option 2: Separate Backend and Frontend
For more control, run backend and frontend separately:
```bash
# Terminal 1: Start backend only
reflex run --env prod --backend-only
# Terminal 2: Start frontend only
reflex run --env prod --frontend-only
```
### Option 3: Static Export
Export the frontend as static files for deployment on static hosting or CDN:
```bash
# Export application
reflex export
# This creates:
# - frontend.zip (static Next.js build)
# - backend.zip (Python application source)
```
Then:
1. Unzip `frontend.zip` and serve via nginx, Apache, or any static file server
2. Run the backend separately using uvicorn/gunicorn
### Option 4: Docker Deployment
### Option 2: Docker Deployment
Create a `Dockerfile` for containerized deployment:
```dockerfile
# Dockerfile
FROM python:3.11-slim
WORKDIR /app
# Install Node.js for Reflex frontend build
RUN apt-get update && apt-get install -y curl && \
curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
apt-get install -y nodejs && \
rm -rf /var/lib/apt/lists/*
# Install uv for fast dependency management
RUN pip install uv
# Copy requirements and install dependencies
COPY requirements.txt pyproject.toml ./
RUN pip install --no-cache-dir -r requirements.txt
# Copy dependency files
COPY pyproject.toml uv.lock ./
# Install dependencies
RUN uv sync --no-dev
# Copy application code
COPY . .
COPY src/ src/
COPY dash_app/ dash_app/
COPY data/ data/
COPY run_dash.py setup_dev.py ./
# Initialize Reflex (downloads frontend dependencies)
RUN reflex init --loglevel debug
# Set up Python path
RUN uv run python setup_dev.py
# Expose ports
EXPOSE 3000 8000
# Expose port
EXPOSE 8050
# Start in production mode
CMD ["reflex", "run", "--env", "prod"]
# Start the application
CMD ["uv", "run", "gunicorn", "dash_app.app:server", "-b", "0.0.0.0:8050", "--workers", "4"]
```
Build and run:
@@ -111,41 +82,24 @@ Build and run:
docker build -t pathway-analysis .
# Run the container
docker run -p 3000:3000 -p 8000:8000 \
docker run -p 8050:8050 \
-v $(pwd)/data:/app/data \
-v $(pwd)/config:/app/config \
pathway-analysis
```
### Option 5: Docker Compose (Recommended for Production)
Create `docker-compose.yml` for multi-container deployment:
### Option 3: Docker Compose
```yaml
version: '3.8'
services:
backend:
app:
build: .
command: reflex run --env prod --backend-only
ports:
- "8000:8000"
- "8050:8050"
volumes:
- ./data:/app/data
- ./config:/app/config
environment:
- REFLEX_ENV=prod
restart: unless-stopped
frontend:
build: .
command: reflex run --env prod --frontend-only
ports:
- "3000:3000"
depends_on:
- backend
environment:
- REFLEX_ENV=prod
- ./src/config:/app/src/config
restart: unless-stopped
```
@@ -162,42 +116,16 @@ docker-compose up -d
For production deployments behind nginx:
```nginx
# /etc/nginx/sites-available/pathway-analysis
server {
listen 80;
server_name your-server.nhs.uk;
# Backend API endpoints
location /admin {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /ping {
proxy_pass http://localhost:8000;
}
location /upload {
proxy_pass http://localhost:8000;
client_max_body_size 100M; # For large data file uploads
}
# WebSocket connections (required for Reflex state sync)
location /_event/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400; # 24 hours for long-running connections
}
# Frontend (all other requests)
location / {
proxy_pass http://localhost:3000;
proxy_pass http://localhost:8050;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
@@ -209,69 +137,21 @@ sudo ln -s /etc/nginx/sites-available/pathway-analysis /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
### Caddy (Alternative)
Caddy provides automatic HTTPS:
```caddyfile
# Caddyfile
your-server.nhs.uk {
# Backend API
handle /admin/* {
reverse_proxy localhost:8000
}
handle /ping {
reverse_proxy localhost:8000
}
handle /upload {
reverse_proxy localhost:8000
}
handle /_event/* {
reverse_proxy localhost:8000
}
# Frontend
handle {
reverse_proxy localhost:3000
}
}
```
## Process Management
### Systemd (Linux)
Create service files for automatic startup:
```ini
# /etc/systemd/system/pathway-backend.service
# /etc/systemd/system/pathway-analysis.service
[Unit]
Description=Pathway Analysis Backend
Description=Pathway Analysis Dash App
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/pathway-analysis
ExecStart=/usr/bin/reflex run --env prod --backend-only
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
```
```ini
# /etc/systemd/system/pathway-frontend.service
[Unit]
Description=Pathway Analysis Frontend
After=network.target pathway-backend.service
[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/pathway-analysis
ExecStart=/usr/bin/reflex run --env prod --frontend-only
ExecStart=/opt/pathway-analysis/.venv/bin/gunicorn dash_app.app:server -b 0.0.0.0:8050 --workers 4
Restart=always
RestartSec=10
@@ -283,8 +163,8 @@ Enable and start:
```bash
sudo systemctl daemon-reload
sudo systemctl enable pathway-backend pathway-frontend
sudo systemctl start pathway-backend pathway-frontend
sudo systemctl enable pathway-analysis
sudo systemctl start pathway-analysis
```
### Windows Service
@@ -296,8 +176,8 @@ Use NSSM (Non-Sucking Service Manager) on Windows:
choco install nssm
# Create service
nssm install PathwayAnalysis "C:\Path\To\reflex.exe" "run --env prod"
nssm set PathwayAnalysis AppDirectory "C:\Path\To\Patient pathway analysis"
nssm install PathwayAnalysis "C:\Path\To\python.exe" "run_dash.py"
nssm set PathwayAnalysis AppDirectory "C:\Path\To\pathway-analysis"
nssm start PathwayAnalysis
```
@@ -305,192 +185,112 @@ nssm start PathwayAnalysis
### Production Environment Variables
Set these environment variables for production:
```bash
# Reflex configuration
export REFLEX_ENV=prod
# Database paths (if using custom locations)
# Database path (if using custom location)
export PATHWAY_DB_PATH=/var/data/pathways.db
export PATHWAY_CACHE_DIR=/var/cache/pathway-analysis
# Snowflake (if using)
# Snowflake (for data refresh only — not needed for the web app)
export SNOWFLAKE_ACCOUNT=your-account
export SNOWFLAKE_WAREHOUSE=your-warehouse
```
### Snowflake Configuration
Ensure `config/snowflake.toml` is properly configured for production:
Snowflake is only needed for the data refresh CLI command, not for running the web application. Ensure `src/config/snowflake.toml` is configured:
```toml
[connection]
[snowflake]
account = "your-production-account"
warehouse = "ANALYTICS_WH"
database = "DATA_HUB"
schema = "CDM"
authenticator = "externalbrowser" # or "oauth" for service accounts
[cache]
enabled = true
directory = "/var/cache/pathway-analysis"
ttl_seconds = 86400 # 24 hours
authenticator = "externalbrowser"
```
## Reflex Cloud
## Data Refresh
For managed hosting, consider [Reflex Cloud](https://reflex.dev/cloud/):
The web application reads pre-computed data from SQLite. To update the data:
```bash
# Deploy to Reflex Cloud
reflex deploy
# Full refresh (both chart types, all date filters)
python -m cli.refresh_pathways --chart-type all
# The app will serve new data immediately — no restart needed
```
Benefits:
- Zero configuration deployment
- Automatic scaling
- Built-in SSL certificates
- Managed state management with Redis
Schedule this as a cron job or Windows Task Scheduler task for periodic updates.
## Security Considerations
### Network Security
1. **Firewall Rules**: Only expose necessary ports (typically just 80/443)
2. **HTTPS**: Use TLS certificates (Let's Encrypt or organizational certs)
1. **Firewall Rules**: Only expose port 8050 (or 80/443 behind reverse proxy)
2. **HTTPS**: Use TLS certificates via reverse proxy (nginx, Caddy)
3. **VPN**: Consider restricting access to NHS network only
### Data Security
1. **Database Access**: Ensure SQLite database permissions are restricted
2. **File Uploads**: Validate file types and scan for malware
3. **Snowflake**: Use least-privilege service accounts
### Authentication
For NHS deployments, consider adding authentication:
```python
# Example: Add basic auth middleware
import reflex as rx
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware
# In rxconfig.py
config = rx.Config(
app_name="pathways_app",
# Add authentication middleware
)
```
1. **Database Access**: The app uses read-only SQLite access
2. **No file uploads**: The Dash app does not accept file uploads
3. **No authentication built in**: Add authentication via reverse proxy or middleware if needed
## Monitoring
### Health Checks
The application provides endpoints for monitoring:
- `/ping` - Basic health check
- Backend port 8000 - FastAPI health
The application serves at `/` — a 200 response indicates the app is running.
### Logging
Configure logging for production:
Dash outputs request logs to stdout. Configure log aggregation as needed:
```python
# In pathways_app/pathways_app.py
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/var/log/pathway-analysis/app.log'),
logging.StreamHandler()
]
)
```bash
# Redirect logs to file
gunicorn dash_app.app:server -b 0.0.0.0:8050 --access-logfile /var/log/pathway-analysis/access.log --error-logfile /var/log/pathway-analysis/error.log
```
## Troubleshooting
### Common Issues
### Port already in use
**Port already in use:**
```bash
# Find and kill process using port 3000
lsof -i :3000
kill -9 <PID>
# Find process using port 8050
lsof -i :8050 # Linux/macOS
netstat -ano | findstr :8050 # Windows
```
**Build cache issues:**
```bash
# Clear Reflex build cache
rm -rf .web
reflex run --env prod
```
### Database not found
**Database connection errors:**
```bash
# Verify database exists and has correct permissions
# Verify database exists
ls -la data/pathways.db
sqlite3 data/pathways.db ".tables"
# Recreate if needed
python -m data_processing.migrate
python -m cli.refresh_pathways --chart-type all
```
**Snowflake authentication:**
- Ensure browser is available for SSO popup
- Check firewall allows connections to Snowflake endpoints
- Verify account identifier is correct
## Performance Tuning
### Backend (FastAPI/Uvicorn)
For high-traffic deployments:
### Import errors
```bash
# Run with multiple workers
uvicorn pathways_app:app --workers 4 --host 0.0.0.0 --port 8000
```
# Ensure src/ is on Python path
uv run python setup_dev.py
### State Management
For multi-instance deployments, configure Redis for state management:
```python
# rxconfig.py
config = rx.Config(
app_name="pathways_app",
state_manager_mode="redis",
redis_url="redis://localhost:6379/0",
)
```
### Caching
Enable aggressive caching for Snowflake queries in `config/snowflake.toml`:
```toml
[cache]
enabled = true
ttl_seconds = 86400 # 24 hours for historical data
ttl_current_data_seconds = 3600 # 1 hour for recent data
max_size_mb = 1000 # 1GB cache
# Verify imports
uv run python -c "from dash_app.app import app; print('OK')"
```
---
## Quick Reference
| Environment | Command | Ports |
|-------------|---------|-------|
| Development | `reflex run` | 3000, 8000 |
| Production | `reflex run --env prod` | 3000, 8000 |
| Backend only | `reflex run --backend-only` | 8000 |
| Frontend only | `reflex run --frontend-only` | 3000 |
| Export | `reflex export` | Static files |
| Cloud | `reflex deploy` | Managed |
| Environment | Command | Port |
|-------------|---------|------|
| Development | `python run_dash.py` | 8050 |
| Production | `gunicorn dash_app.app:server -b 0.0.0.0:8050 --workers 4` | 8050 |
| Docker | `docker run -p 8050:8050 pathway-analysis` | 8050 |
For more information, see:
- [Reflex Documentation](https://reflex.dev/docs/)
- [Reflex Cloud](https://reflex.dev/cloud/)
- [FastAPI Deployment](https://fastapi.tiangolo.com/deployment/)
- [Dash Documentation](https://dash.plotly.com/)
- [Gunicorn Deployment](https://docs.gunicorn.org/en/stable/deploy.html)
+5 -5
View File
@@ -187,8 +187,8 @@ All transitions: 150ms ease-out (faster than before)
}
```
### Reflex Implementation
- Use `height="calc(100vh - 96px)"` for chart container
- Use `width="100%"` with `padding_x="16px"` for full-width
- Use `flex="1"` to let chart grow
- Keep `min_height="500px"` as fallback
### Dash Implementation
- Chart container uses `dcc.Loading` wrapper around `dcc.Graph`
- Full-width layout via CSS class `.chart-card` in `dash_app/assets/nhs.css`
- Minimum height set via CSS: `min-height: 500px`
- Margins controlled in `create_icicle_from_nodes()`: `t:40, l:8, r:8, b:24`
+145 -291
View File
@@ -6,15 +6,11 @@ This guide explains how to use the NHS High-Cost Drug Patient Pathway Analysis T
1. [Getting Started](#getting-started)
2. [Interface Overview](#interface-overview)
3. [Selecting Your Data Source](#selecting-your-data-source)
4. [Configuring Analysis Filters](#configuring-analysis-filters)
5. [Selecting Drugs, Trusts, and Directories](#selecting-drugs-trusts-and-directories)
6. [Running the Analysis](#running-the-analysis)
7. [Understanding the Pathway Chart](#understanding-the-pathway-chart)
8. [Exporting Results](#exporting-results)
9. [GP Indication Validation](#gp-indication-validation)
10. [Keyboard Navigation and Accessibility](#keyboard-navigation-and-accessibility)
11. [Troubleshooting](#troubleshooting)
3. [Filtering Data](#filtering-data)
4. [Using the Drug Browser](#using-the-drug-browser)
5. [Understanding the Pathway Chart](#understanding-the-pathway-chart)
6. [GP Indication Matching](#gp-indication-matching)
7. [Troubleshooting](#troubleshooting)
---
@@ -25,371 +21,229 @@ This guide explains how to use the NHS High-Cost Drug Patient Pathway Analysis T
Start the application by running:
```bash
reflex run
python run_dash.py
```
Then open your browser to **http://localhost:3000**
Then open your browser to **http://localhost:8050**
The application will automatically load reference data (drugs, trusts, directories) when you first access it.
The application automatically loads pre-computed pathway data from SQLite on startup. No additional setup is needed to view existing data.
### First-Time Setup
### Data Freshness
1. Click **Load Reference Data** on the Home page to populate the filter options
2. Select your preferred data source (SQLite, File Upload, or Snowflake)
3. Configure your date range and other filters
4. Click **Run Analysis** to generate your first pathway chart
The header bar shows when data was last refreshed:
- **Patient count**: Total patients in the dataset (e.g., "11,118 patients")
- **Last updated**: Relative time since the last data refresh (e.g., "2h ago")
To refresh the data, run the CLI command (requires Snowflake access):
```bash
python -m cli.refresh_pathways --chart-type all
```
---
## Interface Overview
The application has four main pages, accessible from the sidebar navigation:
The application is a single-page layout with the following components:
| Page | Purpose |
|------|---------|
| **Home** | Main analysis dashboard with data source selection, filters, and chart display |
| **Drug Selection** | Select which high-cost drugs to include in the analysis |
| **Trust Selection** | Filter by specific NHS trusts |
| **Directory Selection** | Filter by medical directories/specialties |
### Header
- NHS branding and application title ("HCD Analysis")
- Green status dot with patient count and last-updated time
### Navigation
### Sidebar (Left)
Navigation items including:
- **Pathway Overview** — main view (always active)
- **Drug Selection** — opens the drug browser drawer
- **Trust Selection** — opens the drawer with trust chips
- **Indications** — opens the drawer with directorate browser
- **Desktop**: Use the sidebar on the left to switch between pages
- **Mobile**: Use the top navigation bar
- **Keyboard**: Press Tab to navigate, Enter to select
### KPI Row
Four summary cards that update dynamically:
- **Unique Patients** — number of distinct patients matching current filters
- **Drug Types** — number of distinct drugs in filtered data
- **Total Cost** — total cost of treatments in the filtered dataset
- **Indication Match** — GP diagnosis match rate (~93% for indication charts, shown as "—" for directory charts)
### Filter Bar
- **Chart type toggle**: "By Directory" / "By Indication" pills
- **Treatment Initiated**: All years, Last 2 years, or Last 1 year
- **Last Seen**: Last 6 months or Last 12 months
### Chart Card
- Dynamic subtitle showing the current hierarchy (e.g., "Trust → Directorate → Drug → Pathway")
- Interactive Plotly icicle chart
- Loading spinner during data fetch
---
## Selecting Your Data Source
## Filtering Data
The application supports three data sources:
### Chart Type
### 1. SQLite Database (Recommended)
Toggle between two views using the pills in the filter bar:
Pre-loaded patient data stored locally for fast performance.
| View | Hierarchy | Best For |
|------|-----------|----------|
| **By Directory** | Trust → Directorate → Drug → Pathway | Understanding treatment by medical specialty |
| **By Indication** | Trust → GP Diagnosis → Drug → Pathway | Understanding treatment by patient condition |
**Advantages:**
- Fastest analysis performance
- Works offline
- No authentication required
### Date Filters
**To use:** Click "Use SQLite" in the Data Source section
Two dropdowns control the time window:
### 2. File Upload
| Filter | Options | Effect |
|--------|---------|--------|
| **Treatment Initiated** | All years, Last 2 years, Last 1 year | When patients started treatment |
| **Last Seen** | Last 6 months, Last 12 months | Most recent activity window |
Upload CSV or Parquet files directly.
The default is "All years / Last 6 months" — showing all patients who have been active in the last 6 months.
**Supported formats:**
- CSV files (.csv)
- Apache Parquet files (.parquet, .pq)
### Drug and Trust Selection
**To use:**
1. Drag and drop a file, or click the upload area
2. Wait for the file to process
3. Click "Use File" to select it as your data source
Open the drawer (right panel) by clicking "Drug Selection" or "Trust Selection" in the sidebar:
### 3. Snowflake
- **Drug chips**: Click to select/deselect specific drugs. Selected drugs filter the chart.
- **Trust chips**: Click to select/deselect specific NHS trusts.
- **Clear All Filters**: Button at the bottom resets all drug and trust selections.
Query live data from the NHS data warehouse.
**Requirements:**
- Snowflake must be configured (see `config/snowflake.toml`)
- Browser-based NHS SSO authentication
**To use:** Click "Use Snowflake" - you'll be prompted to authenticate via your browser
**No selections = show everything.** Leaving chips unselected is the same as selecting all.
---
## Configuring Analysis Filters
## Using the Drug Browser
The Home page provides several filter options:
The drawer contains three sections:
### Date Range
### All Drugs
A flat list of all 42 available drugs as selectable chips. Click one or more to filter the chart to those drugs only.
| Field | Description |
|-------|-------------|
| **Start Date** | Include patients initiated from this date onwards |
| **End Date** | Include patients initiated until this date |
| **Last Seen After** | Only include patients with activity after this date (excludes patients who haven't been seen recently) |
### Trusts
A list of 7 NHS trusts as selectable chips. Click to filter by specific organizations.
**Tip:** The default range is the last 12 months.
### By Directorate
An accordion browser organized by clinical directorate:
### Minimum Patients
1. Click a **directorate** (e.g., "CARDIOLOGY") to expand it
2. Inside, click an **indication** (e.g., "heart failure") to expand further
3. Each indication shows **drug fragment badges** (e.g., "SACUBITRIL", "IVABRADINE")
4. Clicking a drug fragment badge selects all full drug names that contain that fragment
Filter out pathways with fewer patients than the threshold you set.
For example, clicking the "ADALIMUMAB" badge would select "ADALIMUMAB" in the drug chips above.
- Use the slider for quick adjustment (0-100)
- Or type a specific number in the text field
- Set to 0 to show all pathways regardless of patient count
### Fragment Matching
### Custom Title
Drug fragments are substrings, not exact matches. The fragment "INHALED" would match drugs like "INHALED BECLOMETASONE" and "INHALED FLUTICASONE".
Override the automatically generated chart title with your own text.
- Leave empty to use the default title: "Patients initiated [start date] to [end date]"
- Useful for specific reports or presentations
---
## Selecting Drugs, Trusts, and Directories
Each selection page works the same way:
### Navigation
1. Click "Drug Selection", "Trust Selection", or "Directory Selection" in the sidebar
2. The page shows all available options with checkboxes
### Search
Type in the search box to filter the list. The list updates as you type.
### Selection Actions
| Button | Action |
|--------|--------|
| **Select All** | Check all visible items |
| **Clear All** | Uncheck all items |
| **Select Defaults** | (Drugs only) Select pre-configured default drugs (Include=1 in include.csv) |
### Selection Behavior
- **No items selected** = Include ALL items in analysis
- **Some items selected** = Include ONLY the selected items
This means leaving a filter empty is equivalent to "select all".
---
## Running the Analysis
### Steps
1. Ensure your data source is selected and configured
2. Set your date range and other filters
3. Select desired drugs, trusts, and directories (or leave empty for all)
4. Click the green **Run Analysis** button
### During Analysis
- The button shows a spinner while analysis is running
- Status messages appear below the button
- The interface remains responsive - you can review settings
### After Analysis
- The pathway chart appears in the chart section
- Export buttons become available
- GP indication validation results appear (if Snowflake is connected)
Clicking a fragment toggles its matching drugs:
- **First click**: Selects all matching drugs
- **Second click**: Deselects all matching drugs (if all were already selected)
---
## Understanding the Pathway Chart
The analysis generates an interactive **icicle chart** showing patient treatment pathways.
### Hierarchy Structure
The chart displays a hierarchical structure:
The icicle chart displays a hierarchical breakdown:
**Directory view:**
```
N&WICS (Regional Total)
└─ Trust Name (e.g., "Norfolk and Norwich University Hospitals")
└─ Directory (e.g., "Rheumatology", "Gastroenterology")
└─ Drug Name (e.g., "ADALIMUMAB", "INFLIXIMAB")
Root (Regional Total)
└─ Trust (e.g., "Norfolk and Norwich University Hospitals")
└─ Directorate (e.g., "RHEUMATOLOGY")
└─ Drug (e.g., "ADALIMUMAB")
└─ Pathway (e.g., "ADALIMUMAB → INFLIXIMAB")
```
**Indication view:**
```
Root (Regional Total)
└─ Trust
└─ GP Diagnosis (e.g., "rheumatoid arthritis")
└─ Drug
└─ Pathway
```
### Reading the Chart
- **Width** of each section indicates relative patient count
- **Color intensity** indicates proportion of patients at that level
- **Labels** show the category name and patient count
- **Color intensity** (NHS blue gradient) indicates proportion of parent group
- **Labels** show the name and patient count
### Interacting with the Chart
| Action | Effect |
|--------|--------|
| **Click** a section | Zoom in to show details for that branch |
| **Click** the root | Zoom out to show full hierarchy |
| **Hover** over a section | See tooltip with patient count |
| Use the **toolbar** | Reset, download image, pan, zoom |
| **Click** the parent/root | Zoom back out |
| **Hover** over a section | See tooltip with patient count, cost, dosing frequency, dates |
### Plotly Toolbar
### Hover Tooltip Information
The chart includes a Plotly toolbar (top right) with:
- **Download as PNG** - Save static image
- **Zoom controls** - Zoom in/out
- **Pan** - Click and drag to move
- **Reset** - Return to original view
When hovering over a chart section, you'll see:
- Patient count and percentage of parent
- Total cost and cost per patient
- First and last seen dates
- Treatment dosing frequency (for drug nodes)
- Cost per patient per annum
---
## Exporting Results
## GP Indication Matching
Two export options are available after running an analysis:
When viewing "By Indication" charts, the application uses pre-computed GP diagnosis matches:
### Export HTML
### How It Works
Creates an interactive HTML file that can be opened in any browser.
1. During data refresh, each patient's NHS pseudonym is queried against GP primary care records
2. SNOMED cluster codes map clinical conditions to drug indications
3. The most recent GP diagnosis match is used for each patient
4. ~93% of patients are matched to a GP diagnosis
- **Output**: `data/exports/pathway_chart_[timestamp].html`
- **Use case**: Sharing interactive charts via email or file share
- **Features**: Full interactivity, no software required to view
### Unmatched Patients
### Export CSV
Patients without a GP diagnosis match appear under their directorate with a "(no GP dx)" suffix (e.g., "RHEUMATOLOGY (no GP dx)").
Exports the underlying data as a spreadsheet.
- **Output**: `data/exports/pathway_data_[timestamp].csv`
- **Use case**: Further analysis in Excel, importing to other tools
- **Includes**: Patient IDs, drugs, dates, costs, directories, indication validation status
### Export Location
All exports are saved to the `data/exports/` directory with timestamped filenames to prevent overwriting.
---
## GP Indication Validation
When connected to Snowflake, the application validates whether patients have appropriate GP diagnoses for their prescribed drugs.
### What It Does
1. Looks up the drug's licensed indications (e.g., ADALIMUMAB for rheumatoid arthritis)
2. Finds corresponding SNOMED codes for those indications
3. Checks each patient's GP records for matching diagnoses
4. Reports the match rate per drug
### Understanding Results
After analysis, a table shows:
| Column | Meaning |
|--------|---------|
| **Drug Name** | The high-cost drug |
| **Total Patients** | Number of patients prescribed this drug |
| **With GP Indication** | Patients with matching GP diagnosis |
| **Match Rate** | Percentage with valid indication |
### Match Rate Interpretation
| Rate | Meaning | Color |
|------|---------|-------|
| **80%+** | Good coverage - most patients have GP diagnoses | Green |
| **50-79%** | Moderate coverage - investigate missing cases | Orange |
| **<50%** | Low coverage - may indicate data quality issues or off-label use | Red |
### Why Rates May Be Low
Low match rates don't necessarily indicate problems:
- **Cross-provider treatment**: Patient's GP is outside the data coverage
- **Recent diagnoses**: Diagnosis not yet recorded in GP system
- **Specialist-only conditions**: Some conditions are only managed in secondary care
- **Off-label prescribing**: Legitimate use for indications not in the mapping
### Enabling/Disabling
Indication validation is enabled by default when Snowflake is connected. It requires:
- Active Snowflake connection
- Drug-to-cluster mappings in the database
---
## Keyboard Navigation and Accessibility
The application is designed to be accessible:
### Skip Link
Press **Tab** when the page loads to reveal a "Skip to main content" link that bypasses navigation.
### Keyboard Navigation
| Key | Action |
|-----|--------|
| **Tab** | Move to next interactive element |
| **Shift+Tab** | Move to previous element |
| **Enter** | Activate buttons, links, checkboxes |
| **Space** | Toggle checkboxes |
| **Arrow keys** | Adjust sliders |
### Screen Reader Support
- All buttons and inputs have descriptive labels
- Status messages announce via ARIA live regions
- Charts include figure descriptions
### Theme Toggle
A dark/light mode toggle is available at the bottom of the sidebar for visual preference.
Reasons for unmatched patients:
- GP is outside the data coverage area
- Diagnosis not yet recorded in GP system
- Condition managed only in secondary care
- Off-label prescribing
---
## Troubleshooting
### "No data available" Error
### No data showing
**Cause**: No data matches your current filter settings
1. Check the filter bar — are filters too restrictive?
2. Try clearing all drug/trust selections in the drawer
3. Widen the date range (e.g., "All years / Last 12 months")
**Solutions:**
1. Check your date range - is it too narrow?
2. Verify your data source has data loaded
3. Check if selected trusts/drugs have any matching records
4. Try clearing all selections (to include everything)
### Chart shows "No matching pathways found"
### Chart Not Displaying
The current filter combination matches zero patients. Adjust filters or click "Clear All Filters" in the drawer.
**Cause**: Analysis completed but no data met the minimum patients threshold
### App won't start
**Solutions:**
1. Lower the minimum patients threshold
2. Expand your date range
3. Select more drugs or trusts
```bash
# Ensure dependencies are installed
uv sync
### Snowflake Connection Failed
# Ensure src/ is on Python path
uv run python setup_dev.py
**Cause**: Unable to connect to Snowflake
# Run with uv
uv run python run_dash.py
```
**Solutions:**
1. Check that `config/snowflake.toml` exists and is configured
2. Complete browser authentication when prompted
3. Verify your network allows Snowflake connections
4. Try using SQLite as an alternative data source
### Stale data
### File Upload Failed
Data is as fresh as the last CLI refresh. Check the header's "Last updated" indicator. To refresh:
**Cause**: File format or content issue
**Solutions:**
1. Ensure file is CSV or Parquet format
2. Check file isn't corrupted or empty
3. Verify file contains required columns
4. Try a smaller file to test
### Slow Performance
**Cause**: Large data volume or complex filtering
**Solutions:**
1. Use SQLite instead of file upload for large datasets
2. Narrow your date range
3. Select fewer drugs/trusts to analyze
4. Increase minimum patients threshold to reduce chart complexity
### Reference Data Not Loading
**Cause**: Missing or corrupted reference files
**Solutions:**
1. Click "Load Reference Data" to retry
2. Check that `data/` directory contains required CSV files:
- `include.csv`
- `defaultTrusts.csv`
- `directory_list.csv`
3. Verify files aren't empty or malformed
```bash
python -m cli.refresh_pathways --chart-type all
```
---
@@ -397,7 +251,7 @@ A dark/light mode toggle is available at the bottom of the sidebar for visual pr
If you encounter issues not covered in this guide:
1. Check the [README](../README.md) for installation and setup information
1. Check the [README](../README.md) for installation and setup
2. Review [DEPLOYMENT.md](./DEPLOYMENT.md) for server configuration
3. Consult [CLAUDE.md](../CLAUDE.md) for technical architecture details
4. Contact your local support team for NHS-specific questions
4. Contact the Medicines Intelligence team for NHS-specific questions