medOS ultra

Dose-Pattern Visualization System

12 dose-pattern kinds with auto-detection + rich bilingual visualizations in the order dialog summary card.

13 min read diagramsUpdated 2026-05-17docs/architecture/dose-pattern-visualization-system.md

Overview

The Dose Pattern Visualization System is a comprehensive medication scheduling visualization engine built into the medOS order dialog. It automatically detects and renders rich, interactive visualizations for 12 distinct dose-pattern kinds, covering the full range of clinical medication administration patterns — from simple fixed schedules to complex PCA (patient-controlled analgesia) and sliding scale protocols.

The system is fully bilingual (Thai + English) and integrates into the existing SummaryCard component within the dynamic scheduler, providing clinicians with an immediate visual summary of how a medication will be administered.


Architecture

Order Data (frequency, route, priority, infusionRate, pcaConfig, ...)
        │
        ▼
┌─────────────────────────┐
│   detectDosePattern()   │  ← Priority-based pattern detection engine
│   (dosePatternKind.ts)  │
└────────┬────────────────┘
         │  DetectedPattern { kind, adminProfile, doseDerivation, params }
         ▼
┌─────────────────────────┐
│     PatternBadge        │  ← Color-coded chip with bilingual label
│     + Visualization     │  ← Pattern-specific rich visualization
│     (TimePerDay.tsx)    │
└─────────────────────────┘

Key Files

File Purpose
packages/ui-kit/src/components/dynamic-scheduler-2/summary-container/dosePatternKind.ts Type definitions, detection engine, metadata registry
packages/ui-kit/src/components/dynamic-scheduler-2/summary-container/TimePerDay.tsx All 12 visualization components + PatternBadge + PatternChip
packages/ui-kit/src/components/dynamic-scheduler-2/summary-container/SummaryCard.tsx Parent container — passes orderData to TimePerDay for detection

The 12 Dose-Pattern Kinds

1. Fixed Schedule (fixed)

Use case: Standard scheduled medications (TID, QID, BID, etc.)

Visual: Circadian clock with sun/moon/dawn/dusk icons and green dose dots at each administration hour.

Property Value
Badge color Green (#1b5e20 on #e8f5e9)
Icon schedule
Detection frequency.timePerDay > 0 (fallback)
Label TH ตารางคงที่
Label EN Fixed Schedule

How it renders:

  • Parses the RRULE string to extract BYHOUR values
  • Maps each hour to a time-of-day period (night 0-5, morning 6-11, afternoon 12-17, evening 18-23)
  • Renders icons: moon, sun, sunset, night for each period
  • Green filled dots mark administration times; gray dots fill the rest of the 12-dot row per period

Example data:

frequency: {
  timePerDay: 3,
  abbrName: 'TID',
  rruleString: 'FREQ=DAILY;BYHOUR=8,12,18'
}

2. PRN — As Needed (prn)

Use case: Pain relief, anti-emetics, and other symptom-triggered medications.

Visual: Chip flow: PRNIndicationMin Interval with arrow connectors.

Property Value
Badge color Orange (#e65100 on #fff3e0)
Icon notifications_active
Detection frequency.timePerDay === 0 or frequency.type === 'prn' or /prn/i in abbreviation
Label TH เมื่อจำเป็น
Label EN PRN (As Needed)

Features:

  • Auto-maps medication use-time codes to Thai/English indications (e.g., SP4 = ปวด/Pain, SN2 = คลื่นไส้/Nausea)
  • Shows minimum interval between doses when specified
  • 14 indication codes mapped: cough, constipation, dyspnea, nausea, nasal congestion, pain, headache/fever

Example data:

frequency: {
  timePerDay: 0,
  type: 'prn',
  abbrName: 'PRN q4hr',
  medUseTime: 'SP4',      // → Pain
  typeMedUseTime: '4'     // → every 4 hours minimum
}

3. One-Time / Bolus (one_time)

Use case: Stat doses, single administrations, pre-procedure medications.

Visual: STAT chip → Administration Profile chip (IV Push, Slow Push, Oral, etc.)

Property Value
Badge color Purple (#4a148c on #f3e5f5)
Icon bolt
Detection Priority = 'Stat' or /stat|once/i in abbreviation
Label TH ครั้งเดียว
Label EN One-Time / Bolus

Administration profiles detected:

  • push — IV Push (seconds)
  • slow_push — IV Slow Push (1-5 min)
  • short_infusion — Short Infusion (15-60 min)
  • oral — Oral single dose
  • other — Single administration

Example data:

frequency: { timePerDay: 1, abbrName: 'Stat' },
orderData: { priority: { value: 'Stat' }, route: 'IV' }

4. Continuous Infusion (continuous)

Use case: IV drips, constant-rate infusions (vasopressors, sedation, TPN).

Visual: ContinuousRateDuration chips with animated blue drip progress bar.

Property Value
Badge color Blue (#01579b on #e1f5fe)
Icon water_drop
Detection infusionRate > 0 + IV route, or keyword match (drip|infusion|continuous)
Label TH หยดต่อเนื่อง
Label EN Continuous Infusion

Features:

  • Animated CSS gradient simulates flowing drip
  • Shows rate, unit, and duration when available
  • Calculates: Qty = rate x duration

Example data:

orderData: {
  route: 'IV drip',
  infusionRate: 125,
  infusionRateUnit: 'mL/hr',
  infusionDuration: 480
}

5. Taper (taper)

Use case: Steroid tapers, antibiotic step-down, gradual dose reduction.

Visual: Taper chip + step count chip + descending bar chart (orange, fading opacity).

Property Value
Badge color Orange (#e65100 on #fff3e0)
Icon trending_down
Detection taperSteps array present, or keyword match (taper|ลดขนาด|step.?down|wean)
Label TH ลดขนาดยา
Label EN Taper

Features:

  • Each bar represents a taper step with proportional height
  • Hover tooltip shows dose and duration per step
  • Interactive hover highlights individual steps
  • Summary shows start→end dose and total duration

Example data:

orderData: {
  taperSteps: [
    { day: 1, dose: 60, unit: 'mg' },
    { day: 3, dose: 40, unit: 'mg' },
    { day: 5, dose: 20, unit: 'mg' },
    { day: 7, dose: 10, unit: 'mg' },
  ]
}

6. Titration (titration)

Use case: Insulin dose adjustments, blood pressure medications, pain management.

Visual: Titrationปรับตามผล (adjust by result) chips + ascending bar chart (blue).

Property Value
Badge color Blue (#1565c0 on #e3f2fd)
Icon trending_up
Detection Explicit dosePattern: 'titration' or keyword match (titrat|ไตเตรท|adjust|ปรับขนาด)
Label TH ไตเตรท
Label EN Titration

Features:

  • 7-step ascending visualization showing dose escalation concept
  • Hover tooltip per step
  • Complementary to Taper (ascending vs descending)

7. Sliding Scale (sliding_scale)

Use case: Insulin sliding scale, heparin protocols.

Visual: Sliding Scale chip + Glucose/Dose data table.

Property Value
Badge color Purple (#6a1b9a on #f3e5f5)
Icon table_chart
Detection slidingScaleTable array present, or keyword match (sliding.?scale)
Label TH Sliding Scale
Label EN Sliding Scale

Features:

  • Compact 2-column grid table (Glucose range → Dose)
  • Purple-highlighted dose cells for non-zero doses
  • Falls back to default 6-tier insulin scale if no data provided

Example data:

orderData: {
  slidingScaleTable: [
    { rangeLow: 150, rangeHigh: 200, dose: 2, unit: 'units' },
    { rangeLow: 201, rangeHigh: 250, dose: 4, unit: 'units' },
    { rangeLow: 251, rangeHigh: 300, dose: 6, unit: 'units' },
    { rangeLow: 301, rangeHigh: 350, dose: 8, unit: 'units' },
  ]
}

8. Cyclic / Pulse (cyclic)

Use case: Chemotherapy cycles, pulse steroids, on/off antibiotic schedules.

Visual: Cyclic + Xd on / Yd off chips + striped on/off bar visualization.

Property Value
Badge color Teal (#00695c on #e0f2f1)
Icon loop
Detection cycleDaysOn && cycleDaysOff present, or keyword match (cycl|pulse|on.?off)
Label TH รอบ/พัลส์
Label EN Cyclic / Pulse

Features:

  • Renders 3 complete cycles as a bar chart
  • Green bars = treatment days; gray/light bars = rest days
  • Hover tooltip shows cycle number and day number
  • Summary calculates total treatment duration

Example data:

orderData: {
  cycleDaysOn: 21,
  cycleDaysOff: 7
}
// → "21 days on, 7 days off — repeat 3 cycles (84 days total)"

9. Loading + Maintenance (loading_maintenance)

Use case: Antibiotics (vancomycin), anticoagulants (heparin), antiarrhythmics (amiodarone).

Visual: LoadingMaintenance chips + split bar (small loading block + large maintenance block).

Property Value
Badge color Red-brown (#bf360c on #fbe9e7)
Icon rocket_launch
Detection loadingDose && maintenanceDose present, or keyword match (loading|โหลด)
Label TH โหลด+บำรุงรักษา
Label EN Loading + Maintenance

Features:

  • Split bar: dark purple loading portion + light green maintenance portion
  • Shows actual doses in each segment
  • Calculates: Qty = loading + (maintenance x freq x days)

Example data:

orderData: {
  loadingDose: 500,
  maintenanceDose: 250
}

10. Bolus + Infusion (bolus_infusion)

Use case: tPA for stroke, heparin bolus+drip, antibiotics with loading push.

Visual: BolusDrip Rate chips + split bar (BOLUS block + infusion block).

Property Value
Badge color Indigo (#283593 on #e8eaf6)
Icon bolt
Detection infusionRate > 0 + IV route + Stat priority or bolus keyword
Label TH โบลัส+หยด
Label EN Bolus + Infusion

Features:

  • Split bar visualization: compact dark “BOLUS” segment + wide light “rate” segment
  • Shows infusion rate and unit
  • Calculates: Qty = bolus + (rate x duration)

Example data:

orderData: {
  route: 'IV',
  method: 'bolus',
  infusionRate: 50,
  infusionRateUnit: 'mL/hr',
  priority: { value: 'Stat' }
}

11. PCA — Patient-Controlled Analgesia (pca)

Use case: Post-operative pain management, cancer pain, severe acute pain.

Visual: PCA chip + 4-quadrant config card (Basal Rate, Demand Dose, Lockout, 1-hr Cap).

Property Value
Badge color Pink (#ad1457 on #fce4ec)
Icon touch_app
Detection pcaConfig object present, or keyword match (pca|patient.controlled)
Label TH PCA
Label EN Patient-Controlled Analgesia

Features:

  • 2x2 grid showing all PCA parameters at a glance
  • Fields: Basal Rate, Demand Dose, Lockout interval, 1-hour Cap
  • Calculates: Qty = (basal + max demand/hr) x duration

Example data:

orderData: {
  pcaConfig: {
    demand: 1,
    lockout: 8,
    basal: 0.5,
    hourLimit: 10,
    unit: 'mg'
  }
}

12. Range Order (range)

Use case: Nurse-titrated analgesics, sedation ranges, PRN with dose discretion.

Visual: RangeMin–Max chips + gradient bar from min to max.

Property Value
Badge color Green (#33691e on #f1f8e9)
Icon swap_horiz
Detection doseMin != null && doseMax != null && doseMin !== doseMax
Label TH ช่วงขนาดยา
Label EN Range Order

Features:

  • Green gradient bar spanning min→max range
  • Labels at each end show the boundaries
  • Summary explains nurse decision authority and dispensing max

Example data:

orderData: {
  doseMin: 2,
  doseMax: 5
}
// → "Nurse picks 2–5mg per dose — dispense for max (5mg)"

Detection Priority Chain

The detectDosePattern() function uses a priority-based chain to resolve the most specific pattern from order data. Earlier matches take precedence:

1. Explicit dosePattern field     → Use as-is
2. PCA config / keywords          → pca
3. Sliding scale table / keywords → sliding_scale
4. Loading + maintenance doses    → loading_maintenance
5. Taper steps / keywords         → taper
6. Min/Max dose range             → range
7. Cycle on/off days / keywords   → cyclic
8. IV infusion rate + bolus       → bolus_infusion
9. IV infusion rate alone         → continuous
10. Drip/infusion keywords        → continuous
11. Titration keywords            → titration
12. Taper keywords                → taper
13. Cyclic keywords               → cyclic
14. Loading keywords              → loading_maintenance
15. Bolus keywords                → one_time (with push profile)
16. Stat/once priority            → one_time
17. PRN frequency                 → prn
18. timePerDay > 0                → fixed
19. Fallback                      → fixed

Type System

Core Types

type DosePatternKind =
  | 'fixed' | 'prn' | 'one_time' | 'continuous'
  | 'taper' | 'titration' | 'sliding_scale' | 'cyclic'
  | 'loading_maintenance' | 'bolus_infusion' | 'pca' | 'range';

type AdministrationProfile =
  | 'push' | 'slow_push' | 'short_infusion'
  | 'infusion' | 'drip' | 'oral' | 'other';

type DoseDerivation =
  | 'literal' | 'weight_based' | 'bsa_based'
  | 'renal_adjusted' | 'age_based' | 'protocol_lookup';

interface DetectedPattern {
  kind: DosePatternKind;
  adminProfile?: AdministrationProfile;
  doseDerivation?: DoseDerivation;
  params: Record<string, any>;
}

Metadata Registry

Each pattern kind has a DosePatternMeta entry with:

  • label — Bilingual name ({ th, en })
  • color / bgcolor / borderColor — Visual theme
  • icon — Material icon name
  • description — Bilingual tooltip description

Access via: DOSE_PATTERN_META[kind]


Shared UI Components

PatternBadge

Renders the detected pattern’s bilingual label as a color-coded MUI Chip using metadata from DOSE_PATTERN_META.

<PatternBadge kind="pca" />
// → Pink chip: "Patient-Controlled Analgesia"

PatternChip

Lower-level chip with optional icon, used to build chip-flow visualizations.

<PatternChip
  icon={<BoltIcon />}
  label="STAT"
  color="#4a148c"
  bgcolor="#f3e5f5"
  borderColor="#ce93d8"
/>

Arrow

Simple directional connector between chips:

PatternLabel

Caption-style description text below the visualization.


Integration Guide

How it works in the Order Dialog

  1. User selects a medication in the order list
  2. The order edit dialog (DialogNewEditOrder2026.tsx) renders SummaryCard
  3. SummaryCard passes the full order object as orderData to TimePerDay
  4. TimePerDay calls detectDosePattern(orderData) to resolve the pattern kind
  5. The matching visualization component renders automatically

Adding a new pattern kind

  1. Add the kind to DosePatternKind union in dosePatternKind.ts
  2. Add metadata to DOSE_PATTERN_META (label, colors, icon, description)
  3. Add detection logic in detectDosePattern() at the appropriate priority level
  4. Create a visualization component in TimePerDay.tsx (follow existing patterns)
  5. Wire it into the Schedule component’s switch/if chain

Testing in the sandbox

A standalone test target renders all 12 patterns side-by-side:

cd web
pnpm dev:sandbox
# Open: http://localhost:5179/?target=DosePattern

The target is at sandbox/targets/DosePatternTarget.tsx and can be extended with additional test scenarios.


Route & Injection Detection

The system automatically detects IV and injection routes to determine administration profiles:

IV Routes: iv, intravenous, iv push, iv drip, iv infusion, ivpb, iv piggyback

Injection Routes: im, intramuscular, sc, subcutaneous, subcut, sq, id, intradermal


Keyword Detection (Bilingual)

Pattern detection supports Thai and English keywords:

Pattern English Thai
Continuous drip, infusion, continuous หยดต่อเนื่อง, ให้ทางสายน้ำเกลือ
Titration titrat, adjust ไตเตรท, ปรับขนาด
Taper taper, step down, wean ลดขนาด
Cyclic cycl, pulse, on/off รอบ
Loading loading โหลด
Bolus bolus โบลัส
Stat stat, once ครั้งเดียว

Design Tokens

Token Value Usage
Chip font weight 600 All PatternChip labels
Chip font size 12px Small chips
Bar chart height 40-48px Taper, titration, cyclic bars
Drip bar height 8px Continuous infusion progress
Grid gap 1px Sliding scale table, split bars
Border radius 4px (bars), 1px (tables) Consistent rounding
Transition 300ms ease Bar hover effects

Color Palette by Pattern

Kind Primary Background Border
fixed #1b5e20 #e8f5e9 #a5d6a7
prn #e65100 #fff3e0 #ffcc80
one_time #4a148c #f3e5f5 #ce93d8
continuous #01579b #e1f5fe #81d4fa
taper #e65100 #fff3e0 #ffcc80
titration #1565c0 #e3f2fd #90caf9
sliding_scale #6a1b9a #f3e5f5 #ce93d8
cyclic #00695c #e0f2f1 #80cbc4
loading_maintenance #bf360c #fbe9e7 #ffab91
bolus_infusion #283593 #e8eaf6 #9fa8da
pca #ad1457 #fce4ec #f48fb1
range #33691e #f1f8e9 #aed581
Ask Anything